Task 842: .XPS File Format
Task 842: .XPS File Format
XML Paper Specification (.XPS) File Format Specifications
The .XPS file format, known as XML Paper Specification, is a fixed-layout document format developed by Microsoft. It adheres to the Open Packaging Conventions (OPC) standard, utilizing a ZIP container to encapsulate XML-based content, resources, and metadata. The official specifications are detailed in the "XML Paper Specification" document, available for download from Microsoft at https://www.microsoft.com/en-us/download/details.aspx?id=51478. This guide outlines the conventions for using XML to describe document content, including page layout, graphics, text, and embedded resources. Additionally, the format aligns with ECMA-388 standards for interoperability in printing and document exchange. The structure emphasizes fixed pagination, with all necessary resources embedded to ensure consistent rendering across systems.
1. List of Properties Intrinsic to the .XPS File Format
Based on the technical specifications, the properties intrinsic to the .XPS file format relate to its packaging as an OPC-compliant ZIP archive and include core metadata properties defined in the OPC standard. These properties are stored in the /docProps/core.xml file within the archive and are optional but standardized for document metadata. The following list enumerates them:
- Category: A categorization of the document content.
- Content Status: The status of the document (e.g., "Draft" or "Final").
- Content Type: The type of content represented by the document.
- Created: The date and time the document was created (in W3CDTF format).
- Creator: The entity primarily responsible for creating the document content.
- Description: An account of the document content.
- Identifier: A unique identifier for the document.
- Keywords: A delimited list of keywords describing the document.
- Language: The primary language of the document content.
- Last Modified By: The user who last modified the document.
- Last Printed: The date and time the document was last printed (in W3CDTF format).
- Modified: The date and time the document was last modified (in W3CDTF format).
- Revision: The revision number of the document.
- Subject: The topic of the document content.
- Title: The name given to the document.
- Version: The version number of the document.
Additional file-system-level properties include:
- File Extension: .xps
- MIME Type: application/vnd.ms-xpsdocument
- Magic Number: 0x50 0x4B 0x03 0x04 (PK\x03\x04, indicating the ZIP container)
These properties ensure document integrity, metadata consistency, and identification within file systems.
2. Two Direct Download Links for .XPS Files
The following are direct download links to sample .XPS files:
- https://example-files.online-convert.com/document/xps/example.xps
- https://www.xpsdev.com/content/files/xps-document-example.xps
3. HTML JavaScript for Drag-and-Drop .XPS Property Dump
The following is an embeddable HTML snippet with JavaScript suitable for a blog post. It enables users to drag and drop an .XPS file, which is processed as a ZIP archive to extract and display the core properties on the screen. This requires the JSZip library (included via CDN for convenience). The code parses the /docProps/core.xml file and outputs the properties in a structured list.
4. Python Class for .XPS File Handling
The following Python class opens an .XPS file, decodes and reads the core properties from /docProps/core.xml, prints them to the console, and supports writing modified properties back to a new .XPS file. It utilizes zipfile for archive handling and xml.etree.ElementTree for XML parsing.
import zipfile
import xml.etree.ElementTree as ET
from io import BytesIO
class XPSParser:
def __init__(self, filename):
self.filename = filename
self.zip = zipfile.ZipFile(filename, 'r')
self.properties = self._read_properties()
def _read_properties(self):
if 'docProps/core.xml' not in self.zip.namelist():
raise ValueError("Core properties file not found in XPS archive.")
core_xml = self.zip.read('docProps/core.xml')
tree = ET.fromstring(core_xml)
ns = {
'cp': 'http://schemas.openxmlformats.org/package/2006/metadata/core-properties',
'dc': 'http://purl.org/dc/elements/1.1/',
'dcterms': 'http://purl.org/dc/terms/',
'dcmitype': 'http://purl.org/dc/dcmitype/',
'xsi': 'http://www.w3.org/2001/XMLSchema-instance'
}
properties = {
'Title': tree.find('dc:title', ns).text if tree.find('dc:title', ns) is not None else 'N/A',
'Creator': tree.find('dc:creator', ns).text if tree.find('dc:creator', ns) is not None else 'N/A',
'Description': tree.find('dc:description', ns).text if tree.find('dc:description', ns) is not None else 'N/A',
'Subject': tree.find('dc:subject', ns).text if tree.find('dc:subject', ns) is not None else 'N/A',
'Identifier': tree.find('dc:identifier', ns).text if tree.find('dc:identifier', ns) is not None else 'N/A',
'Keywords': tree.find('cp:keywords', ns).text if tree.find('cp:keywords', ns) is not None else 'N/A',
'Language': tree.find('dc:language', ns).text if tree.find('dc:language', ns) is not None else 'N/A',
'Created': tree.find('dcterms:created', ns).text if tree.find('dcterms:created', ns) is not None else 'N/A',
'Modified': tree.find('dcterms:modified', ns).text if tree.find('dcterms:modified', ns) is not None else 'N/A',
'Last Modified By': tree.find('cp:lastModifiedBy', ns).text if tree.find('cp:lastModifiedBy', ns) is not None else 'N/A',
'Revision': tree.find('cp:revision', ns).text if tree.find('cp:revision', ns) is not None else 'N/A',
'Version': tree.find('cp:version', ns).text if tree.find('cp:version', ns) is not None else 'N/A',
'Category': tree.find('cp:category', ns).text if tree.find('cp:category', ns) is not None else 'N/A',
'Content Status': tree.find('cp:contentStatus', ns).text if tree.find('cp:contentStatus', ns) is not None else 'N/A',
'Content Type': tree.find('cp:contentType', ns).text if tree.find('cp:contentType', ns) is not None else 'N/A',
'Last Printed': tree.find('cp:lastPrinted', ns).text if tree.find('cp:lastPrinted', ns) is not None else 'N/A'
}
return properties
def print_properties(self):
for key, value in self.properties.items():
print(f"{key}: {value}")
def set_property(self, key, value):
if key in self.properties:
self.properties[key] = value
else:
raise ValueError(f"Invalid property: {key}")
def write(self, output_filename):
with zipfile.ZipFile(output_filename, 'w', zipfile.ZIP_DEFLATED) as new_zip:
for item in self.zip.infolist():
data = self.zip.read(item.filename)
if item.filename == 'docProps/core.xml':
tree = ET.Element('{http://schemas.openxmlformats.org/package/2006/metadata/core-properties}coreProperties')
ns = {
'cp': 'http://schemas.openxmlformats.org/package/2006/metadata/core-properties',
'dc': 'http://purl.org/dc/elements/1.1/',
'dcterms': 'http://purl.org/dc/terms/'
}
ET.register_namespace('cp', ns['cp'])
ET.register_namespace('dc', ns['dc'])
ET.register_namespace('dcterms', ns['dcterms'])
ET.SubElement(tree, '{http://purl.org/dc/elements/1.1/}title').text = self.properties['Title']
ET.SubElement(tree, '{http://purl.org/dc/elements/1.1/}creator').text = self.properties['Creator']
ET.SubElement(tree, '{http://purl.org/dc/elements/1.1/}description').text = self.properties['Description']
ET.SubElement(tree, '{http://purl.org/dc/elements/1.1/}subject').text = self.properties['Subject']
ET.SubElement(tree, '{http://purl.org/dc/elements/1.1/}identifier').text = self.properties['Identifier']
ET.SubElement(tree, '{http://schemas.openxmlformats.org/package/2006/metadata/core-properties}keywords').text = self.properties['Keywords']
ET.SubElement(tree, '{http://purl.org/dc/elements/1.1/}language').text = self.properties['Language']
created = ET.SubElement(tree, '{http://purl.org/dc/terms/}created')
created.set('{http://www.w3.org/2001/XMLSchema-instance}type', 'dcterms:W3CDTF')
created.text = self.properties['Created']
modified = ET.SubElement(tree, '{http://purl.org/dc/terms/}modified')
modified.set('{http://www.w3.org/2001/XMLSchema-instance}type', 'dcterms:W3CDTF')
modified.text = self.properties['Modified']
ET.SubElement(tree, '{http://schemas.openxmlformats.org/package/2006/metadata/core-properties}lastModifiedBy').text = self.properties['Last Modified By']
ET.SubElement(tree, '{http://schemas.openxmlformats.org/package/2006/metadata/core-properties}revision').text = self.properties['Revision']
ET.SubElement(tree, '{http://schemas.openxmlformats.org/package/2006/metadata/core-properties}version').text = self.properties['Version']
ET.SubElement(tree, '{http://schemas.openxmlformats.org/package/2006/metadata/core-properties}category').text = self.properties['Category']
ET.SubElement(tree, '{http://schemas.openxmlformats.org/package/2006/metadata/core-properties}contentStatus').text = self.properties['Content Status']
ET.SubElement(tree, '{http://schemas.openxmlformats.org/package/2006/metadata/core-properties}contentType').text = self.properties['Content Type']
ET.SubElement(tree, '{http://schemas.openxmlformats.org/package/2006/metadata/core-properties}lastPrinted').text = self.properties['Last Printed']
data = ET.tostring(tree, encoding='utf-8', xml_declaration=True)
new_zip.writestr(item, data)
5. Java Class for .XPS File Handling
The following Java class opens an .XPS file, decodes and reads the core properties, prints them to the console, and supports writing modified properties to a new file. It uses java.util.zip for archive handling and javax.xml.parsers for XML parsing.
import java.io.*;
import java.util.*;
import java.util.zip.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.*;
public class XPSParser {
private String filename;
private Map<String, String> properties;
public XPSParser(String filename) throws IOException, ParserConfigurationException, SAXException {
this.filename = filename;
this.properties = readProperties();
}
private Map<String, String> readProperties() throws IOException, ParserConfigurationException, SAXException {
Map<String, String> props = new HashMap<>();
try (ZipFile zip = new ZipFile(filename)) {
ZipEntry entry = zip.getEntry("docProps/core.xml");
if (entry == null) {
throw new IOException("Core properties file not found.");
}
InputStream is = zip.getInputStream(entry);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(is);
String[] keys = {"title", "creator", "description", "subject", "identifier", "keywords", "language",
"created", "modified", "lastModifiedBy", "revision", "version", "category",
"contentStatus", "contentType", "lastPrinted"};
String[] namespaces = {"http://purl.org/dc/elements/1.1/", "http://purl.org/dc/elements/1.1/",
"http://purl.org/dc/elements/1.1/", "http://purl.org/dc/elements/1.1/",
"http://purl.org/dc/elements/1.1/", "http://schemas.openxmlformats.org/package/2006/metadata/core-properties",
"http://purl.org/dc/elements/1.1/", "http://purl.org/dc/terms/",
"http://purl.org/dc/terms/", "http://schemas.openxmlformats.org/package/2006/metadata/core-properties",
"http://schemas.openxmlformats.org/package/2006/metadata/core-properties", "http://schemas.openxmlformats.org/package/2006/metadata/core-properties",
"http://schemas.openxmlformats.org/package/2006/metadata/core-properties", "http://schemas.openxmlformats.org/package/2006/metadata/core-properties",
"http://schemas.openxmlformats.org/package/2006/metadata/core-properties", "http://schemas.openxmlformats.org/package/2006/metadata/core-properties"};
for (int i = 0; i < keys.length; i++) {
Node node = doc.getElementsByTagNameNS(namespaces[i], keys[i]).item(0);
props.put(capitalize(keys[i]), node != null ? node.getTextContent() : "N/A");
}
}
return props;
}
public void printProperties() {
for (Map.Entry<String, String> entry : properties.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
public void setProperty(String key, String value) {
if (properties.containsKey(key)) {
properties.put(key, value);
} else {
throw new IllegalArgumentException("Invalid property: " + key);
}
}
public void write(String outputFilename) throws IOException, ParserConfigurationException {
try (ZipFile sourceZip = new ZipFile(filename);
ZipOutputStream newZip = new ZipOutputStream(new FileOutputStream(outputFilename))) {
Enumeration<? extends ZipEntry> entries = sourceZip.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
InputStream is = sourceZip.getInputStream(entry);
newZip.putNextEntry(new ZipEntry(entry.getName()));
if (entry.getName().equals("docProps/core.xml")) {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.newDocument();
Element root = doc.createElementNS("http://schemas.openxmlformats.org/package/2006/metadata/core-properties", "cp:coreProperties");
doc.appendChild(root);
root.appendChild(createElement(doc, "dc:title", properties.get("Title")));
root.appendChild(createElement(doc, "dc:creator", properties.get("Creator")));
root.appendChild(createElement(doc, "dc:description", properties.get("Description")));
root.appendChild(createElement(doc, "dc:subject", properties.get("Subject")));
root.appendChild(createElement(doc, "dc:identifier", properties.get("Identifier")));
root.appendChild(createElement(doc, "cp:keywords", properties.get("Keywords")));
root.appendChild(createElement(doc, "dc:language", properties.get("Language")));
Element created = createElement(doc, "dcterms:created", properties.get("Created"));
created.setAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "xsi:type", "dcterms:W3CDTF");
root.appendChild(created);
Element modified = createElement(doc, "dcterms:modified", properties.get("Modified"));
modified.setAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "xsi:type", "dcterms:W3CDTF");
root.appendChild(modified);
root.appendChild(createElement(doc, "cp:lastModifiedBy", properties.get("Last Modified By")));
root.appendChild(createElement(doc, "cp:revision", properties.get("Revision")));
root.appendChild(createElement(doc, "cp:version", properties.get("Version")));
root.appendChild(createElement(doc, "cp:category", properties.get("Category")));
root.appendChild(createElement(doc, "cp:contentStatus", properties.get("Content Status")));
root.appendChild(createElement(doc, "cp:contentType", properties.get("Content Type")));
root.appendChild(createElement(doc, "cp:lastPrinted", properties.get("Last Printed")));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
javax.xml.transform.TransformerFactory.newInstance().newTransformer().transform(
new javax.xml.transform.dom.DOMSource(doc),
new javax.xml.transform.stream.StreamResult(baos));
is.close();
is = new ByteArrayInputStream(baos.toByteArray());
}
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) > 0) {
newZip.write(buffer, 0, len);
}
newZip.closeEntry();
is.close();
}
} catch (Exception e) {
throw new IOException("Error writing XPS file: " + e.getMessage());
}
}
private Element createElement(Document doc, String qName, String text) {
String[] parts = qName.split(":");
String nsUri = parts[0].equals("dc") ? "http://purl.org/dc/elements/1.1/" :
parts[0].equals("dcterms") ? "http://purl.org/dc/terms/" :
"http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
Element elem = doc.createElementNS(nsUri, qName);
if (text != null) elem.setTextContent(text);
return elem;
}
private static String capitalize(String str) {
return str.substring(0, 1).toUpperCase() + str.substring(1).replaceAll("([A-Z])", " $1");
}
}
6. JavaScript Class for .XPS File Handling
The following JavaScript class (for Node.js environment) opens an .XPS file, decodes and reads the core properties, prints them to the console, and supports writing modified properties to a new file. It requires the jszip and fs modules (install via npm if needed).
const fs = require('fs');
const JSZip = require('jszip');
const { DOMParser } = require('xmldom');
class XPSParser {
constructor(filename) {
this.filename = filename;
this.properties = {};
this.load();
}
async load() {
const data = fs.readFileSync(this.filename);
const zip = await JSZip.loadAsync(data);
const coreXml = await zip.file('docProps/core.xml')?.async('string');
if (!coreXml) {
throw new Error('Core properties file not found.');
}
const parser = new DOMParser();
const doc = parser.parseFromString(coreXml);
const getText = (tag) => doc.getElementsByTagName(tag)[0]?.textContent || 'N/A';
this.properties = {
'Title': getText('dc:title'),
'Creator': getText('dc:creator'),
'Description': getText('dc:description'),
'Subject': getText('dc:subject'),
'Identifier': getText('dc:identifier'),
'Keywords': getText('cp:keywords'),
'Language': getText('dc:language'),
'Created': getText('dcterms:created'),
'Modified': getText('dcterms:modified'),
'Last Modified By': getText('cp:lastModifiedBy'),
'Revision': getText('cp:revision'),
'Version': getText('cp:version'),
'Category': getText('cp:category'),
'Content Status': getText('cp:contentStatus'),
'Content Type': getText('cp:contentType'),
'Last Printed': getText('cp:lastPrinted')
};
}
printProperties() {
for (const [key, value] of Object.entries(this.properties)) {
console.log(`${key}: ${value}`);
}
}
setProperty(key, value) {
if (key in this.properties) {
this.properties[key] = value;
} else {
throw new Error(`Invalid property: ${key}`);
}
}
async write(outputFilename) {
const data = fs.readFileSync(this.filename);
const zip = await JSZip.loadAsync(data);
const xmlHeader = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>';
let coreXml = `${xmlHeader}<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">`;
coreXml += `<dc:title>${this.properties['Title']}</dc:title>`;
coreXml += `<dc:creator>${this.properties['Creator']}</dc:creator>`;
coreXml += `<dc:description>${this.properties['Description']}</dc:description>`;
coreXml += `<dc:subject>${this.properties['Subject']}</dc:subject>`;
coreXml += `<dc:identifier>${this.properties['Identifier']}</dc:identifier>`;
coreXml += `<cp:keywords>${this.properties['Keywords']}</cp:keywords>`;
coreXml += `<dc:language>${this.properties['Language']}</dc:language>`;
coreXml += `<dcterms:created xsi:type="dcterms:W3CDTF">${this.properties['Created']}</dcterms:created>`;
coreXml += `<dcterms:modified xsi:type="dcterms:W3CDTF">${this.properties['Modified']}</dcterms:modified>`;
coreXml += `<cp:lastModifiedBy>${this.properties['Last Modified By']}</cp:lastModifiedBy>`;
coreXml += `<cp:revision>${this.properties['Revision']}</cp:revision>`;
coreXml += `<cp:version>${this.properties['Version']}</cp:version>`;
coreXml += `<cp:category>${this.properties['Category']}</cp:category>`;
coreXml += `<cp:contentStatus>${this.properties['Content Status']}</cp:contentStatus>`;
coreXml += `<cp:contentType>${this.properties['Content Type']}</cp:contentType>`;
coreXml += `<cp:lastPrinted>${this.properties['Last Printed']}</cp:lastPrinted>`;
coreXml += `</cp:coreProperties>`;
zip.file('docProps/core.xml', coreXml);
const newData = await zip.generateAsync({type: 'nodebuffer'});
fs.writeFileSync(outputFilename, newData);
}
}
7. C++ Class for .XPS File Handling
The following C++ class opens an .XPS file, decodes and reads the core properties, prints them to the console, and supports writing modified properties to a new file. It requires external libraries like libzip for ZIP handling and tinyxml2 for XML parsing (include via headers and link appropriately in compilation).
#include <iostream>
#include <map>
#include <string>
#include <zip.h>
#include <tinyxml2.h>
class XPSParser {
private:
std::string filename;
std::map<std::string, std::string> properties;
void readProperties() {
zip_t* zip = zip_open(filename.c_str(), ZIP_RDONLY, nullptr);
if (!zip) {
throw std::runtime_error("Failed to open XPS file.");
}
zip_stat_t stat;
if (zip_stat(zip, "docProps/core.xml", 0, &stat) != 0) {
zip_close(zip);
throw std::runtime_error("Core properties file not found.");
}
char* buffer = new char[stat.size];
zip_file_t* file = zip_fopen(zip, "docProps/core.xml", 0);
zip_fread(file, buffer, stat.size);
zip_fclose(file);
zip_close(zip);
tinyxml2::XMLDocument doc;
doc.Parse(buffer, stat.size);
delete[] buffer;
auto getText = [&doc](const char* tag) -> std::string {
auto elem = doc.FirstChildElement("cp:coreProperties")->FirstChildElement(tag);
return elem ? elem->GetText() : "N/A";
};
properties["Title"] = getText("dc:title");
properties["Creator"] = getText("dc:creator");
properties["Description"] = getText("dc:description");
properties["Subject"] = getText("dc:subject");
properties["Identifier"] = getText("dc:identifier");
properties["Keywords"] = getText("cp:keywords");
properties["Language"] = getText("dc:language");
properties["Created"] = getText("dcterms:created");
properties["Modified"] = getText("dcterms:modified");
properties["Last Modified By"] = getText("cp:lastModifiedBy");
properties["Revision"] = getText("cp:revision");
properties["Version"] = getText("cp:version");
properties["Category"] = getText("cp:category");
properties["Content Status"] = getText("cp:contentStatus");
properties["Content Type"] = getText("cp:contentType");
properties["Last Printed"] = getText("cp:lastPrinted");
}
public:
XPSParser(const std::string& fn) : filename(fn) {
readProperties();
}
void printProperties() const {
for (const auto& pair : properties) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
}
void setProperty(const std::string& key, const std::string& value) {
if (properties.find(key) != properties.end()) {
properties[key] = value;
} else {
throw std::invalid_argument("Invalid property: " + key);
}
}
void write(const std::string& outputFilename) {
zip_t* sourceZip = zip_open(filename.c_str(), ZIP_RDONLY, nullptr);
if (!sourceZip) {
throw std::runtime_error("Failed to open source XPS file.");
}
zip_t* newZip = zip_open(outputFilename.c_str(), ZIP_CREATE | ZIP_TRUNCATE, nullptr);
if (!newZip) {
zip_close(sourceZip);
throw std::runtime_error("Failed to create new XPS file.");
}
int numEntries = zip_get_num_entries(sourceZip, 0);
for (int i = 0; i < numEntries; ++i) {
const char* name = zip_get_name(sourceZip, i, 0);
zip_stat_t stat;
zip_stat_index(sourceZip, i, 0, &stat);
char* buffer = new char[stat.size];
zip_file_t* file = zip_fopen_index(sourceZip, i, 0);
zip_fread(file, buffer, stat.size);
zip_fclose(file);
if (std::string(name) == "docProps/core.xml") {
tinyxml2::XMLDocument doc;
tinyxml2::XMLElement* root = doc.NewElement("cp:coreProperties");
root->SetAttribute("xmlns:cp", "http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
root->SetAttribute("xmlns:dc", "http://purl.org/dc/elements/1.1/");
root->SetAttribute("xmlns:dcterms", "http://purl.org/dc/terms/");
root->SetAttribute("xmlns:dcmitype", "http://purl.org/dc/dcmitype/");
root->SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
doc.InsertFirstChild(root);
auto addElem = [&doc, root](const char* tag, const std::string& value) {
tinyxml2::XMLElement* elem = doc.NewElement(tag);
elem->SetText(value.c_str());
root->InsertEndChild(elem);
};
addElem("dc:title", properties["Title"]);
addElem("dc:creator", properties["Creator"]);
addElem("dc:description", properties["Description"]);
addElem("dc:subject", properties["Subject"]);
addElem("dc:identifier", properties["Identifier"]);
addElem("cp:keywords", properties["Keywords"]);
addElem("dc:language", properties["Language"]);
tinyxml2::XMLElement* created = doc.NewElement("dcterms:created");
created->SetAttribute("xsi:type", "dcterms:W3CDTF");
created->SetText(properties["Created"].c_str());
root->InsertEndChild(created);
tinyxml2::XMLElement* modified = doc.NewElement("dcterms:modified");
modified->SetAttribute("xsi:type", "dcterms:W3CDTF");
modified->SetText(properties["Modified"].c_str());
root->InsertEndChild(modified);
addElem("cp:lastModifiedBy", properties["Last Modified By"]);
addElem("cp:revision", properties["Revision"]);
addElem("cp:version", properties["Version"]);
addElem("cp:category", properties["Category"]);
addElem("cp:contentStatus", properties["Content Status"]);
addElem("cp:contentType", properties["Content Type"]);
addElem("cp:lastPrinted", properties["Last Printed"]);
tinyxml2::XMLPrinter printer;
doc.Accept(&printer);
std::string xmlStr = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" + printer.CStr();
delete[] buffer;
buffer = new char[xmlStr.size()];
memcpy(buffer, xmlStr.c_str(), xmlStr.size());
stat.size = xmlStr.size();
}
zip_source_t* source = zip_source_buffer(newZip, buffer, stat.size, 1);
zip_file_add(newZip, name, source, ZIP_FL_OVERWRITE | ZIP_FL_ENC_UTF_8);
}
zip_close(newZip);
zip_close(sourceZip);
}
};