(
buffer: ArrayBuffer,
limits: ZipParseLimits = {}
)
| 72 | * Parse a .pptx file buffer and extract all relevant files, categorized by type. |
| 73 | */ |
| 74 | export async function parseZip( |
| 75 | buffer: ArrayBuffer, |
| 76 | limits: ZipParseLimits = {} |
| 77 | ): Promise<PptxFiles> { |
| 78 | const maxConcurrency = limits.maxConcurrency ?? 8 |
| 79 | if (!Number.isInteger(maxConcurrency) || maxConcurrency < 1) { |
| 80 | throwZipLimitExceeded(`maxConcurrency ${limits.maxConcurrency} must be an integer >= 1`) |
| 81 | } |
| 82 | |
| 83 | const zip = await JSZip.loadAsync(buffer) |
| 84 | const entries = Object.entries(zip.files).filter(([, file]) => !file.dir) |
| 85 | |
| 86 | if (limits.maxEntries !== undefined && entries.length > limits.maxEntries) { |
| 87 | throwZipLimitExceeded(`entries ${entries.length} > maxEntries ${limits.maxEntries}`) |
| 88 | } |
| 89 | |
| 90 | const knownSizeByPath = new Map<string, number>() |
| 91 | let knownTotalBytes = 0 |
| 92 | let knownMediaBytes = 0 |
| 93 | |
| 94 | for (const [rawPath, file] of entries) { |
| 95 | const normalizedPath = rawPath.replace(/\\/g, '/') |
| 96 | const size = readUncompressedSize(file) |
| 97 | if (size === undefined) continue |
| 98 | |
| 99 | knownSizeByPath.set(normalizedPath, size) |
| 100 | |
| 101 | if (limits.maxEntryUncompressedBytes !== undefined && size > limits.maxEntryUncompressedBytes) { |
| 102 | throwZipLimitExceeded( |
| 103 | `${normalizedPath} is ${size} bytes > maxEntryUncompressedBytes ${limits.maxEntryUncompressedBytes}` |
| 104 | ) |
| 105 | } |
| 106 | |
| 107 | knownTotalBytes += size |
| 108 | if ( |
| 109 | limits.maxTotalUncompressedBytes !== undefined && |
| 110 | knownTotalBytes > limits.maxTotalUncompressedBytes |
| 111 | ) { |
| 112 | throwZipLimitExceeded( |
| 113 | `total uncompressed bytes ${knownTotalBytes} > maxTotalUncompressedBytes ${limits.maxTotalUncompressedBytes}` |
| 114 | ) |
| 115 | } |
| 116 | |
| 117 | if (normalizedPath.startsWith('ppt/media/')) { |
| 118 | knownMediaBytes += size |
| 119 | if (limits.maxMediaBytes !== undefined && knownMediaBytes > limits.maxMediaBytes) { |
| 120 | throwZipLimitExceeded( |
| 121 | `media bytes ${knownMediaBytes} > maxMediaBytes ${limits.maxMediaBytes}` |
| 122 | ) |
| 123 | } |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | const result: PptxFiles = { |
| 128 | contentTypes: '', |
| 129 | presentation: '', |
| 130 | presentationRels: '', |
| 131 | slides: new Map(), |
no test coverage detected