@l1yp/file-viewer 0.1.0 → 0.1.2

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 (439) hide show
  1. package/README.md +2 -0
  2. package/dist/FileViewer.js +2 -0
  3. package/dist/FileViewer.js.map +1 -0
  4. package/dist/FileViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  5. package/dist/FileViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  6. package/dist/components/AppxViewer.js +2 -0
  7. package/dist/components/AppxViewer.js.map +1 -0
  8. package/dist/components/AppxViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  9. package/dist/components/AppxViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  10. package/dist/components/ArchiveBrowser.js +2 -0
  11. package/dist/components/ArchiveBrowser.js.map +1 -0
  12. package/dist/components/ArchiveBrowser.vue_vue_type_script_setup_true_lang.js +2 -0
  13. package/dist/components/ArchiveBrowser.vue_vue_type_script_setup_true_lang.js.map +1 -0
  14. package/dist/components/AudioViewer.js +2 -0
  15. package/dist/components/AudioViewer.js.map +1 -0
  16. package/dist/components/AudioViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  17. package/dist/components/AudioViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  18. package/dist/components/BinObjBrowser.js +2 -0
  19. package/dist/components/BinObjBrowser.js.map +1 -0
  20. package/dist/components/BinObjBrowser.vue_vue_type_script_setup_true_lang.js +2 -0
  21. package/dist/components/BinObjBrowser.vue_vue_type_script_setup_true_lang.js.map +1 -0
  22. package/dist/components/CertViewer.js +2 -0
  23. package/dist/components/CertViewer.js.map +1 -0
  24. package/dist/components/CertViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  25. package/dist/components/CertViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  26. package/dist/components/ClassViewer.js +2 -0
  27. package/dist/components/ClassViewer.js.map +1 -0
  28. package/dist/components/ClassViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  29. package/dist/components/ClassViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  30. package/dist/components/CodeBlock.js +2 -0
  31. package/dist/components/CodeBlock.js.map +1 -0
  32. package/dist/components/CodeBlock.vue_vue_type_script_setup_true_lang.js +2 -0
  33. package/dist/components/CodeBlock.vue_vue_type_script_setup_true_lang.js.map +1 -0
  34. package/dist/components/CodeView.js +2 -0
  35. package/dist/components/CodeView.js.map +1 -0
  36. package/dist/components/CodeView.vue_vue_type_script_setup_true_lang.js +2 -0
  37. package/dist/components/CodeView.vue_vue_type_script_setup_true_lang.js.map +1 -0
  38. package/dist/components/CsvViewer.js +2 -0
  39. package/dist/components/CsvViewer.js.map +1 -0
  40. package/dist/components/CsvViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  41. package/dist/components/CsvViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  42. package/dist/components/DicomViewer.js +2 -0
  43. package/dist/components/DicomViewer.js.map +1 -0
  44. package/dist/components/DicomViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  45. package/dist/components/DicomViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  46. package/dist/components/DocxNavigationPane.js +9 -0
  47. package/dist/components/DocxNavigationPane.js.map +1 -0
  48. package/dist/components/DocxNavigationPane.vue.d.ts +23 -0
  49. package/dist/components/DocxNavigationPane.vue_vue_type_script_setup_true_lang.js +98 -0
  50. package/dist/components/DocxNavigationPane.vue_vue_type_script_setup_true_lang.js.map +1 -0
  51. package/dist/components/DocxViewer.js +3 -1
  52. package/dist/components/DocxViewer.js.map +1 -0
  53. package/dist/components/DocxViewer.vue_vue_type_script_setup_true_lang.js +72 -37
  54. package/dist/components/DocxViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  55. package/dist/components/DrawioViewer.js +2 -0
  56. package/dist/components/DrawioViewer.js.map +1 -0
  57. package/dist/components/DrawioViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  58. package/dist/components/DrawioViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  59. package/dist/components/DxfViewer.js +2 -0
  60. package/dist/components/DxfViewer.js.map +1 -0
  61. package/dist/components/DxfViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  62. package/dist/components/DxfViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  63. package/dist/components/EbookViewer.js +2 -0
  64. package/dist/components/EbookViewer.js.map +1 -0
  65. package/dist/components/EbookViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  66. package/dist/components/EbookViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  67. package/dist/components/EmlViewer.js +2 -0
  68. package/dist/components/EmlViewer.js.map +1 -0
  69. package/dist/components/EmlViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  70. package/dist/components/EmlViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  71. package/dist/components/EplViewer.js +2 -0
  72. package/dist/components/EplViewer.js.map +1 -0
  73. package/dist/components/EplViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  74. package/dist/components/EplViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  75. package/dist/components/FileViewerBody.js +3 -1
  76. package/dist/components/FileViewerBody.js.map +1 -0
  77. package/dist/components/FileViewerBody.vue.d.ts +5 -0
  78. package/dist/components/FileViewerBody.vue_vue_type_script_setup_true_lang.js +250 -247
  79. package/dist/components/FileViewerBody.vue_vue_type_script_setup_true_lang.js.map +1 -0
  80. package/dist/components/FileViewerPanel.js +2 -0
  81. package/dist/components/FileViewerPanel.js.map +1 -0
  82. package/dist/components/FileViewerPanel.vue_vue_type_script_setup_true_lang.js +2 -0
  83. package/dist/components/FileViewerPanel.vue_vue_type_script_setup_true_lang.js.map +1 -0
  84. package/dist/components/FontViewer.js +2 -0
  85. package/dist/components/FontViewer.js.map +1 -0
  86. package/dist/components/FontViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  87. package/dist/components/FontViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  88. package/dist/components/FrontmatterCard.js +2 -0
  89. package/dist/components/FrontmatterCard.js.map +1 -0
  90. package/dist/components/FrontmatterCard.vue_vue_type_script_setup_true_lang.js +2 -0
  91. package/dist/components/FrontmatterCard.vue_vue_type_script_setup_true_lang.js.map +1 -0
  92. package/dist/components/GeoViewer.js +2 -0
  93. package/dist/components/GeoViewer.js.map +1 -0
  94. package/dist/components/GeoViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  95. package/dist/components/GeoViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  96. package/dist/components/HarViewer.js +2 -0
  97. package/dist/components/HarViewer.js.map +1 -0
  98. package/dist/components/HarViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  99. package/dist/components/HarViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  100. package/dist/components/HexViewer.js +2 -0
  101. package/dist/components/HexViewer.js.map +1 -0
  102. package/dist/components/HexViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  103. package/dist/components/HexViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  104. package/dist/components/HprofViewer.js +2 -0
  105. package/dist/components/HprofViewer.js.map +1 -0
  106. package/dist/components/HprofViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  107. package/dist/components/HprofViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  108. package/dist/components/ImageLightbox.js +2 -0
  109. package/dist/components/ImageLightbox.js.map +1 -0
  110. package/dist/components/ImageLightbox.vue_vue_type_script_setup_true_lang.js +2 -0
  111. package/dist/components/ImageLightbox.vue_vue_type_script_setup_true_lang.js.map +1 -0
  112. package/dist/components/InlineText.js +2 -0
  113. package/dist/components/InlineText.js.map +1 -0
  114. package/dist/components/JksViewer.js +2 -0
  115. package/dist/components/JksViewer.js.map +1 -0
  116. package/dist/components/JksViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  117. package/dist/components/JksViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  118. package/dist/components/JsonlViewer.js +2 -0
  119. package/dist/components/JsonlViewer.js.map +1 -0
  120. package/dist/components/JsonlViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  121. package/dist/components/JsonlViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  122. package/dist/components/LogViewer.js +2 -0
  123. package/dist/components/LogViewer.js.map +1 -0
  124. package/dist/components/LogViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  125. package/dist/components/LogViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  126. package/dist/components/LrcViewer.js +2 -0
  127. package/dist/components/LrcViewer.js.map +1 -0
  128. package/dist/components/LrcViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  129. package/dist/components/LrcViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  130. package/dist/components/MarkdownTable.js +2 -0
  131. package/dist/components/MarkdownTable.js.map +1 -0
  132. package/dist/components/MarkdownTable.vue_vue_type_script_setup_true_lang.js +2 -0
  133. package/dist/components/MarkdownTable.vue_vue_type_script_setup_true_lang.js.map +1 -0
  134. package/dist/components/MarkdownText.js +2 -0
  135. package/dist/components/MarkdownText.js.map +1 -0
  136. package/dist/components/MhtViewer.js +2 -0
  137. package/dist/components/MhtViewer.js.map +1 -0
  138. package/dist/components/MhtViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  139. package/dist/components/MhtViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  140. package/dist/components/MindMapView.js +2 -0
  141. package/dist/components/MindMapView.js.map +1 -0
  142. package/dist/components/MindMapView.vue_vue_type_script_setup_true_lang.js +2 -0
  143. package/dist/components/MindMapView.vue_vue_type_script_setup_true_lang.js.map +1 -0
  144. package/dist/components/MissingDependency.js +2 -0
  145. package/dist/components/MissingDependency.js.map +1 -0
  146. package/dist/components/MissingDependency.vue_vue_type_script_setup_true_lang.js +2 -0
  147. package/dist/components/MissingDependency.vue_vue_type_script_setup_true_lang.js.map +1 -0
  148. package/dist/components/ModelViewer.js +2 -0
  149. package/dist/components/ModelViewer.js.map +1 -0
  150. package/dist/components/ModelViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  151. package/dist/components/ModelViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  152. package/dist/components/MsiViewer.js +2 -0
  153. package/dist/components/MsiViewer.js.map +1 -0
  154. package/dist/components/MsiViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  155. package/dist/components/MsiViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  156. package/dist/components/NotebookViewer.js +2 -0
  157. package/dist/components/NotebookViewer.js.map +1 -0
  158. package/dist/components/NotebookViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  159. package/dist/components/NotebookViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  160. package/dist/components/PdfViewer.js +2 -0
  161. package/dist/components/PdfViewer.js.map +1 -0
  162. package/dist/components/PdfViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  163. package/dist/components/PdfViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  164. package/dist/components/PptxNavigationPane.js +9 -0
  165. package/dist/components/PptxNavigationPane.js.map +1 -0
  166. package/dist/components/PptxNavigationPane.vue.d.ts +20 -0
  167. package/dist/components/PptxNavigationPane.vue_vue_type_script_setup_true_lang.js +120 -0
  168. package/dist/components/PptxNavigationPane.vue_vue_type_script_setup_true_lang.js.map +1 -0
  169. package/dist/components/PptxViewer.js +3 -1
  170. package/dist/components/PptxViewer.js.map +1 -0
  171. package/dist/components/PptxViewer.vue_vue_type_script_setup_true_lang.js +71 -39
  172. package/dist/components/PptxViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  173. package/dist/components/PsdViewer.js +2 -0
  174. package/dist/components/PsdViewer.js.map +1 -0
  175. package/dist/components/PsdViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  176. package/dist/components/PsdViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  177. package/dist/components/QmcAudioViewer.js +2 -0
  178. package/dist/components/QmcAudioViewer.js.map +1 -0
  179. package/dist/components/QmcAudioViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  180. package/dist/components/QmcAudioViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  181. package/dist/components/RasterViewer.js +2 -0
  182. package/dist/components/RasterViewer.js.map +1 -0
  183. package/dist/components/RasterViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  184. package/dist/components/RasterViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  185. package/dist/components/RtfViewer.js +2 -0
  186. package/dist/components/RtfViewer.js.map +1 -0
  187. package/dist/components/RtfViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  188. package/dist/components/RtfViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  189. package/dist/components/SevenZipBrowser.js +2 -0
  190. package/dist/components/SevenZipBrowser.js.map +1 -0
  191. package/dist/components/SevenZipBrowser.vue_vue_type_script_setup_true_lang.js +2 -0
  192. package/dist/components/SevenZipBrowser.vue_vue_type_script_setup_true_lang.js.map +1 -0
  193. package/dist/components/SqliteViewer.js +2 -0
  194. package/dist/components/SqliteViewer.js.map +1 -0
  195. package/dist/components/SqliteViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  196. package/dist/components/SqliteViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  197. package/dist/components/SubtitleViewer.js +2 -0
  198. package/dist/components/SubtitleViewer.js.map +1 -0
  199. package/dist/components/SubtitleViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  200. package/dist/components/SubtitleViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  201. package/dist/components/XlsxChart.js +2 -0
  202. package/dist/components/XlsxChart.js.map +1 -0
  203. package/dist/components/XlsxChart.vue_vue_type_script_setup_true_lang.js +2 -0
  204. package/dist/components/XlsxChart.vue_vue_type_script_setup_true_lang.js.map +1 -0
  205. package/dist/components/XlsxViewer.js +3 -1
  206. package/dist/components/XlsxViewer.js.map +1 -0
  207. package/dist/components/XlsxViewer.vue_vue_type_script_setup_true_lang.js +301 -304
  208. package/dist/components/XlsxViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  209. package/dist/components/XmindViewer.js +2 -0
  210. package/dist/components/XmindViewer.js.map +1 -0
  211. package/dist/components/XmindViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  212. package/dist/components/XmindViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  213. package/dist/components/ZipBrowser.js +3 -1
  214. package/dist/components/ZipBrowser.js.map +1 -0
  215. package/dist/components/ZipBrowser.vue.d.ts +3 -1
  216. package/dist/components/ZipBrowser.vue_vue_type_script_setup_true_lang.js +154 -122
  217. package/dist/components/ZipBrowser.vue_vue_type_script_setup_true_lang.js.map +1 -0
  218. package/dist/components/ZoomImage.js +2 -0
  219. package/dist/components/ZoomImage.js.map +1 -0
  220. package/dist/components/ZoomImage.vue_vue_type_script_setup_true_lang.js +2 -0
  221. package/dist/components/ZoomImage.vue_vue_type_script_setup_true_lang.js.map +1 -0
  222. package/dist/components/epl/EplCodeBlock.js +2 -0
  223. package/dist/components/epl/EplCodeBlock.js.map +1 -0
  224. package/dist/components/epl/EplCodeBlock.vue_vue_type_script_setup_true_lang.js +2 -0
  225. package/dist/components/epl/EplCodeBlock.vue_vue_type_script_setup_true_lang.js.map +1 -0
  226. package/dist/components/epl/EplDoc.js +2 -0
  227. package/dist/components/epl/EplDoc.js.map +1 -0
  228. package/dist/components/epl/EplDoc.vue_vue_type_script_setup_true_lang.js +2 -0
  229. package/dist/components/epl/EplDoc.vue_vue_type_script_setup_true_lang.js.map +1 -0
  230. package/dist/components/epl/EplMethod.js +2 -0
  231. package/dist/components/epl/EplMethod.js.map +1 -0
  232. package/dist/components/epl/EplMethod.vue_vue_type_script_setup_true_lang.js +2 -0
  233. package/dist/components/epl/EplMethod.vue_vue_type_script_setup_true_lang.js.map +1 -0
  234. package/dist/components/epl/EplResource.js +2 -0
  235. package/dist/components/epl/EplResource.js.map +1 -0
  236. package/dist/components/epl/EplResource.vue_vue_type_script_setup_true_lang.js +2 -0
  237. package/dist/components/epl/EplResource.vue_vue_type_script_setup_true_lang.js.map +1 -0
  238. package/dist/components/epl/EplTree.js +2 -0
  239. package/dist/components/epl/EplTree.js.map +1 -0
  240. package/dist/components/epl/EplTree.vue_vue_type_script_setup_true_lang.js +2 -0
  241. package/dist/components/epl/EplTree.vue_vue_type_script_setup_true_lang.js.map +1 -0
  242. package/dist/components/epl/EplVarTable.js +2 -0
  243. package/dist/components/epl/EplVarTable.js.map +1 -0
  244. package/dist/components/epl/EplVarTable.vue_vue_type_script_setup_true_lang.js +2 -0
  245. package/dist/components/epl/EplVarTable.vue_vue_type_script_setup_true_lang.js.map +1 -0
  246. package/dist/components/epl/numbering.js +2 -0
  247. package/dist/components/epl/numbering.js.map +1 -0
  248. package/dist/components/icons/Icon.js +2 -0
  249. package/dist/components/icons/Icon.js.map +1 -0
  250. package/dist/components/icons/Icon.vue_vue_type_script_setup_true_lang.js +2 -0
  251. package/dist/components/icons/Icon.vue_vue_type_script_setup_true_lang.js.map +1 -0
  252. package/dist/components/icons/iconPaths.js +2 -0
  253. package/dist/components/icons/iconPaths.js.map +1 -0
  254. package/dist/components/optionalViewer.js +2 -0
  255. package/dist/components/optionalViewer.js.map +1 -0
  256. package/dist/components/ui/ClampBlock.js +2 -0
  257. package/dist/components/ui/ClampBlock.js.map +1 -0
  258. package/dist/composables/useElementNavigation.d.ts +21 -0
  259. package/dist/composables/useElementNavigation.js +63 -0
  260. package/dist/composables/useElementNavigation.js.map +1 -0
  261. package/dist/composables/useFileViewer.js +2 -0
  262. package/dist/composables/useFileViewer.js.map +1 -0
  263. package/dist/composables/useLightbox.js +2 -0
  264. package/dist/composables/useLightbox.js.map +1 -0
  265. package/dist/composables/useLogRules.js +2 -0
  266. package/dist/composables/useLogRules.js.map +1 -0
  267. package/dist/lib/aes.js +2 -0
  268. package/dist/lib/aes.js.map +1 -0
  269. package/dist/lib/appx.js +2 -0
  270. package/dist/lib/appx.js.map +1 -0
  271. package/dist/lib/archiveHtml.d.ts +49 -0
  272. package/dist/lib/archiveHtml.js +377 -0
  273. package/dist/lib/archiveHtml.js.map +1 -0
  274. package/dist/lib/asn1.js +2 -0
  275. package/dist/lib/asn1.js.map +1 -0
  276. package/dist/lib/binobj.js +2 -0
  277. package/dist/lib/binobj.js.map +1 -0
  278. package/dist/lib/brotli.js +2 -0
  279. package/dist/lib/brotli.js.map +1 -0
  280. package/dist/lib/bzip2.js +2 -0
  281. package/dist/lib/bzip2.js.map +1 -0
  282. package/dist/lib/classfile.js +2 -0
  283. package/dist/lib/classfile.js.map +1 -0
  284. package/dist/lib/codePreview.js +2 -0
  285. package/dist/lib/codePreview.js.map +1 -0
  286. package/dist/lib/codefold.js +2 -0
  287. package/dist/lib/codefold.js.map +1 -0
  288. package/dist/lib/codeformat.js +2 -0
  289. package/dist/lib/codeformat.js.map +1 -0
  290. package/dist/lib/csv.js +2 -0
  291. package/dist/lib/csv.js.map +1 -0
  292. package/dist/lib/des.js +2 -0
  293. package/dist/lib/des.js.map +1 -0
  294. package/dist/lib/diagram.js +2 -0
  295. package/dist/lib/diagram.js.map +1 -0
  296. package/dist/lib/dicom.js +2 -0
  297. package/dist/lib/dicom.js.map +1 -0
  298. package/dist/lib/dicomCodecs.js +2 -0
  299. package/dist/lib/dicomCodecs.js.map +1 -0
  300. package/dist/lib/dicomRender.js +2 -0
  301. package/dist/lib/dicomRender.js.map +1 -0
  302. package/dist/lib/docxNavigation.d.ts +31 -0
  303. package/dist/lib/docxNavigation.js +65 -0
  304. package/dist/lib/docxNavigation.js.map +1 -0
  305. package/dist/lib/dxf.js +2 -0
  306. package/dist/lib/dxf.js.map +1 -0
  307. package/dist/lib/eml.js +2 -0
  308. package/dist/lib/eml.js.map +1 -0
  309. package/dist/lib/encoding.js +2 -0
  310. package/dist/lib/encoding.js.map +1 -0
  311. package/dist/lib/epl/code/codeDataParser.js +2 -0
  312. package/dist/lib/epl/code/codeDataParser.js.map +1 -0
  313. package/dist/lib/epl/code/codeLines.js +2 -0
  314. package/dist/lib/epl/code/codeLines.js.map +1 -0
  315. package/dist/lib/epl/code/textCode.js +2 -0
  316. package/dist/lib/epl/code/textCode.js.map +1 -0
  317. package/dist/lib/epl/eplDocument.js +2 -0
  318. package/dist/lib/epl/eplDocument.js.map +1 -0
  319. package/dist/lib/epl/imageList.js +2 -0
  320. package/dist/lib/epl/imageList.js.map +1 -0
  321. package/dist/lib/epl/index.js +2 -0
  322. package/dist/lib/epl/index.js.map +1 -0
  323. package/dist/lib/epl/io/binaryReader.js +2 -0
  324. package/dist/lib/epl/io/binaryReader.js.map +1 -0
  325. package/dist/lib/epl/io/encoding.js +2 -0
  326. package/dist/lib/epl/io/encoding.js.map +1 -0
  327. package/dist/lib/epl/model/eplSystemId.js +2 -0
  328. package/dist/lib/epl/model/eplSystemId.js.map +1 -0
  329. package/dist/lib/epl/names/eplLibData.js +2 -0
  330. package/dist/lib/epl/names/eplLibData.js.map +1 -0
  331. package/dist/lib/epl/names/idToNameMap.js +2 -0
  332. package/dist/lib/epl/names/idToNameMap.js.map +1 -0
  333. package/dist/lib/epl/names/libNameProvider.js +2 -0
  334. package/dist/lib/epl/names/libNameProvider.js.map +1 -0
  335. package/dist/lib/epl/program.js +2 -0
  336. package/dist/lib/epl/program.js.map +1 -0
  337. package/dist/lib/epl/projectFileReader.js +2 -0
  338. package/dist/lib/epl/projectFileReader.js.map +1 -0
  339. package/dist/lib/fb2.js +2 -0
  340. package/dist/lib/fb2.js.map +1 -0
  341. package/dist/lib/fileType.js +2 -0
  342. package/dist/lib/fileType.js.map +1 -0
  343. package/dist/lib/fonts.js +2 -0
  344. package/dist/lib/fonts.js.map +1 -0
  345. package/dist/lib/format.js +2 -0
  346. package/dist/lib/format.js.map +1 -0
  347. package/dist/lib/frontmatter.js +2 -0
  348. package/dist/lib/frontmatter.js.map +1 -0
  349. package/dist/lib/geo.js +2 -0
  350. package/dist/lib/geo.js.map +1 -0
  351. package/dist/lib/har.js +2 -0
  352. package/dist/lib/har.js.map +1 -0
  353. package/dist/lib/highlight.js +2 -0
  354. package/dist/lib/highlight.js.map +1 -0
  355. package/dist/lib/highlightLangs.js +2 -0
  356. package/dist/lib/highlightLangs.js.map +1 -0
  357. package/dist/lib/hprof.js +2 -0
  358. package/dist/lib/hprof.js.map +1 -0
  359. package/dist/lib/ipynb.js +2 -0
  360. package/dist/lib/ipynb.js.map +1 -0
  361. package/dist/lib/jks.js +2 -0
  362. package/dist/lib/jks.js.map +1 -0
  363. package/dist/lib/jsonl.js +2 -0
  364. package/dist/lib/jsonl.js.map +1 -0
  365. package/dist/lib/lrc.js +2 -0
  366. package/dist/lib/lrc.js.map +1 -0
  367. package/dist/lib/lzma.js +2 -0
  368. package/dist/lib/lzma.js.map +1 -0
  369. package/dist/lib/markdown/blocks.js +2 -0
  370. package/dist/lib/markdown/blocks.js.map +1 -0
  371. package/dist/lib/markdown/inline.js +2 -0
  372. package/dist/lib/markdown/inline.js.map +1 -0
  373. package/dist/lib/markdown/math.js +2 -0
  374. package/dist/lib/markdown/math.js.map +1 -0
  375. package/dist/lib/markdown/segmentize.js +2 -0
  376. package/dist/lib/markdown/segmentize.js.map +1 -0
  377. package/dist/lib/markdown/styles.js +2 -0
  378. package/dist/lib/markdown/styles.js.map +1 -0
  379. package/dist/lib/mht.js +2 -0
  380. package/dist/lib/mht.js.map +1 -0
  381. package/dist/lib/midi.js +2 -0
  382. package/dist/lib/midi.js.map +1 -0
  383. package/dist/lib/mime.js +2 -0
  384. package/dist/lib/mime.js.map +1 -0
  385. package/dist/lib/mindmap.js +2 -0
  386. package/dist/lib/mindmap.js.map +1 -0
  387. package/dist/lib/mobi.js +2 -0
  388. package/dist/lib/mobi.js.map +1 -0
  389. package/dist/lib/msi.js +2 -0
  390. package/dist/lib/msi.js.map +1 -0
  391. package/dist/lib/optionalDep.js +2 -0
  392. package/dist/lib/optionalDep.js.map +1 -0
  393. package/dist/lib/pkcs12.js +2 -0
  394. package/dist/lib/pkcs12.js.map +1 -0
  395. package/dist/lib/pptxNavigation.d.ts +7 -0
  396. package/dist/lib/pptxNavigation.js +29 -0
  397. package/dist/lib/pptxNavigation.js.map +1 -0
  398. package/dist/lib/qmc.js +2 -0
  399. package/dist/lib/qmc.js.map +1 -0
  400. package/dist/lib/rar.js +2 -0
  401. package/dist/lib/rar.js.map +1 -0
  402. package/dist/lib/rawPreview.js +2 -0
  403. package/dist/lib/rawPreview.js.map +1 -0
  404. package/dist/lib/rc2.js +2 -0
  405. package/dist/lib/rc2.js.map +1 -0
  406. package/dist/lib/resolveInput.js +2 -0
  407. package/dist/lib/resolveInput.js.map +1 -0
  408. package/dist/lib/rtf.js +2 -0
  409. package/dist/lib/rtf.js.map +1 -0
  410. package/dist/lib/sevenZip.js +2 -0
  411. package/dist/lib/sevenZip.js.map +1 -0
  412. package/dist/lib/sha1.js +2 -0
  413. package/dist/lib/sha1.js.map +1 -0
  414. package/dist/lib/sha256.js +2 -0
  415. package/dist/lib/sha256.js.map +1 -0
  416. package/dist/lib/speechAudio.js +2 -0
  417. package/dist/lib/speechAudio.js.map +1 -0
  418. package/dist/lib/sqlite.js +2 -0
  419. package/dist/lib/sqlite.js.map +1 -0
  420. package/dist/lib/subtitle.js +2 -0
  421. package/dist/lib/subtitle.js.map +1 -0
  422. package/dist/lib/tarball.js +2 -0
  423. package/dist/lib/tarball.js.map +1 -0
  424. package/dist/lib/viewerFormats.js +2 -0
  425. package/dist/lib/viewerFormats.js.map +1 -0
  426. package/dist/lib/viewerKind.js +2 -0
  427. package/dist/lib/viewerKind.js.map +1 -0
  428. package/dist/lib/x509.js +2 -0
  429. package/dist/lib/x509.js.map +1 -0
  430. package/dist/lib/xlsx.js +2 -0
  431. package/dist/lib/xlsx.js.map +1 -0
  432. package/dist/lib/xlsxCharts.js +2 -0
  433. package/dist/lib/xlsxCharts.js.map +1 -0
  434. package/dist/lib/xmind.js +2 -0
  435. package/dist/lib/xmind.js.map +1 -0
  436. package/dist/lib/zip.js +2 -0
  437. package/dist/lib/zip.js.map +1 -0
  438. package/dist/style.css +1 -1
  439. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rtf.js","names":[],"sources":["../../src/lib/rtf.ts"],"sourcesContent":["/**\n * Zero-dependency RTF (Rich Text Format) → HTML renderer for the side viewer's {@link RtfViewer}.\n *\n * RTF is a 7-bit-ASCII control-word format — `{\\rtf1 … }` groups, `\\word`/`\\word42` control words, `\\'hh` raw\n * bytes, `\\uN` unicode — so (like the eml / mht / har / asn1 parsers) we hand-roll it rather than pull a heavy\n * canvas-based library. We interpret the document with a group state stack and emit a small, SAFE HTML tree:\n *\n * - paragraphs (`\\par`) → `<p>` with text-align; soft breaks (`\\line`) → `\\n` (the container is white-space:\n * pre-wrap, so `\\tab`/`\\n`/runs of spaces survive without needing `<br>`);\n * - character runs → `<span style>` carrying ONLY whitelisted, self-computed values: bold/italic via\n * font-weight/style, underline/strike via text-decoration, `\\cfN` → `#rrggbb` from the parsed color table,\n * `\\fsN` → pt, `\\fN` → a sanitized font-family stack from the font table, `\\super`/`\\sub` → vertical-align.\n *\n * Security: every byte of text is HTML-escaped and the only attributes we emit are numbers (sizes), `#rrggbb`\n * colors, and a quote-/bracket-stripped font name — there is NO path for upstream markup, URLs, or scripts to\n * reach the output, so the component can inline it with `v-html` (same posture as DrawioViewer/WidgetBlock's\n * self-generated SVG). Unknown control words, binary blobs (`\\bin`), pictures and other destinations we don't\n * render are skipped, never dumped as raw text.\n *\n * Charset handling: `\\'hh` bytes are decoded with a TextDecoder chosen from the current font's `\\fcharset` (or\n * the document's `\\ansicpg`), so CJK / Cyrillic / etc. documents read correctly; `\\uN` carries unicode directly\n * (with `\\ucN` fallback bytes skipped). Multi-byte `\\'hh` pairs are buffered and decoded together — we only\n * flush the byte buffer at formatting/group boundaries, never between two adjacent `\\'` escapes.\n */\n\n/** One styled text run within a paragraph. Booleans/values map 1:1 to a `<span style>` (see {@link runHtml}). */\nexport interface RtfRun {\n text: string\n bold: boolean\n italic: boolean\n underline: boolean\n strike: boolean\n superscript: boolean\n subscript: boolean\n /** '#rrggbb' from the color table (`\\cfN`), or null for the automatic/default color. */\n color: string | null\n /** Point size (`\\fsN` is half-points), or null to inherit the container's size. */\n size: number | null\n /** A sanitized CSS font-family stack (e.g. `'Times New Roman', serif`), or null to inherit. */\n font: string | null\n}\n\n/** A paragraph: its alignment plus the styled runs it holds (empty runs ⇒ a blank line). */\nexport interface RtfPara {\n align: 'left' | 'center' | 'right' | 'justify'\n runs: RtfRun[]\n}\n\nexport interface RtfDoc {\n paras: RtfPara[]\n}\n\n/** Per-group interpreter state — cloned on `{`, restored on `}`. Character + paragraph formatting both live here\n * (RTF saves/restores both with the group), alongside the active destination and the `\\uc` fallback width. */\ninterface Frame {\n bold: boolean\n italic: boolean\n underline: boolean\n strike: boolean\n sup: boolean\n sub: boolean\n /** Font size in HALF-points (`\\fsN`), or null when unspecified. */\n size: number | null\n /** Index into the color table (`\\cfN`); 0 / negative ⇒ automatic. */\n colorIdx: number\n /** Index into the font table (`\\fN`); negative ⇒ use the document default font. */\n fontIdx: number\n align: 'left' | 'center' | 'right' | 'justify'\n /**\n * null = normal body text. Otherwise a destination we treat specially: 'fonttbl'/'colortbl' route bytes to\n * those table parsers; 'skip' swallows everything (ignorable groups, pictures, stylesheet, info, …).\n */\n dest: null | 'fonttbl' | 'colortbl' | 'skip'\n /** `\\ucN`: how many fallback bytes/chars follow a `\\uN` and must be discarded. */\n uc: number\n}\n\ninterface FontEntry {\n charset: number\n /** Generic CSS family from `\\froman`/`\\fswiss`/… ('serif'|'sans-serif'|'monospace'|'cursive'|'fantasy'|''). */\n family: string\n name: string\n}\n\nconst BACKSLASH = 0x5c\nconst LBRACE = 0x7b\nconst RBRACE = 0x7d\nconst SEMI = 0x3b\nconst APOS = 0x27 // '\n\n// Destinations whose content must NOT appear in the body. fonttbl/colortbl are handled separately (parsed, not\n// skipped); these are pure-skip. `\\*` (ignorable-destination marker) adds skip for anything we don't understand.\nconst SKIP_DESTS = new Set([\n 'stylesheet',\n 'info',\n 'pict',\n 'object',\n 'header',\n 'headerl',\n 'headerr',\n 'headerf',\n 'footer',\n 'footerl',\n 'footerr',\n 'footerf',\n 'footnote',\n 'annotation',\n 'atnid',\n 'atnauthor',\n 'generator',\n 'datastore',\n 'themedata',\n 'colorschememapping',\n 'latentstyles',\n 'listtable',\n 'listoverridetable',\n 'revtbl',\n 'rsidtbl',\n 'xmlnstbl',\n 'fldinst',\n 'pgptbl',\n 'sn',\n 'sv',\n 'company',\n 'operator',\n 'nesttableprops',\n 'bkmkstart',\n 'bkmkend',\n])\n\nfunction isAlpha(b: number): boolean {\n return (b >= 0x41 && b <= 0x5a) || (b >= 0x61 && b <= 0x7a)\n}\nfunction isDigit(b: number): boolean {\n return b >= 0x30 && b <= 0x39\n}\nfunction hexVal(b: number): number {\n if (b >= 0x30 && b <= 0x39) return b - 0x30\n if (b >= 0x61 && b <= 0x66) return b - 0x61 + 10\n if (b >= 0x41 && b <= 0x46) return b - 0x41 + 10\n return 0\n}\n\nconst decoderCache = new Map<string, TextDecoder>()\nfunction decode(bytes: number[], label: string): string {\n let dec = decoderCache.get(label)\n if (!dec) {\n try {\n dec = new TextDecoder(label)\n } catch {\n dec = new TextDecoder('windows-1252')\n }\n decoderCache.set(label, dec)\n }\n return dec.decode(new Uint8Array(bytes))\n}\n\n/** Windows code page (`\\ansicpgN`) → a WHATWG encoding label a TextDecoder understands. */\nfunction labelForCpg(cpg: number): string {\n switch (cpg) {\n case 65001:\n return 'utf-8'\n case 936:\n return 'gb18030' // superset of GBK/GB2312\n case 950:\n return 'big5'\n case 932:\n return 'shift_jis'\n case 949:\n return 'euc-kr'\n case 874:\n return 'windows-874'\n case 1250:\n return 'windows-1250'\n case 1251:\n return 'windows-1251'\n case 1253:\n return 'windows-1253'\n case 1254:\n return 'windows-1254'\n case 1255:\n return 'windows-1255'\n case 1256:\n return 'windows-1256'\n case 1257:\n return 'windows-1257'\n case 1258:\n return 'windows-1258'\n case 10000:\n return 'macintosh'\n default:\n return 'windows-1252'\n }\n}\n\nexport function parseRtf(bytes: Uint8Array): RtfDoc {\n const n = bytes.length\n let i = 0\n\n const base: Frame = {\n bold: false,\n italic: false,\n underline: false,\n strike: false,\n sup: false,\n sub: false,\n size: null,\n colorIdx: 0,\n fontIdx: -1,\n align: 'left',\n dest: null,\n uc: 1,\n }\n const stack: Frame[] = [base]\n const top = (): Frame => stack[stack.length - 1]\n\n let docCpg = 1252\n let defFont = 0\n const fonts: Record<number, FontEntry> = {}\n const colors: (string | null)[] = []\n\n // Font-charset (`\\fcharsetN`) → encoding label; charset 0/1 (ansi/default) defer to the document code page.\n function labelForCharset(cs: number): string {\n switch (cs) {\n case 77:\n return 'macintosh'\n case 128:\n return 'shift_jis'\n case 129:\n case 130:\n return 'euc-kr'\n case 134:\n return 'gb18030'\n case 136:\n return 'big5'\n case 161:\n return 'windows-1253'\n case 162:\n return 'windows-1254'\n case 163:\n return 'windows-1258'\n case 177:\n return 'windows-1255'\n case 178:\n return 'windows-1256'\n case 186:\n return 'windows-1257'\n case 204:\n return 'windows-1251'\n case 222:\n return 'windows-874'\n case 238:\n return 'windows-1250'\n default:\n return labelForCpg(docCpg)\n }\n }\n\n // ---- output accumulation ----\n const paras: RtfPara[] = []\n let curRuns: RtfRun[] = []\n const pendingBytes: number[] = []\n let unicodeSkip = 0\n\n // ---- font-table parse temp ----\n let ftIndex = -1\n let ftCharset = 0\n let ftFamily = ''\n let ftName: number[] = []\n // ---- color-table parse temp ----\n let ctR = 0\n let ctG = 0\n let ctB = 0\n let ctHas = false\n\n function colorFor(idx: number): string | null {\n if (idx <= 0) return null\n return colors[idx] ?? null\n }\n function fontStackFor(idx: number): string | null {\n const f = fonts[idx] ?? fonts[defFont]\n if (!f) return null\n const name = f.name\n .replace(/['\"<>;{}\\\\\\r\\n]/g, '')\n .trim()\n .slice(0, 64)\n if (name && f.family) return `'${name}', ${f.family}`\n if (name) return `'${name}'`\n return f.family || null\n }\n\n function currentFmt(): RtfRun {\n const f = top()\n return {\n text: '',\n bold: f.bold,\n italic: f.italic,\n underline: f.underline,\n strike: f.strike,\n superscript: f.sup,\n subscript: f.sub,\n color: colorFor(f.colorIdx),\n size: f.size != null ? f.size / 2 : null,\n font: fontStackFor(f.fontIdx >= 0 ? f.fontIdx : defFont),\n }\n }\n function sameFmt(a: RtfRun, b: RtfRun): boolean {\n return (\n a.bold === b.bold &&\n a.italic === b.italic &&\n a.underline === b.underline &&\n a.strike === b.strike &&\n a.superscript === b.superscript &&\n a.subscript === b.subscript &&\n a.color === b.color &&\n a.size === b.size &&\n a.font === b.font\n )\n }\n /** Append intended (already-decoded) body text, extending the last run when its formatting matches. */\n function pushText(s: string): void {\n if (!s) return\n const fmt = currentFmt()\n const last = curRuns[curRuns.length - 1]\n if (last && sameFmt(last, fmt)) last.text += s\n else {\n fmt.text = s\n curRuns.push(fmt)\n }\n }\n /** Decode the buffered body bytes under the CURRENT font/codepage and emit them as text. */\n function flushBytes(): void {\n if (!pendingBytes.length) return\n const f = top()\n const idx = f.fontIdx >= 0 ? f.fontIdx : defFont\n const cs = fonts[idx]?.charset\n const label = cs != null && cs > 1 ? labelForCharset(cs) : labelForCpg(docCpg)\n const s = decode(pendingBytes, label)\n pendingBytes.length = 0\n pushText(s)\n }\n /** Emit a single intended character (special chars: tab/line/quotes/dashes). Respects the `\\uc` skip window. */\n function emitChar(s: string): void {\n if (top().dest !== null) return\n if (unicodeSkip > 0) {\n unicodeSkip--\n return\n }\n pushText(s)\n }\n function endParagraph(): void {\n flushBytes()\n paras.push({ align: top().align, runs: curRuns })\n curRuns = []\n }\n\n function finalizeColor(): void {\n colors.push(ctHas ? rgbHex(ctR, ctG, ctB) : null)\n ctR = ctG = ctB = 0\n ctHas = false\n }\n function finalizeFont(): void {\n if (ftIndex >= 0) {\n const name = ftName.length\n ? decode(ftName, ftCharset > 1 ? labelForCharset(ftCharset) : labelForCpg(docCpg)).trim()\n : ''\n fonts[ftIndex] = { charset: ftCharset, family: ftFamily, name }\n }\n ftFamily = ''\n ftCharset = 0\n ftName = []\n }\n\n /** A raw literal byte of document content — routed by the active destination. */\n function literalByte(b: number): void {\n const f = top()\n if (unicodeSkip > 0) {\n unicodeSkip--\n return\n }\n if (f.dest === null) {\n pendingBytes.push(b)\n } else if (f.dest === 'colortbl') {\n if (b === SEMI) finalizeColor()\n } else if (f.dest === 'fonttbl') {\n if (b === SEMI) finalizeFont()\n else if (b !== 0x20 || ftName.length) ftName.push(b) // drop leading spaces before the name\n }\n // 'skip' → discard\n }\n\n function handleWord(word: string, param: number | null): void {\n const f = top()\n\n // Font-table entries (inside \\fonttbl): build the table rather than emit text.\n if (f.dest === 'fonttbl') {\n switch (word) {\n case 'f':\n finalizeFont() // a new \\fN starts a fresh entry (flat-form tables have no per-entry braces)\n ftIndex = param ?? 0\n return\n case 'fcharset':\n ftCharset = param ?? 0\n return\n case 'froman':\n ftFamily = 'serif'\n return\n case 'fswiss':\n ftFamily = 'sans-serif'\n return\n case 'fmodern':\n ftFamily = 'monospace'\n return\n case 'fscript':\n ftFamily = 'cursive'\n return\n case 'fdecor':\n ftFamily = 'fantasy'\n return\n case 'fnil':\n case 'ftech':\n case 'fbidi':\n ftFamily = ''\n return\n default:\n return // \\fprq, \\cpg, names handled as bytes, etc.\n }\n }\n // Color-table entries (inside \\colortbl): accumulate r/g/b; ';' (a literal byte) finalizes.\n if (f.dest === 'colortbl') {\n if (word === 'red') {\n ctR = param ?? 0\n ctHas = true\n } else if (word === 'green') {\n ctG = param ?? 0\n ctHas = true\n } else if (word === 'blue') {\n ctB = param ?? 0\n ctHas = true\n }\n return\n }\n\n switch (word) {\n // structural / header\n case 'rtf':\n case 'ansi':\n case 'mac':\n case 'pc':\n case 'pca':\n return\n case 'ansicpg':\n docCpg = param ?? 1252\n return\n case 'deff':\n defFont = param ?? 0\n return\n case 'uc':\n f.uc = param ?? 1\n return\n case 'fonttbl':\n f.dest = 'fonttbl'\n ftIndex = -1\n ftFamily = ''\n ftCharset = 0\n ftName = []\n return\n case 'colortbl':\n f.dest = 'colortbl'\n ctR = ctG = ctB = 0\n ctHas = false\n return\n case 'bin': {\n // Raw binary run: skip exactly param bytes so braces inside them can't corrupt group nesting.\n const len = Math.max(0, param ?? 0)\n i += len\n if (i > n) i = n\n return\n }\n\n // character formatting\n case 'b':\n f.bold = param !== 0\n return\n case 'i':\n f.italic = param !== 0\n return\n case 'ul':\n f.underline = param !== 0\n return\n case 'ulnone':\n f.underline = false\n return\n case 'strike':\n case 'striked':\n f.strike = param !== 0\n return\n case 'super':\n f.sup = param !== 0\n if (f.sup) f.sub = false\n return\n case 'sub':\n f.sub = param !== 0\n if (f.sub) f.sup = false\n return\n case 'nosupersub':\n f.sup = false\n f.sub = false\n return\n case 'fs':\n f.size = param ?? f.size\n return\n case 'cf':\n f.colorIdx = param ?? 0\n return\n case 'f':\n f.fontIdx = param ?? 0\n return\n case 'plain':\n f.bold = f.italic = f.underline = f.strike = f.sup = f.sub = false\n f.size = null\n f.colorIdx = 0\n f.fontIdx = defFont\n return\n\n // paragraph formatting\n case 'pard':\n f.align = 'left'\n return\n case 'ql':\n f.align = 'left'\n return\n case 'qc':\n f.align = 'center'\n return\n case 'qr':\n f.align = 'right'\n return\n case 'qj':\n case 'qd':\n f.align = 'justify'\n return\n\n // breaks\n case 'par':\n case 'sect':\n case 'row':\n case 'page':\n case 'column':\n endParagraph()\n return\n case 'line':\n case 'softline':\n emitChar('\\n')\n return\n case 'tab':\n case 'cell':\n emitChar('\\t')\n return\n\n // named special characters\n case 'lquote':\n emitChar('‘')\n return\n case 'rquote':\n emitChar('’')\n return\n case 'ldblquote':\n emitChar('“')\n return\n case 'rdblquote':\n emitChar('”')\n return\n case 'bullet':\n emitChar('•')\n return\n case 'endash':\n emitChar('–')\n return\n case 'emdash':\n emitChar('—')\n return\n case 'emspace':\n emitChar(' ')\n return\n case 'enspace':\n emitChar(' ')\n return\n case 'qmspace':\n emitChar(' ')\n return\n case 'zwnj':\n emitChar('‌')\n return\n case 'zwj':\n emitChar('‍')\n return\n\n // unicode code point + fallback-skip window\n case 'u': {\n let cp = param ?? 0\n if (cp < 0) cp += 0x10000\n if (f.dest === null && cp > 0) {\n try {\n pushText(String.fromCodePoint(cp))\n } catch {\n /* out-of-range code point — drop it */\n }\n }\n unicodeSkip = f.uc\n return\n }\n\n default:\n if (SKIP_DESTS.has(word)) f.dest = 'skip'\n // otherwise an unknown control word — ignore it (its group text still renders unless skipped)\n return\n }\n }\n\n function handleSymbol(c: number): void {\n switch (c) {\n case BACKSLASH:\n emitChar('\\\\')\n return\n case LBRACE:\n emitChar('{')\n return\n case RBRACE:\n emitChar('}')\n return\n case 0x7e: // \\~ non-breaking space\n emitChar(' ')\n return\n case 0x5f: // \\_ non-breaking hyphen\n emitChar('‑')\n return\n case 0x2d: // \\- optional hyphen → render nothing\n return\n case 0x2a: // \\* ignorable-destination marker\n top().dest = 'skip'\n return\n case 0x0a:\n case 0x0d: // escaped newline ⇒ paragraph break\n endParagraph()\n return\n default:\n return // \\:, \\|, etc. — ignore\n }\n }\n\n // ---- main scan ----\n while (i < n) {\n const b = bytes[i]\n if (b === LBRACE) {\n flushBytes()\n stack.push({ ...top() })\n i++\n } else if (b === RBRACE) {\n flushBytes()\n if (stack.length > 1) stack.pop()\n i++\n } else if (b === BACKSLASH) {\n i++\n if (i >= n) break\n const c = bytes[i]\n if (isAlpha(c)) {\n flushBytes() // a control word may change formatting/destination — decode pending bytes first\n let word = ''\n while (i < n && isAlpha(bytes[i])) {\n word += String.fromCharCode(bytes[i])\n i++\n }\n let param: number | null = null\n let neg = false\n if (i < n && bytes[i] === 0x2d) {\n neg = true\n i++\n }\n if (i < n && isDigit(bytes[i])) {\n let num = 0\n while (i < n && isDigit(bytes[i])) {\n num = num * 10 + (bytes[i] - 0x30)\n i++\n }\n param = neg ? -num : num\n }\n if (i < n && bytes[i] === 0x20) i++ // consume the single optional delimiter space\n handleWord(word, param)\n } else if (c === APOS) {\n // \\'hh — a raw byte; buffer it (NO flush) so adjacent escapes form multi-byte sequences.\n i++\n let byte = 0\n if (i < n) byte = hexVal(bytes[i++])\n if (i < n) byte = byte * 16 + hexVal(bytes[i++])\n literalByte(byte)\n } else {\n i++\n flushBytes()\n handleSymbol(c)\n }\n } else if (b === 0x0d || b === 0x0a) {\n i++ // raw CR/LF in the source is not body text\n } else {\n i++\n literalByte(b)\n }\n }\n\n flushBytes()\n if (curRuns.length) paras.push({ align: top().align, runs: curRuns })\n return { paras }\n}\n\nfunction rgbHex(r: number, g: number, b: number): string {\n const h = (v: number): string => Math.max(0, Math.min(255, v)).toString(16).padStart(2, '0')\n return `#${h(r)}${h(g)}${h(b)}`\n}\n\nfunction escapeHtml(s: string): string {\n return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')\n}\n\n/** Render one run to a `<span style>` (or bare escaped text when it carries no formatting). */\nfunction runHtml(r: RtfRun): string {\n const styles: string[] = []\n if (r.bold) styles.push('font-weight:bold')\n if (r.italic) styles.push('font-style:italic')\n if (r.underline && r.strike) styles.push('text-decoration:underline line-through')\n else if (r.underline) styles.push('text-decoration:underline')\n else if (r.strike) styles.push('text-decoration:line-through')\n if (r.color) styles.push(`color:${r.color}`)\n if (r.font) styles.push(`font-family:${r.font}`)\n let fontSize = r.size ? `${r.size}pt` : ''\n if (r.superscript || r.subscript) {\n styles.push(`vertical-align:${r.superscript ? 'super' : 'sub'}`)\n fontSize = r.size ? `${(r.size * 0.83).toFixed(1)}pt` : '0.83em'\n }\n if (fontSize) styles.push(`font-size:${fontSize}`)\n const text = escapeHtml(r.text)\n return styles.length ? `<span style=\"${styles.join(';')}\">${text}</span>` : text\n}\n\n/** Render a parsed document to a safe HTML string (self-generated, fully escaped — see the file header). */\nexport function rtfToHtml(doc: RtfDoc): string {\n let html = ''\n for (const p of doc.paras) {\n const inner = p.runs.map(runHtml).join('')\n const align = p.align !== 'left' ? ` style=\"text-align:${p.align}\"` : ''\n html += `<p${align}>${inner || '<br>'}</p>`\n }\n return html\n}\n\n/** Parse + render in one step: RTF bytes → safe HTML. */\nexport function renderRtf(bytes: Uint8Array): string {\n return rtfToHtml(parseRtf(bytes))\n}\n"],"mappings":"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"}
@@ -393,3 +393,5 @@ function q(e, t, n, r) {
393
393
  }
394
394
  //#endregion
395
395
  export { w as SevenZipEncryptedError, T as SevenZipPasswordError, q as extractSevenZipEntry, W as readSevenZip };
396
+
397
+ //# sourceMappingURL=sevenZip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sevenZip.js","names":[],"sources":["../../src/lib/sevenZip.ts"],"sourcesContent":["/**\n * Minimal in-browser 7z reader — no dependency, no WASM.\n *\n * Mirrors {@link lib/zip.ts}: hand-rolled structural parsing over a DataView/Uint8Array, decoding only\n * what conversation artifacts actually ship. The 7z container is considerably more involved than ZIP —\n * its directory (\"header\") is itself usually LZMA-compressed and describes *folders* (chains of coders)\n * rather than per-file streams — so this leans on the bundled LZMA decoder ({@link lib/lzma.ts}) both to\n * read the header and to extract files. Supported coders: Copy (00), LZMA (03 01 01), LZMA2 (21) and the\n * x86 BCJ filter (03 03 01 03); anything else (other branch filters, BCJ2, AES) is surfaced as an error.\n *\n * Used by SevenZipBrowser (the side viewer's 7z mode): the bytes come from the same download endpoint as\n * any other file, are decompressed entirely client-side, and never leave the browser.\n */\n\nimport { aesCbcDecrypt } from '@/lib/aes'\nimport { bcjX86Decode, lzma2Decode, lzmaDecode } from '@/lib/lzma'\nimport { Sha256 } from '@/lib/sha256'\n\nconst SIGNATURE = [0x37, 0x7a, 0xbc, 0xaf, 0x27, 0x1c] // \"7z\\xBC\\xAF\\x27\\x1C\"\nconst SIG_HEADER_SIZE = 32\n\n// Header property ids.\nconst K_END = 0x00\nconst K_HEADER = 0x01\nconst K_MAIN_STREAMS_INFO = 0x04\nconst K_FILES_INFO = 0x05\nconst K_PACK_INFO = 0x06\nconst K_UNPACK_INFO = 0x07\nconst K_SUBSTREAMS_INFO = 0x08\nconst K_SIZE = 0x09\nconst K_CRC = 0x0a\nconst K_FOLDER = 0x0b\nconst K_CODERS_UNPACK_SIZE = 0x0c\nconst K_NUM_UNPACK_STREAM = 0x0d\nconst K_EMPTY_STREAM = 0x0e\nconst K_EMPTY_FILE = 0x0f\nconst K_NAME = 0x11\nconst K_ENCODED_HEADER = 0x17\n\n// AES-256 + SHA-256 coder method id — 7z whole-header (\"encrypt file names\") or per-file content encryption.\nconst AES_CODER = '06f10701'\n\n/** Thrown when the archive (its header or an entry) is AES-encrypted and no password was supplied. */\nexport class SevenZipEncryptedError extends Error {\n constructor() {\n super('该 7z 已加密,需要密码')\n this.name = 'SevenZipEncryptedError'\n }\n}\n/** Thrown when the supplied password fails to decrypt the header/content. */\nexport class SevenZipPasswordError extends Error {\n constructor() {\n super('密码错误,无法解压')\n this.name = 'SevenZipPasswordError'\n }\n}\n\nexport interface SevenZipEntry {\n /** Full path within the archive, forward-slashed. */\n path: string\n /** Basename (last path segment). */\n name: string\n /** Uncompressed size in bytes. */\n size: number\n /** Directory entry. */\n isDir: boolean\n /** True when this file's folder is AES-encrypted (extraction / listing needs a password). */\n encrypted: boolean\n /** Index of the folder holding this file's bytes (-1 for empty files / directories). */\n folderIndex: number\n /** Byte offset of this file within its (solid) folder's decoded output. */\n offsetInFolder: number\n}\n\ninterface Coder {\n /** Method id as a hex string, e.g. \"00\", \"21\", \"030101\", \"03030103\". */\n id: string\n numIn: number\n numOut: number\n props: Uint8Array\n}\n\ninterface BindPair {\n inIndex: number\n outIndex: number\n}\n\ninterface Folder {\n coders: Coder[]\n bindPairs: BindPair[]\n /** Global in-stream indices fed by the archive's packed streams, in pack order. */\n packedIndices: number[]\n /** Unpacked size per global out-stream. */\n unpackSizes: number[]\n numPackStreams: number\n /** Byte ranges (absolute offsets into the archive) of this folder's packed streams. */\n packStreams: { offset: number; size: number }[]\n}\n\nexport interface SevenZipArchive {\n entries: SevenZipEntry[]\n /** Internal: parsed folder metadata, consumed by {@link extractSevenZipEntry}. */\n folders: Folder[]\n}\n\n/** A cursor over the (already-decoded) header byte stream. */\nclass Reader {\n pos = 0\n constructor(public readonly buf: Uint8Array) {}\n\n byte(): number {\n if (this.pos >= this.buf.length) throw new Error('7z 头部意外结束')\n return this.buf[this.pos++]\n }\n\n bytes(n: number): Uint8Array {\n const s = this.buf.subarray(this.pos, this.pos + n)\n this.pos += n\n return s\n }\n\n /** 7z variable-length number (REAL_UINT64): the first byte's high bits count the extra bytes. */\n number(): number {\n const first = this.byte()\n let mask = 0x80\n let value = 0\n for (let i = 0; i < 8; i++) {\n if ((first & mask) === 0) {\n value += (first & (mask - 1)) * 2 ** (8 * i)\n break\n }\n value += this.byte() * 2 ** (8 * i)\n mask >>= 1\n }\n return value\n }\n\n /** A bit vector of `n` bits, MSB-first within each byte. */\n bitVector(n: number): boolean[] {\n const v: boolean[] = []\n let b = 0\n let mask = 0\n for (let i = 0; i < n; i++) {\n if (mask === 0) {\n b = this.byte()\n mask = 0x80\n }\n v.push((b & mask) !== 0)\n mask >>= 1\n }\n return v\n }\n\n /** A \"defined\" vector: a leading all-defined flag, else an explicit bit vector. */\n boolVectorWithAll(n: number): boolean[] {\n if (this.byte() !== 0) return Array.from({ length: n }, () => true)\n return this.bitVector(n)\n }\n}\n\nfunction readUInt64LE(view: DataView, off: number): number {\n return view.getUint32(off + 4, true) * 0x100000000 + view.getUint32(off, true)\n}\n\n// ── Folder / streams parsing ──────────────────────────────────────────────────────────────────────\n\nfunction readFolder(r: Reader): Folder {\n const numCoders = r.number()\n const coders: Coder[] = []\n let totalIn = 0\n let totalOut = 0\n for (let i = 0; i < numCoders; i++) {\n const flags = r.byte()\n const idSize = flags & 0x0f\n const idBytes = r.bytes(idSize)\n let id = ''\n for (const b of idBytes) id += b.toString(16).padStart(2, '0')\n let numIn = 1\n let numOut = 1\n if (flags & 0x10) {\n numIn = r.number()\n numOut = r.number()\n }\n let props = new Uint8Array(0)\n if (flags & 0x20) props = r.bytes(r.number()).slice()\n coders.push({ id, numIn, numOut, props })\n totalIn += numIn\n totalOut += numOut\n }\n\n const numBindPairs = totalOut - 1\n const bindPairs: BindPair[] = []\n for (let i = 0; i < numBindPairs; i++) {\n bindPairs.push({ inIndex: r.number(), outIndex: r.number() })\n }\n\n const numPackStreams = totalIn - numBindPairs\n const packedIndices: number[] = []\n if (numPackStreams === 1) {\n // the single in-stream not used by any bind pair\n for (let i = 0; i < totalIn; i++) {\n if (!bindPairs.some((bp) => bp.inIndex === i)) {\n packedIndices.push(i)\n break\n }\n }\n } else {\n for (let i = 0; i < numPackStreams; i++) packedIndices.push(r.number())\n }\n\n return {\n coders,\n bindPairs,\n packedIndices,\n unpackSizes: [],\n numPackStreams,\n packStreams: [],\n }\n}\n\n/** The folder's final output is the one out-stream not consumed by any bind pair. */\nfunction folderFinalOutIndex(folder: Folder): number {\n let total = 0\n for (const c of folder.coders) total += c.numOut\n for (let i = 0; i < total; i++) {\n if (!folder.bindPairs.some((bp) => bp.outIndex === i)) return i\n }\n return total - 1\n}\n\nfunction folderUnpackSize(folder: Folder): number {\n return folder.unpackSizes[folderFinalOutIndex(folder)] ?? 0\n}\n\ninterface StreamsInfo {\n packPos: number\n packSizes: number[]\n folders: Folder[]\n /** Per-folder substream count (solid archives pack several files into one folder). */\n numUnpackStreamsInFolders: number[]\n /** Flat list of substream sizes, in folder order. */\n subSizes: number[]\n /** Whether each folder carried its own CRC in UnpackInfo (affects the SubStreamsInfo digest count). */\n folderHasCrc: boolean[]\n}\n\nfunction readStreamsInfo(r: Reader): StreamsInfo {\n const info: StreamsInfo = {\n packPos: 0,\n packSizes: [],\n folders: [],\n numUnpackStreamsInFolders: [],\n subSizes: [],\n folderHasCrc: [],\n }\n let id = r.byte()\n\n if (id === K_PACK_INFO) {\n info.packPos = r.number()\n const numPack = r.number()\n let sub = r.byte()\n while (sub !== K_END) {\n if (sub === K_SIZE) {\n for (let i = 0; i < numPack; i++) info.packSizes.push(r.number())\n } else if (sub === K_CRC) {\n readDigests(r, numPack)\n } else {\n throw new Error(`7z PackInfo 未知字段 0x${sub.toString(16)}`)\n }\n sub = r.byte()\n }\n id = r.byte()\n }\n\n if (id === K_UNPACK_INFO) {\n if (r.byte() !== K_FOLDER) throw new Error('7z UnpackInfo 缺少 Folder')\n const numFolders = r.number()\n const external = r.byte()\n if (external !== 0) throw new Error('7z 不支持外部 Folder 定义')\n for (let i = 0; i < numFolders; i++) info.folders.push(readFolder(r))\n if (r.byte() !== K_CODERS_UNPACK_SIZE) throw new Error('7z 缺少 CodersUnpackSize')\n for (const folder of info.folders) {\n let totalOut = 0\n for (const c of folder.coders) totalOut += c.numOut\n for (let i = 0; i < totalOut; i++) folder.unpackSizes.push(r.number())\n }\n info.folderHasCrc = info.folders.map(() => false)\n let sub = r.byte()\n while (sub !== K_END) {\n if (sub === K_CRC) {\n info.folderHasCrc = readDigests(r, info.folders.length)\n } else {\n throw new Error(`7z UnpackInfo 未知字段 0x${sub.toString(16)}`)\n }\n sub = r.byte()\n }\n id = r.byte()\n }\n\n // Default: one substream per folder. SubStreamsInfo overrides when present.\n info.numUnpackStreamsInFolders = info.folders.map(() => 1)\n if (id === K_SUBSTREAMS_INFO) {\n readSubStreamsInfo(r, info)\n id = r.byte()\n } else {\n info.subSizes = info.folders.map((f) => folderUnpackSize(f))\n }\n\n if (id !== K_END) throw new Error(`7z StreamsInfo 未以 End 结束 (0x${id.toString(16)})`)\n\n // Slice the archive's pack streams across folders in order, computing absolute offsets.\n let packIndex = 0\n let offset = SIG_HEADER_SIZE + info.packPos\n const packOffsets: number[] = []\n for (const sz of info.packSizes) {\n packOffsets.push(offset)\n offset += sz\n }\n for (const folder of info.folders) {\n for (let i = 0; i < folder.numPackStreams; i++) {\n folder.packStreams.push({ offset: packOffsets[packIndex], size: info.packSizes[packIndex] })\n packIndex++\n }\n }\n return info\n}\n\nfunction readSubStreamsInfo(r: Reader, info: StreamsInfo): void {\n let type = r.byte()\n if (type === K_NUM_UNPACK_STREAM) {\n info.numUnpackStreamsInFolders = info.folders.map(() => r.number())\n type = r.byte()\n } else {\n info.numUnpackStreamsInFolders = info.folders.map(() => 1)\n }\n\n const subSizes: number[] = []\n for (let f = 0; f < info.folders.length; f++) {\n const num = info.numUnpackStreamsInFolders[f]\n if (num === 0) continue\n let sum = 0\n if (type === K_SIZE) {\n for (let i = 1; i < num; i++) {\n const s = r.number()\n subSizes.push(s)\n sum += s\n }\n }\n subSizes.push(folderUnpackSize(info.folders[f]) - sum)\n }\n info.subSizes = subSizes\n if (type === K_SIZE) type = r.byte()\n\n // The SubStreamsInfo CRC block lists a digest only for substreams that don't already inherit a\n // folder-level CRC: a folder contributes its substream count, except a 1-substream folder that already\n // has its own CRC (which contributes none).\n let numDigests = 0\n for (let f = 0; f < info.folders.length; f++) {\n const num = info.numUnpackStreamsInFolders[f]\n if (num !== 1 || !info.folderHasCrc[f]) numDigests += num\n }\n if (type === K_CRC) {\n readDigests(r, numDigests)\n type = r.byte()\n }\n while (type !== K_END) type = r.byte() // defensively skip any unknown trailing field\n}\n\n/**\n * Read a digest block — an all-defined flag (or explicit bit vector) followed by a CRC32 per defined\n * entry — and return which entries were defined. The CRC values themselves are discarded (we don't verify).\n */\nfunction readDigests(r: Reader, count: number): boolean[] {\n const defined = r.boolVectorWithAll(count)\n for (const d of defined) if (d) r.bytes(4)\n return defined\n}\n\n// ── Files info ──────────────────────────────────────────────────────────────────────────────────\n\ninterface FilesInfo {\n names: string[]\n emptyStream: boolean[]\n emptyFile: boolean[]\n}\n\nfunction readFilesInfo(r: Reader): FilesInfo {\n const numFiles = r.number()\n const out: FilesInfo = {\n names: Array.from({ length: numFiles }, () => ''),\n emptyStream: Array.from({ length: numFiles }, () => false),\n emptyFile: [],\n }\n let numEmptyStreams = 0\n\n for (;;) {\n const propType = r.number()\n if (propType === K_END) break\n const size = r.number()\n const end = r.pos + size\n switch (propType) {\n case K_EMPTY_STREAM: {\n out.emptyStream = r.bitVector(numFiles)\n numEmptyStreams = out.emptyStream.filter(Boolean).length\n out.emptyFile = Array.from({ length: numEmptyStreams }, () => false)\n break\n }\n case K_EMPTY_FILE: {\n out.emptyFile = r.bitVector(numEmptyStreams)\n break\n }\n case K_NAME: {\n const external = r.byte()\n if (external !== 0) throw new Error('7z 不支持外部文件名')\n out.names = readNames(r, end, numFiles)\n break\n }\n default:\n break // CTime/ATime/MTime/Attributes/Dummy/… — not needed for browsing\n }\n r.pos = end // robust to partial reads\n }\n return out\n}\n\n/** Names are NUL-terminated UTF-16LE, concatenated. */\nfunction readNames(r: Reader, end: number, numFiles: number): string[] {\n const names: string[] = []\n let cur = ''\n while (r.pos + 1 < end && names.length < numFiles) {\n const lo = r.byte()\n const hi = r.byte()\n const code = lo | (hi << 8)\n if (code === 0) {\n names.push(cur)\n cur = ''\n } else {\n cur += String.fromCharCode(code)\n }\n }\n return names\n}\n\n// ── Header assembly ───────────────────────────────────────────────────────────────────────────────\n\nfunction buildEntries(streams: StreamsInfo | null, files: FilesInfo): SevenZipEntry[] {\n const entries: SevenZipEntry[] = []\n const numFiles = files.names.length\n\n // Walk the per-folder substreams in order, assigning each to the next file that has a stream.\n let folderIdx = 0\n let subInFolder = 0\n let offsetInFolder = 0\n let subSizeIdx = 0\n let emptyIdx = 0\n\n const advanceFolder = (): void => {\n // Move to the next folder that actually has substreams.\n while (\n streams &&\n folderIdx < streams.folders.length &&\n subInFolder >= streams.numUnpackStreamsInFolders[folderIdx]\n ) {\n folderIdx++\n subInFolder = 0\n offsetInFolder = 0\n }\n }\n\n for (let i = 0; i < numFiles; i++) {\n const path = files.names[i].replace(/\\\\/g, '/')\n const name = path.replace(/\\/+$/, '').split('/').pop() ?? path\n const hasStream = !files.emptyStream[i]\n if (hasStream) {\n advanceFolder()\n const size = streams ? streams.subSizes[subSizeIdx++] : 0\n entries.push({\n path,\n name,\n size,\n isDir: false,\n encrypted: streams ? folderHasAes(streams.folders[folderIdx]) : false,\n folderIndex: folderIdx,\n offsetInFolder,\n })\n offsetInFolder += size\n subInFolder++\n } else {\n // No stream: an empty file or a directory (distinguished by the emptyFile vector).\n const isEmptyFile = files.emptyFile[emptyIdx++] === true\n entries.push({\n path,\n name,\n size: 0,\n isDir: !isEmptyFile,\n encrypted: false,\n folderIndex: -1,\n offsetInFolder: 0,\n })\n }\n }\n return entries\n}\n\nfunction parseHeader(r: Reader): SevenZipArchive {\n const top = r.byte()\n if (top !== K_HEADER) throw new Error(`7z 头部类型异常 (0x${top.toString(16)})`)\n let id = r.byte()\n let streams: StreamsInfo | null = null\n let files: FilesInfo = { names: [], emptyStream: [], emptyFile: [] }\n\n // ArchiveProperties / AdditionalStreamsInfo are skipped — none of our archives use them.\n if (id === K_MAIN_STREAMS_INFO) {\n streams = readStreamsInfo(r)\n id = r.byte()\n }\n if (id === K_FILES_INFO) {\n files = readFilesInfo(r)\n id = r.byte()\n }\n\n return { entries: buildEntries(streams, files), folders: streams?.folders ?? [] }\n}\n\n// ── AES-256 decryption (encrypted 7z) ─────────────────────────────────────────────────────────────\n\ninterface DecodeCtx {\n password?: string\n}\n\n/** Does any coder in this folder apply 7z AES encryption? */\nfunction folderHasAes(folder: Folder): boolean {\n return folder.coders.some((c) => c.id === AES_CODER)\n}\n\n/** Password bytes as UTF-16LE (7z hashes the password this way). */\nfunction utf16le(s: string): Uint8Array {\n const b = new Uint8Array(s.length * 2)\n for (let i = 0; i < s.length; i++) {\n const c = s.charCodeAt(i)\n b[2 * i] = c & 0xff\n b[2 * i + 1] = (c >> 8) & 0xff\n }\n return b\n}\n\n/**\n * Derive the AES-256 key + IV for a 7z AES coder from its property bytes and the password. Property layout:\n * byte0 = numCyclesPower(bits 0-5) | saltPresent(bit 7) | ivPresent(bit 6); an optional byte1 packs extra\n * salt size (high nibble) + iv size (low nibble); then `saltSize` salt bytes, then `ivSize` iv bytes (zero-\n * padded to 16). The key is SHA-256( (salt ‖ passwordUTF16LE ‖ counterLE64) repeated 2^numCyclesPower times ),\n * the counter incrementing each round. numCyclesPower 0x3F is the degenerate \"no hashing\" form (key = salt ‖\n * password, truncated / zero-padded to 32 bytes).\n */\nfunction deriveSevenZipKey(\n props: Uint8Array,\n password: string,\n): { key: Uint8Array; iv: Uint8Array } {\n const b0 = props[0] ?? 0\n const numCyclesPower = b0 & 0x3f\n let saltSize = (b0 >> 7) & 1\n let ivSize = (b0 >> 6) & 1\n if (props.length >= 2) {\n const b1 = props[1]\n saltSize += b1 >> 4\n ivSize += b1 & 0x0f\n }\n const salt = props.subarray(2, 2 + saltSize)\n const iv = new Uint8Array(16)\n iv.set(props.subarray(2 + saltSize, 2 + saltSize + ivSize))\n\n const pass = utf16le(password)\n const key = new Uint8Array(32)\n if (numCyclesPower === 0x3f) {\n let pos = 0\n for (let i = 0; i < salt.length && pos < 32; i++) key[pos++] = salt[i]\n for (let i = 0; i < pass.length && pos < 32; i++) key[pos++] = pass[i]\n return { key, iv }\n }\n const rounds = 2 ** numCyclesPower\n const sha = new Sha256()\n const counter = new Uint8Array(8)\n for (let r = 0; r < rounds; r++) {\n if (salt.length) sha.update(salt)\n sha.update(pass)\n sha.update(counter)\n for (let i = 0; i < 8; i++) {\n counter[i] = (counter[i] + 1) & 0xff\n if (counter[i] !== 0) break\n }\n }\n key.set(sha.digest())\n return { key, iv }\n}\n\n// ── Coder / folder decoding ─────────────────────────────────────────────────────────────────────\n\nfunction decodeCoder(\n coder: Coder,\n inputs: Uint8Array[],\n outSize: number,\n ctx?: DecodeCtx,\n): Uint8Array {\n switch (coder.id) {\n case '00': // Copy\n return inputs[0].length === outSize ? inputs[0] : inputs[0].subarray(0, outSize)\n case '21': // LZMA2\n return lzma2Decode(inputs[0], coder.props, outSize)\n case '030101': // LZMA\n return lzmaDecode(inputs[0], coder.props, outSize)\n case '03030103': {\n // x86 BCJ — an in-place filter; copy so we don't mutate a shared buffer, then decode.\n const data = inputs[0].slice(0, outSize)\n bcjX86Decode(data)\n return data\n }\n case AES_CODER: {\n // AES-256-CBC: derive key+IV from the password, decrypt, then trim to the coder's real output size\n // (the ciphertext is padded up to a 16-byte boundary).\n if (!ctx?.password) throw new SevenZipEncryptedError()\n const { key, iv } = deriveSevenZipKey(coder.props, ctx.password)\n const dec = aesCbcDecrypt(key, iv, inputs[0])\n return dec.length === outSize ? dec : dec.subarray(0, outSize)\n }\n default:\n throw new Error(`不支持的压缩方式 (coder ${coder.id})`)\n }\n}\n\n/** Decode a folder's final output by resolving the coder graph (bind pairs ↔ packed streams). */\nfunction decodeFolder(buf: Uint8Array, folder: Folder, ctx?: DecodeCtx): Uint8Array {\n // Per-coder global stream base indices.\n const inBase: number[] = []\n const outBase: number[] = []\n let ti = 0\n let to = 0\n for (const c of folder.coders) {\n inBase.push(ti)\n outBase.push(to)\n ti += c.numIn\n to += c.numOut\n }\n\n const coderForOut = (outIndex: number): number => {\n for (let c = 0; c < folder.coders.length; c++) {\n if (outIndex >= outBase[c] && outIndex < outBase[c] + folder.coders[c].numOut) return c\n }\n throw new Error('7z folder 输出流索引越界')\n }\n\n const memo = new Map<number, Uint8Array>()\n const resolveOut = (outIndex: number): Uint8Array => {\n const cached = memo.get(outIndex)\n if (cached) return cached\n const c = coderForOut(outIndex)\n const coder = folder.coders[c]\n const inputs: Uint8Array[] = []\n for (let k = 0; k < coder.numIn; k++) {\n const globalIn = inBase[c] + k\n const bp = folder.bindPairs.find((b) => b.inIndex === globalIn)\n if (bp) {\n inputs.push(resolveOut(bp.outIndex))\n } else {\n const packPos = folder.packedIndices.indexOf(globalIn)\n if (packPos < 0) throw new Error('7z folder 输入流未绑定也非打包流')\n const ps = folder.packStreams[packPos]\n inputs.push(buf.subarray(ps.offset, ps.offset + ps.size))\n }\n }\n const result = decodeCoder(coder, inputs, folder.unpackSizes[outIndex], ctx)\n memo.set(outIndex, result)\n return result\n }\n\n return resolveOut(folderFinalOutIndex(folder))\n}\n\n// ── Public API ────────────────────────────────────────────────────────────────────────────────────\n\n/** Is the buffer a 7z archive (by signature)? */\nexport function isSevenZip(buf: ArrayBuffer): boolean {\n if (buf.byteLength < SIG_HEADER_SIZE) return false\n const b = new Uint8Array(buf, 0, SIGNATURE.length)\n return SIGNATURE.every((s, i) => b[i] === s)\n}\n\n/**\n * Parse a 7z archive's header into a flat entry list (+ folder metadata for extraction). When the header\n * itself is AES-encrypted (\"encrypt file names\"), listing needs the `password`: without one this throws\n * {@link SevenZipEncryptedError} (so the UI can prompt); with a wrong one it throws {@link SevenZipPasswordError}.\n */\nexport function readSevenZip(buf: ArrayBuffer, password?: string): SevenZipArchive {\n if (!isSevenZip(buf)) throw new Error('不是有效的 7z 文件')\n const view = new DataView(buf)\n const bytes = new Uint8Array(buf)\n\n const nextHeaderOffset = readUInt64LE(view, 12)\n const nextHeaderSize = readUInt64LE(view, 20)\n if (nextHeaderSize === 0) return { entries: [], folders: [] } // empty archive\n\n const headerStart = SIG_HEADER_SIZE + nextHeaderOffset\n if (headerStart + nextHeaderSize > buf.byteLength) throw new Error('7z 头部超出文件范围')\n\n let headerBytes: Uint8Array = bytes.subarray(headerStart, headerStart + nextHeaderSize)\n let r = new Reader(headerBytes)\n let first = r.byte()\n let encryptedHeader = false\n\n // The header is often itself a compressed stream (kEncodedHeader): decode that folder to get the real\n // header bytes, then parse those. That folder can additionally be AES-encrypted (encrypted file names).\n if (first === K_ENCODED_HEADER) {\n const streams = readStreamsInfo(r)\n if (streams.folders.length !== 1) throw new Error('7z 编码头部格式异常')\n encryptedHeader = folderHasAes(streams.folders[0])\n try {\n headerBytes = decodeFolder(bytes, streams.folders[0], { password })\n } catch (e) {\n // No password → propagate SevenZipEncryptedError (UI prompts); a wrong one makes the LZMA stage choke\n // on garbage — report it as a password error.\n if (encryptedHeader && password && !(e instanceof SevenZipEncryptedError)) {\n throw new SevenZipPasswordError()\n }\n throw e\n }\n r = new Reader(headerBytes)\n first = r.byte()\n }\n if (first !== K_HEADER) {\n if (encryptedHeader && password) throw new SevenZipPasswordError() // garbage from a wrong password\n throw new Error(`7z 头部类型异常 (0x${first.toString(16)})`)\n }\n // Re-run the header parse from the top (parseHeader expects to read the kHeader id itself).\n r.pos = 0\n try {\n return parseHeader(r)\n } catch (e) {\n if (encryptedHeader && password) throw new SevenZipPasswordError()\n throw e\n }\n}\n\n// Cache the last decoded folder so extracting several files from one solid block doesn't re-decompress it.\nlet lastFolderKey: { buf: ArrayBuffer; index: number } | null = null\nlet lastFolderBytes: Uint8Array | null = null\n\n/**\n * Extract one entry's bytes. Decodes the whole folder (caching it) and slices out the file's span. For an\n * AES-encrypted folder the `password` is required — missing → {@link SevenZipEncryptedError}, wrong →\n * {@link SevenZipPasswordError}.\n */\nexport function extractSevenZipEntry(\n buf: ArrayBuffer,\n archive: SevenZipArchive,\n entry: SevenZipEntry,\n password?: string,\n): Uint8Array {\n if (entry.isDir || entry.folderIndex < 0 || entry.size === 0) return new Uint8Array(0)\n const folder = archive.folders[entry.folderIndex]\n if (!folder) throw new Error('7z 条目缺少对应 folder')\n\n let folderBytes: Uint8Array\n if (\n lastFolderBytes &&\n lastFolderKey &&\n lastFolderKey.buf === buf &&\n lastFolderKey.index === entry.folderIndex\n ) {\n folderBytes = lastFolderBytes\n } else {\n try {\n folderBytes = decodeFolder(new Uint8Array(buf), folder, { password })\n } catch (e) {\n if (folderHasAes(folder) && password && !(e instanceof SevenZipEncryptedError)) {\n throw new SevenZipPasswordError()\n }\n throw e\n }\n lastFolderKey = { buf, index: entry.folderIndex }\n lastFolderBytes = folderBytes\n }\n return folderBytes.subarray(entry.offsetInFolder, entry.offsetInFolder + entry.size).slice()\n}\n"],"mappings":"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"}
package/dist/lib/sha1.js CHANGED
@@ -51,3 +51,5 @@ function t(t) {
51
51
  }
52
52
  //#endregion
53
53
  export { e as Sha1, t as sha1 };
54
+
55
+ //# sourceMappingURL=sha1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sha1.js","names":[],"sources":["../../src/lib/sha1.ts"],"sourcesContent":["/**\n * Minimal synchronous SHA-1 (FIPS 180-4) — no dependency, no WASM.\n *\n * JKS / JCEKS keystores lean on SHA-1 in two synchronous, tight loops (see lib/jks.ts): the store-integrity\n * MAC — SHA1(passwordUtf16BE ‖ \"Mighty Aphrodite\" ‖ storeBytes) — and Sun's KeyProtector, which chains SHA-1\n * over password‖runningDigest once per 20 bytes of key material. WebCrypto's digest is async + one-shot, which\n * would turn the whole parse path async and force a throwaway buffer each round; this incremental hasher stays\n * synchronous and lets the KeyProtector feed the password + running digest directly, mirroring {@link Sha256}.\n *\n * SHA-1 is broken for collision resistance — used here ONLY because the JKS on-disk format mandates it, never\n * as a security primitive for anything new. Not constant-time (fine for reading a keystore locally).\n */\n\nexport class Sha1 {\n private readonly h = new Uint32Array([0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0])\n private readonly block = new Uint8Array(64)\n private readonly w = new Uint32Array(80)\n private blen = 0\n private total = 0 // total bytes fed (for the length suffix)\n\n update(data: Uint8Array): this {\n this.total += data.length\n for (let i = 0; i < data.length; i++) {\n this.block[this.blen++] = data[i]\n if (this.blen === 64) {\n this.compress()\n this.blen = 0\n }\n }\n return this\n }\n\n digest(): Uint8Array {\n const bitLen = this.total * 8\n // Append 0x80, pad with zeros, then a 64-bit big-endian bit length.\n this.block[this.blen++] = 0x80\n if (this.blen > 56) {\n while (this.blen < 64) this.block[this.blen++] = 0\n this.compress()\n this.blen = 0\n }\n while (this.blen < 56) this.block[this.blen++] = 0\n // High 32 bits (bitLen can exceed 2^32; use division to stay exact).\n const hi = Math.floor(bitLen / 0x100000000)\n const lo = bitLen >>> 0\n this.block[56] = (hi >>> 24) & 0xff\n this.block[57] = (hi >>> 16) & 0xff\n this.block[58] = (hi >>> 8) & 0xff\n this.block[59] = hi & 0xff\n this.block[60] = (lo >>> 24) & 0xff\n this.block[61] = (lo >>> 16) & 0xff\n this.block[62] = (lo >>> 8) & 0xff\n this.block[63] = lo & 0xff\n this.compress()\n\n const out = new Uint8Array(20)\n for (let i = 0; i < 5; i++) {\n out[4 * i] = (this.h[i] >>> 24) & 0xff\n out[4 * i + 1] = (this.h[i] >>> 16) & 0xff\n out[4 * i + 2] = (this.h[i] >>> 8) & 0xff\n out[4 * i + 3] = this.h[i] & 0xff\n }\n return out\n }\n\n private compress(): void {\n const w = this.w\n const blk = this.block\n for (let i = 0; i < 16; i++) {\n w[i] = (blk[4 * i] << 24) | (blk[4 * i + 1] << 16) | (blk[4 * i + 2] << 8) | blk[4 * i + 3]\n }\n for (let i = 16; i < 80; i++) {\n const x = w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]\n w[i] = (x << 1) | (x >>> 31)\n }\n let a = this.h[0]\n let b = this.h[1]\n let c = this.h[2]\n let d = this.h[3]\n let e = this.h[4]\n for (let i = 0; i < 80; i++) {\n let f: number\n let k: number\n if (i < 20) {\n f = (b & c) | (~b & d)\n k = 0x5a827999\n } else if (i < 40) {\n f = b ^ c ^ d\n k = 0x6ed9eba1\n } else if (i < 60) {\n f = (b & c) | (b & d) | (c & d)\n k = 0x8f1bbcdc\n } else {\n f = b ^ c ^ d\n k = 0xca62c1d6\n }\n const t = (((a << 5) | (a >>> 27)) + f + e + k + w[i]) | 0\n e = d\n d = c\n c = (b << 30) | (b >>> 2)\n b = a\n a = t\n }\n this.h[0] = (this.h[0] + a) | 0\n this.h[1] = (this.h[1] + b) | 0\n this.h[2] = (this.h[2] + c) | 0\n this.h[3] = (this.h[3] + d) | 0\n this.h[4] = (this.h[4] + e) | 0\n }\n}\n\n/** One-shot convenience: SHA-1 of a single buffer. */\nexport function sha1(data: Uint8Array): Uint8Array {\n return new Sha1().update(data).digest()\n}\n"],"mappings":"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"}
@@ -117,3 +117,5 @@ function n(e) {
117
117
  }
118
118
  //#endregion
119
119
  export { t as Sha256, n as sha256 };
120
+
121
+ //# sourceMappingURL=sha256.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sha256.js","names":[],"sources":["../../src/lib/sha256.ts"],"sourcesContent":["/**\n * Minimal synchronous SHA-256 (FIPS 180-4) — no dependency, no WASM.\n *\n * WebCrypto's digest is async and one-shot (no streaming), which is awkward for the 7z key-derivation loop\n * that hashes salt‖password‖counter hundreds of thousands of times: a one-shot API would force a ~10 MB\n * throwaway buffer AND make the whole 7z decode path async. This incremental hasher lets {@link lib/sevenZip}\n * feed each round's bytes directly and stay synchronous. Not constant-time — fine for archive key derivation,\n * not for anything that must resist timing attacks.\n */\n\nconst K = /* @__PURE__ */ new Uint32Array([\n 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\n 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\n 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\n 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\n 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,\n])\n\nexport class Sha256 {\n private readonly h = new Uint32Array([\n 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,\n ])\n private readonly block = new Uint8Array(64)\n private readonly w = new Uint32Array(64)\n private blen = 0\n private total = 0 // total bytes fed (for the length suffix)\n\n update(data: Uint8Array): this {\n this.total += data.length\n for (let i = 0; i < data.length; i++) {\n this.block[this.blen++] = data[i]\n if (this.blen === 64) {\n this.compress()\n this.blen = 0\n }\n }\n return this\n }\n\n digest(): Uint8Array {\n const bitLen = this.total * 8\n // Append 0x80, pad with zeros, then a 64-bit big-endian bit length.\n this.block[this.blen++] = 0x80\n if (this.blen > 56) {\n while (this.blen < 64) this.block[this.blen++] = 0\n this.compress()\n this.blen = 0\n }\n while (this.blen < 56) this.block[this.blen++] = 0\n // High 32 bits (bitLen can exceed 2^32; use division to stay exact).\n const hi = Math.floor(bitLen / 0x100000000)\n const lo = bitLen >>> 0\n this.block[56] = (hi >>> 24) & 0xff\n this.block[57] = (hi >>> 16) & 0xff\n this.block[58] = (hi >>> 8) & 0xff\n this.block[59] = hi & 0xff\n this.block[60] = (lo >>> 24) & 0xff\n this.block[61] = (lo >>> 16) & 0xff\n this.block[62] = (lo >>> 8) & 0xff\n this.block[63] = lo & 0xff\n this.compress()\n\n const out = new Uint8Array(32)\n for (let i = 0; i < 8; i++) {\n out[4 * i] = (this.h[i] >>> 24) & 0xff\n out[4 * i + 1] = (this.h[i] >>> 16) & 0xff\n out[4 * i + 2] = (this.h[i] >>> 8) & 0xff\n out[4 * i + 3] = this.h[i] & 0xff\n }\n return out\n }\n\n private compress(): void {\n const w = this.w\n const b = this.block\n for (let i = 0; i < 16; i++) {\n w[i] = (b[4 * i] << 24) | (b[4 * i + 1] << 16) | (b[4 * i + 2] << 8) | b[4 * i + 3]\n }\n for (let i = 16; i < 64; i++) {\n const x = w[i - 15]\n const y = w[i - 2]\n const s0 = ((x >>> 7) | (x << 25)) ^ ((x >>> 18) | (x << 14)) ^ (x >>> 3)\n const s1 = ((y >>> 17) | (y << 15)) ^ ((y >>> 19) | (y << 13)) ^ (y >>> 10)\n w[i] = (w[i - 16] + s0 + w[i - 7] + s1) | 0\n }\n let a = this.h[0]\n let bb = this.h[1]\n let c = this.h[2]\n let d = this.h[3]\n let e = this.h[4]\n let f = this.h[5]\n let g = this.h[6]\n let hh = this.h[7]\n for (let i = 0; i < 64; i++) {\n const S1 = ((e >>> 6) | (e << 26)) ^ ((e >>> 11) | (e << 21)) ^ ((e >>> 25) | (e << 7))\n const ch = (e & f) ^ (~e & g)\n const t1 = (hh + S1 + ch + K[i] + w[i]) | 0\n const S0 = ((a >>> 2) | (a << 30)) ^ ((a >>> 13) | (a << 19)) ^ ((a >>> 22) | (a << 10))\n const maj = (a & bb) ^ (a & c) ^ (bb & c)\n const t2 = (S0 + maj) | 0\n hh = g\n g = f\n f = e\n e = (d + t1) | 0\n d = c\n c = bb\n bb = a\n a = (t1 + t2) | 0\n }\n this.h[0] = (this.h[0] + a) | 0\n this.h[1] = (this.h[1] + bb) | 0\n this.h[2] = (this.h[2] + c) | 0\n this.h[3] = (this.h[3] + d) | 0\n this.h[4] = (this.h[4] + e) | 0\n this.h[5] = (this.h[5] + f) | 0\n this.h[6] = (this.h[6] + g) | 0\n this.h[7] = (this.h[7] + hh) | 0\n }\n}\n\n/** One-shot convenience: SHA-256 of a single buffer. */\nexport function sha256(data: Uint8Array): Uint8Array {\n return new Sha256().update(data).digest()\n}\n"],"mappings":"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"}
@@ -83,3 +83,5 @@ async function d(e) {
83
83
  }
84
84
  //#endregion
85
85
  export { d as decodeSpeechToWav, i as sniffSpeechCodec };
86
+
87
+ //# sourceMappingURL=speechAudio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"speechAudio.js","names":[],"sources":["../../src/lib/speechAudio.ts"],"sourcesContent":["/**\n * 语音编解码(3GPP AMR / 腾讯 SILK)→ WAV 的浏览器内解码器 —— 按需懒加载 WASM。\n *\n * 浏览器原生 <audio> 不认 3GPP AMR,也不认腾讯 SILK(微信 / QQ 语音;文件常见 `.silk` / `.slk`,也\n * 大量以 `.amr` 为扩展名而内容其实是 SILK)。两者都是 CELP 系语音编解码,无法手搓,故各引一个编译好的\n * WASM 解码器(与 lib/brotli、lib/sqlite 的 wasm 同思路:仅在真正播放这类文件时才 `import()`):\n * - AMR-NB(8kHz) / AMR-WB(16kHz):`@audio/decode-amr`(opencore-amr 编译;wasm 内联进 .cjs,无独立资源)\n * - SILK v3:`silk-wasm`(腾讯 SILK 编解码;独立 `silk.wasm`,Vite 经 `import.meta.url` 产出同源资源)\n *\n * 解出 PCM(s16le) 后用手写的 44 字节 PCM WAV 头包成 WAV,交给 <audio> 原生播放(同 QMC 解密后播放)。\n * 识别一律按**文件头魔数**而非扩展名 —— 微信 `.amr` 实为 SILK,故 `.amr` 既可能是真 AMR 也可能是 SILK。\n */\n\nexport type SpeechCodec = 'silk' | 'amr-nb' | 'amr-wb'\n\n// \"#!AMR\\n\" / \"#!AMR-WB\\n\"(RFC 4867 单声道存储头);\"#!SILK_V3\"(SILK 容器标记)。\nconst MAGIC_AMR_NB = [0x23, 0x21, 0x41, 0x4d, 0x52, 0x0a]\nconst MAGIC_AMR_WB = [0x23, 0x21, 0x41, 0x4d, 0x52, 0x2d, 0x57, 0x42, 0x0a]\nconst MAGIC_SILK = [0x23, 0x21, 0x53, 0x49, 0x4c, 0x4b, 0x5f, 0x56, 0x33]\n\nfunction matchAt(b: Uint8Array, off: number, magic: number[]): boolean {\n if (off + magic.length > b.length) return false\n for (let i = 0; i < magic.length; i++) if (b[off + i] !== magic[i]) return false\n return true\n}\n\n/**\n * 按文件头判别语音编解码;非语音编解码(普通 mp3/wav/… 或无法识别)返回 null。\n * SILK 容器有两种头:Skype 裸头 `#!SILK_V3`(偏移 0)与腾讯头 `\\x02#!SILK_V3`(偏移 1)。\n * AMR-WB 必须先于 AMR-NB 判断(`#!AMR` 是 `#!AMR-WB` 的前缀)。\n */\nexport function sniffSpeechCodec(bytes: Uint8Array): SpeechCodec | null {\n if (matchAt(bytes, 0, MAGIC_SILK) || matchAt(bytes, 1, MAGIC_SILK)) return 'silk'\n if (matchAt(bytes, 0, MAGIC_AMR_WB)) return 'amr-wb'\n if (matchAt(bytes, 0, MAGIC_AMR_NB)) return 'amr-nb'\n return null\n}\n\n// SILK 容器不在头部记采样率(SILK 本身与采样率解耦),业界解码器(silk-v3-decoder 等)一律按 24000Hz\n// 还原微信 / QQ 语音,这里沿用该约定。\nconst SILK_SAMPLE_RATE = 24000\n\nexport interface DecodedSpeech {\n /** 完整 WAV 字节(44 字节头 + PCM s16le)。 */\n wav: Uint8Array\n codec: SpeechCodec\n sampleRate: number\n channels: number\n durationSec: number\n}\n\nexport class SpeechDecodeError extends Error {}\n\n/** Float32(−1..1) → PCM s16le 字节。 */\nfunction floatToS16le(f: Float32Array): Uint8Array {\n const out = new Uint8Array(f.length * 2)\n const dv = new DataView(out.buffer)\n for (let i = 0; i < f.length; i++) {\n const s = Math.max(-1, Math.min(1, f[i]))\n dv.setInt16(i * 2, s < 0 ? s * 0x8000 : s * 0x7fff, true)\n }\n return out\n}\n\n/** 用 PCM s16le 数据包出一段标准 44 字节头的 WAV(单声道、16 位)。 */\nexport function wavFromPcmS16le(pcm: Uint8Array, sampleRate: number, channels = 1): Uint8Array {\n const blockAlign = channels * 2\n const out = new Uint8Array(44 + pcm.length)\n const dv = new DataView(out.buffer)\n const tag = (o: number, s: string): void => {\n for (let i = 0; i < s.length; i++) out[o + i] = s.charCodeAt(i)\n }\n tag(0, 'RIFF')\n dv.setUint32(4, 36 + pcm.length, true)\n tag(8, 'WAVE')\n tag(12, 'fmt ')\n dv.setUint32(16, 16, true) // fmt chunk 长度(PCM)\n dv.setUint16(20, 1, true) // 格式 = PCM\n dv.setUint16(22, channels, true)\n dv.setUint32(24, sampleRate, true)\n dv.setUint32(28, sampleRate * blockAlign, true) // 字节率\n dv.setUint16(32, blockAlign, true)\n dv.setUint16(34, 16, true) // 位深\n tag(36, 'data')\n dv.setUint32(40, pcm.length, true)\n out.set(pcm, 44)\n return out\n}\n\nasync function decodeSilk(bytes: Uint8Array): Promise<DecodedSpeech> {\n const { decode } = await import('silk-wasm')\n const { data, duration } = await decode(bytes, SILK_SAMPLE_RATE)\n if (!data.length) throw new SpeechDecodeError('SILK 解码结果为空')\n return {\n wav: wavFromPcmS16le(data, SILK_SAMPLE_RATE),\n codec: 'silk',\n sampleRate: SILK_SAMPLE_RATE,\n channels: 1,\n durationSec: duration / 1000,\n }\n}\n\nasync function decodeAmr(bytes: Uint8Array, codec: 'amr-nb' | 'amr-wb'): Promise<DecodedSpeech> {\n const { default: amrDecode } = await import('@audio/decode-amr')\n const { channelData, sampleRate } = await amrDecode(bytes)\n const mono = channelData[0]\n if (!mono || !mono.length) throw new SpeechDecodeError('AMR 解码结果为空')\n return {\n wav: wavFromPcmS16le(floatToS16le(mono), sampleRate),\n codec,\n sampleRate,\n channels: 1,\n durationSec: mono.length / sampleRate,\n }\n}\n\n/**\n * 把一段 AMR / SILK 语音字节解码成可播放的 WAV:先 {@link sniffSpeechCodec} 判型,再懒加载对应 WASM\n * 解码器解出 PCM 并包成 WAV。非 AMR/SILK 抛 {@link SpeechDecodeError}(调用方据此回退原生播放)。\n */\nexport async function decodeSpeechToWav(input: ArrayBuffer | Uint8Array): Promise<DecodedSpeech> {\n const bytes = input instanceof Uint8Array ? input : new Uint8Array(input)\n const codec = sniffSpeechCodec(bytes)\n if (!codec) throw new SpeechDecodeError('不是可识别的 AMR / SILK 语音文件')\n try {\n if (codec === 'silk') return await decodeSilk(bytes)\n return await decodeAmr(bytes, codec)\n } catch (e) {\n if (e instanceof SpeechDecodeError) throw e\n throw new SpeechDecodeError(e instanceof Error ? e.message : String(e))\n }\n}\n"],"mappings":"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"}
@@ -102,3 +102,5 @@ function d(e, t) {
102
102
  }
103
103
  //#endregion
104
104
  export { d as execSql, r as initSqlEngine, l as listTables, i as loadDatabase, u as readPage };
105
+
106
+ //# sourceMappingURL=sqlite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite.js","names":[],"sources":["../../src/lib/sqlite.ts"],"sourcesContent":["/**\n * SQLite 只读读取层 —— 基于 sql.js(WASM),不依赖 Vue / DOM。\n *\n * 移植自 sqlite-viewer 项目(D:\\web-work\\sqlite-viewer\\src\\db\\engine.ts),但**裁剪为只读预览**:仅\n * 保留「加载库 → 列出表/视图 → 按需分页读行 → 执行任意 SQL」这条链路,去掉建表/改表/编辑/事务等写操作\n * (文件查看器是只读的,且各组件都强制 attachment 下载、不回写)。\n *\n * sql.js 的 wasm 走 Vite `?url` 同源资源(与 lib/rar.ts 的 unrar.wasm 同款),不连任何 CDN;引擎实例\n * 全局复用一次初始化。本模块被 SqliteViewer.vue 动态 import,故 sql.js + wasm 仅在打开 .sqlite 时才下载。\n */\nimport initSqlJs from 'sql.js'\nimport type { Database, SqlJsStatic, SqlValue } from 'sql.js'\nimport wasmUrl from 'sql.js/dist/sql-wasm.wasm?url'\n\nlet sqlPromise: Promise<SqlJsStatic> | null = null\n\n/** 加载并初始化 sql.js(WASM)。多次调用复用同一实例。 */\nexport function initSqlEngine(): Promise<SqlJsStatic> {\n if (!sqlPromise) sqlPromise = initSqlJs({ locateFile: () => wasmUrl })\n return sqlPromise\n}\n\n/** 从 .sqlite / .db 文件字节加载一个库(一次性入内存,sql.js 全在内存运行)。 */\nexport function loadDatabase(SQL: SqlJsStatic, bytes: Uint8Array): Database {\n return new SQL.Database(bytes)\n}\n\nexport type CellValue = string | number | null\n\nexport interface Column {\n name: string\n type: string\n pk?: boolean\n fk?: boolean\n idx?: boolean\n notnull?: boolean\n}\n\n/** 一张表 / 视图的概要(不含行数据,行数据按需分页读取)。 */\nexport interface TableInfo {\n name: string\n kind: 'table' | 'view'\n rowCount: number\n columns: Column[]\n}\n\nexport interface QueryResult {\n columns: string[]\n rows: CellValue[][]\n rowCount: number\n elapsedMs: number\n error: string\n}\n\n/** 标识符加双引号转义,安全拼进 SQL(表名来自库自身,仍按规范转义)。 */\nfunction quoteIdent(name: string): string {\n return '\"' + name.replace(/\"/g, '\"\"') + '\"'\n}\n\n/** SqlValue → CellValue(BLOB 以占位文本展示,避免把二进制塞进表格)。 */\nfunction toCell(v: SqlValue): CellValue {\n if (v == null) return null\n if (v instanceof Uint8Array) return `[BLOB ${v.length}B]`\n return v\n}\n\n/** 读出某表/视图的列结构(含 pk / fk / idx / notnull 徽标信息)。 */\nexport function readColumns(db: Database, table: string): Column[] {\n const qi = quoteIdent(table)\n\n // 外键列\n const fkCols = new Set<string>()\n const fkRes = db.exec(`PRAGMA foreign_key_list(${qi})`)\n if (fkRes.length) {\n const fromIdx = fkRes[0].columns.indexOf('from')\n for (const r of fkRes[0].values) fkCols.add(String(r[fromIdx]))\n }\n\n // 非主键索引涉及的列(用于列徽标)\n const idxCols = new Set<string>()\n const idxList = db.exec(`PRAGMA index_list(${qi})`)\n if (idxList.length) {\n const ic = idxList[0].columns\n const nameIdx = ic.indexOf('name')\n const originIdx = ic.indexOf('origin')\n for (const r of idxList[0].values) {\n const iname = String(r[nameIdx])\n const origin = originIdx >= 0 ? String(r[originIdx]) : 'c'\n if (origin === 'pk') continue\n const infoRes = db.exec(`PRAGMA index_info(${quoteIdent(iname)})`)\n if (infoRes.length) {\n const colIdx = infoRes[0].columns.indexOf('name')\n for (const ir of infoRes[0].values) {\n if (ir[colIdx] != null) idxCols.add(String(ir[colIdx]))\n }\n }\n }\n }\n\n const columns: Column[] = []\n const info = db.exec(`PRAGMA table_info(${qi})`)\n if (info.length) {\n const c = info[0].columns\n const nameI = c.indexOf('name')\n const typeI = c.indexOf('type')\n const pkI = c.indexOf('pk')\n const nnI = c.indexOf('notnull')\n for (const r of info[0].values) {\n const col: Column = { name: String(r[nameI]), type: String(r[typeI] ?? '') }\n if (Number(r[pkI]) > 0) col.pk = true\n if (nnI >= 0 && Number(r[nnI]) === 1) col.notnull = true\n if (fkCols.has(col.name)) col.fk = true\n if (idxCols.has(col.name)) col.idx = true\n columns.push(col)\n }\n }\n return columns\n}\n\n/** 表/视图行数(视图可能为表达式,失败回退 0)。 */\nexport function rowCount(db: Database, table: string): number {\n try {\n const res = db.exec(`SELECT COUNT(*) FROM ${quoteIdent(table)}`)\n return res.length && res[0].values.length ? Number(res[0].values[0][0]) : 0\n } catch {\n return 0\n }\n}\n\n/** 列出所有用户表与视图(含列结构与行数),按名称排序;排除 sqlite_ 内部表。 */\nexport function listTables(db: Database): TableInfo[] {\n const res = db.exec(\n \"SELECT name, type FROM sqlite_master WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%' ORDER BY type, name\",\n )\n if (!res.length) return []\n const out: TableInfo[] = []\n for (const r of res[0].values) {\n const name = String(r[0])\n const kind = String(r[1]) === 'view' ? 'view' : 'table'\n out.push({ name, kind, rowCount: rowCount(db, name), columns: readColumns(db, name) })\n }\n return out\n}\n\n/** 按页读取某表/视图的行(LIMIT/OFFSET)。仅取数据,不带列结构(列结构走 readColumns)。 */\nexport function readPage(\n db: Database,\n table: string,\n limit: number,\n offset: number,\n): CellValue[][] {\n const res = db.exec(`SELECT * FROM ${quoteIdent(table)} LIMIT ${limit} OFFSET ${offset}`)\n return res.length ? res[0].values.map((r) => r.map(toCell)) : []\n}\n\n/** 执行任意 SQL,返回最后一个结果集;出错时 error 非空(只读预览,不强制只读但不暴露写 UI)。 */\nexport function execSql(db: Database, sql: string): QueryResult {\n const start = performance.now()\n try {\n const res = db.exec(sql)\n const elapsed = performance.now() - start\n const last = res.length ? res[res.length - 1] : null\n if (last) {\n return {\n columns: last.columns,\n rows: last.values.map((r) => r.map(toCell)),\n rowCount: last.values.length,\n elapsedMs: elapsed,\n error: '',\n }\n }\n return { columns: [], rows: [], rowCount: 0, elapsedMs: elapsed, error: '' }\n } catch (e) {\n return {\n columns: [],\n rows: [],\n rowCount: 0,\n elapsedMs: performance.now() - start,\n error: e instanceof Error ? e.message : String(e),\n }\n }\n}\n"],"mappings":"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"}
@@ -97,3 +97,5 @@ function c(e, t) {
97
97
  }
98
98
  //#endregion
99
99
  export { c as parseSubtitle };
100
+
101
+ //# sourceMappingURL=subtitle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subtitle.js","names":[],"sources":["../../src/lib/subtitle.ts"],"sourcesContent":["/**\n * Hand-rolled, zero-dependency subtitle parser for the side viewer.\n *\n * Parses the three common caption formats into a uniform cue list:\n * - SubRip (.srt): block = optional index line, `HH:MM:SS,mmm --> HH:MM:SS,mmm`, then text lines\n * - WebVTT (.vtt): a `WEBVTT` header, optional cue ids / NOTE / STYLE / REGION blocks, and\n * `HH:MM:SS.mmm --> HH:MM:SS.mmm <settings>` timing lines; inline tags stripped\n * - SubStation Alpha (.ass/.ssa): an `[Events]` section with a `Format:` line + `Dialogue:` rows;\n * override tags `{\\…}` and the `\\N` / `\\h` escapes are handled\n *\n * The viewer only needs start/end/text (plus an optional speaker from the ASS Name field), so styling,\n * positioning, karaoke timing, etc. are intentionally discarded — this is a readable transcript, not a\n * pixel-accurate renderer. Times are normalized to milliseconds.\n */\n\nexport interface SubtitleCue {\n start: number // ms\n end: number // ms\n text: string // plain text, lines joined with '\\n', markup stripped\n speaker?: string // ASS \"Name\"/actor field, when present\n}\n\nexport interface ParsedSubtitle {\n format: 'srt' | 'vtt' | 'ass'\n cues: SubtitleCue[]\n}\n\n/** A clock anywhere in a string: optional hours, then MM:SS, then `.`/`,` and 1–3 fractional digits. */\nconst CLOCK_RE = /(?:(\\d+):)?(\\d{1,2}):(\\d{1,2})[.,](\\d{1,3})/\n\n// Extract the first clock found in `s` (so trailing VTT cue settings / SRT coords are ignored) → ms.\n// ASS centiseconds (`.cc`) round-trip correctly: `.05` → \"050\" → 50ms, `.5` → \"500\" → 500ms.\nfunction extractClock(s: string): number | null {\n const m = s.match(CLOCK_RE)\n if (!m) return null\n const h = m[1] ? parseInt(m[1], 10) : 0\n const min = parseInt(m[2], 10)\n const sec = parseInt(m[3], 10)\n const frac = parseInt(m[4].padEnd(3, '0').slice(0, 3), 10)\n return ((h * 60 + min) * 60 + sec) * 1000 + frac\n}\n\n// Strip WebVTT / SubRip inline markup: HTML-ish tags (<b>, <i>, <c.color>, <v Speaker>) and the\n// `<00:00:01.000>` karaoke timestamps. Leaves the readable text.\nfunction stripCueMarkup(s: string): string {\n return s\n .replace(/<[^>]*>/g, '')\n .replace(/\\{\\\\[^}]*\\}/g, '')\n .replace(/[ \\t]+\\n/g, '\\n')\n .trim()\n}\n\nfunction parseSrtVtt(text: string, vtt: boolean): SubtitleCue[] {\n const cues: SubtitleCue[] = []\n for (const block of text.split(/\\n{2,}/)) {\n // VTT preamble / metadata blocks never carry a cue.\n if (vtt && /^\\s*(WEBVTT|NOTE|STYLE|REGION)\\b/.test(block)) continue\n const lines = block.split('\\n')\n const tIdx = lines.findIndex((l) => l.includes('-->'))\n if (tIdx < 0) continue\n const [left, right = ''] = lines[tIdx].split('-->')\n const start = extractClock(left)\n const end = extractClock(right)\n if (start === null || end === null) continue\n // Lines before the timing line are an optional index (SRT) or cue id (VTT) — dropped.\n const body = lines\n .slice(tIdx + 1)\n .join('\\n')\n .trim()\n cues.push({ start, end, text: stripCueMarkup(body) })\n }\n return cues\n}\n\n// Standard ASS/SSA Events field order, used when a `[Events]` section omits its `Format:` line.\nconst DEFAULT_ASS_FMT = [\n 'layer',\n 'start',\n 'end',\n 'style',\n 'name',\n 'marginl',\n 'marginr',\n 'marginv',\n 'effect',\n 'text',\n]\n\n// The ASS Text field is always last and may itself contain commas, so split into exactly `count`\n// fields — the first count-1 on commas, the remainder (text) kept whole.\nfunction splitAssFields(rest: string, count: number): string[] {\n if (count <= 1) return [rest]\n const out: string[] = []\n let i = 0\n for (let f = 0; f < count - 1; f++) {\n const c = rest.indexOf(',', i)\n if (c < 0) break\n out.push(rest.slice(i, c))\n i = c + 1\n }\n out.push(rest.slice(i))\n return out\n}\n\n// Drop override blocks `{\\…}`, turn `\\N`/`\\n` (hard breaks) into newlines and `\\h` into a space.\nfunction cleanAssText(s: string): string {\n return s\n .replace(/\\{[^}]*\\}/g, '')\n .replace(/\\\\N/gi, '\\n')\n .replace(/\\\\h/gi, ' ')\n .trim()\n}\n\nfunction parseAss(text: string): SubtitleCue[] {\n const cues: SubtitleCue[] = []\n let inEvents = false\n let fmt: string[] = []\n for (const raw of text.split('\\n')) {\n const line = raw.trim()\n if (line.startsWith('[')) {\n inEvents = /^\\[events\\]/i.test(line)\n continue\n }\n if (!inEvents || !line) continue\n if (/^format\\s*:/i.test(line)) {\n fmt = line\n .slice(line.indexOf(':') + 1)\n .split(',')\n .map((s) => s.trim().toLowerCase())\n continue\n }\n if (/^dialogue\\s*:/i.test(line)) {\n const order = fmt.length ? fmt : DEFAULT_ASS_FMT\n const fields = splitAssFields(line.slice(line.indexOf(':') + 1), order.length)\n const get = (key: string): string => {\n const i = order.indexOf(key)\n return i >= 0 ? (fields[i] ?? '') : ''\n }\n const start = extractClock(get('start'))\n const end = extractClock(get('end'))\n if (start === null || end === null) continue\n const speaker = get('name').trim()\n cues.push({\n start,\n end,\n text: cleanAssText(get('text') || fields[fields.length - 1] || ''),\n speaker: speaker || undefined,\n })\n }\n }\n return cues\n}\n\n/** Parse subtitle source text into a sorted cue list. `ext` (when known) disambiguates the format. */\nexport function parseSubtitle(input: string, ext?: string): ParsedSubtitle {\n // Strip a leading UTF-8 BOM (U+FEFF) and normalize CRLF/CR line endings.\n const text = (input.charCodeAt(0) === 0xfeff ? input.slice(1) : input).replace(/\\r\\n?/g, '\\n')\n const e = (ext || '').toLowerCase()\n let result: ParsedSubtitle\n if (e === 'ass' || e === 'ssa' || /^\\s*\\[script info\\]/i.test(text)) {\n result = { format: 'ass', cues: parseAss(text) }\n } else if (e === 'vtt' || /^\\s*WEBVTT/.test(text)) {\n result = { format: 'vtt', cues: parseSrtVtt(text, true) }\n } else {\n result = { format: 'srt', cues: parseSrtVtt(text, false) }\n }\n result.cues.sort((a, b) => a.start - b.start || a.end - b.end)\n return result\n}\n"],"mappings":"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"}
@@ -246,3 +246,5 @@ async function S(e, t) {
246
246
  }
247
247
  //#endregion
248
248
  export { S as openTarball };
249
+
250
+ //# sourceMappingURL=tarball.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tarball.js","names":[],"sources":["../../src/lib/tarball.ts"],"sourcesContent":["/**\n * In-browser reader for the tar family — `.tar` and its compressed wrappers `.gz`/`.tgz`, `.xz`/`.txz`,\n * `.bz2`/`.tbz2`, `.br`/`.tar.br` — plus a lone compressed file (`foo.json.gz`). No dependency beyond the\n * browser's native gzip; xz reuses the project's hand-rolled LZMA2 decoder ({@link lib/lzma}), bzip2 its BWT\n * decoder ({@link lib/bzip2}), and Brotli a lazily-loaded WASM decoder ({@link lib/brotli}).\n *\n * Unlike ZIP/7z (random-access central directories), a tar is solid: the whole stream is decompressed to\n * memory once, then tar headers are walked to index each file as an (offset, size) slice into that buffer —\n * so extraction is a cheap, synchronous sub-array copy. The result is exposed through the shared\n * {@link OpenedArchive} interface so {@link components/ArchiveBrowser} can browse it like any other archive.\n *\n * If the decompressed bytes aren't a tar (a bare `foo.txt.gz`), the archive is presented as a single entry\n * named by stripping the compression suffix.\n */\n\nimport { bcjX86Decode, lzma2Decode } from '@/lib/lzma'\nimport { bzip2Decode } from '@/lib/bzip2'\nimport { decodeFileNameBytes } from '@/lib/encoding'\nimport type { ArchiveEntry, OpenedArchive } from '@/lib/archive'\n\nconst GZIP_MAGIC = [0x1f, 0x8b]\nconst XZ_MAGIC = [0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00]\nconst BZIP2_MAGIC = [0x42, 0x5a, 0x68] // \"BZh\"\n\nfunction hasMagic(b: Uint8Array, magic: number[], off = 0): boolean {\n if (b.length < off + magic.length) return false\n return magic.every((m, i) => b[off + i] === m)\n}\n\n// ── gzip (browser-native) ───────────────────────────────────────────────────────────────────────\n\nasync function gunzip(data: Uint8Array): Promise<Uint8Array> {\n if (typeof DecompressionStream === 'undefined') {\n throw new Error('当前浏览器不支持解压 gzip(缺少 DecompressionStream)')\n }\n const stream = new Blob([data]).stream().pipeThrough(new DecompressionStream('gzip'))\n return new Uint8Array(await new Response(stream).arrayBuffer())\n}\n\n// ── xz (LZMA2 in the xz container) ────────────────────────────────────────────────────────────────\n\n// Check sizes per the stream-flags check id (0/4/8/16/32/64). None=0, CRC32=1, CRC64=4, SHA256=10.\nconst XZ_CHECK_SIZE = [0, 4, 4, 4, 8, 8, 8, 16, 16, 16, 32, 32, 32, 64, 64, 64]\n\n/** Read an xz/LZMA2 variable-length integer (base-128 little-endian). */\nfunction readVli(b: Uint8Array, pos: number): { value: number; next: number } {\n let value = 0\n let shift = 0\n let i = pos\n for (;;) {\n const byte = b[i++]\n value += (byte & 0x7f) * 2 ** shift\n if ((byte & 0x80) === 0) break\n shift += 7\n if (shift > 63) throw new Error('xz VLI 过长')\n }\n return { value, next: i }\n}\n\n/**\n * Walk an LZMA2 chunk stream (without decoding) to find where it ends (its 0x00 terminator) and sum the\n * uncompressed size — xz block headers usually omit both, but the chunk framing carries them. Mirrors the\n * framing in {@link lzma2Decode}.\n */\nfunction scanLzma2(b: Uint8Array, start: number): { compLen: number; uncompSize: number } {\n let ip = start\n let uncomp = 0\n for (;;) {\n const control = b[ip++]\n if (control === 0) break\n if (control >= 0x80) {\n const unpackSize = ((control & 0x1f) << 16) + (b[ip] << 8) + b[ip + 1] + 1\n ip += 2\n const packSize = (b[ip] << 8) + b[ip + 1] + 1\n ip += 2\n if (((control >> 5) & 3) >= 2) ip++ // props byte\n ip += packSize\n uncomp += unpackSize\n } else {\n if (control > 2) throw new Error(`xz LZMA2 非法控制字节 0x${control.toString(16)}`)\n const size = (b[ip] << 8) + b[ip + 1] + 1\n ip += 2\n ip += size\n uncomp += size\n }\n }\n return { compLen: ip - start, uncompSize: uncomp }\n}\n\nfunction xzDecode(data: Uint8Array): Uint8Array {\n if (!hasMagic(data, XZ_MAGIC)) throw new Error('不是有效的 xz 文件')\n const checkSize = XZ_CHECK_SIZE[data[7] & 0x0f]\n const chunks: Uint8Array[] = []\n let pos = 12 // past the 12-byte stream header\n while (pos < data.length) {\n const hsByte = data[pos]\n if (hsByte === 0x00) break // index indicator — blocks are done\n const headerSize = (hsByte + 1) * 4\n const flags = data[pos + 1]\n const numFilters = (flags & 0x03) + 1\n let c = pos + 2\n if (flags & 0x40) c = readVli(data, c).next // compressed size present (unused — scan finds it)\n let declaredUncomp = -1\n if (flags & 0x80) {\n const r = readVli(data, c)\n declaredUncomp = r.value\n c = r.next\n }\n let lzma2Props = new Uint8Array(0)\n let useBcj = false\n for (let f = 0; f < numFilters; f++) {\n const id = readVli(data, c)\n c = id.next\n const ps = readVli(data, c)\n c = ps.next\n const props = data.subarray(c, c + ps.value)\n c += ps.value\n if (id.value === 0x21) lzma2Props = props.slice()\n else if (id.value === 0x04)\n useBcj = true // x86 BCJ\n else throw new Error(`xz 不支持的过滤器 0x${id.value.toString(16)}`)\n }\n const dataStart = pos + headerSize\n const { compLen, uncompSize } = scanLzma2(data, dataStart)\n const outSize = declaredUncomp >= 0 ? declaredUncomp : uncompSize\n const out = lzma2Decode(data.subarray(dataStart, dataStart + compLen), lzma2Props, outSize)\n if (useBcj) bcjX86Decode(out)\n chunks.push(out)\n let next = dataStart + compLen\n next += (4 - (compLen % 4)) % 4 // block padding aligns compressed data to 4 bytes\n next += checkSize\n pos = next\n }\n let total = 0\n for (const c of chunks) total += c.length\n const out = new Uint8Array(total)\n let off = 0\n for (const c of chunks) {\n out.set(c, off)\n off += c.length\n }\n return out\n}\n\n// ── tar ───────────────────────────────────────────────────────────────────────────────────────────\n\ninterface TarItem {\n path: string\n name: string\n size: number\n isDir: boolean\n /** Byte offset of this file's data within the decompressed tar buffer. */\n offset: number\n}\n\nconst td = new TextDecoder('utf-8')\n\n/** Read a NUL-terminated field from a 512-byte tar header block. */\nfunction field(block: Uint8Array, off: number, len: number): string {\n let end = off\n while (end < off + len && block[end] !== 0) end++\n return td.decode(block.subarray(off, end))\n}\n\n/** Like {@link field}, but for a name field — sniffs the encoding (UTF-8 → GBK → \\uXXXX) instead of forcing UTF-8. */\nfunction nameField(block: Uint8Array, off: number, len: number): string {\n let end = off\n while (end < off + len && block[end] !== 0) end++\n return decodeFileNameBytes(block.subarray(off, end))\n}\n\n/** Parse a tar numeric field — octal, or GNU base-256 when the high bit of the first byte is set. */\nfunction numField(block: Uint8Array, off: number, len: number): number {\n if (block[off] & 0x80) {\n let v = block[off] & 0x7f\n for (let i = 1; i < len; i++) v = v * 256 + block[off + i]\n return v\n }\n const s = field(block, off, len).trim()\n return s ? parseInt(s, 8) || 0 : 0\n}\n\n/** Extract `path=` / `size=` overrides from a pax extended header's \"<len> key=value\\n\" records. */\nfunction parsePax(text: string): { path?: string; size?: number } {\n const out: { path?: string; size?: number } = {}\n let i = 0\n while (i < text.length) {\n const sp = text.indexOf(' ', i)\n if (sp < 0) break\n const len = parseInt(text.slice(i, sp), 10)\n if (!len || len <= 0) break\n const record = text.slice(sp + 1, i + len - 1) // drop the trailing newline\n const eq = record.indexOf('=')\n if (eq > 0) {\n const key = record.slice(0, eq)\n const val = record.slice(eq + 1)\n if (key === 'path') out.path = val\n else if (key === 'size') out.size = parseInt(val, 10) || 0\n }\n i += len\n }\n return out\n}\n\nconst ceil512 = (n: number): number => (n + 511) & ~511\n\n/** Walk a decompressed tar buffer into a flat file list. Handles GNU long names ('L') and pax ('x') headers. */\nfunction parseTar(data: Uint8Array): TarItem[] {\n const items: TarItem[] = []\n let off = 0\n let longName = '' // pending GNU 'L' override for the next entry\n let pax: { path?: string; size?: number } = {} // pending pax override for the next entry\n while (off + 512 <= data.length) {\n const block = data.subarray(off, off + 512)\n // An all-zero block marks end-of-archive.\n let allZero = true\n for (let i = 0; i < 512; i++) {\n if (block[i] !== 0) {\n allZero = false\n break\n }\n }\n if (allZero) break\n\n const name = nameField(block, 0, 100)\n const prefix = nameField(block, 345, 155)\n const type = String.fromCharCode(block[156])\n let size = numField(block, 124, 12)\n const dataOff = off + 512\n\n if (type === 'L') {\n // GNU long name: the real name is this entry's payload.\n longName = nameField(data.subarray(dataOff, dataOff + size), 0, size)\n off = dataOff + ceil512(size)\n continue\n }\n if (type === 'K') {\n // GNU long link target — irrelevant to browsing; skip its payload.\n off = dataOff + ceil512(size)\n continue\n }\n if (type === 'x' || type === 'g') {\n // pax extended header: parse path/size for the following entry (g = global, applied likewise).\n pax = parsePax(td.decode(data.subarray(dataOff, dataOff + size)))\n off = dataOff + ceil512(size)\n continue\n }\n\n let full = longName || pax.path || (prefix ? `${prefix}/${name}` : name)\n if (pax.size !== undefined) size = pax.size\n longName = ''\n pax = {}\n\n const isDir = type === '5' || full.endsWith('/')\n full = full.replace(/\\/+$/, '')\n if (full) {\n items.push({\n path: full,\n name: full.split('/').pop() ?? full,\n size: isDir ? 0 : size,\n isDir,\n offset: dataOff,\n })\n }\n off = dataOff + (isDir ? 0 : ceil512(size))\n }\n return items\n}\n\n// ── format dispatch ─────────────────────────────────────────────────────────────────────────────\n\n/** A decompressed buffer is a tar if it carries the ustar magic at offset 257. */\nfunction isTar(data: Uint8Array): boolean {\n return data.length >= 512 && field(data.subarray(257, 263), 0, 5) === 'ustar'\n}\n\n/** Strip a compression suffix to name the single inner file of a non-tar `.gz`/`.xz`/`.bz2`. */\nfunction strippedName(name: string): string {\n const lower = name.toLowerCase()\n for (const [suf, rep] of [\n ['.tar.gz', '.tar'],\n ['.tar.xz', '.tar'],\n ['.tar.bz2', '.tar'],\n ['.tgz', '.tar'],\n ['.txz', '.tar'],\n ['.tbz2', '.tar'],\n ['.tbz', '.tar'],\n ['.tar.br', '.tar'],\n ['.tbr', '.tar'],\n ] as const) {\n if (lower.endsWith(suf)) return name.slice(0, -suf.length) + rep\n }\n for (const suf of ['.gz', '.xz', '.bz2', '.bz', '.br']) {\n if (lower.endsWith(suf)) return name.slice(0, -suf.length)\n }\n return `${name}.out`\n}\n\n/**\n * Open a tar-family archive: decompress the outer wrapper (gzip/xz/bzip2, by magic) if present, then either\n * index it as a tar or, failing that, surface the single decompressed file.\n */\nexport async function openTarball(buf: ArrayBuffer, name: string): Promise<OpenedArchive> {\n let data: Uint8Array = new Uint8Array(buf)\n if (hasMagic(data, GZIP_MAGIC)) data = await gunzip(data)\n else if (hasMagic(data, XZ_MAGIC)) data = xzDecode(data)\n else if (hasMagic(data, BZIP2_MAGIC)) data = bzip2Decode(data)\n else if (!isTar(data)) {\n // Brotli streams carry NO magic bytes. Anything routed here that isn't gzip/xz/bzip2 and isn't already a\n // bare tar (the only other no-magic tar-family member) is treated as Brotli (.br / .tar.br). The WASM\n // decoder is dynamic-imported so its ~250KB wasm loads only when a Brotli file is actually opened.\n const { brotliDecode } = await import('@/lib/brotli')\n data = await brotliDecode(data)\n }\n\n if (isTar(data)) {\n const items = parseTar(data)\n const entries: ArchiveEntry[] = items.map((it, i) => ({\n path: it.path,\n name: it.name,\n size: it.size,\n isDir: it.isDir,\n ref: i,\n }))\n const bytes = data\n return {\n entries,\n extract(e) {\n const it = items[e.ref]\n if (!it || it.isDir) return new Uint8Array(0)\n return bytes.subarray(it.offset, it.offset + it.size).slice()\n },\n }\n }\n\n // Not a tar — a lone compressed file. Present it as one entry.\n const inner = strippedName(name)\n const single = data\n return {\n entries: [{ path: inner, name: inner, size: single.length, isDir: false, ref: 0 }],\n extract() {\n return single\n },\n }\n}\n"],"mappings":"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"}
@@ -81,3 +81,5 @@ function n(e, t) {
81
81
  }
82
82
  //#endregion
83
83
  export { e as VIEWER_FORMATTERS, n as applyFormatter, t as findFormatter };
84
+
85
+ //# sourceMappingURL=viewerFormats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewerFormats.js","names":[],"sources":["../../src/lib/viewerFormats.ts"],"sourcesContent":["/**\n * The \"open with\" formatter set — the universal escape hatch for the side viewer.\n *\n * Auto-detection ({@link classifyViewerFile}) routes a file to a specialized viewer by extension/mime, but that\n * guess can be wrong (a mislabeled file, a `.voice` blob that's really SILK, bytes worth eyeballing as hex).\n * Each formatter here REINTERPRETS the same name/url/size/content as a different {@link ViewerFile}, so it\n * applies to ANY file regardless of what detection picked. The list is shared by:\n * - {@link FileViewerPanel} — renders the header \"打开方式\" menu (available for every file), and\n * - {@link FileViewerBody} — applies the choice and also offers the same chips on its unpreviewable-binary\n * card (the archive-browser context, where there is no host header).\n *\n * These are deliberately the GENERIC reinterpretations that work on raw bytes — hex / text / markdown / html /\n * svg / image / audio / video. The heavy structured viewers (docx / xlsx / zip / …) stay auto-detected only:\n * forcing arbitrary bytes through them just errors, so they'd be noise in a \"force open as\" list.\n */\nimport type { StrokeIconName } from '@/components/icons/iconPaths'\nimport type { ViewerFile } from '@/composables/useFileViewer'\n\nexport interface ViewerFormatter {\n /** Stable id (used for the active-selection highlight and the body↔header sync). */\n key: string\n label: string\n icon: StrokeIconName\n /** Merged onto the base file to force this interpretation; `lang` is always set (it drives the source view). */\n patch: Partial<ViewerFile> & { lang: string }\n}\n\nexport const VIEWER_FORMATTERS: ViewerFormatter[] = [\n { key: 'hex', label: '十六进制', icon: 'hex', patch: { lang: '', hex: true } },\n { key: 'text', label: '文本 / 源码', icon: 'code', patch: { lang: '' } },\n { key: 'markdown', label: 'Markdown', icon: 'fileOutline', patch: { lang: 'markdown' } },\n { key: 'html', label: 'HTML', icon: 'globe', patch: { lang: 'xml', html: true } },\n { key: 'svg', label: 'SVG', icon: 'image', patch: { lang: 'xml', svg: true } },\n { key: 'image', label: '图片', icon: 'image', patch: { lang: '', image: true } },\n { key: 'audio', label: '音频', icon: 'music', patch: { lang: '', audio: true } },\n { key: 'video', label: '视频', icon: 'play', patch: { lang: '', video: true } },\n]\n\n/** Look a formatter up by its {@link ViewerFormatter.key}; undefined for an unknown key. */\nexport function findFormatter(key: string): ViewerFormatter | undefined {\n return VIEWER_FORMATTERS.find((f) => f.key === key)\n}\n\n/**\n * Build the EFFECTIVE file for a chosen formatter: same name/url/size/content as the original, but only the\n * formatter's flags (no carried-over detection flags), so the body's dispatch re-runs cleanly as that format.\n */\nexport function applyFormatter(file: ViewerFile, f: ViewerFormatter): ViewerFile {\n return { name: file.name, url: file.url, size: file.size, content: file.content, ...f.patch }\n}\n"],"mappings":";AA2BA,IAAa,IAAuC;CAClD;EAAE,KAAK;EAAO,OAAO;EAAQ,MAAM;EAAO,OAAO;GAAE,MAAM;GAAI,KAAK;EAAK;CAAE;CACzE;EAAE,KAAK;EAAQ,OAAO;EAAW,MAAM;EAAQ,OAAO,EAAE,MAAM,GAAG;CAAE;CACnE;EAAE,KAAK;EAAY,OAAO;EAAY,MAAM;EAAe,OAAO,EAAE,MAAM,WAAW;CAAE;CACvF;EAAE,KAAK;EAAQ,OAAO;EAAQ,MAAM;EAAS,OAAO;GAAE,MAAM;GAAO,MAAM;EAAK;CAAE;CAChF;EAAE,KAAK;EAAO,OAAO;EAAO,MAAM;EAAS,OAAO;GAAE,MAAM;GAAO,KAAK;EAAK;CAAE;CAC7E;EAAE,KAAK;EAAS,OAAO;EAAM,MAAM;EAAS,OAAO;GAAE,MAAM;GAAI,OAAO;EAAK;CAAE;CAC7E;EAAE,KAAK;EAAS,OAAO;EAAM,MAAM;EAAS,OAAO;GAAE,MAAM;GAAI,OAAO;EAAK;CAAE;CAC7E;EAAE,KAAK;EAAS,OAAO;EAAM,MAAM;EAAQ,OAAO;GAAE,MAAM;GAAI,OAAO;EAAK;CAAE;AAC9E;AAGA,SAAgB,EAAc,GAA0C;CACtE,OAAO,EAAkB,MAAM,MAAM,EAAE,QAAQ,CAAG;AACpD;AAMA,SAAgB,EAAe,GAAkB,GAAgC;CAC/E,OAAO;EAAE,MAAM,EAAK;EAAM,KAAK,EAAK;EAAK,MAAM,EAAK;EAAM,SAAS,EAAK;EAAS,GAAG,EAAE;CAAM;AAC9F"}
@@ -231,3 +231,5 @@ function Z(e, n) {
231
231
  }
232
232
  //#endregion
233
233
  export { Z as canToggleView, q as classifyViewerFile, Y as mediaMimeForName, X as skipsTextLoad };
234
+
235
+ //# sourceMappingURL=viewerKind.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewerKind.js","names":[],"sources":["../../src/lib/viewerKind.ts"],"sourcesContent":["/**\n * Maps a file (name / mime / size / URL) to a {@link ViewerFile} — the single source of truth for \"which\n * in-browser viewer renders this\", shared by:\n * - {@link FileChip} (the chip in a conversation): routes images/videos to the lightbox itself, then\n * delegates everything else here.\n * - the archive browsers (Zip / 7z / tar / rar): an entry, once extracted to a blob URL, is classified the\n * same way and handed to {@link FileViewerBody} — so a file INSIDE an archive previews with the very same\n * viewers as a top-level file (the previous archive detail view only handled text/image/office/dicom).\n *\n * Detection order mirrors FileChip's historical priority exactly (raster/ebook beat the image lightbox; the\n * textual specializations — har/subtitle/geo/csv/notebook/cert — beat the generic source route). The only\n * additions for the archive context are `image` / `video` (rendered inline in the body instead of the lightbox)\n * and a `binary` fall-through (an entry that matches no viewer and isn't text → a download card).\n */\nimport {\n ebookKind,\n fileExt,\n hljsLang,\n isAppxFile,\n isAudioFile,\n isBinaryObjFile,\n isCertFile,\n isCsvFile,\n isDicomFile,\n isDocxFile,\n isDxfFile,\n isEmlFile,\n isEplFile,\n isFontFile,\n isGeoFile,\n isHarFile,\n isHprofFile,\n isHtmlFile,\n isImageFile,\n isJavaClassFile,\n isJksFile,\n isJsonlFile,\n isLogFile,\n isMhtFile,\n isMindMapFile,\n isModelFile,\n isLrcFile,\n isMsiFile,\n isNotebookFile,\n isPdfFile,\n isQmcAudioFile,\n isPptxFile,\n isRarFile,\n isRtfFile,\n isSevenZipFile,\n isSqliteFile,\n isSubtitleFile,\n isSvgFile,\n isTarballFile,\n isTextFile,\n isVideoFile,\n isXlsxFile,\n isXmindFile,\n isZipFile,\n rasterImageKind,\n} from '@/lib/fileType'\nimport { isDiagramFile } from '@/lib/diagram'\nimport { looksLikeMindMap } from '@/lib/mindmap'\nimport type { ViewerFile } from '@/composables/useFileViewer'\n\nexport interface ClassifyOpts {\n /** Display name (becomes {@link ViewerFile.name}). */\n name: string\n /** Fetch / download URL — the real endpoint, or a `blob:` URL for an extracted archive entry. */\n url: string\n /** Provider mime when known; null for archive entries (extension-driven detection). */\n mime?: string | null\n /** Byte size when known (drives the large-file / log routing). */\n size?: number\n /** Name used for TYPE detection when it differs from the display name (e.g. a chip captioned \"16×16 PNG\"). */\n detectName?: string\n /** Fall-back hint when nothing matches and the extension is ambiguous (archive NUL-sniff says \"looks textual\"). */\n textHint?: boolean\n}\n\n/**\n * Classify a file into the {@link ViewerFile} the side viewer should render. Pure — no lightbox / fetching\n * side effects (FileChip handles the lightbox before calling this). Never returns image/video for the main\n * chip flow (FileChip routes those itself); archive callers DO get image/video/binary.\n */\nexport function classifyViewerFile(o: ClassifyOpts): ViewerFile {\n const name = o.name\n const dn = o.detectName ?? o.name\n const mime = o.mime ?? null\n const size = o.size\n const base = { name, url: o.url, size }\n\n // Decoding images (TIFF/PSD/HEIC/RAW) and e-books carry image/* mimes, so they must beat the image route.\n const raster = rasterImageKind(dn, mime)\n if (raster) return { ...base, lang: '', raster }\n const eb = ebookKind(dn, mime)\n if (eb) return { ...base, lang: '', ebook: eb }\n // Diagrams (.drawio/.excalidraw) are XML/JSON under the hood — render as SVG, with the raw text on the source\n // toggle (lang feeds that highlight: xml for drawio, json for excalidraw).\n const diagram = isDiagramFile(dn, mime)\n if (diagram) return { ...base, lang: diagram === 'excalidraw' ? 'json' : 'xml', diagram }\n // image / video render inline in the body (archive context); the main FileChip flow never reaches here for\n // those (it opens the lightbox first), so this only fires for archive entries.\n if (isImageFile(dn, mime)) return { ...base, lang: '', image: true }\n if (isVideoFile(dn, mime)) return { ...base, lang: '', video: true }\n // APPX/MSIX are zip containers, so they MUST be claimed before the generic zip route; MSI is an OLE\n // compound file (not a zip), grouped here with the other Windows installer/package formats.\n if (isAppxFile(dn, mime)) return { ...base, lang: '', appx: true }\n if (isMsiFile(dn, mime)) return { ...base, lang: '', msi: true }\n // XMind is a zip container → claim it before the generic zip route (renders as a mind map, not an archive).\n if (isXmindFile(dn, mime)) return { ...base, lang: '', xmind: true }\n if (isZipFile(dn, mime)) return { ...base, lang: '', zip: true }\n if (isSevenZipFile(dn, mime)) return { ...base, lang: '', sevenZip: true }\n if (isTarballFile(dn, mime)) return { ...base, lang: '', archive: 'tar' }\n if (isRarFile(dn, mime)) return { ...base, lang: '', archive: 'rar' }\n if (isDicomFile(dn, mime)) return { ...base, lang: '', dicom: true }\n if (isBinaryObjFile(dn, mime)) return { ...base, lang: '', binobj: true }\n if (isEplFile(dn, mime)) return { ...base, lang: '', epl: true }\n if (isJavaClassFile(dn, mime)) return { ...base, lang: '', javaClass: true }\n if (isHprofFile(dn, mime)) return { ...base, lang: '', hprof: true }\n if (isDocxFile(dn, mime)) return { ...base, lang: '', docx: true }\n if (isXlsxFile(dn, mime)) return { ...base, lang: '', xlsx: true }\n if (isPptxFile(dn, mime)) return { ...base, lang: '', pptx: true }\n if (isRtfFile(dn, mime)) return { ...base, lang: '', rtf: true }\n if (isPdfFile(dn, mime)) return { ...base, lang: '', pdf: true }\n if (isMindMapFile(dn, mime)) return { ...base, lang: hljsLang(dn, mime), mindmap: true }\n // DXF is textual (ASCII CAD) → claim it before the generic text route so it renders as a drawing.\n if (isDxfFile(dn, mime)) return { ...base, lang: '', dxf: true }\n if (isMhtFile(dn, mime)) return { ...base, lang: '', mht: true }\n if (isEmlFile(dn, mime)) return { ...base, lang: '', eml: true }\n if (isHarFile(dn, mime)) return { ...base, lang: '', har: true }\n if (isSqliteFile(dn, mime)) return { ...base, lang: '', sqlite: true }\n if (isSubtitleFile(dn, mime)) return { ...base, lang: '', subtitle: true }\n if (isGeoFile(dn, mime)) return { ...base, lang: hljsLang(dn, mime), geo: true }\n // QQ Music encrypted audio (.mflac/.mgg/…) → decrypt + play; LRC lyrics (.lrc) → synced lyric list. LRC must\n // beat the generic text route (its viewer self-fetches so it can sniff the usual GBK encoding).\n if (isQmcAudioFile(dn, mime)) return { ...base, lang: '', qmc: true }\n if (isLrcFile(dn, mime)) return { ...base, lang: '', lrc: true }\n if (isAudioFile(dn, mime)) return { ...base, lang: '', audio: true }\n // Logs / large text before the generic text + csv routes (a huge CSV streams through the log viewer).\n if (isLogFile(dn, mime, size)) return { ...base, lang: '', log: true }\n if (isCsvFile(dn, mime)) return { ...base, lang: '', csv: true }\n if (isJsonlFile(dn, mime)) return { ...base, lang: 'json', jsonl: true }\n if (isModelFile(dn, mime)) return { ...base, lang: '', model: true }\n if (isFontFile(dn, mime)) return { ...base, lang: '', font: true }\n if (isNotebookFile(dn, mime)) return { ...base, lang: '', ipynb: true }\n // Keystores (JKS/JCEKS + PKCS#12) before the cert route — the viewer sniffs the bytes to pick the parser.\n if (isJksFile(dn, mime)) return { ...base, lang: '', jks: true }\n if (isCertFile(dn, mime)) return { ...base, lang: '', cert: true }\n // SVG / HTML get a render/source toggle; plain text/code falls to the source view.\n if (isSvgFile(dn, mime)) return { ...base, lang: hljsLang(dn, mime), svg: true }\n if (isHtmlFile(dn, mime)) return { ...base, lang: hljsLang(dn, mime), html: true }\n if (isTextFile(dn, mime) || o.textHint) return { ...base, lang: hljsLang(dn, mime) }\n // Nothing matched and it isn't text → an unpreviewable binary (archive entries only; FileChip never opens these).\n return { ...base, lang: '', binary: true }\n}\n\n// Common image/video/audio MIME by extension — used when an archive browser wraps extracted entry bytes in a\n// Blob URL, so an <img>/<video>/<audio> reliably decodes it (an untyped blob makes the browser guess). Returns\n// '' for non-media (text/office/etc. sub-viewers fetch the bytes themselves, where the blob type is irrelevant).\nconst MEDIA_MIME: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n jfif: 'image/jpeg',\n gif: 'image/gif',\n webp: 'image/webp',\n bmp: 'image/bmp',\n ico: 'image/x-icon',\n avif: 'image/avif',\n apng: 'image/apng',\n svg: 'image/svg+xml',\n mp4: 'video/mp4',\n m4v: 'video/mp4',\n webm: 'video/webm',\n ogv: 'video/ogg',\n mov: 'video/quicktime',\n mkv: 'video/x-matroska',\n mp3: 'audio/mpeg',\n wav: 'audio/wav',\n flac: 'audio/flac',\n ogg: 'audio/ogg',\n oga: 'audio/ogg',\n m4a: 'audio/mp4',\n aac: 'audio/aac',\n opus: 'audio/opus',\n}\n\n/** Best-effort media MIME for an extracted archive entry's Blob (see {@link MEDIA_MIME}); '' when not media. */\nexport function mediaMimeForName(name: string): string {\n return MEDIA_MIME[fileExt(name)] ?? ''\n}\n\n/**\n * Does this file render WITHOUT the panel-loaded text — i.e. a self-fetching sub-viewer (it pulls its own\n * bytes), or an image/video/binary (rendered straight from the URL)? When true the panel skips the text\n * fetch and hides the copy/refresh actions; when false the content is built from fetched text (markdown /\n * html / svg / subtitle / geo / csv / mind-map / source) or inline `content`.\n */\nexport function skipsTextLoad(file: ViewerFile | null): boolean {\n if (!file) return false\n return !!(\n file.zip ||\n file.sevenZip ||\n file.xmind ||\n file.dxf ||\n file.archive ||\n file.binobj ||\n file.epl ||\n file.javaClass ||\n file.hprof ||\n file.msi ||\n file.appx ||\n file.dicom ||\n file.docx ||\n file.xlsx ||\n file.pptx ||\n file.rtf ||\n file.pdf ||\n file.eml ||\n file.mht ||\n file.har ||\n file.sqlite ||\n file.cert ||\n file.jks ||\n file.font ||\n file.ipynb ||\n file.audio ||\n file.qmc ||\n file.lrc ||\n file.log ||\n file.model ||\n file.raster ||\n file.ebook ||\n file.image ||\n file.video ||\n file.binary ||\n file.hex\n )\n}\n\n/**\n * Can this file be shown both rendered and as source (so the header offers an eye/code toggle)? True for\n * markdown / html / svg / subtitle / geo / csv, and for a mind map only once the loaded text actually looks\n * like one (a non-mind-map `.mm` reads as plain source, no toggle).\n */\nexport function canToggleView(file: ViewerFile | null, text: string): boolean {\n if (!file) return false\n if (\n file.lang === 'markdown' ||\n file.html === true ||\n file.svg === true ||\n file.subtitle === true ||\n file.geo === true ||\n file.csv === true ||\n file.jsonl === true ||\n file.diagram != null\n ) {\n return true\n }\n if (file.mindmap === true) return looksLikeMindMap(text, fileExt(file.name))\n return false\n}\n"],"mappings":"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"}
package/dist/lib/x509.js CHANGED
@@ -265,3 +265,5 @@ async function O(e) {
265
265
  }
266
266
  //#endregion
267
267
  export { D as describePrivateKey, u as looksLikePem, s as oidName, C as parseCertificate, w as parseCsr, l as parsePemBlocks, O as sha256Hex, T as summarizeBlock };
268
+
269
+ //# sourceMappingURL=x509.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"x509.js","names":[],"sources":["../../src/lib/x509.ts"],"sourcesContent":["/**\n * Zero-dependency X.509 / PKCS#10 reading on top of the ASN.1 decoder (lib/asn1.ts), for the certificate\n * viewer (CertViewer.vue). It extracts the human-meaningful fields — subject / issuer, validity, serial,\n * signature + public-key algorithm, SANs, key usages, CA flag — from a DER certificate or CSR, and splits a\n * PEM file into its blocks. This is a READ-ONLY visualizer: it does NOT verify signatures or trust chains, so\n * a malformed or untrusted file is shown, not rejected. Anything it can't map to a friendly field still shows\n * in the raw ASN.1 structure tree the viewer renders alongside.\n */\n\nimport {\n asn1String,\n asn1Time,\n bytesToHex,\n decodeAsn1,\n oidToString,\n TAG,\n type Asn1Node,\n} from './asn1'\n\n// OID → short name. Covers the attribute types, algorithms, curves and extensions seen on real certificates;\n// unknown OIDs fall back to their dotted form (see oidName).\nconst OID_NAMES: Record<string, string> = {\n // Distinguished-name attribute types\n '2.5.4.3': 'CN',\n '2.5.4.4': 'SN',\n '2.5.4.5': 'serialNumber',\n '2.5.4.6': 'C',\n '2.5.4.7': 'L',\n '2.5.4.8': 'ST',\n '2.5.4.9': 'street',\n '2.5.4.10': 'O',\n '2.5.4.11': 'OU',\n '2.5.4.12': 'title',\n '2.5.4.42': 'GN',\n '2.5.4.43': 'initials',\n '1.2.840.113549.1.9.1': 'E',\n '0.9.2342.19200300.100.1.25': 'DC',\n '0.9.2342.19200300.100.1.1': 'UID',\n // Signature / public-key algorithms\n '1.2.840.113549.1.1.1': 'RSA',\n '1.2.840.113549.1.1.5': 'sha1WithRSA',\n '1.2.840.113549.1.1.11': 'sha256WithRSA',\n '1.2.840.113549.1.1.12': 'sha384WithRSA',\n '1.2.840.113549.1.1.13': 'sha512WithRSA',\n '1.2.840.113549.1.1.10': 'RSASSA-PSS',\n '1.2.840.10045.2.1': 'EC',\n '1.2.840.10045.4.3.2': 'ecdsa-with-SHA256',\n '1.2.840.10045.4.3.3': 'ecdsa-with-SHA384',\n '1.2.840.10045.4.3.4': 'ecdsa-with-SHA512',\n '1.3.101.112': 'Ed25519',\n '1.3.101.113': 'Ed448',\n // EC named curves\n '1.2.840.10045.3.1.7': 'P-256 (secp256r1)',\n '1.3.132.0.34': 'P-384 (secp384r1)',\n '1.3.132.0.35': 'P-521 (secp521r1)',\n '1.3.132.0.10': 'secp256k1',\n // Certificate extensions\n '2.5.29.14': 'subjectKeyIdentifier',\n '2.5.29.15': 'keyUsage',\n '2.5.29.17': 'subjectAltName',\n '2.5.29.19': 'basicConstraints',\n '2.5.29.31': 'cRLDistributionPoints',\n '2.5.29.32': 'certificatePolicies',\n '2.5.29.35': 'authorityKeyIdentifier',\n '2.5.29.37': 'extKeyUsage',\n '1.3.6.1.5.5.7.1.1': 'authorityInfoAccess',\n // Extended key usages\n '1.3.6.1.5.5.7.3.1': 'serverAuth',\n '1.3.6.1.5.5.7.3.2': 'clientAuth',\n '1.3.6.1.5.5.7.3.3': 'codeSigning',\n '1.3.6.1.5.5.7.3.4': 'emailProtection',\n '1.3.6.1.5.5.7.3.8': 'timeStamping',\n}\n\nexport function oidName(oid: string): string {\n return OID_NAMES[oid] ?? oid\n}\n\nexport interface RDN {\n oid: string\n name: string\n value: string\n}\n\nexport type CertKind = 'certificate' | 'request' | 'key' | 'crl' | 'pkcs12' | 'pkcs7' | 'unknown'\n\nexport interface CertSummary {\n ok: boolean\n kind: CertKind\n label: string\n subject: RDN[]\n issuer: RDN[]\n subjectCN?: string\n issuerCN?: string\n serialHex?: string\n version?: number\n sigAlg?: string\n pubKeyAlg?: string\n pubKeyBits?: number\n pubKeyCurve?: string\n notBefore?: string\n notAfter?: string\n notBeforeMs?: number\n notAfterMs?: number\n sans: string[]\n keyUsages: string[]\n extKeyUsages: string[]\n isCa?: boolean\n pathLen?: number\n der: Uint8Array\n fingerprintSha256?: string // hex, filled in asynchronously by the viewer\n note?: string\n}\n\nexport interface PemBlock {\n label: string\n der: Uint8Array\n}\n\nfunction b64ToBytes(b64: string): Uint8Array {\n const bin = atob(b64)\n const out = new Uint8Array(bin.length)\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i)\n return out\n}\n\n/** Split a PEM document into its `-----BEGIN X-----`…`-----END X-----` blocks (base64 → DER bytes). */\nexport function parsePemBlocks(text: string): PemBlock[] {\n const blocks: PemBlock[] = []\n const re = /-----BEGIN ([^-]+)-----([\\s\\S]*?)-----END \\1-----/g\n let m: RegExpExecArray | null\n while ((m = re.exec(text)) !== null) {\n const b64 = m[2].replace(/[^A-Za-z0-9+/=]/g, '')\n if (!b64) continue\n try {\n blocks.push({ label: m[1].trim(), der: b64ToBytes(b64) })\n } catch {\n /* malformed base64 — skip this block */\n }\n }\n return blocks\n}\n\n/** Does this text look like a PEM document (has at least one BEGIN marker)? */\nexport function looksLikePem(text: string): boolean {\n return /-----BEGIN [^-]+-----/.test(text)\n}\n\nfunction emptySummary(label: string, kind: CertKind, der: Uint8Array): CertSummary {\n return {\n ok: false,\n kind,\n label,\n subject: [],\n issuer: [],\n sans: [],\n keyUsages: [],\n extKeyUsages: [],\n der,\n }\n}\n\nfunction intValue(node: Asn1Node): number {\n let v = 0\n for (const b of node.content) v = v * 256 + b\n return v\n}\n\nfunction stripLeadingZero(bytes: Uint8Array): Uint8Array {\n return bytes.length > 1 && bytes[0] === 0 ? bytes.subarray(1) : bytes\n}\n\nfunction cnOf(rdns: RDN[]): string | undefined {\n return rdns.find((r) => r.name === 'CN')?.value\n}\n\nfunction algName(algId: Asn1Node | undefined): string {\n const oidNode = algId?.children[0]\n return oidNode ? oidName(oidToString(oidNode.content)) : ''\n}\n\n// Name ::= SEQUENCE OF RelativeDistinguishedName (SET OF AttributeTypeAndValue { type OID, value ANY }).\nfunction parseName(name: Asn1Node | undefined): RDN[] {\n const out: RDN[] = []\n if (!name) return out\n for (const rdn of name.children) {\n for (const atv of rdn.children) {\n const oidNode = atv.children[0]\n const valNode = atv.children[1]\n if (!oidNode || !valNode) continue\n const oid = oidToString(oidNode.content)\n out.push({ oid, name: oidName(oid), value: asn1String(valNode) })\n }\n }\n return out\n}\n\n// SubjectPublicKeyInfo ::= SEQUENCE { algorithm AlgorithmIdentifier, subjectPublicKey BIT STRING }.\nfunction applyPubKey(summary: CertSummary, spki: Asn1Node | undefined): void {\n const algId = spki?.children[0]\n const bitStr = spki?.children[1]\n const algOidNode = algId?.children[0]\n if (!algOidNode) return\n const algOid = oidToString(algOidNode.content)\n summary.pubKeyAlg = oidName(algOid)\n if (algOid === '1.2.840.113549.1.1.1' && bitStr) {\n // RSA: BIT STRING = [unusedBits byte][DER RSAPublicKey SEQUENCE { modulus INTEGER, exponent INTEGER }].\n const seq = decodeAsn1(bitStr.content.subarray(1))[0]\n const modulus = seq?.children[0]\n if (modulus) summary.pubKeyBits = stripLeadingZero(modulus.content).length * 8\n } else if (algOid === '1.2.840.10045.2.1') {\n // EC: AlgorithmIdentifier.parameters is the named-curve OID.\n const params = algId?.children[1]\n if (params) {\n summary.pubKeyCurve = oidName(oidToString(params.content))\n const m = summary.pubKeyCurve.match(/(\\d{3})/)\n if (m) summary.pubKeyBits = parseInt(m[1], 10)\n }\n } else if (algOid === '1.3.101.112') {\n summary.pubKeyBits = 256 // Ed25519\n }\n}\n\nconst KEY_USAGE = [\n 'digitalSignature',\n 'nonRepudiation',\n 'keyEncipherment',\n 'dataEncipherment',\n 'keyAgreement',\n 'keyCertSign',\n 'cRLSign',\n 'encipherOnly',\n 'decipherOnly',\n]\n\nfunction parseKeyUsage(bitStr: Asn1Node): string[] {\n const content = bitStr.content\n if (content.length < 2) return []\n const bits = content.subarray(1)\n const total = bits.length * 8 - content[0]\n const out: string[] = []\n for (let i = 0; i < total && i < KEY_USAGE.length; i++) {\n if (bits[Math.floor(i / 8)] & (0x80 >> (i % 8))) out.push(KEY_USAGE[i])\n }\n return out\n}\n\nfunction ipFromBytes(b: Uint8Array): string {\n if (b.length === 4) return Array.from(b).join('.')\n if (b.length === 16) {\n const parts: string[] = []\n for (let i = 0; i < 16; i += 2) parts.push(((b[i] << 8) | b[i + 1]).toString(16))\n return parts.join(':')\n }\n return bytesToHex(b)\n}\n\n// SubjectAltName ::= SEQUENCE OF GeneralName (context-tagged: [1]email [2]DNS [6]URI [7]IP, the common ones).\nfunction parseSan(seq: Asn1Node): string[] {\n const out: string[] = []\n for (const gn of seq.children) {\n if (gn.tagClass !== 2) continue\n const txt = new TextDecoder('latin1').decode(gn.content)\n if (gn.tagNumber === 2) out.push(`DNS:${txt}`)\n else if (gn.tagNumber === 1) out.push(`email:${txt}`)\n else if (gn.tagNumber === 6) out.push(`URI:${txt}`)\n else if (gn.tagNumber === 7) out.push(`IP:${ipFromBytes(gn.content)}`)\n }\n return out\n}\n\nfunction applyExtensions(summary: CertSummary, extSeq: Asn1Node): void {\n for (const ext of extSeq.children) {\n const oidNode = ext.children[0]\n if (!oidNode) continue\n const oid = oidToString(oidNode.content)\n const valNode = ext.children[ext.children.length - 1] // extnValue OCTET STRING (after optional critical)\n const inner = valNode ? decodeAsn1(valNode.content)[0] : undefined\n if (!inner) continue\n if (oid === '2.5.29.17') {\n summary.sans = parseSan(inner)\n } else if (oid === '2.5.29.19') {\n const ca = inner.children.find((c) => c.tagNumber === TAG.BOOLEAN)\n summary.isCa = ca ? ca.content[0] !== 0 : false\n const pl = inner.children.find((c) => c.tagNumber === TAG.INTEGER)\n if (pl) summary.pathLen = intValue(pl)\n } else if (oid === '2.5.29.37') {\n for (const eku of inner.children) summary.extKeyUsages.push(oidName(oidToString(eku.content)))\n } else if (oid === '2.5.29.15') {\n summary.keyUsages = parseKeyUsage(inner)\n }\n }\n}\n\n/** Parse a DER X.509 Certificate into its friendly fields (best effort; `ok=false` + `note` on failure). */\nexport function parseCertificate(der: Uint8Array, label = 'CERTIFICATE'): CertSummary {\n const summary = emptySummary(label, 'certificate', der)\n try {\n const top = decodeAsn1(der)[0]\n const tbs = top?.children[0]\n if (!top || top.tagNumber !== TAG.SEQUENCE || !tbs) {\n summary.note = '不是有效的 X.509 证书结构'\n return summary\n }\n const c = tbs.children\n let idx = 0\n if (c[idx] && c[idx].tagClass === 2 && c[idx].tagNumber === 0) {\n const vint = c[idx].children[0]\n summary.version = vint ? intValue(vint) + 1 : 1\n idx++\n } else {\n summary.version = 1\n }\n if (c[idx]) summary.serialHex = bytesToHex(stripLeadingZero(c[idx++].content), ':')\n if (c[idx]) summary.sigAlg = algName(c[idx++])\n if (c[idx]) summary.issuer = parseName(c[idx++])\n if (c[idx]) {\n const nb = c[idx].children[0] && asn1Time(c[idx].children[0])\n const na = c[idx].children[1] && asn1Time(c[idx].children[1])\n if (nb) {\n summary.notBefore = nb.text\n summary.notBeforeMs = nb.ms\n }\n if (na) {\n summary.notAfter = na.text\n summary.notAfterMs = na.ms\n }\n idx++\n }\n if (c[idx]) summary.subject = parseName(c[idx++])\n if (c[idx]) applyPubKey(summary, c[idx++])\n const extWrap = c.find((n) => n.tagClass === 2 && n.tagNumber === 3)\n if (extWrap && extWrap.children[0]) applyExtensions(summary, extWrap.children[0])\n summary.subjectCN = cnOf(summary.subject)\n summary.issuerCN = cnOf(summary.issuer)\n summary.ok = true\n } catch (e) {\n summary.note = e instanceof Error ? e.message : String(e)\n }\n return summary\n}\n\n/** Parse a DER PKCS#10 CertificationRequest (CSR): subject + public key (best effort). */\nexport function parseCsr(der: Uint8Array, label = 'CERTIFICATE REQUEST'): CertSummary {\n const summary = emptySummary(label, 'request', der)\n try {\n const cri = decodeAsn1(der)[0]?.children[0]\n if (!cri) {\n summary.note = '不是有效的 PKCS#10 请求结构'\n return summary\n }\n // CertificationRequestInfo ::= SEQUENCE { version, subject Name, subjectPKInfo, attributes [0] }\n summary.subject = parseName(cri.children[1])\n applyPubKey(summary, cri.children[2])\n summary.subjectCN = cnOf(summary.subject)\n summary.ok = true\n } catch (e) {\n summary.note = e instanceof Error ? e.message : String(e)\n }\n return summary\n}\n\n/** Pick a parser from a PEM block label (CERTIFICATE / CERTIFICATE REQUEST / *KEY* / *CRL* / fallback). */\nexport function summarizeBlock(label: string, der: Uint8Array): CertSummary {\n const up = label.toUpperCase()\n if (up.includes('CERTIFICATE REQUEST')) return parseCsr(der, label)\n if (up.includes('CERTIFICATE')) return parseCertificate(der, label)\n if (up.includes('CRL')) {\n const s = emptySummary(label, 'crl', der)\n s.ok = true\n s.note = 'X.509 证书吊销列表(CRL)—— 展开下方结构树查看条目。'\n return s\n }\n if (up.includes('KEY')) {\n const s = emptySummary(label, 'key', der)\n s.ok = true\n // PKCS#8 PrivateKeyInfo / SubjectPublicKeyInfo both start with an AlgorithmIdentifier we can name.\n try {\n const top = decodeAsn1(der)[0]\n const algId = top?.children.find((n) => n.tagNumber === TAG.SEQUENCE)\n summarizeKeyAlg(s, algId)\n } catch {\n /* leave the algorithm unset */\n }\n s.note = up.includes('PUBLIC')\n ? '公钥文件 —— 仅展示算法与结构,不含私密材料。'\n : '私钥文件 —— 仅展示算法与结构,密钥材料请勿外泄。'\n return s\n }\n // Unknown label — try a certificate, else just mark the structure as inspectable.\n const cert = parseCertificate(der, label)\n if (cert.ok) return cert\n const s = emptySummary(label, 'unknown', der)\n s.ok = true\n return s\n}\n\nfunction summarizeKeyAlg(s: CertSummary, algId: Asn1Node | undefined): void {\n const oidNode = algId?.children[0]\n if (oidNode && oidNode.tagNumber === TAG.OID) s.pubKeyAlg = oidName(oidToString(oidNode.content))\n}\n\n/**\n * Best-effort algorithm / size read from a DER PKCS#8 PrivateKeyInfo (never throws) — shared by the keystore\n * viewers (lib/jks.ts, lib/pkcs12.ts) to label a decrypted private key. Returns the friendly algorithm name\n * plus, for RSA, the modulus bit-length, and for EC, the named curve (+ its bit size when the name encodes it).\n */\nexport function describePrivateKey(pkcs8: Uint8Array): {\n algorithm: string\n bits?: number\n curve?: string\n} {\n try {\n // PrivateKeyInfo ::= SEQUENCE { version INTEGER, privateKeyAlgorithm AlgorithmIdentifier, privateKey OCTET STRING }\n const top = decodeAsn1(pkcs8)[0]\n const algId = top?.children[1]\n const oidNode = algId?.children[0]\n const oid = oidNode ? oidToString(oidNode.content) : ''\n const res: { algorithm: string; bits?: number; curve?: string } = {\n algorithm: oid ? oidName(oid) : '未知',\n }\n if (oid === '1.2.840.113549.1.1.1') {\n // RSA: privateKey OCTET STRING wraps an RSAPrivateKey SEQUENCE { version, modulus INTEGER, ... }.\n const pk = top?.children[2]\n const rsa = pk ? decodeAsn1(pk.content)[0] : undefined\n const modulus = rsa?.children[1]\n if (modulus) res.bits = stripLeadingZero(modulus.content).length * 8\n } else if (oid === '1.2.840.10045.2.1') {\n // EC: the named curve is the algorithm parameters OID.\n const params = algId?.children[1]\n if (params && params.tagNumber === TAG.OID) {\n res.curve = oidName(oidToString(params.content))\n const m = res.curve.match(/(\\d{3})/)\n if (m) res.bits = parseInt(m[1], 10)\n }\n }\n return res\n } catch {\n return { algorithm: '未知' }\n }\n}\n\n/** SHA-256 fingerprint of DER bytes, as colon-separated hex (e.g. `AB:CD:…`). */\nexport async function sha256Hex(der: Uint8Array): Promise<string> {\n // Copy into a fresh ArrayBuffer so a subarray view's offset doesn't confuse digest.\n const copy = der.slice()\n const digest = await crypto.subtle.digest('SHA-256', copy)\n return bytesToHex(new Uint8Array(digest), ':').toUpperCase()\n}\n"],"mappings":"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"}
package/dist/lib/xlsx.js CHANGED
@@ -319,3 +319,5 @@ async function F(t) {
319
319
  }
320
320
  //#endregion
321
321
  export { o as numToCol, F as parseXlsx };
322
+
323
+ //# sourceMappingURL=xlsx.js.map