std::unique_ptr<SkPDFObject> SkPDFMetadata::MakeDocumentInformationDict( const SkPDF::Metadata& metadata) { auto dict = SkPDFMakeDict(); for (constauto keyValuePtr : gMetadataKeys) { const SkString& value = metadata.*(keyValuePtr.valuePtr); if (value.size() > 0) {
dict->insertTextString(keyValuePtr.key, value);
}
} if (metadata.fCreation != kZeroTime) {
dict->insertTextString("CreationDate", pdf_date(metadata.fCreation));
} if (metadata.fModified != kZeroTime) {
dict->insertTextString("ModDate", pdf_date(metadata.fModified));
} return dict;
}
SkUUID SkPDFMetadata::CreateUUID(const SkPDF::Metadata& metadata) { // The main requirement is for the UUID to be unique; the exact // format of the data that will be hashed is not important.
SkMD5 md5; constchar uuidNamespace[] = "org.skia.pdf\n";
md5.writeText(uuidNamespace); double msec = SkTime::GetMSecs();
md5.write(&msec, sizeof(msec));
SkPDF::DateTime dateTime;
SkPDFUtils::GetDateTime(&dateTime);
md5.write(&dateTime, sizeof(dateTime));
md5.write(&metadata.fCreation, sizeof(metadata.fCreation));
md5.write(&metadata.fModified, sizeof(metadata.fModified));
// Convert a block of memory to hexadecimal. Input and output pointers will be // moved to end of the range. staticvoid hexify(const uint8_t** inputPtr, char** outputPtr, int count) {
SkASSERT(inputPtr && *inputPtr);
SkASSERT(outputPtr && *outputPtr); while (count-- > 0) {
uint8_t value = *(*inputPtr)++;
*(*outputPtr)++ = SkHexadecimalDigits::gLower[value >> 4];
*(*outputPtr)++ = SkHexadecimalDigits::gLower[value & 0xF];
}
}
namespace { class PDFXMLObject final : public SkPDFObject { public:
PDFXMLObject(SkString xml) : fXML(std::move(xml)) {} void emitObject(SkWStream* stream) const override {
SkPDFDict dict("Metadata");
dict.insertName("Subtype", "XML");
dict.insertInt("Length", fXML.size());
dict.emitObject(stream); staticconstchar streamBegin[] = " stream\n";
stream->writeText(streamBegin); // Do not compress this. The standard requires that a // program that does not understand PDF can grep for // "<?xpacket" and extract the entire XML.
stream->write(fXML.c_str(), fXML.size()); staticconstchar streamEnd[] = "\nendstream";
stream->writeText(streamEnd);
}
private: const SkString fXML;
};
} // namespace
staticint count_xml_escape_size(const SkString& input) { int extra = 0; for (size_t i = 0; i < input.size(); ++i) { if (input[i] == '&') {
extra += 4; // strlen("&") - strlen("&")
} elseif (input[i] == '<') {
extra += 3; // strlen("<") - strlen("<")
}
} return extra;
}
SkString escape_xml(const SkString& input, constchar* before = nullptr, constchar* after = nullptr) { if (input.size() == 0) { return input;
} // "&" --> "&" and "<" --> "<" // text is assumed to be in UTF-8 // all strings are xml content, not attribute values.
size_t beforeLen = before ? strlen(before) : 0;
size_t afterLen = after ? strlen(after) : 0; int extra = count_xml_escape_size(input);
SkString output(input.size() + extra + beforeLen + afterLen); char* out = output.data(); if (before) {
strncpy(out, before, beforeLen);
out += beforeLen;
} staticconstchar kAmp[] = "&"; staticconstchar kLt[] = "<"; for (size_t i = 0; i < input.size(); ++i) { if (input[i] == '&') {
memcpy(out, kAmp, strlen(kAmp));
out += strlen(kAmp);
} elseif (input[i] == '<') {
memcpy(out, kLt, strlen(kLt));
out += strlen(kLt);
} else {
*out++ = input[i];
}
} if (after) {
strncpy(out, after, afterLen);
out += afterLen;
} // Validate that we haven't written outside of our string.
SkASSERT(out == &output.data()[output.size()]);
*out = '\0'; return output;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.