ppt-codec 0.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +174 -0
  3. package/dist/content.cjs +72 -0
  4. package/dist/content.d.cts +6 -0
  5. package/dist/content.d.ts +6 -0
  6. package/dist/content.js +71 -0
  7. package/dist/document/document-atom.cjs +27 -0
  8. package/dist/document/document-atom.d.cts +17 -0
  9. package/dist/document/document-atom.d.ts +17 -0
  10. package/dist/document/document-atom.js +26 -0
  11. package/dist/document/fonts.cjs +29 -0
  12. package/dist/document/fonts.d.cts +5 -0
  13. package/dist/document/fonts.d.ts +5 -0
  14. package/dist/document/fonts.js +28 -0
  15. package/dist/document/slide-list.cjs +40 -0
  16. package/dist/document/slide-list.d.cts +14 -0
  17. package/dist/document/slide-list.d.ts +14 -0
  18. package/dist/document/slide-list.js +39 -0
  19. package/dist/drawing/shapes.cjs +109 -0
  20. package/dist/drawing/shapes.d.cts +16 -0
  21. package/dist/drawing/shapes.d.ts +16 -0
  22. package/dist/drawing/shapes.js +108 -0
  23. package/dist/errors.cjs +17 -0
  24. package/dist/errors.d.cts +9 -0
  25. package/dist/errors.d.ts +9 -0
  26. package/dist/errors.js +15 -0
  27. package/dist/header-C5eAd16_.d.cts +13 -0
  28. package/dist/header-C5eAd16_.d.ts +13 -0
  29. package/dist/index.cjs +112 -0
  30. package/dist/index.d.cts +16 -0
  31. package/dist/index.d.ts +16 -0
  32. package/dist/index.js +16 -0
  33. package/dist/read.cjs +119 -0
  34. package/dist/read.d.cts +13 -0
  35. package/dist/read.d.ts +13 -0
  36. package/dist/read.js +114 -0
  37. package/dist/record/header.cjs +25 -0
  38. package/dist/record/header.d.cts +2 -0
  39. package/dist/record/header.d.ts +2 -0
  40. package/dist/record/header.js +21 -0
  41. package/dist/record/tree.cjs +55 -0
  42. package/dist/record/tree.d.cts +2 -0
  43. package/dist/record/tree.d.ts +2 -0
  44. package/dist/record/tree.js +49 -0
  45. package/dist/record/types.cjs +87 -0
  46. package/dist/record/types.d.cts +45 -0
  47. package/dist/record/types.d.ts +45 -0
  48. package/dist/record/types.js +45 -0
  49. package/dist/stream/current-user.cjs +49 -0
  50. package/dist/stream/current-user.d.cts +11 -0
  51. package/dist/stream/current-user.d.ts +11 -0
  52. package/dist/stream/current-user.js +46 -0
  53. package/dist/stream/persist.cjs +71 -0
  54. package/dist/stream/persist.d.cts +20 -0
  55. package/dist/stream/persist.d.ts +20 -0
  56. package/dist/stream/persist.js +67 -0
  57. package/dist/text/atoms.cjs +70 -0
  58. package/dist/text/atoms.d.cts +22 -0
  59. package/dist/text/atoms.d.ts +22 -0
  60. package/dist/text/atoms.js +56 -0
  61. package/dist/text/style.cjs +173 -0
  62. package/dist/text/style.d.cts +39 -0
  63. package/dist/text/style.d.ts +39 -0
  64. package/dist/text/style.js +165 -0
  65. package/dist/tree-Du_LXAF0.d.cts +17 -0
  66. package/dist/tree-PMcPNgd-.d.ts +17 -0
  67. package/dist/units.cjs +12 -0
  68. package/dist/units.d.cts +6 -0
  69. package/dist/units.d.ts +6 -0
  70. package/dist/units.js +9 -0
  71. package/package.json +93 -2
@@ -0,0 +1,49 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_errors = require("../errors.cjs");
3
+ const require_record_tree = require("../record/tree.cjs");
4
+ const require_record_types = require("../record/types.cjs");
5
+ //#region src/stream/current-user.ts
6
+ const CURRENT_USER_HEADER_TOKEN_PLAIN = 3817979999;
7
+ const CURRENT_USER_HEADER_TOKEN_ENCRYPTED = 4090610911;
8
+ const CURRENT_USER_FIXED_SIZE = 20;
9
+ const CURRENT_USER_DOC_FILE_VERSION = 1012;
10
+ function decodeAnsi(bytes) {
11
+ let text = "";
12
+ for (const byte of bytes) text += String.fromCharCode(byte);
13
+ return text;
14
+ }
15
+ function decodeUtf16Le(bytes) {
16
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
17
+ let text = "";
18
+ for (let at = 0; at + 1 < bytes.length; at += 2) text += String.fromCharCode(view.getUint16(at, true));
19
+ return text;
20
+ }
21
+ function readCurrentUserAtom(streamBytes) {
22
+ const record = require_record_tree.readRecordAt(streamBytes, 0);
23
+ if (record.header.recType !== 4086) throw new require_errors.PptFormatError(`Current User stream begins with record type 0x${record.header.recType.toString(16)}, not RT_CurrentUserAtom (0x${require_record_types.RT_CurrentUserAtom.toString(16)})`);
24
+ const { data } = record;
25
+ if (data.length < CURRENT_USER_FIXED_SIZE) throw new require_errors.PptFormatError(`CurrentUserAtom carries ${data.length} bytes of data, fewer than the ${CURRENT_USER_FIXED_SIZE}-byte fixed portion the record requires`);
26
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
27
+ const size = view.getUint32(0, true);
28
+ if (size !== CURRENT_USER_FIXED_SIZE) throw new require_errors.PptFormatError(`CurrentUserAtom size field is 0x${size.toString(16)}, not the mandated 0x${CURRENT_USER_FIXED_SIZE.toString(16)}`);
29
+ const headerToken = view.getUint32(4, true);
30
+ if (headerToken !== 3817979999 && headerToken !== 4090610911) throw new require_errors.PptFormatError(`CurrentUserAtom headerToken is 0x${headerToken.toString(16)}, neither the plaintext 0x${CURRENT_USER_HEADER_TOKEN_PLAIN.toString(16)} nor the encrypted 0x${CURRENT_USER_HEADER_TOKEN_ENCRYPTED.toString(16)}`);
31
+ const offsetToCurrentEdit = view.getUint32(8, true);
32
+ const lenUserName = view.getUint16(12, true);
33
+ const docFileVersion = view.getUint16(14, true);
34
+ if (docFileVersion !== CURRENT_USER_DOC_FILE_VERSION) throw new require_errors.PptFormatError(`CurrentUserAtom docFileVersion is 0x${docFileVersion.toString(16)}, not the mandated 0x${CURRENT_USER_DOC_FILE_VERSION.toString(16)}`);
35
+ const ansiEnd = CURRENT_USER_FIXED_SIZE + lenUserName;
36
+ if (ansiEnd > data.length) throw new require_errors.PptFormatError(`CurrentUserAtom declares a ${lenUserName}-byte ansiUserName that runs past the record's ${data.length} bytes`);
37
+ const unicodeStart = ansiEnd + 4;
38
+ const unicodeEnd = unicodeStart + lenUserName * 2;
39
+ const userName = unicodeEnd <= data.length && lenUserName > 0 ? decodeUtf16Le(data.subarray(unicodeStart, unicodeEnd)) : decodeAnsi(data.subarray(CURRENT_USER_FIXED_SIZE, ansiEnd));
40
+ return {
41
+ offsetToCurrentEdit,
42
+ encrypted: headerToken === CURRENT_USER_HEADER_TOKEN_ENCRYPTED,
43
+ userName
44
+ };
45
+ }
46
+ //#endregion
47
+ exports.CURRENT_USER_HEADER_TOKEN_ENCRYPTED = CURRENT_USER_HEADER_TOKEN_ENCRYPTED;
48
+ exports.CURRENT_USER_HEADER_TOKEN_PLAIN = CURRENT_USER_HEADER_TOKEN_PLAIN;
49
+ exports.readCurrentUserAtom = readCurrentUserAtom;
@@ -0,0 +1,11 @@
1
+ //#region src/stream/current-user.d.ts
2
+ declare const CURRENT_USER_HEADER_TOKEN_PLAIN = 3817979999;
3
+ declare const CURRENT_USER_HEADER_TOKEN_ENCRYPTED = 4090610911;
4
+ interface CurrentUser {
5
+ readonly offsetToCurrentEdit: number;
6
+ readonly encrypted: boolean;
7
+ readonly userName: string;
8
+ }
9
+ declare function readCurrentUserAtom(streamBytes: Uint8Array<ArrayBuffer>): CurrentUser;
10
+ //#endregion
11
+ export { CURRENT_USER_HEADER_TOKEN_ENCRYPTED, CURRENT_USER_HEADER_TOKEN_PLAIN, CurrentUser, readCurrentUserAtom };
@@ -0,0 +1,11 @@
1
+ //#region src/stream/current-user.d.ts
2
+ declare const CURRENT_USER_HEADER_TOKEN_PLAIN = 3817979999;
3
+ declare const CURRENT_USER_HEADER_TOKEN_ENCRYPTED = 4090610911;
4
+ interface CurrentUser {
5
+ readonly offsetToCurrentEdit: number;
6
+ readonly encrypted: boolean;
7
+ readonly userName: string;
8
+ }
9
+ declare function readCurrentUserAtom(streamBytes: Uint8Array<ArrayBuffer>): CurrentUser;
10
+ //#endregion
11
+ export { CURRENT_USER_HEADER_TOKEN_ENCRYPTED, CURRENT_USER_HEADER_TOKEN_PLAIN, CurrentUser, readCurrentUserAtom };
@@ -0,0 +1,46 @@
1
+ import { PptFormatError } from "../errors.js";
2
+ import { readRecordAt } from "../record/tree.js";
3
+ import { RT_CurrentUserAtom } from "../record/types.js";
4
+ //#region src/stream/current-user.ts
5
+ const CURRENT_USER_HEADER_TOKEN_PLAIN = 3817979999;
6
+ const CURRENT_USER_HEADER_TOKEN_ENCRYPTED = 4090610911;
7
+ const CURRENT_USER_FIXED_SIZE = 20;
8
+ const CURRENT_USER_DOC_FILE_VERSION = 1012;
9
+ function decodeAnsi(bytes) {
10
+ let text = "";
11
+ for (const byte of bytes) text += String.fromCharCode(byte);
12
+ return text;
13
+ }
14
+ function decodeUtf16Le(bytes) {
15
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
16
+ let text = "";
17
+ for (let at = 0; at + 1 < bytes.length; at += 2) text += String.fromCharCode(view.getUint16(at, true));
18
+ return text;
19
+ }
20
+ function readCurrentUserAtom(streamBytes) {
21
+ const record = readRecordAt(streamBytes, 0);
22
+ if (record.header.recType !== 4086) throw new PptFormatError(`Current User stream begins with record type 0x${record.header.recType.toString(16)}, not RT_CurrentUserAtom (0x${RT_CurrentUserAtom.toString(16)})`);
23
+ const { data } = record;
24
+ if (data.length < CURRENT_USER_FIXED_SIZE) throw new PptFormatError(`CurrentUserAtom carries ${data.length} bytes of data, fewer than the ${CURRENT_USER_FIXED_SIZE}-byte fixed portion the record requires`);
25
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
26
+ const size = view.getUint32(0, true);
27
+ if (size !== CURRENT_USER_FIXED_SIZE) throw new PptFormatError(`CurrentUserAtom size field is 0x${size.toString(16)}, not the mandated 0x${CURRENT_USER_FIXED_SIZE.toString(16)}`);
28
+ const headerToken = view.getUint32(4, true);
29
+ if (headerToken !== 3817979999 && headerToken !== 4090610911) throw new PptFormatError(`CurrentUserAtom headerToken is 0x${headerToken.toString(16)}, neither the plaintext 0x${CURRENT_USER_HEADER_TOKEN_PLAIN.toString(16)} nor the encrypted 0x${CURRENT_USER_HEADER_TOKEN_ENCRYPTED.toString(16)}`);
30
+ const offsetToCurrentEdit = view.getUint32(8, true);
31
+ const lenUserName = view.getUint16(12, true);
32
+ const docFileVersion = view.getUint16(14, true);
33
+ if (docFileVersion !== CURRENT_USER_DOC_FILE_VERSION) throw new PptFormatError(`CurrentUserAtom docFileVersion is 0x${docFileVersion.toString(16)}, not the mandated 0x${CURRENT_USER_DOC_FILE_VERSION.toString(16)}`);
34
+ const ansiEnd = CURRENT_USER_FIXED_SIZE + lenUserName;
35
+ if (ansiEnd > data.length) throw new PptFormatError(`CurrentUserAtom declares a ${lenUserName}-byte ansiUserName that runs past the record's ${data.length} bytes`);
36
+ const unicodeStart = ansiEnd + 4;
37
+ const unicodeEnd = unicodeStart + lenUserName * 2;
38
+ const userName = unicodeEnd <= data.length && lenUserName > 0 ? decodeUtf16Le(data.subarray(unicodeStart, unicodeEnd)) : decodeAnsi(data.subarray(CURRENT_USER_FIXED_SIZE, ansiEnd));
39
+ return {
40
+ offsetToCurrentEdit,
41
+ encrypted: headerToken === CURRENT_USER_HEADER_TOKEN_ENCRYPTED,
42
+ userName
43
+ };
44
+ }
45
+ //#endregion
46
+ export { CURRENT_USER_HEADER_TOKEN_ENCRYPTED, CURRENT_USER_HEADER_TOKEN_PLAIN, readCurrentUserAtom };
@@ -0,0 +1,71 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_errors = require("../errors.cjs");
3
+ const require_record_tree = require("../record/tree.cjs");
4
+ const require_record_types = require("../record/types.cjs");
5
+ //#region src/stream/persist.ts
6
+ const USER_EDIT_LEN_WITHOUT_ENCRYPT_SESSION = 28;
7
+ const USER_EDIT_LEN_WITH_ENCRYPT_SESSION = 32;
8
+ function readUserEditAtom(record) {
9
+ if (record.header.recType !== 4085) throw new require_errors.PptFormatError(`expected RT_UserEditAtom (0x${require_record_types.RT_UserEditAtom.toString(16)}) at offset ${record.offset}, found record type 0x${record.header.recType.toString(16)}`);
10
+ const { recLen } = record.header;
11
+ if (recLen !== USER_EDIT_LEN_WITHOUT_ENCRYPT_SESSION && recLen !== USER_EDIT_LEN_WITH_ENCRYPT_SESSION) throw new require_errors.PptFormatError(`UserEditAtom at offset ${record.offset} declares recLen 0x${recLen.toString(16)}, neither 0x${USER_EDIT_LEN_WITHOUT_ENCRYPT_SESSION.toString(16)} nor 0x${USER_EDIT_LEN_WITH_ENCRYPT_SESSION.toString(16)}`);
12
+ const { data } = record;
13
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
14
+ return {
15
+ lastSlideIdRef: view.getUint32(0, true),
16
+ offsetLastEdit: view.getUint32(8, true),
17
+ offsetPersistDirectory: view.getUint32(12, true),
18
+ docPersistIdRef: view.getUint32(16, true),
19
+ persistIdSeed: view.getUint32(20, true),
20
+ encryptSessionPersistIdRef: recLen === USER_EDIT_LEN_WITH_ENCRYPT_SESSION ? view.getUint32(28, true) : void 0
21
+ };
22
+ }
23
+ function readPersistDirectoryAtom(record) {
24
+ if (record.header.recType !== 6002) throw new require_errors.PptFormatError(`expected RT_PersistDirectoryAtom (0x${require_record_types.RT_PersistDirectoryAtom.toString(16)}) at offset ${record.offset}, found record type 0x${record.header.recType.toString(16)}`);
25
+ const { data } = record;
26
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
27
+ const entries = /* @__PURE__ */ new Map();
28
+ let at = 0;
29
+ while (at < data.length) {
30
+ if (at + 4 > data.length) throw new require_errors.PptFormatError(`PersistDirectoryAtom at offset ${record.offset} has a ${data.length - at}-byte trailing fragment, too short for a PersistDirectoryEntry header word`);
31
+ const packed = view.getUint32(at, true);
32
+ const persistId = packed & 1048575;
33
+ const cPersist = packed >>> 20 & 4095;
34
+ if (cPersist === 0) throw new require_errors.PptFormatError(`PersistDirectoryEntry at offset ${record.dataOffset + at} declares cPersist 0x000, but the spec requires at least 0x001`);
35
+ at += 4;
36
+ const offsetsEnd = at + cPersist * 4;
37
+ if (offsetsEnd > data.length) throw new require_errors.PptFormatError(`PersistDirectoryEntry at offset ${record.dataOffset + at - 4} declares ${cPersist} offsets, which run past the atom's ${data.length} bytes`);
38
+ for (let i = 0; i < cPersist; i++) entries.set(persistId + i, view.getUint32(at + i * 4, true));
39
+ at = offsetsEnd;
40
+ }
41
+ return entries;
42
+ }
43
+ function buildPersistDirectory(streamBytes, offsetToCurrentEdit) {
44
+ const edits = [];
45
+ let at = offsetToCurrentEdit;
46
+ while (true) {
47
+ const edit = readUserEditAtom(require_record_tree.readRecordAt(streamBytes, at));
48
+ edits.push(edit);
49
+ if (edit.offsetLastEdit === 0) break;
50
+ if (edit.offsetLastEdit >= at) throw new require_errors.PptFormatError(`UserEditAtom at offset ${at} points at a previous edit at offset ${edit.offsetLastEdit}, which is not earlier in the stream; the edit chain would cycle`);
51
+ at = edit.offsetLastEdit;
52
+ }
53
+ const directory = /* @__PURE__ */ new Map();
54
+ for (const edit of [...edits].reverse()) for (const [persistId, offset] of readPersistDirectoryAtom(require_record_tree.readRecordAt(streamBytes, edit.offsetPersistDirectory))) directory.set(persistId, offset);
55
+ const currentEdit = edits[0];
56
+ if (currentEdit === void 0) throw new require_errors.PptFormatError("the user edit chain produced no edits, so no document persist object can be located");
57
+ return {
58
+ directory,
59
+ currentEdit
60
+ };
61
+ }
62
+ function resolvePersistObject(streamBytes, directory, persistId, describe) {
63
+ const offset = directory.get(persistId);
64
+ if (offset === void 0) throw new require_errors.PptFormatError(`${describe} references persist object ${persistId}, which the persist directory does not contain`);
65
+ return require_record_tree.readRecordAt(streamBytes, offset);
66
+ }
67
+ //#endregion
68
+ exports.buildPersistDirectory = buildPersistDirectory;
69
+ exports.readPersistDirectoryAtom = readPersistDirectoryAtom;
70
+ exports.readUserEditAtom = readUserEditAtom;
71
+ exports.resolvePersistObject = resolvePersistObject;
@@ -0,0 +1,20 @@
1
+ import { t as PptRecord } from "../tree-Du_LXAF0.cjs";
2
+ //#region src/stream/persist.d.ts
3
+ interface UserEdit {
4
+ readonly lastSlideIdRef: number;
5
+ readonly offsetLastEdit: number;
6
+ readonly offsetPersistDirectory: number;
7
+ readonly docPersistIdRef: number;
8
+ readonly persistIdSeed: number;
9
+ readonly encryptSessionPersistIdRef: number | undefined;
10
+ }
11
+ declare function readUserEditAtom(record: PptRecord): UserEdit;
12
+ declare function readPersistDirectoryAtom(record: PptRecord): Map<number, number>;
13
+ interface PersistDirectory {
14
+ readonly directory: ReadonlyMap<number, number>;
15
+ readonly currentEdit: UserEdit;
16
+ }
17
+ declare function buildPersistDirectory(streamBytes: Uint8Array<ArrayBuffer>, offsetToCurrentEdit: number): PersistDirectory;
18
+ declare function resolvePersistObject(streamBytes: Uint8Array<ArrayBuffer>, directory: ReadonlyMap<number, number>, persistId: number, describe: string): PptRecord;
19
+ //#endregion
20
+ export { PersistDirectory, UserEdit, buildPersistDirectory, readPersistDirectoryAtom, readUserEditAtom, resolvePersistObject };
@@ -0,0 +1,20 @@
1
+ import { t as PptRecord } from "../tree-PMcPNgd-.js";
2
+ //#region src/stream/persist.d.ts
3
+ interface UserEdit {
4
+ readonly lastSlideIdRef: number;
5
+ readonly offsetLastEdit: number;
6
+ readonly offsetPersistDirectory: number;
7
+ readonly docPersistIdRef: number;
8
+ readonly persistIdSeed: number;
9
+ readonly encryptSessionPersistIdRef: number | undefined;
10
+ }
11
+ declare function readUserEditAtom(record: PptRecord): UserEdit;
12
+ declare function readPersistDirectoryAtom(record: PptRecord): Map<number, number>;
13
+ interface PersistDirectory {
14
+ readonly directory: ReadonlyMap<number, number>;
15
+ readonly currentEdit: UserEdit;
16
+ }
17
+ declare function buildPersistDirectory(streamBytes: Uint8Array<ArrayBuffer>, offsetToCurrentEdit: number): PersistDirectory;
18
+ declare function resolvePersistObject(streamBytes: Uint8Array<ArrayBuffer>, directory: ReadonlyMap<number, number>, persistId: number, describe: string): PptRecord;
19
+ //#endregion
20
+ export { PersistDirectory, UserEdit, buildPersistDirectory, readPersistDirectoryAtom, readUserEditAtom, resolvePersistObject };
@@ -0,0 +1,67 @@
1
+ import { PptFormatError } from "../errors.js";
2
+ import { readRecordAt } from "../record/tree.js";
3
+ import { RT_PersistDirectoryAtom, RT_UserEditAtom } from "../record/types.js";
4
+ //#region src/stream/persist.ts
5
+ const USER_EDIT_LEN_WITHOUT_ENCRYPT_SESSION = 28;
6
+ const USER_EDIT_LEN_WITH_ENCRYPT_SESSION = 32;
7
+ function readUserEditAtom(record) {
8
+ if (record.header.recType !== 4085) throw new PptFormatError(`expected RT_UserEditAtom (0x${RT_UserEditAtom.toString(16)}) at offset ${record.offset}, found record type 0x${record.header.recType.toString(16)}`);
9
+ const { recLen } = record.header;
10
+ if (recLen !== USER_EDIT_LEN_WITHOUT_ENCRYPT_SESSION && recLen !== USER_EDIT_LEN_WITH_ENCRYPT_SESSION) throw new PptFormatError(`UserEditAtom at offset ${record.offset} declares recLen 0x${recLen.toString(16)}, neither 0x${USER_EDIT_LEN_WITHOUT_ENCRYPT_SESSION.toString(16)} nor 0x${USER_EDIT_LEN_WITH_ENCRYPT_SESSION.toString(16)}`);
11
+ const { data } = record;
12
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
13
+ return {
14
+ lastSlideIdRef: view.getUint32(0, true),
15
+ offsetLastEdit: view.getUint32(8, true),
16
+ offsetPersistDirectory: view.getUint32(12, true),
17
+ docPersistIdRef: view.getUint32(16, true),
18
+ persistIdSeed: view.getUint32(20, true),
19
+ encryptSessionPersistIdRef: recLen === USER_EDIT_LEN_WITH_ENCRYPT_SESSION ? view.getUint32(28, true) : void 0
20
+ };
21
+ }
22
+ function readPersistDirectoryAtom(record) {
23
+ if (record.header.recType !== 6002) throw new PptFormatError(`expected RT_PersistDirectoryAtom (0x${RT_PersistDirectoryAtom.toString(16)}) at offset ${record.offset}, found record type 0x${record.header.recType.toString(16)}`);
24
+ const { data } = record;
25
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
26
+ const entries = /* @__PURE__ */ new Map();
27
+ let at = 0;
28
+ while (at < data.length) {
29
+ if (at + 4 > data.length) throw new PptFormatError(`PersistDirectoryAtom at offset ${record.offset} has a ${data.length - at}-byte trailing fragment, too short for a PersistDirectoryEntry header word`);
30
+ const packed = view.getUint32(at, true);
31
+ const persistId = packed & 1048575;
32
+ const cPersist = packed >>> 20 & 4095;
33
+ if (cPersist === 0) throw new PptFormatError(`PersistDirectoryEntry at offset ${record.dataOffset + at} declares cPersist 0x000, but the spec requires at least 0x001`);
34
+ at += 4;
35
+ const offsetsEnd = at + cPersist * 4;
36
+ if (offsetsEnd > data.length) throw new PptFormatError(`PersistDirectoryEntry at offset ${record.dataOffset + at - 4} declares ${cPersist} offsets, which run past the atom's ${data.length} bytes`);
37
+ for (let i = 0; i < cPersist; i++) entries.set(persistId + i, view.getUint32(at + i * 4, true));
38
+ at = offsetsEnd;
39
+ }
40
+ return entries;
41
+ }
42
+ function buildPersistDirectory(streamBytes, offsetToCurrentEdit) {
43
+ const edits = [];
44
+ let at = offsetToCurrentEdit;
45
+ while (true) {
46
+ const edit = readUserEditAtom(readRecordAt(streamBytes, at));
47
+ edits.push(edit);
48
+ if (edit.offsetLastEdit === 0) break;
49
+ if (edit.offsetLastEdit >= at) throw new PptFormatError(`UserEditAtom at offset ${at} points at a previous edit at offset ${edit.offsetLastEdit}, which is not earlier in the stream; the edit chain would cycle`);
50
+ at = edit.offsetLastEdit;
51
+ }
52
+ const directory = /* @__PURE__ */ new Map();
53
+ for (const edit of [...edits].reverse()) for (const [persistId, offset] of readPersistDirectoryAtom(readRecordAt(streamBytes, edit.offsetPersistDirectory))) directory.set(persistId, offset);
54
+ const currentEdit = edits[0];
55
+ if (currentEdit === void 0) throw new PptFormatError("the user edit chain produced no edits, so no document persist object can be located");
56
+ return {
57
+ directory,
58
+ currentEdit
59
+ };
60
+ }
61
+ function resolvePersistObject(streamBytes, directory, persistId, describe) {
62
+ const offset = directory.get(persistId);
63
+ if (offset === void 0) throw new PptFormatError(`${describe} references persist object ${persistId}, which the persist directory does not contain`);
64
+ return readRecordAt(streamBytes, offset);
65
+ }
66
+ //#endregion
67
+ export { buildPersistDirectory, readPersistDirectoryAtom, readUserEditAtom, resolvePersistObject };
@@ -0,0 +1,70 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_errors = require("../errors.cjs");
3
+ const require_record_tree = require("../record/tree.cjs");
4
+ const require_record_types = require("../record/types.cjs");
5
+ //#region src/text/atoms.ts
6
+ const TEXT_TYPE_TITLE = 0;
7
+ const TEXT_TYPE_BODY = 1;
8
+ const TEXT_TYPE_NOTES = 2;
9
+ const TEXT_TYPE_OTHER = 4;
10
+ const TEXT_TYPE_CENTER_BODY = 5;
11
+ const TEXT_TYPE_CENTER_TITLE = 6;
12
+ const TEXT_TYPE_HALF_BODY = 7;
13
+ const TEXT_TYPE_QUARTER_BODY = 8;
14
+ const PARAGRAPH_SEPARATOR = "\r";
15
+ const LINE_BREAK = "\v";
16
+ function readTextHeaderAtom(record) {
17
+ if (record.header.recType !== 3999) throw new require_errors.PptFormatError(`expected RT_TextHeaderAtom (0x${require_record_types.RT_TextHeaderAtom.toString(16)}), found record type 0x${record.header.recType.toString(16)}`);
18
+ if (record.data.length < 4) throw new require_errors.PptFormatError(`TextHeaderAtom carries ${record.data.length} bytes, fewer than the 4 its textType field needs`);
19
+ return new DataView(record.data.buffer, record.data.byteOffset, record.data.byteLength).getUint32(0, true);
20
+ }
21
+ function decodeTextBytes(bytes) {
22
+ let text = "";
23
+ for (const byte of bytes) text += String.fromCharCode(byte);
24
+ return text;
25
+ }
26
+ function decodeTextChars(bytes) {
27
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
28
+ let text = "";
29
+ for (let at = 0; at + 1 < bytes.length; at += 2) text += String.fromCharCode(view.getUint16(at, true));
30
+ return text;
31
+ }
32
+ function readTextBody(records) {
33
+ const chars = require_record_tree.findChild(records, require_record_types.RT_TextCharsAtom);
34
+ if (chars !== void 0) return decodeTextChars(chars.data);
35
+ const bytes = require_record_tree.findChild(records, require_record_types.RT_TextBytesAtom);
36
+ if (bytes !== void 0) return decodeTextBytes(bytes.data);
37
+ }
38
+ function characterCountOf(text) {
39
+ return text.length + 1;
40
+ }
41
+ function splitParagraphs(text) {
42
+ const paragraphs = [];
43
+ let start = 0;
44
+ while (start <= text.length) {
45
+ const separatorAt = text.indexOf("\r", start);
46
+ const end = separatorAt === -1 ? text.length : separatorAt;
47
+ paragraphs.push({
48
+ text: text.slice(start, end).split("\v").join("\n"),
49
+ start
50
+ });
51
+ if (separatorAt === -1) break;
52
+ start = separatorAt + 1;
53
+ }
54
+ return paragraphs;
55
+ }
56
+ //#endregion
57
+ exports.LINE_BREAK = LINE_BREAK;
58
+ exports.PARAGRAPH_SEPARATOR = PARAGRAPH_SEPARATOR;
59
+ exports.TEXT_TYPE_BODY = TEXT_TYPE_BODY;
60
+ exports.TEXT_TYPE_CENTER_BODY = TEXT_TYPE_CENTER_BODY;
61
+ exports.TEXT_TYPE_CENTER_TITLE = TEXT_TYPE_CENTER_TITLE;
62
+ exports.TEXT_TYPE_HALF_BODY = TEXT_TYPE_HALF_BODY;
63
+ exports.TEXT_TYPE_NOTES = TEXT_TYPE_NOTES;
64
+ exports.TEXT_TYPE_OTHER = TEXT_TYPE_OTHER;
65
+ exports.TEXT_TYPE_QUARTER_BODY = TEXT_TYPE_QUARTER_BODY;
66
+ exports.TEXT_TYPE_TITLE = TEXT_TYPE_TITLE;
67
+ exports.characterCountOf = characterCountOf;
68
+ exports.readTextBody = readTextBody;
69
+ exports.readTextHeaderAtom = readTextHeaderAtom;
70
+ exports.splitParagraphs = splitParagraphs;
@@ -0,0 +1,22 @@
1
+ import { t as PptRecord } from "../tree-Du_LXAF0.cjs";
2
+ //#region src/text/atoms.d.ts
3
+ declare const TEXT_TYPE_TITLE = 0;
4
+ declare const TEXT_TYPE_BODY = 1;
5
+ declare const TEXT_TYPE_NOTES = 2;
6
+ declare const TEXT_TYPE_OTHER = 4;
7
+ declare const TEXT_TYPE_CENTER_BODY = 5;
8
+ declare const TEXT_TYPE_CENTER_TITLE = 6;
9
+ declare const TEXT_TYPE_HALF_BODY = 7;
10
+ declare const TEXT_TYPE_QUARTER_BODY = 8;
11
+ declare const PARAGRAPH_SEPARATOR = "\r";
12
+ declare const LINE_BREAK = "\v";
13
+ declare function readTextHeaderAtom(record: PptRecord): number;
14
+ declare function readTextBody(records: readonly PptRecord[]): string | undefined;
15
+ declare function characterCountOf(text: string): number;
16
+ interface TextParagraph {
17
+ readonly text: string;
18
+ readonly start: number;
19
+ }
20
+ declare function splitParagraphs(text: string): TextParagraph[];
21
+ //#endregion
22
+ export { LINE_BREAK, PARAGRAPH_SEPARATOR, TEXT_TYPE_BODY, TEXT_TYPE_CENTER_BODY, TEXT_TYPE_CENTER_TITLE, TEXT_TYPE_HALF_BODY, TEXT_TYPE_NOTES, TEXT_TYPE_OTHER, TEXT_TYPE_QUARTER_BODY, TEXT_TYPE_TITLE, TextParagraph, characterCountOf, readTextBody, readTextHeaderAtom, splitParagraphs };
@@ -0,0 +1,22 @@
1
+ import { t as PptRecord } from "../tree-PMcPNgd-.js";
2
+ //#region src/text/atoms.d.ts
3
+ declare const TEXT_TYPE_TITLE = 0;
4
+ declare const TEXT_TYPE_BODY = 1;
5
+ declare const TEXT_TYPE_NOTES = 2;
6
+ declare const TEXT_TYPE_OTHER = 4;
7
+ declare const TEXT_TYPE_CENTER_BODY = 5;
8
+ declare const TEXT_TYPE_CENTER_TITLE = 6;
9
+ declare const TEXT_TYPE_HALF_BODY = 7;
10
+ declare const TEXT_TYPE_QUARTER_BODY = 8;
11
+ declare const PARAGRAPH_SEPARATOR = "\r";
12
+ declare const LINE_BREAK = "\v";
13
+ declare function readTextHeaderAtom(record: PptRecord): number;
14
+ declare function readTextBody(records: readonly PptRecord[]): string | undefined;
15
+ declare function characterCountOf(text: string): number;
16
+ interface TextParagraph {
17
+ readonly text: string;
18
+ readonly start: number;
19
+ }
20
+ declare function splitParagraphs(text: string): TextParagraph[];
21
+ //#endregion
22
+ export { LINE_BREAK, PARAGRAPH_SEPARATOR, TEXT_TYPE_BODY, TEXT_TYPE_CENTER_BODY, TEXT_TYPE_CENTER_TITLE, TEXT_TYPE_HALF_BODY, TEXT_TYPE_NOTES, TEXT_TYPE_OTHER, TEXT_TYPE_QUARTER_BODY, TEXT_TYPE_TITLE, TextParagraph, characterCountOf, readTextBody, readTextHeaderAtom, splitParagraphs };
@@ -0,0 +1,56 @@
1
+ import { PptFormatError } from "../errors.js";
2
+ import { findChild } from "../record/tree.js";
3
+ import { RT_TextBytesAtom, RT_TextCharsAtom, RT_TextHeaderAtom } from "../record/types.js";
4
+ //#region src/text/atoms.ts
5
+ const TEXT_TYPE_TITLE = 0;
6
+ const TEXT_TYPE_BODY = 1;
7
+ const TEXT_TYPE_NOTES = 2;
8
+ const TEXT_TYPE_OTHER = 4;
9
+ const TEXT_TYPE_CENTER_BODY = 5;
10
+ const TEXT_TYPE_CENTER_TITLE = 6;
11
+ const TEXT_TYPE_HALF_BODY = 7;
12
+ const TEXT_TYPE_QUARTER_BODY = 8;
13
+ const PARAGRAPH_SEPARATOR = "\r";
14
+ const LINE_BREAK = "\v";
15
+ function readTextHeaderAtom(record) {
16
+ if (record.header.recType !== 3999) throw new PptFormatError(`expected RT_TextHeaderAtom (0x${RT_TextHeaderAtom.toString(16)}), found record type 0x${record.header.recType.toString(16)}`);
17
+ if (record.data.length < 4) throw new PptFormatError(`TextHeaderAtom carries ${record.data.length} bytes, fewer than the 4 its textType field needs`);
18
+ return new DataView(record.data.buffer, record.data.byteOffset, record.data.byteLength).getUint32(0, true);
19
+ }
20
+ function decodeTextBytes(bytes) {
21
+ let text = "";
22
+ for (const byte of bytes) text += String.fromCharCode(byte);
23
+ return text;
24
+ }
25
+ function decodeTextChars(bytes) {
26
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
27
+ let text = "";
28
+ for (let at = 0; at + 1 < bytes.length; at += 2) text += String.fromCharCode(view.getUint16(at, true));
29
+ return text;
30
+ }
31
+ function readTextBody(records) {
32
+ const chars = findChild(records, RT_TextCharsAtom);
33
+ if (chars !== void 0) return decodeTextChars(chars.data);
34
+ const bytes = findChild(records, RT_TextBytesAtom);
35
+ if (bytes !== void 0) return decodeTextBytes(bytes.data);
36
+ }
37
+ function characterCountOf(text) {
38
+ return text.length + 1;
39
+ }
40
+ function splitParagraphs(text) {
41
+ const paragraphs = [];
42
+ let start = 0;
43
+ while (start <= text.length) {
44
+ const separatorAt = text.indexOf("\r", start);
45
+ const end = separatorAt === -1 ? text.length : separatorAt;
46
+ paragraphs.push({
47
+ text: text.slice(start, end).split("\v").join("\n"),
48
+ start
49
+ });
50
+ if (separatorAt === -1) break;
51
+ start = separatorAt + 1;
52
+ }
53
+ return paragraphs;
54
+ }
55
+ //#endregion
56
+ export { LINE_BREAK, PARAGRAPH_SEPARATOR, TEXT_TYPE_BODY, TEXT_TYPE_CENTER_BODY, TEXT_TYPE_CENTER_TITLE, TEXT_TYPE_HALF_BODY, TEXT_TYPE_NOTES, TEXT_TYPE_OTHER, TEXT_TYPE_QUARTER_BODY, TEXT_TYPE_TITLE, characterCountOf, readTextBody, readTextHeaderAtom, splitParagraphs };
@@ -0,0 +1,173 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_errors = require("../errors.cjs");
3
+ const require_record_types = require("../record/types.cjs");
4
+ //#region src/text/style.ts
5
+ const ALIGN_LEFT = 0;
6
+ const ALIGN_CENTER = 1;
7
+ const ALIGN_RIGHT = 2;
8
+ const ALIGN_JUSTIFY = 3;
9
+ const ALIGN_DISTRIBUTED = 4;
10
+ const ALIGN_THAI_DISTRIBUTED = 5;
11
+ const ALIGN_JUSTIFY_LOW = 6;
12
+ const PF_BULLET_FONT = 16;
13
+ const PF_BULLET_COLOR = 32;
14
+ const PF_BULLET_SIZE = 64;
15
+ const PF_BULLET_CHAR = 128;
16
+ const PF_LEFT_MARGIN = 256;
17
+ const PF_INDENT = 1024;
18
+ const PF_ALIGN = 2048;
19
+ const PF_LINE_SPACING = 4096;
20
+ const PF_SPACE_BEFORE = 8192;
21
+ const PF_SPACE_AFTER = 16384;
22
+ const PF_DEFAULT_TAB_SIZE = 32768;
23
+ const PF_FONT_ALIGN = 65536;
24
+ const PF_TAB_STOPS = 1 << 20;
25
+ const PF_TEXT_DIRECTION = 1 << 21;
26
+ const CF_BOLD = 1;
27
+ const CF_ITALIC = 2;
28
+ const CF_UNDERLINE = 4;
29
+ const CF_SHADOW = 16;
30
+ const CF_EMBOSS = 512;
31
+ const CF_TYPEFACE = 65536;
32
+ const CF_SIZE = 1 << 17;
33
+ const CF_COLOR = 1 << 18;
34
+ const CF_POSITION = 1 << 19;
35
+ const CF_OLD_EA_TYPEFACE = 1 << 21;
36
+ const CF_ANSI_TYPEFACE = 1 << 22;
37
+ const CF_SYMBOL_TYPEFACE = 1 << 23;
38
+ const STYLE_BOLD = 1;
39
+ const STYLE_ITALIC = 2;
40
+ const STYLE_UNDERLINE = 4;
41
+ const STYLE_SHADOW = 16;
42
+ const STYLE_EMBOSS = 512;
43
+ const COLOR_INDEX_SRGB = 254;
44
+ var FieldCursor = class {
45
+ data;
46
+ describe;
47
+ at;
48
+ view;
49
+ constructor(data, start, describe) {
50
+ this.data = data;
51
+ this.describe = describe;
52
+ this.at = start;
53
+ this.view = new DataView(data.buffer, data.byteOffset, data.byteLength);
54
+ }
55
+ get offset() {
56
+ return this.at;
57
+ }
58
+ require(size) {
59
+ if (this.at + size > this.data.length) throw new require_errors.PptFormatError(`${this.describe} needs ${size} more bytes at offset ${this.at} but the atom holds only ${this.data.length}`);
60
+ const at = this.at;
61
+ this.at += size;
62
+ return at;
63
+ }
64
+ u16() {
65
+ return this.view.getUint16(this.require(2), true);
66
+ }
67
+ i16() {
68
+ return this.view.getInt16(this.require(2), true);
69
+ }
70
+ u32() {
71
+ return this.view.getUint32(this.require(4), true);
72
+ }
73
+ bytes(size) {
74
+ const at = this.require(size);
75
+ return this.data.subarray(at, at + size);
76
+ }
77
+ skip(size) {
78
+ this.require(size);
79
+ }
80
+ };
81
+ function readColorIndexStruct(cursor) {
82
+ const [red, green, blue, index] = cursor.bytes(4);
83
+ if (red === void 0 || green === void 0 || blue === void 0 || index === void 0) throw new require_errors.PptFormatError("ColorIndexStruct read returned fewer than its four bytes");
84
+ return index === COLOR_INDEX_SRGB ? {
85
+ red,
86
+ green,
87
+ blue
88
+ } : void 0;
89
+ }
90
+ function readTextPFException(cursor, indentLevel) {
91
+ const masks = cursor.u32();
92
+ if ((masks & 15) !== 0) cursor.skip(2);
93
+ if ((masks & PF_BULLET_CHAR) !== 0) cursor.skip(2);
94
+ if ((masks & PF_BULLET_FONT) !== 0) cursor.skip(2);
95
+ if ((masks & PF_BULLET_SIZE) !== 0) cursor.skip(2);
96
+ if ((masks & PF_BULLET_COLOR) !== 0) cursor.skip(4);
97
+ const alignment = (masks & PF_ALIGN) !== 0 ? cursor.u16() : void 0;
98
+ for (const mask of [
99
+ PF_LINE_SPACING,
100
+ PF_SPACE_BEFORE,
101
+ PF_SPACE_AFTER,
102
+ PF_LEFT_MARGIN,
103
+ PF_INDENT,
104
+ PF_DEFAULT_TAB_SIZE
105
+ ]) if ((masks & mask) !== 0) cursor.skip(2);
106
+ if ((masks & PF_TAB_STOPS) !== 0) cursor.skip(cursor.u16() * 4);
107
+ if ((masks & PF_FONT_ALIGN) !== 0) cursor.skip(2);
108
+ if ((masks & 917504) !== 0) cursor.skip(2);
109
+ if ((masks & PF_TEXT_DIRECTION) !== 0) cursor.skip(2);
110
+ return {
111
+ indentLevel,
112
+ alignment
113
+ };
114
+ }
115
+ function styleFlag(masks, maskBit, fontStyle, styleBit) {
116
+ if ((masks & maskBit) === 0 || fontStyle === void 0) return;
117
+ return (fontStyle & styleBit) !== 0;
118
+ }
119
+ function readTextCFException(cursor) {
120
+ const masks = cursor.u32();
121
+ const fontStyle = (masks & 16055) !== 0 ? cursor.u16() : void 0;
122
+ const fontRef = (masks & CF_TYPEFACE) !== 0 ? cursor.u16() : void 0;
123
+ if ((masks & CF_OLD_EA_TYPEFACE) !== 0) cursor.skip(2);
124
+ if ((masks & CF_ANSI_TYPEFACE) !== 0) cursor.skip(2);
125
+ if ((masks & CF_SYMBOL_TYPEFACE) !== 0) cursor.skip(2);
126
+ const sizePt = (masks & CF_SIZE) !== 0 ? cursor.i16() : void 0;
127
+ const color = (masks & CF_COLOR) !== 0 ? readColorIndexStruct(cursor) : void 0;
128
+ if ((masks & CF_POSITION) !== 0) cursor.skip(2);
129
+ return {
130
+ bold: styleFlag(masks, CF_BOLD, fontStyle, STYLE_BOLD),
131
+ italic: styleFlag(masks, CF_ITALIC, fontStyle, STYLE_ITALIC),
132
+ underline: styleFlag(masks, CF_UNDERLINE, fontStyle, STYLE_UNDERLINE),
133
+ shadow: styleFlag(masks, CF_SHADOW, fontStyle, STYLE_SHADOW),
134
+ emboss: styleFlag(masks, CF_EMBOSS, fontStyle, STYLE_EMBOSS),
135
+ fontRef,
136
+ sizePt,
137
+ color
138
+ };
139
+ }
140
+ function readRuns(cursor, characterCount, describe, readProperties) {
141
+ const runs = [];
142
+ let covered = 0;
143
+ while (covered < characterCount) {
144
+ const count = cursor.u32();
145
+ const properties = readProperties(cursor);
146
+ covered += count;
147
+ if (covered > characterCount) throw new require_errors.PptFormatError(`${describe} cover ${covered} characters, more than the ${characterCount} in the corresponding text body`);
148
+ runs.push({
149
+ count,
150
+ properties
151
+ });
152
+ }
153
+ return runs;
154
+ }
155
+ function readStyleTextPropAtom(record, characterCount) {
156
+ if (record.header.recType !== 4001) throw new require_errors.PptFormatError(`expected RT_StyleTextPropAtom (0x${require_record_types.RT_StyleTextPropAtom.toString(16)}), found record type 0x${record.header.recType.toString(16)}`);
157
+ const cursor = new FieldCursor(record.data, 0, "StyleTextPropAtom");
158
+ return {
159
+ paragraphRuns: readRuns(cursor, characterCount, "StyleTextPropAtom paragraph runs", (at) => {
160
+ return readTextPFException(at, at.u16());
161
+ }),
162
+ characterRuns: readRuns(cursor, characterCount, "StyleTextPropAtom character runs", readTextCFException)
163
+ };
164
+ }
165
+ //#endregion
166
+ exports.ALIGN_CENTER = ALIGN_CENTER;
167
+ exports.ALIGN_DISTRIBUTED = ALIGN_DISTRIBUTED;
168
+ exports.ALIGN_JUSTIFY = ALIGN_JUSTIFY;
169
+ exports.ALIGN_JUSTIFY_LOW = ALIGN_JUSTIFY_LOW;
170
+ exports.ALIGN_LEFT = ALIGN_LEFT;
171
+ exports.ALIGN_RIGHT = ALIGN_RIGHT;
172
+ exports.ALIGN_THAI_DISTRIBUTED = ALIGN_THAI_DISTRIBUTED;
173
+ exports.readStyleTextPropAtom = readStyleTextPropAtom;