Task 567: .PPSX File Format
Task 567: .PPSX File Format
File Format Specifications for .PPSX
The .PPSX file format is part of the Office Open XML (OOXML) standard, defined in ISO/IEC 29500 (specifically Parts 1 and 4 for PresentationML and DrawingML). It is an XML-based format compressed in a ZIP container using Open Packaging Conventions (OPC). .PPSX is identical in structure to .PPTX but is configured as a slideshow (it opens directly in Slide Show view in compatible software like Microsoft PowerPoint). The key difference is in the content type declaration in [Content_Types].xml, which uses application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml for .PPSX. The format supports slides, themes, media, animations, transitions, and metadata. It is backward-compatible with .PPS files and is the default slideshow format since PowerPoint 2007.
- List of All Properties Intrinsic to the .PPSX File Format
These are the metadata properties stored within the file's structure (in docProps/core.xml for core properties and docProps/app.xml for extended properties). They are intrinsic to the OOXML format and can be read/written without external dependencies. Core properties are based on Dublin Core standards; extended properties are application-specific (for PowerPoint in this case).
Core Properties (from docProps/core.xml):
- category: The categorization of the document content.
- contentStatus: The status of the content (e.g., "Draft", "Final").
- contentType: The type of content (not to be confused with MIME type).
- created: The date and time the document was created.
- creator: The name of the document's author.
- description: A textual description or abstract of the document.
- identifier: A unique identifier for the document.
- keywords: Keywords associated with the document.
- language: The primary language of the document.
- lastModifiedBy: The name of the last user to modify the document.
- lastPrinted: The date and time the document was last printed.
- modified: The date and time the document was last modified.
- revision: The revision number of the document.
- subject: The subject or topic of the document.
- title: The title of the document.
- version: The version number of the document.
Extended Properties (from docProps/app.xml, specific to PowerPoint):
- Template: The name of the template used.
- Manager: The name of the manager associated with the document.
- Company: The company or organization name.
- Pages: The number of pages (for print views).
- Words: The word count.
- Characters: The character count (excluding spaces).
- PresentationFormat: The intended presentation format (e.g., "On-screen", "35mm").
- Lines: The line count.
- Paragraphs: The paragraph count.
- Slides: The number of slides.
- Notes: The number of notes pages.
- TotalTime: The total editing time in minutes.
- HiddenSlides: The number of hidden slides.
- MultimediaClips: The number of multimedia clips (e.g., audio/video).
- ScaleCrop: A boolean indicating if scaling/cropping is applied.
- HeadingPairs: A vector of heading pairs (for outline structure).
- TitlesOfParts: Titles of document parts (e.g., slide titles).
- LinksUpToDate: A boolean indicating if links are up to date.
- CharactersWithSpaces: The character count including spaces.
- SharedDocument: A boolean indicating if the document is shared.
- HyperlinkBase: The base URL for hyperlinks.
- HyperlinkList: A list of hyperlinks.
- HyperlinksChanged: A boolean indicating if hyperlinks have changed.
- DigitalSignature: Information about digital signatures.
- Application: The name of the application that created the document (e.g., "Microsoft Office PowerPoint").
- ApplicationVersion: The version of the application.
- DocumentSecurity: The security level (0-4, where 0 is none).
These properties are stored in XML files within the ZIP archive and can be decoded/encoded programmatically.
- Two Direct Download Links for .PPSX Files
- https://example-files.online-convert.com/presentation/ppsx/example.ppsx
- http://file.fyicenter.com/b/sample.ppsx
- Ghost Blog Embedded HTML JavaScript for Drag-and-Drop .PPSX Property Dump
This is an embeddable HTML snippet with JavaScript (using JSZip for ZIP handling) that can be placed in a Ghost blog post. It creates a drag-and-drop area; when a .PPSX file is dropped, it extracts and displays all the above properties on the screen. Include JSZip via CDN for simplicity.
- Python Class for .PPSX Property Handling
This class uses built-in zipfile and xml.etree.ElementTree to open, read, decode, print, and write properties. To write, it updates the XML and re-zips.
import zipfile
import xml.etree.ElementTree as ET
from io import BytesIO
class PPSXHandler:
def __init__(self, filepath):
self.filepath = filepath
self.core_props = {}
self.ext_props = {}
self._load_properties()
def _load_properties(self):
with zipfile.ZipFile(self.filepath, 'r') as zf:
if 'docProps/core.xml' in zf.namelist():
core_xml = zf.read('docProps/core.xml').decode('utf-8')
core_root = ET.fromstring(core_xml)
cp_ns = {'cp': 'http://schemas.openxmlformats.org/package/2006/metadata/core-properties',
'dc': 'http://purl.org/dc/elements/1.1/'}
for prop in ['category', 'contentStatus', 'contentType', 'created', 'creator', 'description', 'identifier', 'keywords', 'language', 'lastModifiedBy', 'lastPrinted', 'modified', 'revision', 'subject', 'title', 'version']:
elem = core_root.find(f'.//cp:{prop}', cp_ns) or core_root.find(f'.//dc:{prop}', cp_ns)
self.core_props[prop] = elem.text if elem is not None else 'N/A'
if 'docProps/app.xml' in zf.namelist():
app_xml = zf.read('docProps/app.xml').decode('utf-8')
app_root = ET.fromstring(app_xml)
ep_ns = {'ep': 'http://schemas.openxmlformats.org/officeDocument/2006/extended-properties'}
for prop in ['Template', 'Manager', 'Company', 'Pages', 'Words', 'Characters', 'PresentationFormat', 'Lines', 'Paragraphs', 'Slides', 'Notes', 'TotalTime', 'HiddenSlides', 'MultimediaClips', 'ScaleCrop', 'HeadingPairs', 'TitlesOfParts', 'LinksUpToDate', 'CharactersWithSpaces', 'SharedDocument', 'HyperlinkBase', 'HyperlinkList', 'HyperlinksChanged', 'DigitalSignature', 'Application', 'ApplicationVersion', 'DocumentSecurity']:
elem = app_root.find(f'.//ep:{prop}', ep_ns)
self.ext_props[prop] = elem.text if elem is not None else 'N/A'
def print_properties(self):
print("Core Properties:")
for key, value in self.core_props.items():
print(f"{key}: {value}")
print("\nExtended Properties:")
for key, value in self.ext_props.items():
print(f"{key}: {value}")
def write_property(self, prop_name, new_value, is_core=True):
with zipfile.ZipFile(self.filepath, 'r') as zf_in:
mem_file = BytesIO()
with zipfile.ZipFile(mem_file, 'w', zipfile.ZIP_DEFLATED) as zf_out:
for item in zf_in.infolist():
data = zf_in.read(item.filename)
if (is_core and item.filename == 'docProps/core.xml') or (not is_core and item.filename == 'docProps/app.xml'):
root = ET.fromstring(data)
ns = {'cp': 'http://schemas.openxmlformats.org/package/2006/metadata/core-properties',
'dc': 'http://purl.org/dc/elements/1.1/',
'ep': 'http://schemas.openxmlformats.org/officeDocument/2006/extended-properties'}
elem = root.find(f'.//*{{{list(ns.values())[0] if is_core else list(ns.values())[2]}}}{prop_name}', ns)
if elem is not None:
elem.text = new_value
data = ET.tostring(root, encoding='utf-8', xml_declaration=True)
zf_out.writestr(item, data)
mem_file.seek(0)
with open(self.filepath, 'wb') as f:
f.write(mem_file.read())
self._load_properties() # Reload after write
# Example usage:
# handler = PPSXHandler('example.ppsx')
# handler.print_properties()
# handler.write_property('title', 'New Title')
- Java Class for .PPSX Property Handling
This class uses java.util.zip and javax.xml.parsers to handle ZIP and XML.
import java.io.*;
import java.util.zip.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
public class PPSXHandler {
private String filepath;
private java.util.Map<String, String> coreProps = new java.util.HashMap<>();
private java.util.Map<String, String> extProps = new java.util.HashMap<>();
public PPSXHandler(String filepath) {
this.filepath = filepath;
loadProperties();
}
private void loadProperties() {
try (ZipFile zf = new ZipFile(filepath)) {
ZipEntry coreEntry = zf.getEntry("docProps/core.xml");
if (coreEntry != null) {
Document doc = parseXml(zf.getInputStream(coreEntry));
String[] props = {"category", "contentStatus", "contentType", "created", "creator", "description", "identifier", "keywords", "language", "lastModifiedBy", "lastPrinted", "modified", "revision", "subject", "title", "version"};
for (String prop : props) {
Node node = doc.getElementsByTagNameNS("http://schemas.openxmlformats.org/package/2006/metadata/core-properties", prop).item(0);
if (node == null) node = doc.getElementsByTagNameNS("http://purl.org/dc/elements/1.1/", prop).item(0);
coreProps.put(prop, node != null ? node.getTextContent() : "N/A");
}
}
ZipEntry appEntry = zf.getEntry("docProps/app.xml");
if (appEntry != null) {
Document doc = parseXml(zf.getInputStream(appEntry));
String[] props = {"Template", "Manager", "Company", "Pages", "Words", "Characters", "PresentationFormat", "Lines", "Paragraphs", "Slides", "Notes", "TotalTime", "HiddenSlides", "MultimediaClips", "ScaleCrop", "HeadingPairs", "TitlesOfParts", "LinksUpToDate", "CharactersWithSpaces", "SharedDocument", "HyperlinkBase", "HyperlinkList", "HyperlinksChanged", "DigitalSignature", "Application", "ApplicationVersion", "DocumentSecurity"};
for (String prop : props) {
Node node = doc.getElementsByTagNameNS("http://schemas.openxmlformats.org/officeDocument/2006/extended-properties", prop).item(0);
extProps.put(prop, node != null ? node.getTextContent() : "N/A");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private Document parseXml(InputStream is) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new InputSource(is));
}
public void printProperties() {
System.out.println("Core Properties:");
coreProps.forEach((key, value) -> System.out.println(key + ": " + value));
System.out.println("\nExtended Properties:");
extProps.forEach((key, value) -> System.out.println(key + ": " + value));
}
public void writeProperty(String propName, String newValue, boolean isCore) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipFile zfIn = new ZipFile(filepath); ZipOutputStream zos = new ZipOutputStream(baos)) {
java.util.Enumeration<? extends ZipEntry> entries = zfIn.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
InputStream is = zfIn.getInputStream(entry);
zos.putNextEntry(new ZipEntry(entry.getName()));
if ((isCore && entry.getName().equals("docProps/core.xml")) || (!isCore && entry.getName().equals("docProps/app.xml"))) {
Document doc = parseXml(is);
Node node = doc.getElementsByTagNameNS(isCore ? "http://schemas.openxmlformats.org/package/2006/metadata/core-properties" : "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties", propName).item(0);
if (node == null && isCore) node = doc.getElementsByTagNameNS("http://purl.org/dc/elements/1.1/", propName).item(0);
if (node != null) node.setTextContent(newValue);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
t.transform(new DOMSource(doc), new StreamResult(new OutputStreamWriter(zos, "UTF-8")));
} else {
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) > 0) {
zos.write(buffer, 0, len);
}
}
zos.closeEntry();
is.close();
}
}
try (FileOutputStream fos = new FileOutputStream(filepath)) {
fos.write(baos.toByteArray());
}
loadProperties(); // Reload
} catch (Exception e) {
e.printStackTrace();
}
}
// Example usage:
// public static void main(String[] args) {
// PPSXHandler handler = new PPSXHandler("example.ppsx");
// handler.printProperties();
// handler.writeProperty("title", "New Title", true);
// }
}
- JavaScript Class for .PPSX Property Handling
This class uses JSZip for browser/node. For node, require 'jszip' and 'fs'.
const JSZip = require('jszip'); // For Node.js; in browser, use CDN
const fs = require('fs'); // For Node.js
class PPSXHandler {
constructor(filepath) {
this.filepath = filepath;
this.coreProps = {};
this.extProps = {};
}
async loadProperties() {
const data = fs.readFileSync(this.filepath);
const zip = await JSZip.loadAsync(data);
const coreXml = await zip.file('docProps/core.xml')?.async('string');
if (coreXml) {
const parser = new DOMParser();
const doc = parser.parseFromString(coreXml, 'application/xml');
const props = ['category', 'contentStatus', 'contentType', 'created', 'creator', 'description', 'identifier', 'keywords', 'language', 'lastModifiedBy', 'lastPrinted', 'modified', 'revision', 'subject', 'title', 'version'];
props.forEach(prop => {
let elem = doc.querySelector(`[xmlns="http://schemas.openxmlformats.org/package/2006/metadata/core-properties"] > ${prop}`) || doc.querySelector(`[xmlns="http://purl.org/dc/elements/1.1/"] > ${prop}`);
this.coreProps[prop] = elem ? elem.textContent : 'N/A';
});
}
const appXml = await zip.file('docProps/app.xml')?.async('string');
if (appXml) {
const parser = new DOMParser();
const doc = parser.parseFromString(appXml, 'application/xml');
const props = ['Template', 'Manager', 'Company', 'Pages', 'Words', 'Characters', 'PresentationFormat', 'Lines', 'Paragraphs', 'Slides', 'Notes', 'TotalTime', 'HiddenSlides', 'MultimediaClips', 'ScaleCrop', 'HeadingPairs', 'TitlesOfParts', 'LinksUpToDate', 'CharactersWithSpaces', 'SharedDocument', 'HyperlinkBase', 'HyperlinkList', 'HyperlinksChanged', 'DigitalSignature', 'Application', 'ApplicationVersion', 'DocumentSecurity'];
props.forEach(prop => {
let elem = doc.querySelector(`[xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"] > ${prop}`);
this.extProps[prop] = elem ? elem.textContent : 'N/A';
});
}
}
printProperties() {
console.log('Core Properties:');
Object.entries(this.coreProps).forEach(([key, value]) => console.log(`${key}: ${value}`));
console.log('\nExtended Properties:');
Object.entries(this.extProps).forEach(([key, value]) => console.log(`${key}: ${value}`));
}
async writeProperty(propName, newValue, isCore = true) {
const data = fs.readFileSync(this.filepath);
const zip = await JSZip.loadAsync(data);
const xmlPath = isCore ? 'docProps/core.xml' : 'docProps/app.xml';
let xml = await zip.file(xmlPath)?.async('string');
if (xml) {
const parser = new DOMParser();
const doc = parser.parseFromString(xml, 'application/xml');
let elem = doc.querySelector(`${propName}`);
if (elem) elem.textContent = newValue;
const serializer = new XMLSerializer();
zip.file(xmlPath, serializer.serializeToString(doc));
}
const newData = await zip.generateAsync({type: 'nodebuffer'});
fs.writeFileSync(this.filepath, newData);
await this.loadProperties(); // Reload
}
}
// Example usage (Node.js):
// const handler = new PPSXHandler('example.ppsx');
// await handler.loadProperties();
// handler.printProperties();
// await handler.writeProperty('title', 'New Title');
- C++ Class for .PPSX Property Handling
This uses libzip for ZIP handling and tinyxml2 for XML (assume included via headers). Compile with -lzip -ltinyxml2.
#include <iostream>
#include <map>
#include <string>
#include <zip.h>
#include <tinyxml2.h>
class PPSXHandler {
private:
std::string filepath;
std::map<std::string, std::string> coreProps;
std::map<std::string, std::string> extProps;
void loadProperties() {
zip_t* za = zip_open(filepath.c_str(), ZIP_RDONLY, nullptr);
if (!za) return;
struct zip_stat st;
zip_stat_init(&st);
// Core
if (zip_stat(za, "docProps/core.xml", 0, &st) == 0) {
char* contents = new char[st.size + 1];
zip_file_t* f = zip_fopen(za, "docProps/core.xml", 0);
zip_fread(f, contents, st.size);
contents[st.size] = '\0';
zip_fclose(f);
tinyxml2::XMLDocument doc;
doc.Parse(contents);
const char* props[] = {"category", "contentStatus", "contentType", "created", "creator", "description", "identifier", "keywords", "language", "lastModifiedBy", "lastPrinted", "modified", "revision", "subject", "title", "version"};
for (auto prop : props) {
tinyxml2::XMLElement* elem = doc.FirstChildElement("cp:coreProperties")->FirstChildElement(prop);
if (!elem) elem = doc.FirstChildElement("dc:coreProperties")->FirstChildElement(prop); // Fallback namespace
coreProps[prop] = elem ? elem->GetText() : "N/A";
}
delete[] contents;
}
// Extended
if (zip_stat(za, "docProps/app.xml", 0, &st) == 0) {
char* contents = new char[st.size + 1];
zip_file_t* f = zip_fopen(za, "docProps/app.xml", 0);
zip_fread(f, contents, st.size);
contents[st.size] = '\0';
zip_fclose(f);
tinyxml2::XMLDocument doc;
doc.Parse(contents);
const char* props[] = {"Template", "Manager", "Company", "Pages", "Words", "Characters", "PresentationFormat", "Lines", "Paragraphs", "Slides", "Notes", "TotalTime", "HiddenSlides", "MultimediaClips", "ScaleCrop", "HeadingPairs", "TitlesOfParts", "LinksUpToDate", "CharactersWithSpaces", "SharedDocument", "HyperlinkBase", "HyperlinkList", "HyperlinksChanged", "DigitalSignature", "Application", "ApplicationVersion", "DocumentSecurity"};
for (auto prop : props) {
tinyxml2::XMLElement* elem = doc.FirstChildElement("Properties")->FirstChildElement(prop);
extProps[prop] = elem ? elem->GetText() : "N/A";
}
delete[] contents;
}
zip_close(za);
}
public:
PPSXHandler(const std::string& fp) : filepath(fp) {
loadProperties();
}
void printProperties() {
std::cout << "Core Properties:" << std::endl;
for (const auto& pair : coreProps) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
std::cout << "\nExtended Properties:" << std::endl;
for (const auto& pair : extProps) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
}
void writeProperty(const std::string& propName, const std::string& newValue, bool isCore = true) {
zip_t* zaIn = zip_open(filepath.c_str(), ZIP_RDONLY, nullptr);
if (!zaIn) return;
std::string tempFile = filepath + ".tmp";
zip_t* zaOut = zip_open(tempFile.c_str(), ZIP_CREATE | ZIP_TRUNCATE, nullptr);
if (!zaOut) {
zip_close(zaIn);
return;
}
int numEntries = zip_get_num_entries(zaIn, 0);
for (int i = 0; i < numEntries; ++i) {
const char* name = zip_get_name(zaIn, i, 0);
struct zip_stat st;
zip_stat_index(zaIn, i, 0, &st);
char* contents = new char[st.size + 1];
zip_file_t* f = zip_fopen_index(zaIn, i, 0);
zip_fread(f, contents, st.size);
contents[st.size] = '\0';
zip_fclose(f);
bool modify = (isCore && std::string(name) == "docProps/core.xml") || (!isCore && std::string(name) == "docProps/app.xml");
if (modify) {
tinyxml2::XMLDocument doc;
doc.Parse(contents);
tinyxml2::XMLElement* elem = doc.FirstChildElement(isCore ? "cp:coreProperties" : "Properties")->FirstChildElement(propName.c_str());
if (elem) elem->SetText(newValue.c_str());
tinyxml2::XMLPrinter printer;
doc.Print(&printer);
delete[] contents;
contents = const_cast<char*>(printer.CStr());
st.size = printer.Size();
}
zip_source_t* src = zip_source_buffer(zaOut, contents, st.size, 0);
zip_file_add(zaOut, name, src, ZIP_FL_OVERWRITE);
}
zip_close(zaOut);
zip_close(zaIn);
std::remove(filepath.c_str());
std::rename(tempFile.c_str(), filepath.c_str());
loadProperties(); // Reload
}
};
// Example usage:
// int main() {
// PPSXHandler handler("example.ppsx");
// handler.printProperties();
// handler.writeProperty("title", "New Title");
// return 0;
// }