| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkMilestone.h" | 8 #include "SkMilestone.h" |
| 9 #include "SkPDFMetadata.h" | 9 #include "SkPDFMetadata.h" |
| 10 #include "SkPDFTypes.h" | 10 #include "SkPDFTypes.h" |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 *out++ = input[i]; | 256 *out++ = input[i]; |
| 257 } | 257 } |
| 258 } | 258 } |
| 259 if (after) { | 259 if (after) { |
| 260 strncpy(out, after, afterLen); | 260 strncpy(out, after, afterLen); |
| 261 out += afterLen; | 261 out += afterLen; |
| 262 } | 262 } |
| 263 // Validate that we haven't written outside of our string. | 263 // Validate that we haven't written outside of our string. |
| 264 SkASSERT(out == &output.writable_str()[output.size()]); | 264 SkASSERT(out == &output.writable_str()[output.size()]); |
| 265 *out = '\0'; | 265 *out = '\0'; |
| 266 return std::move(output); | 266 return output; |
| 267 } | 267 } |
| 268 | 268 |
| 269 SkPDFObject* SkPDFMetadata::createXMPObject(const UUID& doc, | 269 SkPDFObject* SkPDFMetadata::createXMPObject(const UUID& doc, |
| 270 const UUID& instance) const { | 270 const UUID& instance) const { |
| 271 static const char templateString[] = | 271 static const char templateString[] = |
| 272 "<?xpacket begin=\"\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n" | 272 "<?xpacket begin=\"\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n" |
| 273 "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\"\n" | 273 "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\"\n" |
| 274 " x:xmptk=\"Adobe XMP Core 5.4-c005 78.147326, " | 274 " x:xmptk=\"Adobe XMP Core 5.4-c005 78.147326, " |
| 275 "2012/08/23-13:03:03\">\n" | 275 "2012/08/23-13:03:03\">\n" |
| 276 "<rdf:RDF " | 276 "<rdf:RDF " |
| 277 "xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n" | 277 "xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n" |
| 278 "<rdf:Description rdf:about=\"\"\n" | 278 "<rdf:Description rdf:about=\"\"\n" |
| 279 " xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\"\n" | 279 " xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\"\n" |
| 280 " xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n" | 280 " xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n" |
| 281 " xmlns:xmpMM=\"http://ns.adobe.com/xap/1.0/mm/\"\n" | 281 " xmlns:xmpMM=\"http://ns.adobe.com/xap/1.0/mm/\"\n" |
| 282 " xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\"\n" | 282 " xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\"\n" |
| 283 " xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n" | 283 " xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n" |
| 284 "<pdfaid:part>2</pdfaid:part>\n" | 284 "<pdfaid:part>2</pdfaid:part>\n" |
| 285 "<pdfaid:conformance>B</pdfaid:conformance>\n" | 285 "<pdfaid:conformance>B</pdfaid:conformance>\n" |
| 286 "%s" // ModifyDate | 286 "%s" // ModifyDate |
| 287 "%s" // CreateDate | 287 "%s" // CreateDate |
| 288 "%s" // MetadataDate | |
| 289 "%s" // xmp:CreatorTool | 288 "%s" // xmp:CreatorTool |
| 290 "<dc:format>application/pdf</dc:format>\n" | 289 "<dc:format>application/pdf</dc:format>\n" |
| 291 "%s" // dc:title | 290 "%s" // dc:title |
| 292 "%s" // dc:description | 291 "%s" // dc:description |
| 293 "%s" // author | 292 "%s" // author |
| 294 "%s" // keywords | 293 "%s" // keywords |
| 295 "<xmpMM:DocumentID>uuid:%s</xmpMM:DocumentID>\n" | 294 "<xmpMM:DocumentID>uuid:%s</xmpMM:DocumentID>\n" |
| 296 "<xmpMM:InstanceID>uuid:%s</xmpMM:InstanceID>\n" | 295 "<xmpMM:InstanceID>uuid:%s</xmpMM:InstanceID>\n" |
| 297 "<pdf:Producer>Skia/PDF m" SKPDF_STRING(SK_MILESTONE) "</pdf:Produce
r>\n" | 296 "<pdf:Producer>Skia/PDF m" SKPDF_STRING(SK_MILESTONE) "</pdf:Produce
r>\n" |
| 298 "%s" // pdf:Keywords | 297 "%s" // pdf:Keywords |
| 299 "</rdf:Description>\n" | 298 "</rdf:Description>\n" |
| 300 "</rdf:RDF>\n" | 299 "</rdf:RDF>\n" |
| 301 "</x:xmpmeta>\n" // Note: the standard suggests 4k of padding. | 300 "</x:xmpmeta>\n" // Note: the standard suggests 4k of padding. |
| 302 "<?xpacket end=\"w\"?>\n"; | 301 "<?xpacket end=\"w\"?>\n"; |
| 303 | 302 |
| 304 SkString creationDate; | 303 SkString creationDate; |
| 305 SkString modificationDate; | 304 SkString modificationDate; |
| 306 SkString metadataDate; | |
| 307 if (fCreation) { | 305 if (fCreation) { |
| 308 SkString tmp; | 306 SkString tmp; |
| 309 fCreation->toISO8601(&tmp); | 307 fCreation->toISO8601(&tmp); |
| 310 SkASSERT(0 == count_xml_escape_size(tmp)); | 308 SkASSERT(0 == count_xml_escape_size(tmp)); |
| 311 // YYYY-mm-ddTHH:MM:SS[+|-]ZZ:ZZ; no need to escape | 309 // YYYY-mm-ddTHH:MM:SS[+|-]ZZ:ZZ; no need to escape |
| 312 creationDate = sk_string_printf("<xmp:CreateDate>%s</xmp:CreateDate>\n", | 310 creationDate = sk_string_printf("<xmp:CreateDate>%s</xmp:CreateDate>\n", |
| 313 tmp.c_str()); | 311 tmp.c_str()); |
| 314 } | 312 } |
| 315 if (fModified) { | 313 if (fModified) { |
| 316 SkString tmp; | 314 SkString tmp; |
| 317 fModified->toISO8601(&tmp); | 315 fModified->toISO8601(&tmp); |
| 318 SkASSERT(0 == count_xml_escape_size(tmp)); | 316 SkASSERT(0 == count_xml_escape_size(tmp)); |
| 319 modificationDate = sk_string_printf( | 317 modificationDate = sk_string_printf( |
| 320 "<xmp:ModifyDate>%s</xmp:ModifyDate>\n", tmp.c_str()); | 318 "<xmp:ModifyDate>%s</xmp:ModifyDate>\n", tmp.c_str()); |
| 321 metadataDate = sk_string_printf( | |
| 322 "<xmp:MetadataDate>%s</xmp:MetadataDate>\n", tmp.c_str()); | |
| 323 } | 319 } |
| 324 | 320 SkString title = escape_xml( |
| 325 SkString title = | 321 get(fInfo, "Title"), |
| 326 escape_xml(get(fInfo, "Title"), "<dc:title><rdf:Alt><rdf:li>", | 322 "<dc:title><rdf:Alt><rdf:li xml:lang=\"x-default\">", |
| 327 "</rdf:li></rdf:Alt></dc:title>\n"); | 323 "</rdf:li></rdf:Alt></dc:title>\n"); |
| 328 SkString author = | 324 SkString author = escape_xml( |
| 329 escape_xml(get(fInfo, "Author"), "<dc:creator><rdf:Bag><rdf:li>", | 325 get(fInfo, "Author"), "<dc:creator><rdf:Bag><rdf:li>", |
| 330 "</rdf:li></rdf:Bag></dc:creator>\n"); | 326 "</rdf:li></rdf:Bag></dc:creator>\n"); |
| 331 // TODO: in theory, XMP can support multiple authors. Split on a delimiter? | 327 // TODO: in theory, XMP can support multiple authors. Split on a delimiter? |
| 332 SkString subject = escape_xml(get(fInfo, "Subject"), | 328 SkString subject = escape_xml( |
| 333 "<dc:description><rdf:Alt><rdf:li>", | 329 get(fInfo, "Subject"), |
| 334 "</rdf:li></rdf:Alt></dc:description>\n"); | 330 "<dc:description><rdf:Alt><rdf:li xml:lang=\"x-default\">", |
| 335 SkString keywords1 = | 331 "</rdf:li></rdf:Alt></dc:description>\n"); |
| 336 escape_xml(get(fInfo, "Keywords"), "<dc:subject><rdf:Bag><rdf:li>", | 332 SkString keywords1 = escape_xml( |
| 337 "</rdf:li></rdf:Bag></dc:subject>\n"); | 333 get(fInfo, "Keywords"), "<dc:subject><rdf:Bag><rdf:li>", |
| 338 SkString keywords2 = escape_xml(get(fInfo, "Keywords"), "<pdf:Keywords>", | 334 "</rdf:li></rdf:Bag></dc:subject>\n"); |
| 339 "</pdf:Keywords>\n"); | 335 SkString keywords2 = escape_xml( |
| 336 get(fInfo, "Keywords"), "<pdf:Keywords>", |
| 337 "</pdf:Keywords>\n"); |
| 340 | 338 |
| 341 // TODO: in theory, keywords can be a list too. | 339 // TODO: in theory, keywords can be a list too. |
| 342 SkString creator = escape_xml(get(fInfo, "Creator"), "<xmp:CreatorTool>", | 340 SkString creator = escape_xml(get(fInfo, "Creator"), "<xmp:CreatorTool>", |
| 343 "</xmp:CreatorTool>\n"); | 341 "</xmp:CreatorTool>\n"); |
| 344 SkString documentID = uuid_to_string(doc); // no need to escape | 342 SkString documentID = uuid_to_string(doc); // no need to escape |
| 345 SkASSERT(0 == count_xml_escape_size(documentID)); | 343 SkASSERT(0 == count_xml_escape_size(documentID)); |
| 346 SkString instanceID = uuid_to_string(instance); | 344 SkString instanceID = uuid_to_string(instance); |
| 347 SkASSERT(0 == count_xml_escape_size(instanceID)); | 345 SkASSERT(0 == count_xml_escape_size(instanceID)); |
| 348 return new PDFXMLObject(sk_string_printf( | 346 return new PDFXMLObject(sk_string_printf( |
| 349 templateString, modificationDate.c_str(), creationDate.c_str(), | 347 templateString, modificationDate.c_str(), creationDate.c_str(), |
| 350 metadataDate.c_str(), creator.c_str(), title.c_str(), | 348 creator.c_str(), title.c_str(), |
| 351 subject.c_str(), author.c_str(), keywords1.c_str(), | 349 subject.c_str(), author.c_str(), keywords1.c_str(), |
| 352 documentID.c_str(), instanceID.c_str(), keywords2.c_str())); | 350 documentID.c_str(), instanceID.c_str(), keywords2.c_str())); |
| 353 } | 351 } |
| 354 | 352 |
| 355 #endif // SK_PDF_GENERATE_PDFA | 353 #endif // SK_PDF_GENERATE_PDFA |
| 356 | 354 |
| 357 #undef SKPDF_STRING | 355 #undef SKPDF_STRING |
| 358 #undef SKPDF_STRING_IMPL | 356 #undef SKPDF_STRING_IMPL |
| 359 | 357 |
| OLD | NEW |