summaryrefslogtreecommitdiff
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
parented28a166dace50d1a555689b9d5353e62a1b1e69 (diff)
downloadmupdf-4bd83a37c63e9aff2938fed9192e815e9d0c1d66.tar.xz
jni/js: Add support for annotation modification dates.
-rw-r--r--include/mupdf/pdf/annot.h11
-rw-r--r--platform/java/example/Viewer.java1
-rw-r--r--platform/java/mupdf_native.c35
-rw-r--r--platform/java/mupdf_native.h16
-rw-r--r--platform/java/src/com/artifex/mupdf/fitz/PDFAnnotation.java10
-rw-r--r--source/pdf/pdf-annot-edit.c129
-rw-r--r--source/tools/murun.c30
7 files changed, 223 insertions, 9 deletions
diff --git a/include/mupdf/pdf/annot.h b/include/mupdf/pdf/annot.h
index e03ded3f..bebe77f7 100644
--- a/include/mupdf/pdf/annot.h
+++ b/include/mupdf/pdf/annot.h
@@ -205,11 +205,14 @@ char *pdf_copy_annot_author(fz_context *ctx, pdf_annot *annot);
void pdf_set_annot_author(fz_context *ctx, pdf_annot *annot, const char *author);
/*
- pdf_annot_author: return the date of an annotation.
+ pdf_annot_modification_date: Get annotation's modification date in seconds since the epoch.
*/
-// TODO: creation date
-// TODO: modification date
-const char *pdf_annot_date(fz_context *ctx, pdf_annot *annot);
+int pdf_annot_modification_date(fz_context *ctx, pdf_annot *annot);
+
+/*
+ pdf_set_annot_modification_date: Set annotation's modification date in seconds since the epoch.
+*/
+void pdf_set_annot_modification_date(fz_context *ctx, pdf_annot *annot, int time);
/*
pdf_annot_irt: return the indirect reference that this annotation is in reply to.
diff --git a/platform/java/example/Viewer.java b/platform/java/example/Viewer.java
index a559c218..e9a24eae 100644
--- a/platform/java/example/Viewer.java
+++ b/platform/java/example/Viewer.java
@@ -10,6 +10,7 @@ import java.io.File;
import java.io.FilenameFilter;
import java.lang.reflect.Field;
import java.util.Vector;
+import java.util.Date;
public class Viewer extends Frame implements WindowListener, ActionListener, ItemListener, TextListener
{
diff --git a/platform/java/mupdf_native.c b/platform/java/mupdf_native.c
index 890bc6b1..eda01ed9 100644
--- a/platform/java/mupdf_native.c
+++ b/platform/java/mupdf_native.c
@@ -8300,6 +8300,41 @@ FUN(PDFAnnotation_setAuthor)(JNIEnv *env, jobject self, jstring jauthor)
jni_rethrow(env, ctx);
}
+JNIEXPORT jlong JNICALL
+FUN(PDFAnnotation_getModificationDateNative)(JNIEnv *env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ pdf_annot *annot = from_PDFAnnotation(env, self);
+ jlong t;
+
+ if (!ctx || !annot) return -1;
+
+ fz_try(ctx)
+ t = pdf_annot_modification_date(ctx, annot);
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ return -1;
+ }
+
+ return t * 1000;
+}
+
+JNIEXPORT void JNICALL
+FUN(PDFAnnotation_setModificationDate)(JNIEnv *env, jobject self, jlong time)
+{
+ fz_context *ctx = get_context(env);
+ pdf_annot *annot = from_PDFAnnotation(env, self);
+
+ fz_try(ctx)
+ pdf_set_annot_modification_date(ctx, annot, time / 1000);
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ return;
+ }
+}
+
JNIEXPORT jobject JNICALL
FUN(PDFAnnotation_getRect)(JNIEnv *env, jobject self)
{
diff --git a/platform/java/mupdf_native.h b/platform/java/mupdf_native.h
index dfc62d85..2065f93e 100644
--- a/platform/java/mupdf_native.h
+++ b/platform/java/mupdf_native.h
@@ -1522,6 +1522,22 @@ JNIEXPORT void JNICALL Java_com_artifex_mupdf_fitz_PDFAnnotation_setAuthor
/*
* Class: com_artifex_mupdf_fitz_PDFAnnotation
+ * Method: getModificationDateNative
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_com_artifex_mupdf_fitz_PDFAnnotation_getModificationDateNative
+ (JNIEnv *, jobject);
+
+/*
+ * Class: com_artifex_mupdf_fitz_PDFAnnotation
+ * Method: setModificationDate
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_artifex_mupdf_fitz_PDFAnnotation_setModificationDate
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: com_artifex_mupdf_fitz_PDFAnnotation
* Method: getLineEndingStyles
* Signature: ()[I
*/
diff --git a/platform/java/src/com/artifex/mupdf/fitz/PDFAnnotation.java b/platform/java/src/com/artifex/mupdf/fitz/PDFAnnotation.java
index f836a601..52a433de 100644
--- a/platform/java/src/com/artifex/mupdf/fitz/PDFAnnotation.java
+++ b/platform/java/src/com/artifex/mupdf/fitz/PDFAnnotation.java
@@ -1,5 +1,7 @@
package com.artifex.mupdf.fitz;
+import java.util.Date;
+
public class PDFAnnotation extends Annotation
{
static {
@@ -62,6 +64,14 @@ public class PDFAnnotation extends Annotation
public native void setInteriorColor(float[] color);
public native String getAuthor();
public native void setAuthor(String author);
+ protected native long getModificationDateNative();
+ protected native void setModificationDate(long time);
+ public Date getModificationDate() {
+ return new Date(getModificationDateNative());
+ }
+ public void setModificationDate(Date date) {
+ setModificationDate(date.getTime());
+ }
public native int[] getLineEndingStyles();
public native void setLineEndingStyles(int startStyle, int endStyle);
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");