summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorSebastian Rasmussen <sebras@gmail.com>2017-11-13 19:31:29 +0100
committerTor Andersson <tor.andersson@artifex.com>2017-11-22 23:09:51 +0100
commit4bd83a37c63e9aff2938fed9192e815e9d0c1d66 (patch)
treec4da78e07ffd3f2e641fc1ca103d4c432966b329 /source
parented28a166dace50d1a555689b9d5353e62a1b1e69 (diff)
downloadmupdf-4bd83a37c63e9aff2938fed9192e815e9d0c1d66.tar.xz
jni/js: Add support for annotation modification dates.
Diffstat (limited to 'source')
-rw-r--r--source/pdf/pdf-annot-edit.c129
-rw-r--r--source/tools/murun.c30
2 files changed, 154 insertions, 5 deletions
diff --git a/source/pdf/pdf-annot-edit.c b/source/pdf/pdf-annot-edit.c
index 09e63002..730d7b93 100644
--- a/source/pdf/pdf-annot-edit.c
+++ b/source/pdf/pdf-annot-edit.c
@@ -2,9 +2,16 @@
#include "mupdf/pdf.h"
#include <string.h>
+#include <time.h>
+
+#ifdef _WIN32
+#define timegm _mkgmtime
+#endif
#define TEXT_ANNOT_SIZE (25.0f)
+#define isdigit(c) (c >= '0' && c <= '9')
+
const char *
pdf_string_from_annot_type(fz_context *ctx, fz_annot_type type)
{
@@ -280,7 +287,6 @@ static pdf_obj *open_subtypes[] = {
NULL,
};
-
int
pdf_annot_has_open(fz_context *ctx, pdf_annot *annot)
{
@@ -843,6 +849,106 @@ pdf_set_text_annot_position(fz_context *ctx, pdf_annot *annot, fz_point pt)
pdf_dict_put_drop(ctx, annot->obj, PDF_NAME_F, pdf_new_int(ctx, doc, flags));
}
+static void
+pdf_format_date(fz_context *ctx, char *s, int n, time_t secs)
+{
+#ifdef _POSIX_SOURCE
+ struct tm tmbuf, *tm = gmtime_r(&secs, &tmbuf);
+#else
+ struct tm *tm = gmtime(&secs);
+#endif
+ if (!tm)
+ fz_strlcpy(s, "D:19700101000000Z", n);
+ else
+ strftime(s, n, "D:%Y%m%d%H%M%SZ", tm);
+}
+
+static int
+pdf_parse_date(fz_context *ctx, const char *s)
+{
+ int tz_sign, tz_hour, tz_min, tz_adj;
+ struct tm tm;
+ time_t utc;
+
+ if (!s)
+ return 0;
+
+ memset(&tm, 0, sizeof tm);
+ tm.tm_mday = 1;
+
+ tz_sign = 1;
+ tz_hour = 0;
+ tz_min = 0;
+
+ if (s[0] == 'D' && s[1] == ':')
+ s += 2;
+
+ if (!isdigit(s[0]) || !isdigit(s[1]) || !isdigit(s[2]) || !isdigit(s[3]))
+ {
+ fz_warn(ctx, "invalid date format (missing year)");
+ return 0;
+ }
+ tm.tm_year = (s[0]-'0')*1000 + (s[1]-'0')*100 + (s[2]-'0')*10 + (s[3]-'0') - 1900;
+ s += 4;
+
+ if (isdigit(s[0]) && isdigit(s[1]))
+ {
+ tm.tm_mon = (s[0]-'0')*10 + (s[1]-'0') - 1; /* month is 0-11 in struct tm */
+ s += 2;
+ if (isdigit(s[0]) && isdigit(s[1]))
+ {
+ tm.tm_mday = (s[0]-'0')*10 + (s[1]-'0');
+ s += 2;
+ if (isdigit(s[0]) && isdigit(s[1]))
+ {
+ tm.tm_hour = (s[0]-'0')*10 + (s[1]-'0');
+ s += 2;
+ if (isdigit(s[0]) && isdigit(s[1]))
+ {
+ tm.tm_min = (s[0]-'0')*10 + (s[1]-'0');
+ s += 2;
+ if (isdigit(s[0]) && isdigit(s[1]))
+ {
+ tm.tm_sec = (s[0]-'0')*10 + (s[1]-'0');
+ s += 2;
+ }
+ }
+ }
+ }
+ }
+
+ if (s[0] == 'Z')
+ {
+ s += 1;
+ }
+ else if ((s[0] == '-' || s[0] == '+') && isdigit(s[1]) && isdigit(s[2]))
+ {
+ tz_sign = (s[0] == '-') ? -1 : 1;
+ tz_hour = (s[1]-'0')*10 + (s[2]-'0');
+ s += 3;
+ if (s[0] == '\'' && isdigit(s[1]) && isdigit(s[2]))
+ {
+ tz_min = (s[1]-'0')*10 + (s[2]-'0');
+ s += 3;
+ if (s[0] == '\'')
+ s += 1;
+ }
+ }
+
+ if (s[0] != 0)
+ fz_warn(ctx, "invalid date format (garbage at end)");
+
+ utc = timegm(&tm);
+ if (utc == (time_t)-1)
+ {
+ fz_warn(ctx, "date overflow error");
+ return 0;
+ }
+
+ tz_adj = tz_sign * (tz_hour * 3600 + tz_min * 60);
+ return utc - tz_adj;
+}
+
static pdf_obj *markup_subtypes[] = {
PDF_NAME_Text,
PDF_NAME_FreeText,
@@ -863,11 +969,24 @@ static pdf_obj *markup_subtypes[] = {
NULL,
};
-const char *
-pdf_annot_date(fz_context *ctx, pdf_annot *annot)
+int
+pdf_annot_modification_date(fz_context *ctx, pdf_annot *annot)
{
- // TODO: PDF_NAME_M
- return pdf_to_str_buf(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME_CreationDate));
+ pdf_obj *date = pdf_dict_get(ctx, annot->obj, PDF_NAME_M);
+ return date ? pdf_parse_date(ctx, pdf_to_str_buf(ctx, date)) : 0;
+}
+
+void
+pdf_set_annot_modification_date(fz_context *ctx, pdf_annot *annot, int secs)
+{
+ pdf_document *doc = annot->page->doc;
+ char s[40];
+
+ check_allowed_subtypes(ctx, annot, PDF_NAME_M, markup_subtypes);
+
+ pdf_format_date(ctx, s, sizeof s, secs);
+ pdf_dict_put_drop(ctx, annot->obj, PDF_NAME_M, pdf_new_string(ctx, doc, s, strlen(s)));
+ pdf_dirty_annot(ctx, annot);
}
int
diff --git a/source/tools/murun.c b/source/tools/murun.c
index 69765164..3b03e8f7 100644
--- a/source/tools/murun.c
+++ b/source/tools/murun.c
@@ -4312,6 +4312,34 @@ static void ffi_PDFAnnotation_setAuthor(js_State *J)
rethrow(J);
}
+static void ffi_PDFAnnotation_getModificationDate(js_State *J)
+{
+ fz_context *ctx = js_getcontext(J);
+ pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
+ double time;
+
+ fz_try(ctx)
+ time = pdf_annot_modification_date(ctx, annot);
+ fz_catch(ctx)
+ rethrow(J);
+
+ js_getglobal(J, "Date");
+ js_pushnumber(J, time * 1000);
+ js_construct(J, 1);
+}
+
+static void ffi_PDFAnnotation_setModificationDate(js_State *J)
+{
+ fz_context *ctx = js_getcontext(J);
+ pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
+ double time = js_tonumber(J, 1);
+
+ fz_try(ctx)
+ pdf_set_annot_modification_date(ctx, annot, time / 1000);
+ fz_catch(ctx)
+ rethrow(J);
+}
+
static void ffi_PDFAnnotation_updateAppearance(js_State *J)
{
fz_context *ctx = js_getcontext(J);
@@ -4643,6 +4671,8 @@ int murun_main(int argc, char **argv)
jsB_propfun(J, "PDFAnnotation.setInkList", ffi_PDFAnnotation_setInkList, 1);
jsB_propfun(J, "PDFAnnotation.getAuthor", ffi_PDFAnnotation_getAuthor, 0);
jsB_propfun(J, "PDFAnnotation.setAuthor", ffi_PDFAnnotation_setAuthor, 1);
+ jsB_propfun(J, "PDFAnnotation.getModificationDate", ffi_PDFAnnotation_getModificationDate, 0);
+ jsB_propfun(J, "PDFAnnotation.setModificationDate", ffi_PDFAnnotation_setModificationDate, 0);
jsB_propfun(J, "PDFAnnotation.updateAppearance", ffi_PDFAnnotation_updateAppearance, 0);
}
js_setregistry(J, "pdf_annot");