返回 oh-my-ppt
slide-pack-archive.ts
根目录 / src / main / session-import / slide-pack-archive.ts
1 import { unzipSync } from 'fflate'
2
3 export const normalizeSlidePackArchivePath = (rawName: string): string | null => {
4 const normalized = rawName.replace(/\\/g, '/').replace(/^\/+/, '')
5 if (!normalized || normalized.endsWith('/')) return null
6 const parts = normalized.split('/').filter(Boolean)
7 if (parts.length === 0 || parts.some((part) => part === '..' || part === '.')) return null
8 return parts.join('/')
9 }
10
11 export const tryReadSlidePackZip = (zipData: Uint8Array): Record<string, Uint8Array> | null => {
12 try {
13 return unzipSync(zipData)
14 } catch {
15 return null
16 }
17 }
18
19 export const archiveHasRootIndexHtml = (zipData: Uint8Array): boolean => {
20 const files = tryReadSlidePackZip(zipData)
21 if (!files) return false
22 return Object.keys(files).some((rawName) => {
23 const relativePath = normalizeSlidePackArchivePath(rawName)
24 return relativePath?.toLowerCase() === 'index.html'
25 })
26 }
27
28 export const findSlidePackResourceZipInsideZip = (zipData: Uint8Array): Uint8Array | null => {
29 const files = tryReadSlidePackZip(zipData)
30 if (!files) return null
31 const candidates = Object.entries(files)
32 .map(([name, data]) => ({ name: normalizeSlidePackArchivePath(name), data }))
33 .filter((entry): entry is { name: string; data: Uint8Array } => {
34 if (!entry.name) return false
35 return entry.name.toLowerCase().endsWith('.app/contents/resources/slides.zip')
36 })
37 .filter((entry) => archiveHasRootIndexHtml(entry.data))
38
39 if (candidates.length !== 1) return null
40 return candidates[0].data
41 }
42
42 lines TYPESCRIPT