1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
|
Author: Vagrant Cascadian <vagrant@reproducible-builds.org>
tony mancill <tmancill@debian.org>
Description: Use SOURCE_DATE_EPOCH environment variable when set instead of
current system time to enable reproducible generation of PDF documents.
If you desire the previous behavior, either unset SOURCE_DATE_EPOCH or
overwrite it to a non-integer value.
Also see: https://reproducible-builds.org/docs/source-date-epoch/
Forwarded: not-needed
Last-Update: 2020-12-31
Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=978499
--- a/fop-core/src/main/java/org/apache/fop/pdf/PDFInfo.java
+++ b/fop-core/src/main/java/org/apache/fop/pdf/PDFInfo.java
@@ -305,9 +305,29 @@
* @return the requested String representation
*/
protected static String formatDateTime(final Date time) {
+ final Date sourceDateEpoch = getSourceDateEpoch();
+ if (sourceDateEpoch != null) {
+ return formatDateTime(sourceDateEpoch, TimeZone.getTimeZone("Etc/UTC"));
+ }
return formatDateTime(time, TimeZone.getDefault());
}
+ /** @return a Date initialized from SOURCE_DATE_EPOCH or null if not set */
+ public static Date getSourceDateEpoch() {
+ // https://reproducible-builds.org/docs/source-date-epoch/
+ // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=978499
+ final String sourceDateEpochString = System.getenv("SOURCE_DATE_EPOCH");
+ if (sourceDateEpochString != null) {
+ try {
+ final Long sourcedate = (1000 * Long.parseLong(sourceDateEpochString));
+ return new Date(sourcedate);
+ } catch (NumberFormatException ignored) {
+ // ignored
+ }
+ }
+ return null;
+ }
+
/**
* Adds a custom property to this Info dictionary.
*/
--- a/fop-core/src/main/java/org/apache/fop/pdf/PDFMetadata.java
+++ b/fop-core/src/main/java/org/apache/fop/pdf/PDFMetadata.java
@@ -134,8 +134,12 @@
//Set creation date if not available, yet
if (info.getCreationDate() == null) {
- Date d = new Date();
- info.setCreationDate(d);
+ final Date sourceDateEpoch = PDFInfo.getSourceDateEpoch();
+ if (sourceDateEpoch != null) {
+ info.setCreationDate(sourceDateEpoch);
+ } else {
+ info.setCreationDate(new Date());
+ }
}
//Important: Acrobat 7's preflight check for PDF/A-1b wants the creation date in the Info
--- a/fop-core/src/main/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
+++ b/fop-core/src/main/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
@@ -259,8 +259,14 @@
}
fopXMP.mergeInto(docXMP, exclude);
XMPBasicAdapter xmpBasic = XMPBasicSchema.getAdapter(docXMP);
- //Metadata was changed so update metadata date
- xmpBasic.setMetadataDate(new java.util.Date());
+ //Metadata was changed so potentially update metadata date
+ final Date sourceDateEpoch = PDFInfo.getSourceDateEpoch();
+ if (sourceDateEpoch != null) {
+ xmpBasic.setMetadataDate(sourceDateEpoch);
+ } else {
+ xmpBasic.setMetadataDate(new Date());
+ }
+
PDFMetadata.updateInfoFromMetadata(docXMP, pdfDoc.getInfo());
PDFMetadata pdfMetadata = pdfDoc.getFactory().makeMetadata(
@@ -478,7 +484,13 @@
augmentDictionary((PDFDictionary)currentPage.get("DPart"), extension);
}
} else if (type == PDFDictionaryType.PagePiece) {
- String date = DateFormatUtil.formatPDFDate(new Date(), TimeZone.getDefault());
+ final Date sourceDateEpoch = PDFInfo.getSourceDateEpoch();
+ final String date;
+ if (sourceDateEpoch != null) {
+ date = DateFormatUtil.formatPDFDate(sourceDateEpoch, TimeZone.getTimeZone("Etc/UTC"));
+ } else {
+ date = DateFormatUtil.formatPDFDate(new Date(), TimeZone.getDefault());
+ }
if (currentPage.get("PieceInfo") == null) {
currentPage.put("PieceInfo", new PDFDictionary());
currentPage.put("LastModified", date);
--- a/fop-core/src/main/java/org/apache/fop/pdf/FileIDGenerator.java
+++ b/fop-core/src/main/java/org/apache/fop/pdf/FileIDGenerator.java
@@ -86,7 +86,12 @@
private void generateFileID() {
DateFormat df = new SimpleDateFormat("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSS");
- digest.update(PDFDocument.encode(df.format(new Date())));
+ final Date sourceDateEpoch = PDFInfo.getSourceDateEpoch();
+ if (sourceDateEpoch != null) {
+ digest.update(PDFDocument.encode(df.format(sourceDateEpoch)));
+ } else {
+ digest.update(PDFDocument.encode(df.format(new Date())));
+ }
// Ignoring the filename here for simplicity even though it's recommended
// by the PDF spec
digest.update(PDFDocument.encode(String.valueOf(document.getCurrentFileSize())));
|