docvortex 0.2.1__py3-none-any.whl

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 (364) hide show
  1. docvortex/__init__.py +21 -0
  2. docvortex/analyzers/__init__.py +3 -0
  3. docvortex/analyzers/native/__init__.py +37 -0
  4. docvortex/analyzers/native/_shared/__init__.py +3 -0
  5. docvortex/analyzers/native/_shared/hyperlink.py +16 -0
  6. docvortex/analyzers/native/_shared/image.py +8 -0
  7. docvortex/analyzers/native/_shared/markup/__init__.py +47 -0
  8. docvortex/analyzers/native/_shared/markup/anchors.py +30 -0
  9. docvortex/analyzers/native/_shared/markup/formula.py +37 -0
  10. docvortex/analyzers/native/_shared/markup/projector.py +57 -0
  11. docvortex/analyzers/native/_shared/markup/styles.py +19 -0
  12. docvortex/analyzers/native/_shared/mathml.py +17 -0
  13. docvortex/analyzers/native/_shared/names.py +7 -0
  14. docvortex/analyzers/native/_shared/xycut.py +414 -0
  15. docvortex/analyzers/native/contracts.py +44 -0
  16. docvortex/analyzers/native/csv.py +351 -0
  17. docvortex/analyzers/native/epub/__init__.py +18 -0
  18. docvortex/analyzers/native/epub/constants.py +45 -0
  19. docvortex/analyzers/native/epub/converter.py +80 -0
  20. docvortex/analyzers/native/epub/errors.py +20 -0
  21. docvortex/analyzers/native/epub/metadata.py +31 -0
  22. docvortex/analyzers/native/epub/package.py +649 -0
  23. docvortex/analyzers/native/epub/xhtml.py +306 -0
  24. docvortex/analyzers/native/html/__init__.py +6 -0
  25. docvortex/analyzers/native/html/anchors.py +271 -0
  26. docvortex/analyzers/native/html/constants.py +25 -0
  27. docvortex/analyzers/native/html/contracts.py +7 -0
  28. docvortex/analyzers/native/html/converter.py +117 -0
  29. docvortex/analyzers/native/html/document.py +389 -0
  30. docvortex/analyzers/native/html/errors.py +12 -0
  31. docvortex/analyzers/native/html/resources.py +365 -0
  32. docvortex/analyzers/native/html/selector.py +421 -0
  33. docvortex/analyzers/native/models.py +209 -0
  34. docvortex/analyzers/native/ofd/__init__.py +14 -0
  35. docvortex/analyzers/native/ofd/constants.py +59 -0
  36. docvortex/analyzers/native/ofd/converter.py +31 -0
  37. docvortex/analyzers/native/ofd/errors.py +16 -0
  38. docvortex/analyzers/native/ofd/geometry.py +215 -0
  39. docvortex/analyzers/native/ofd/images.py +124 -0
  40. docvortex/analyzers/native/ofd/metadata.py +53 -0
  41. docvortex/analyzers/native/ofd/models.py +170 -0
  42. docvortex/analyzers/native/ofd/package.py +346 -0
  43. docvortex/analyzers/native/ofd/path.py +201 -0
  44. docvortex/analyzers/native/ofd/reading_order.py +293 -0
  45. docvortex/analyzers/native/ofd/resources.py +122 -0
  46. docvortex/analyzers/native/ofd/scene.py +347 -0
  47. docvortex/analyzers/native/ofd/table.py +240 -0
  48. docvortex/analyzers/native/ofd/text.py +521 -0
  49. docvortex/analyzers/native/office/__init__.py +3 -0
  50. docvortex/analyzers/native/office/doc/__init__.py +3 -0
  51. docvortex/analyzers/native/office/doc/bookmarks.py +81 -0
  52. docvortex/analyzers/native/office/doc/doc_converter.py +573 -0
  53. docvortex/analyzers/native/office/doc/fib.py +261 -0
  54. docvortex/analyzers/native/office/doc/fields.py +101 -0
  55. docvortex/analyzers/native/office/doc/formatting.py +171 -0
  56. docvortex/analyzers/native/office/doc/images.py +162 -0
  57. docvortex/analyzers/native/office/doc/lists.py +356 -0
  58. docvortex/analyzers/native/office/doc/models.py +164 -0
  59. docvortex/analyzers/native/office/doc/parser.py +851 -0
  60. docvortex/analyzers/native/office/doc/pieces.py +256 -0
  61. docvortex/analyzers/native/office/doc/records.py +40 -0
  62. docvortex/analyzers/native/office/doc/sprm.py +269 -0
  63. docvortex/analyzers/native/office/doc/styles.py +215 -0
  64. docvortex/analyzers/native/office/docx/__init__.py +3 -0
  65. docvortex/analyzers/native/office/docx/context.py +71 -0
  66. docvortex/analyzers/native/office/docx/docx_converter.py +614 -0
  67. docvortex/analyzers/native/office/docx/equationxml.py +119 -0
  68. docvortex/analyzers/native/office/docx/fields.py +816 -0
  69. docvortex/analyzers/native/office/docx/formatting_types.py +23 -0
  70. docvortex/analyzers/native/office/docx/main.py +50 -0
  71. docvortex/analyzers/native/office/docx/numbering.py +491 -0
  72. docvortex/analyzers/native/office/docx/office_xml.py +57 -0
  73. docvortex/analyzers/native/office/docx/package_normalizer.py +248 -0
  74. docvortex/analyzers/native/office/docx/resources.py +526 -0
  75. docvortex/analyzers/native/office/docx/styles.py +693 -0
  76. docvortex/analyzers/native/office/docx/tables.py +515 -0
  77. docvortex/analyzers/native/office/equation/__init__.py +3 -0
  78. docvortex/analyzers/native/office/equation/image.py +470 -0
  79. docvortex/analyzers/native/office/equation/latex_dict.py +324 -0
  80. docvortex/analyzers/native/office/equation/mtef.py +885 -0
  81. docvortex/analyzers/native/office/equation/mtef_v5.py +941 -0
  82. docvortex/analyzers/native/office/equation/omml.py +561 -0
  83. docvortex/analyzers/native/office/equation/ooxml.py +62 -0
  84. docvortex/analyzers/native/office/errors.py +33 -0
  85. docvortex/analyzers/native/office/image.py +307 -0
  86. docvortex/analyzers/native/office/legacy/__init__.py +3 -0
  87. docvortex/analyzers/native/office/legacy/binary.py +43 -0
  88. docvortex/analyzers/native/office/legacy/officeart.py +362 -0
  89. docvortex/analyzers/native/office/legacy/ole.py +110 -0
  90. docvortex/analyzers/native/office/limits.py +12 -0
  91. docvortex/analyzers/native/office/odf/__init__.py +3 -0
  92. docvortex/analyzers/native/office/odf/chart.py +76 -0
  93. docvortex/analyzers/native/office/odf/constants.py +70 -0
  94. docvortex/analyzers/native/office/odf/converters.py +403 -0
  95. docvortex/analyzers/native/office/odf/errors.py +18 -0
  96. docvortex/analyzers/native/office/odf/metadata.py +91 -0
  97. docvortex/analyzers/native/office/odf/models.py +176 -0
  98. docvortex/analyzers/native/office/odf/package.py +270 -0
  99. docvortex/analyzers/native/office/odf/styles.py +329 -0
  100. docvortex/analyzers/native/office/odf/table.py +469 -0
  101. docvortex/analyzers/native/office/odf/text.py +1002 -0
  102. docvortex/analyzers/native/office/ooxml_chart.py +1016 -0
  103. docvortex/analyzers/native/office/opc.py +38 -0
  104. docvortex/analyzers/native/office/ppt/__init__.py +3 -0
  105. docvortex/analyzers/native/office/ppt/models.py +118 -0
  106. docvortex/analyzers/native/office/ppt/parser.py +1895 -0
  107. docvortex/analyzers/native/office/ppt/ppt_converter.py +292 -0
  108. docvortex/analyzers/native/office/ppt/records.py +131 -0
  109. docvortex/analyzers/native/office/ppt/style_text.py +247 -0
  110. docvortex/analyzers/native/office/pptx/__init__.py +3 -0
  111. docvortex/analyzers/native/office/pptx/context.py +113 -0
  112. docvortex/analyzers/native/office/pptx/lists.py +558 -0
  113. docvortex/analyzers/native/office/pptx/main.py +20 -0
  114. docvortex/analyzers/native/office/pptx/package_normalizer.py +321 -0
  115. docvortex/analyzers/native/office/pptx/pptx_converter.py +323 -0
  116. docvortex/analyzers/native/office/pptx/resources.py +329 -0
  117. docvortex/analyzers/native/office/pptx/shapes.py +393 -0
  118. docvortex/analyzers/native/office/pptx/text_styles.py +625 -0
  119. docvortex/analyzers/native/office/pptx/titles.py +178 -0
  120. docvortex/analyzers/native/office/rich_text.py +420 -0
  121. docvortex/analyzers/native/office/rtf/__init__.py +3 -0
  122. docvortex/analyzers/native/office/rtf/converter.py +708 -0
  123. docvortex/analyzers/native/office/rtf/lexer.py +213 -0
  124. docvortex/analyzers/native/office/rtf/math.py +339 -0
  125. docvortex/analyzers/native/office/rtf/models.py +185 -0
  126. docvortex/analyzers/native/office/rtf/parser.py +1553 -0
  127. docvortex/analyzers/native/office/spreadsheet/__init__.py +3 -0
  128. docvortex/analyzers/native/office/spreadsheet/html.py +81 -0
  129. docvortex/analyzers/native/office/spreadsheet/models.py +79 -0
  130. docvortex/analyzers/native/office/spreadsheet/projector.py +928 -0
  131. docvortex/analyzers/native/office/streams.py +18 -0
  132. docvortex/analyzers/native/office/xls/__init__.py +3 -0
  133. docvortex/analyzers/native/office/xls/chart.py +132 -0
  134. docvortex/analyzers/native/office/xls/embedded_chart.py +299 -0
  135. docvortex/analyzers/native/office/xls/models.py +109 -0
  136. docvortex/analyzers/native/office/xls/number_format.py +521 -0
  137. docvortex/analyzers/native/office/xls/parser.py +1145 -0
  138. docvortex/analyzers/native/office/xls/records.py +201 -0
  139. docvortex/analyzers/native/office/xls/strings.py +205 -0
  140. docvortex/analyzers/native/office/xls/xls_converter.py +354 -0
  141. docvortex/analyzers/native/office/xlsx/__init__.py +3 -0
  142. docvortex/analyzers/native/office/xlsx/main.py +20 -0
  143. docvortex/analyzers/native/office/xlsx/ooxml_ole.py +522 -0
  144. docvortex/analyzers/native/office/xlsx/package_normalizer.py +310 -0
  145. docvortex/analyzers/native/office/xlsx/xlsx_converter.py +716 -0
  146. docvortex/analyzers/native/pdf/__init__.py +3 -0
  147. docvortex/analyzers/native/pdf/auxiliary_text.py +1671 -0
  148. docvortex/analyzers/native/pdf/char_geometry.py +1662 -0
  149. docvortex/analyzers/native/pdf/code_blocks.py +535 -0
  150. docvortex/analyzers/native/pdf/formulas.py +1985 -0
  151. docvortex/analyzers/native/pdf/geometry.py +281 -0
  152. docvortex/analyzers/native/pdf/graphics.py +1501 -0
  153. docvortex/analyzers/native/pdf/index_blocks.py +268 -0
  154. docvortex/analyzers/native/pdf/inline/__init__.py +3 -0
  155. docvortex/analyzers/native/pdf/inline/common.py +112 -0
  156. docvortex/analyzers/native/pdf/inline/detection.py +590 -0
  157. docvortex/analyzers/native/pdf/inline/matching.py +1185 -0
  158. docvortex/analyzers/native/pdf/inline/materialize.py +457 -0
  159. docvortex/analyzers/native/pdf/inline/scripts.py +975 -0
  160. docvortex/analyzers/native/pdf/inline/types.py +385 -0
  161. docvortex/analyzers/native/pdf/line_layout.py +1106 -0
  162. docvortex/analyzers/native/pdf/line_merging.py +1223 -0
  163. docvortex/analyzers/native/pdf/models.py +246 -0
  164. docvortex/analyzers/native/pdf/native_text.py +1004 -0
  165. docvortex/analyzers/native/pdf/pipeline.py +1390 -0
  166. docvortex/analyzers/native/pdf/script_geometry.py +636 -0
  167. docvortex/analyzers/native/pdf/shared.py +30 -0
  168. docvortex/analyzers/native/pdf/spatial_text.py +383 -0
  169. docvortex/analyzers/native/pdf/table_annotations.py +446 -0
  170. docvortex/analyzers/native/pdf/table_constants.py +48 -0
  171. docvortex/analyzers/native/pdf/table_detection.py +227 -0
  172. docvortex/analyzers/native/pdf/table_filled_grid.py +218 -0
  173. docvortex/analyzers/native/pdf/table_geometry.py +40 -0
  174. docvortex/analyzers/native/pdf/table_materialization.py +444 -0
  175. docvortex/analyzers/native/pdf/table_recovery/__init__.py +15 -0
  176. docvortex/analyzers/native/pdf/table_recovery/candidate.py +356 -0
  177. docvortex/analyzers/native/pdf/table_recovery/contracts.py +154 -0
  178. docvortex/analyzers/native/pdf/table_recovery/engine.py +609 -0
  179. docvortex/analyzers/native/pdf/table_recovery/geometry.py +164 -0
  180. docvortex/analyzers/native/pdf/table_recovery/sparse_common.py +85 -0
  181. docvortex/analyzers/native/pdf/table_recovery/sparse_hybrid.py +804 -0
  182. docvortex/analyzers/native/pdf/table_recovery/sparse_multiline.py +1122 -0
  183. docvortex/analyzers/native/pdf/table_recovery/text.py +414 -0
  184. docvortex/analyzers/native/pdf/table_recovery/text_grid.py +618 -0
  185. docvortex/analyzers/native/pdf/table_recovery/vector.py +1931 -0
  186. docvortex/analyzers/native/pdf/table_rows.py +34 -0
  187. docvortex/analyzers/native/pdf/table_rules.py +1129 -0
  188. docvortex/analyzers/native/pdf/table_text_styles.py +283 -0
  189. docvortex/analyzers/native/pdf/tables.py +147 -0
  190. docvortex/analyzers/native/pdf/text_assembly/__init__.py +3 -0
  191. docvortex/analyzers/native/pdf/text_assembly/annotations.py +581 -0
  192. docvortex/analyzers/native/pdf/text_assembly/assembly.py +292 -0
  193. docvortex/analyzers/native/pdf/text_assembly/common.py +477 -0
  194. docvortex/analyzers/native/pdf/text_assembly/footnotes.py +394 -0
  195. docvortex/analyzers/native/pdf/text_assembly/merging.py +1274 -0
  196. docvortex/analyzers/native/pdf/text_assembly/rows.py +692 -0
  197. docvortex/analyzers/native/pdf/text_blocks.py +82 -0
  198. docvortex/analyzers/native/pdf/text_styles.py +55 -0
  199. docvortex/analyzers/native/pdf/title_analysis/__init__.py +3 -0
  200. docvortex/analyzers/native/pdf/title_analysis/body_profile.py +215 -0
  201. docvortex/analyzers/native/pdf/title_analysis/common.py +117 -0
  202. docvortex/analyzers/native/pdf/title_analysis/document_profile.py +164 -0
  203. docvortex/analyzers/native/pdf/title_analysis/lane_titles.py +758 -0
  204. docvortex/analyzers/native/pdf/title_analysis/page_titles.py +1024 -0
  205. docvortex/analyzers/native/pdf/title_analysis/prototype.py +194 -0
  206. docvortex/analyzers/native/pdf/title_analysis/structural.py +1081 -0
  207. docvortex/analyzers/native/pdf/titles.py +75 -0
  208. docvortex/analyzers/native/pdf/typography.py +19 -0
  209. docvortex/analyzers/native/pdf/visual_annotations.py +1262 -0
  210. docvortex/api.py +180 -0
  211. docvortex/assets/__init__.py +5 -0
  212. docvortex/assets/store.py +51 -0
  213. docvortex/cli.py +54 -0
  214. docvortex/codecs/__init__.py +3 -0
  215. docvortex/codecs/html/__init__.py +22 -0
  216. docvortex/codecs/html/contracts.py +236 -0
  217. docvortex/codecs/html/materializer.py +331 -0
  218. docvortex/codecs/html/parser.py +763 -0
  219. docvortex/codecs/html/resources.py +34 -0
  220. docvortex/codecs/json.py +17 -0
  221. docvortex/content/__init__.py +5 -0
  222. docvortex/content/inline.py +248 -0
  223. docvortex/content/markup/__init__.py +44 -0
  224. docvortex/content/markup/anchors.py +188 -0
  225. docvortex/content/markup/formula.py +280 -0
  226. docvortex/content/markup/projector.py +1237 -0
  227. docvortex/content/markup/styles.py +327 -0
  228. docvortex/content/mathml.py +167 -0
  229. docvortex/content/normalization.py +188 -0
  230. docvortex/content/spans.py +183 -0
  231. docvortex/content/table/__init__.py +18 -0
  232. docvortex/content/table/blocks.py +152 -0
  233. docvortex/content/table/content.py +425 -0
  234. docvortex/content/table/document.py +104 -0
  235. docvortex/content/table/html.py +399 -0
  236. docvortex/content/table/models.py +76 -0
  237. docvortex/content/table/rules.py +42 -0
  238. docvortex/content/table/structure.py +221 -0
  239. docvortex/content/tree.py +5 -0
  240. docvortex/document/__init__.py +3 -0
  241. docvortex/document/contracts.py +22 -0
  242. docvortex/document/detection.py +389 -0
  243. docvortex/document/filetypes.py +175 -0
  244. docvortex/document/page_range.py +167 -0
  245. docvortex/document/pdf/__init__.py +19 -0
  246. docvortex/document/pdf/classify.py +1138 -0
  247. docvortex/document/pdf/constants.py +132 -0
  248. docvortex/document/pdf/diagnostics.py +350 -0
  249. docvortex/document/pdf/document.py +582 -0
  250. docvortex/document/pdf/font_runtime.py +335 -0
  251. docvortex/document/pdf/geometry.py +31 -0
  252. docvortex/document/pdf/images.py +654 -0
  253. docvortex/document/pdf/native_annotations.py +367 -0
  254. docvortex/document/pdf/native_contracts.py +169 -0
  255. docvortex/document/pdf/native_coordinates.py +216 -0
  256. docvortex/document/pdf/native_lifecycle.py +16 -0
  257. docvortex/document/pdf/native_objects.py +902 -0
  258. docvortex/document/pdf/native_text_geometry.py +315 -0
  259. docvortex/document/pdf/pdfium.py +325 -0
  260. docvortex/document/pdf/raster.py +46 -0
  261. docvortex/document/pdf/text/__init__.py +62 -0
  262. docvortex/document/pdf/text/contracts.py +211 -0
  263. docvortex/document/pdf/text/extract.py +165 -0
  264. docvortex/document/pdf/text/geometry.py +16 -0
  265. docvortex/document/pdf/text/groups.py +162 -0
  266. docvortex/document/pdf/visual_geometry.py +201 -0
  267. docvortex/document/pdf/visuals.py +343 -0
  268. docvortex/document/source.py +92 -0
  269. docvortex/errors.py +21 -0
  270. docvortex/export/__init__.py +3 -0
  271. docvortex/export/bundle.py +98 -0
  272. docvortex/export/files.py +66 -0
  273. docvortex/export/middle.py +208 -0
  274. docvortex/foundation/__init__.py +3 -0
  275. docvortex/foundation/geometry.py +125 -0
  276. docvortex/foundation/hyperlink.py +65 -0
  277. docvortex/foundation/image.py +48 -0
  278. docvortex/foundation/image_encoding.py +30 -0
  279. docvortex/foundation/image_payload.py +280 -0
  280. docvortex/foundation/language.py +92 -0
  281. docvortex/foundation/platform.py +38 -0
  282. docvortex/foundation/text.py +153 -0
  283. docvortex/foundation/type_identity.py +20 -0
  284. docvortex/foundation/xml_names.py +20 -0
  285. docvortex/options.py +30 -0
  286. docvortex/postprocess/__init__.py +3 -0
  287. docvortex/postprocess/content.py +53 -0
  288. docvortex/postprocess/document.py +19 -0
  289. docvortex/postprocess/lists.py +236 -0
  290. docvortex/postprocess/page_blocks.py +214 -0
  291. docvortex/postprocess/pages.py +95 -0
  292. docvortex/postprocess/paragraphs.py +580 -0
  293. docvortex/postprocess/visual.py +715 -0
  294. docvortex/render/__init__.py +48 -0
  295. docvortex/render/_internal/__init__.py +3 -0
  296. docvortex/render/_internal/common/__init__.py +3 -0
  297. docvortex/render/_internal/common/context.py +43 -0
  298. docvortex/render/_internal/common/html_table.py +178 -0
  299. docvortex/render/_internal/common/index.py +33 -0
  300. docvortex/render/_internal/common/list_items.py +158 -0
  301. docvortex/render/_internal/common/planner.py +140 -0
  302. docvortex/render/_internal/docx/__init__.py +3 -0
  303. docvortex/render/_internal/docx/assets.py +202 -0
  304. docvortex/render/_internal/docx/inline.py +434 -0
  305. docvortex/render/_internal/docx/math.py +220 -0
  306. docvortex/render/_internal/docx/renderer.py +905 -0
  307. docvortex/render/_internal/docx/styles.py +195 -0
  308. docvortex/render/_internal/docx/table.py +442 -0
  309. docvortex/render/_internal/epub/__init__.py +5 -0
  310. docvortex/render/_internal/epub/assets.py +173 -0
  311. docvortex/render/_internal/epub/package.py +249 -0
  312. docvortex/render/_internal/epub/renderer.py +1156 -0
  313. docvortex/render/_internal/html/__init__.py +3 -0
  314. docvortex/render/_internal/html/inline.py +346 -0
  315. docvortex/render/_internal/html/renderer.py +1041 -0
  316. docvortex/render/_internal/html/sanitizer.py +478 -0
  317. docvortex/render/_internal/html/table.py +121 -0
  318. docvortex/render/_internal/latex/__init__.py +1 -0
  319. docvortex/render/_internal/latex/assets.py +85 -0
  320. docvortex/render/_internal/latex/inline.py +145 -0
  321. docvortex/render/_internal/latex/renderer.py +506 -0
  322. docvortex/render/_internal/latex/table.py +347 -0
  323. docvortex/render/_internal/markdown/__init__.py +3 -0
  324. docvortex/render/_internal/markdown/assets.py +78 -0
  325. docvortex/render/_internal/markdown/blocks.py +635 -0
  326. docvortex/render/_internal/markdown/escaping.py +51 -0
  327. docvortex/render/_internal/markdown/inline.py +260 -0
  328. docvortex/render/_internal/markdown/renderer.py +93 -0
  329. docvortex/render/_internal/markdown/table.py +281 -0
  330. docvortex/render/_internal/pdf/__init__.py +3 -0
  331. docvortex/render/_internal/pdf/assets.py +197 -0
  332. docvortex/render/_internal/pdf/formula.py +417 -0
  333. docvortex/render/_internal/pdf/inline.py +343 -0
  334. docvortex/render/_internal/pdf/renderer.py +734 -0
  335. docvortex/render/_internal/pdf/styles.py +206 -0
  336. docvortex/render/_internal/pdf/table.py +272 -0
  337. docvortex/render/_internal/structured_content/__init__.py +3 -0
  338. docvortex/render/_internal/structured_content/renderer.py +193 -0
  339. docvortex/render/api.py +199 -0
  340. docvortex/render/contracts.py +205 -0
  341. docvortex/render/docx.py +38 -0
  342. docvortex/render/epub.py +35 -0
  343. docvortex/render/fragments.py +70 -0
  344. docvortex/render/html.py +29 -0
  345. docvortex/render/latex.py +24 -0
  346. docvortex/render/markdown.py +50 -0
  347. docvortex/render/pdf.py +25 -0
  348. docvortex/render/structured_content.py +23 -0
  349. docvortex/resources/epub/docvortex.css +91 -0
  350. docvortex/resources/fasttext-langdetect/lid.176.ftz +0 -0
  351. docvortex/resources/fonts/DroidSansFallbackFull.ttf +0 -0
  352. docvortex/resources/fonts/NOTICE +190 -0
  353. docvortex/resources/fonts/manifest.json +9 -0
  354. docvortex/resources/html/docvortex.css +601 -0
  355. docvortex/resources/html/docvortex.min.css +1 -0
  356. docvortex/result.py +91 -0
  357. docvortex/schema.py +1141 -0
  358. docvortex/version.py +3 -0
  359. docvortex-0.2.1.dist-info/METADATA +193 -0
  360. docvortex-0.2.1.dist-info/RECORD +364 -0
  361. docvortex-0.2.1.dist-info/WHEEL +5 -0
  362. docvortex-0.2.1.dist-info/entry_points.txt +2 -0
  363. docvortex-0.2.1.dist-info/licenses/LICENSE.md +21 -0
  364. docvortex-0.2.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,561 @@
1
+ """
2
+ Office Math Markup Language (OMML)
3
+
4
+ Adapted from https://github.com/xiilei/dwml/blob/master/dwml/omml.py
5
+ On 23/01/2025
6
+ """
7
+
8
+ import re
9
+
10
+ import lxml.etree as ET
11
+ from loguru import logger
12
+ from pylatexenc.latexencode import UnicodeToLatexEncoder
13
+
14
+ from .latex_dict import (
15
+ ALN,
16
+ ARR,
17
+ BACKSLASH,
18
+ BLANK,
19
+ BRK,
20
+ CHARS,
21
+ CHR,
22
+ CHR_BO,
23
+ CHR_DEFAULT,
24
+ D_DEFAULT,
25
+ F_DEFAULT,
26
+ FUNC,
27
+ FUNC_PLACE,
28
+ LIM_FUNC,
29
+ LIM_TO,
30
+ LIM_UPP,
31
+ POS,
32
+ POS_DEFAULT,
33
+ RAD,
34
+ RAD_DEFAULT,
35
+ SUB,
36
+ SUP,
37
+ D,
38
+ F,
39
+ M,
40
+ T,
41
+ )
42
+
43
+ OMML_NS = "{http://schemas.openxmlformats.org/officeDocument/2006/math}"
44
+
45
+ # Mapping from OMML <m:scr> values to LaTeX math font commands.
46
+ # Used in do_r to convert math script/font style to appropriate LaTeX commands.
47
+ SCR_TO_LATEX = {
48
+ "script": "\\mathscr{{{0}}}", # 手写体/花体 — \mathscr covers both upper and lowercase
49
+ "fraktur": "\\mathfrak{{{0}}}", # 德国哥特体 — \mathfrak for upper and lowercase
50
+ "double-struck": "\\mathbb{{{0}}}", # 双线体/黑板粗体 — \mathbb
51
+ "sans-serif": "\\mathsf{{{0}}}", # 无衬线体
52
+ "monospace": "\\mathtt{{{0}}}", # 等宽字体
53
+ }
54
+
55
+ LOWER_GROUP_LIMITS = ("\\underbrace{", "\\underbracket{", "\\underparen{")
56
+ UPPER_GROUP_LIMITS = ("\\overbrace{", "\\overbracket{", "\\overparen{")
57
+
58
+
59
+ def load(stream):
60
+ tree = ET.parse(stream)
61
+ for omath in tree.findall(OMML_NS + "oMath"):
62
+ yield oMath2Latex(omath)
63
+
64
+
65
+ def load_string(string):
66
+ root = ET.fromstring(string)
67
+ for omath in root.findall(OMML_NS + "oMath"):
68
+ yield oMath2Latex(omath)
69
+
70
+
71
+ def escape_latex(strs):
72
+ last = None
73
+ new_chr = []
74
+ strs = strs.replace(r"\\", "\\")
75
+ for c in strs:
76
+ if (c in CHARS) and (last != BACKSLASH):
77
+ new_chr.append(BACKSLASH + c)
78
+ else:
79
+ new_chr.append(c)
80
+ last = c
81
+ return BLANK.join(new_chr)
82
+
83
+
84
+ def get_val(key, default=None, store=CHR):
85
+ if key is not None:
86
+ return key if not store else store.get(key, key)
87
+ else:
88
+ return default
89
+
90
+
91
+ def _normalize_latex_delimiter(delimiter):
92
+ """将 Word OMML 定界符字符转换为 LaTeX/KaTeX 可渲染的定界符。"""
93
+ if delimiter in ("\u2225", "\u2016"):
94
+ return r"\|"
95
+ return delimiter
96
+
97
+
98
+ def _ensure_latex_command_boundary(latex_text):
99
+ """为裸 LaTeX 字母控制词补终止空格,避免后续变量被拼成未知命令。"""
100
+ if re.fullmatch(r"\\[A-Za-z]+", latex_text):
101
+ return f"{latex_text} "
102
+ return latex_text
103
+
104
+
105
+ class Tag2Method:
106
+ def call_method(self, elm, stag=None):
107
+ getmethod = self.tag2meth.get
108
+ if stag is None:
109
+ stag = elm.tag.replace(OMML_NS, "")
110
+ method = getmethod(stag)
111
+ if method:
112
+ return method(self, elm)
113
+ else:
114
+ return None
115
+
116
+ def process_children_list(self, elm, include=None):
117
+ """
118
+ process children of the elm,return iterable
119
+ """
120
+ for _e in list(elm):
121
+ if OMML_NS not in _e.tag:
122
+ continue
123
+ stag = _e.tag.replace(OMML_NS, "")
124
+ if include and (stag not in include):
125
+ continue
126
+ t = self.call_method(_e, stag=stag)
127
+ if t is None:
128
+ t = self.process_unknow(_e, stag)
129
+ if t is None:
130
+ continue
131
+ yield (stag, t, _e)
132
+
133
+ def process_children_dict(self, elm, include=None):
134
+ """
135
+ process children of the elm,return dict
136
+ """
137
+ latex_chars = dict()
138
+ for stag, t, e in self.process_children_list(elm, include):
139
+ latex_chars[stag] = t
140
+ return latex_chars
141
+
142
+ def process_children(self, elm, include=None):
143
+ """
144
+ process children of the elm,return string
145
+ """
146
+ return BLANK.join(
147
+ (t if not isinstance(t, Tag2Method) else str(t) for stag, t, e in self.process_children_list(elm, include))
148
+ )
149
+
150
+ def process_unknow(self, elm, stag):
151
+ return None
152
+
153
+
154
+ class Pr(Tag2Method):
155
+ text = ""
156
+
157
+ __val_tags = ("chr", "pos", "begChr", "endChr", "type")
158
+
159
+ __innerdict = None # can't use the __dict__
160
+
161
+ """ common properties of element"""
162
+
163
+ def __init__(self, elm):
164
+ self.__innerdict = {}
165
+ self.text = self.process_children(elm)
166
+
167
+ def __str__(self):
168
+ return self.text
169
+
170
+ def __unicode__(self):
171
+ return self.__str__(self)
172
+
173
+ def __getattr__(self, name):
174
+ return self.__innerdict.get(name, None)
175
+
176
+ def do_brk(self, elm):
177
+ self.__innerdict["brk"] = BRK
178
+ return BRK
179
+
180
+ def do_common(self, elm):
181
+ stag = elm.tag.replace(OMML_NS, "")
182
+ if stag in self.__val_tags:
183
+ t = elm.get(f"{OMML_NS}val")
184
+ self.__innerdict[stag] = t
185
+ return None
186
+
187
+ tag2meth = {
188
+ "brk": do_brk,
189
+ "chr": do_common,
190
+ "pos": do_common,
191
+ "begChr": do_common,
192
+ "endChr": do_common,
193
+ "type": do_common,
194
+ }
195
+
196
+
197
+ class oMath2Latex(Tag2Method):
198
+ """
199
+ Convert oMath element of omml to latex
200
+ """
201
+
202
+ _t_dict = T
203
+
204
+ __direct_tags = ("box", "sSub", "sSup", "sSubSup", "num", "den", "deg", "e")
205
+ u = UnicodeToLatexEncoder(
206
+ replacement_latex_protection="braces-all",
207
+ unknown_char_policy="keep",
208
+ unknown_char_warning=False,
209
+ )
210
+
211
+ def __init__(self, element):
212
+ self._latex = self.process_children(element)
213
+
214
+ def __str__(self):
215
+ return self.latex.replace(" ", " ")
216
+
217
+ def __unicode__(self):
218
+ return self.__str__(self)
219
+
220
+ def process_unknow(self, elm, stag):
221
+ if stag in self.__direct_tags:
222
+ return self.process_children(elm)
223
+ elif stag[-2:] == "Pr":
224
+ return Pr(elm)
225
+ else:
226
+ return None
227
+
228
+ @property
229
+ def latex(self):
230
+ return self._latex
231
+
232
+ def _apply_limit_marker(self, base_text, limit_text):
233
+ if not isinstance(limit_text, str):
234
+ return None
235
+
236
+ latex_template = CHR.get(limit_text)
237
+ if latex_template and "{0}" in latex_template:
238
+ return latex_template.format(base_text)
239
+ return None
240
+
241
+ def _format_limit_like(self, base_text, limit_text, *, upper):
242
+ marker_wrapped = self._apply_limit_marker(base_text, limit_text)
243
+ if marker_wrapped is not None:
244
+ return marker_wrapped
245
+
246
+ if upper:
247
+ if isinstance(base_text, str) and base_text.lstrip().startswith(UPPER_GROUP_LIMITS):
248
+ return f"{base_text}{SUP.format(limit_text)}"
249
+ return LIM_UPP.format(lim=limit_text, text=base_text)
250
+
251
+ latex_s = LIM_FUNC.get(base_text)
252
+ if latex_s:
253
+ return latex_s.format(lim=limit_text)
254
+
255
+ if isinstance(base_text, str) and base_text.lstrip().startswith(LOWER_GROUP_LIMITS):
256
+ return f"{base_text}{SUB.format(limit_text)}"
257
+
258
+ return f"\\underset{{{limit_text}}}{{{base_text}}}"
259
+
260
+ def do_acc(self, elm):
261
+ """
262
+ the accent function
263
+ """
264
+ c_dict = self.process_children_dict(elm)
265
+ latex_s = get_val(c_dict["accPr"].chr, default=CHR_DEFAULT.get("ACC_VAL"), store=CHR)
266
+ return latex_s.format(c_dict["e"])
267
+
268
+ def do_bar(self, elm):
269
+ """
270
+ the bar function
271
+ """
272
+ c_dict = self.process_children_dict(elm)
273
+ pr = c_dict["barPr"]
274
+ latex_s = get_val(pr.pos, default=POS_DEFAULT.get("BAR_VAL"), store=POS)
275
+ return pr.text + latex_s.format(c_dict["e"])
276
+
277
+ def do_d(self, elm):
278
+ """
279
+ the delimiter object
280
+ """
281
+ c_dict = self.process_children_dict(elm)
282
+ pr = c_dict["dPr"]
283
+ null = D_DEFAULT.get("null")
284
+
285
+ s_val = _normalize_latex_delimiter(get_val(pr.begChr, default=D_DEFAULT.get("left"), store=T))
286
+ e_val = _normalize_latex_delimiter(get_val(pr.endChr, default=D_DEFAULT.get("right"), store=T))
287
+ delim = pr.text + D.format(
288
+ left=null if not s_val else escape_latex(s_val),
289
+ text=c_dict["e"],
290
+ right=null if not e_val else escape_latex(e_val),
291
+ )
292
+ return delim
293
+
294
+ def do_spre(self, elm):
295
+ """
296
+ the Pre-Sub-Superscript object -- Not support yet
297
+ """
298
+
299
+ def do_sub(self, elm):
300
+ text = self.process_children(elm)
301
+ return SUB.format(text)
302
+
303
+ def do_sup(self, elm):
304
+ text = self.process_children(elm)
305
+ return SUP.format(text)
306
+
307
+ def do_f(self, elm):
308
+ """
309
+ the fraction object
310
+ """
311
+ c_dict = self.process_children_dict(elm)
312
+ pr = c_dict.get("fPr")
313
+ if pr is None:
314
+ # Handle missing fPr element gracefully
315
+ logger.debug("Missing fPr element in fraction, using default formatting")
316
+ latex_s = F_DEFAULT
317
+ return latex_s.format(
318
+ num=c_dict.get("num"),
319
+ den=c_dict.get("den"),
320
+ )
321
+ latex_s = get_val(pr.type, default=F_DEFAULT, store=F)
322
+ return pr.text + latex_s.format(num=c_dict.get("num"), den=c_dict.get("den"))
323
+
324
+ def do_func(self, elm):
325
+ """
326
+ the Function-Apply object (Examples:sin cos)
327
+ """
328
+ c_dict = self.process_children_dict(elm)
329
+ func_name = c_dict.get("fName")
330
+ return func_name.replace(FUNC_PLACE, c_dict.get("e"))
331
+
332
+ def do_fname(self, elm):
333
+ """
334
+ the func name
335
+ """
336
+ latex_chars = []
337
+ for stag, t, e in self.process_children_list(elm):
338
+ if stag == "r":
339
+ if FUNC.get(t):
340
+ latex_chars.append(FUNC[t])
341
+ else:
342
+ logger.warning("Function not supported, will default to text: %s", t)
343
+ if isinstance(t, str):
344
+ latex_chars.append(t)
345
+ elif isinstance(t, str):
346
+ latex_chars.append(t)
347
+ t = BLANK.join(latex_chars)
348
+ return t if FUNC_PLACE in t else t + FUNC_PLACE # do_func will replace this
349
+
350
+ def do_groupchr(self, elm):
351
+ """
352
+ the Group-Character object
353
+ """
354
+ c_dict = self.process_children_dict(elm)
355
+ pr = c_dict["groupChrPr"]
356
+ latex_s = get_val(pr.chr)
357
+ return pr.text + latex_s.format(c_dict["e"])
358
+
359
+ def do_rad(self, elm):
360
+ """
361
+ the radical object
362
+ """
363
+ c_dict = self.process_children_dict(elm)
364
+ text = c_dict.get("e")
365
+ deg_text = c_dict.get("deg")
366
+ if deg_text:
367
+ return RAD.format(deg=deg_text, text=text)
368
+ else:
369
+ return RAD_DEFAULT.format(text=text)
370
+
371
+ def do_eqarr(self, elm):
372
+ """
373
+ the Array object.
374
+
375
+ Handles two cases:
376
+ 1. Single-row eqArr with a right-aligned equation tag encoded as
377
+ ``\\#(n)`` at the end of the row (OMML column-alignment syntax).
378
+ The ``#`` column separator and the equation number ``(n)`` are
379
+ converted to LaTeX ``\\tag{n}`` so KaTeX can render the tag,
380
+ and the unnecessary ``\\begin{array}{c}...\\end{array}`` wrapper
381
+ is omitted.
382
+ 2. Single-row eqArr without a tag: content is returned as-is (no
383
+ array wrapper needed).
384
+ 3. Multi-row eqArr: kept as ``\\begin{array}{c}...\\end{array}``.
385
+ """
386
+ rows = [t for stag, t, e in self.process_children_list(elm, include=("e",))]
387
+
388
+ if len(rows) == 1:
389
+ row = rows[0]
390
+ # Detect the OMML equation-tag pattern: the text element "#(n)" is
391
+ # stored verbatim inside the row; do_r converts "#" via pylatexenc
392
+ # to "\# " (escaped hash with surrounding spaces due to brace-
393
+ # protection stripping). Match that at the end of the row,
394
+ # allowing optional whitespace between "\#" and the opening "(".
395
+ tag_match = re.search(r"\\#\s*\(([^)]*)\)\s*$", row)
396
+ if tag_match:
397
+ formula = row[: tag_match.start()].rstrip()
398
+ tag_content = tag_match.group(1)
399
+ return f"{formula}\\tag{{{tag_content}}}"
400
+ # Single row without tag — no array wrapper required.
401
+ return row
402
+
403
+ return ARR.format(text=BRK.join(rows))
404
+
405
+ def do_limlow(self, elm):
406
+ """
407
+ the Lower-Limit object
408
+ """
409
+ t_dict = self.process_children_dict(elm, include=("e", "lim"))
410
+ return self._format_limit_like(
411
+ t_dict.get("e", ""),
412
+ t_dict.get("lim", ""),
413
+ upper=False,
414
+ )
415
+
416
+ def do_limupp(self, elm):
417
+ """
418
+ the Upper-Limit object
419
+ """
420
+ t_dict = self.process_children_dict(elm, include=("e", "lim"))
421
+ return self._format_limit_like(
422
+ t_dict.get("e", ""),
423
+ t_dict.get("lim", ""),
424
+ upper=True,
425
+ )
426
+
427
+ def do_lim(self, elm):
428
+ """
429
+ the lower limit of the limLow object and the upper limit of the limUpp function
430
+ """
431
+ return self.process_children(elm).replace(LIM_TO[0], LIM_TO[1])
432
+
433
+ def do_m(self, elm):
434
+ """
435
+ the Matrix object
436
+ """
437
+ rows = []
438
+ for stag, t, e in self.process_children_list(elm):
439
+ if stag == "mPr":
440
+ pass
441
+ elif stag == "mr":
442
+ rows.append(t)
443
+ return M.format(text=BRK.join(rows))
444
+
445
+ def do_mr(self, elm):
446
+ """
447
+ a single row of the matrix m
448
+ """
449
+ return ALN.join([t for stag, t, e in self.process_children_list(elm, include=("e",))])
450
+
451
+ def do_nary(self, elm):
452
+ """
453
+ the n-ary object
454
+ """
455
+ res = []
456
+ bo = ""
457
+ for stag, t, e in self.process_children_list(elm):
458
+ if stag == "naryPr":
459
+ # if <m:naryPr> contains no <m:chr>, the n-ary represents an integral
460
+ bo = get_val(t.chr, default="\\int", store=CHR_BO)
461
+ else:
462
+ res.append(t)
463
+ return bo + BLANK.join(res)
464
+
465
+ def process_unicode(self, s):
466
+ if s in CHARS:
467
+ return BACKSLASH + s
468
+
469
+ # Check T dictionary first for known math-mode symbols.
470
+ # The T dictionary holds explicit math-mode LaTeX mappings and takes precedence
471
+ # over pylatexenc, which uses text-mode mappings by default and therefore produces
472
+ # text-mode commands like \textperiodcentered (for U+00B7 ·) that are invalid
473
+ # inside math environments.
474
+ t_result = self._t_dict.get(s)
475
+ if t_result is not None:
476
+ return t_result
477
+
478
+ out_latex_str = self.u.unicode_to_latex(s)
479
+
480
+ # pylatexenc常把数学字符包成 {\ensuremath{...}},这里只剥离外层包装,
481
+ # 不能删除内部LaTeX命令的闭合花括号。
482
+ if out_latex_str.startswith(r"{\ensuremath{") and out_latex_str.endswith("}}"):
483
+ out_latex_str = out_latex_str[len(r"{\ensuremath{") : -2]
484
+ out_latex_str = _ensure_latex_command_boundary(out_latex_str)
485
+ elif out_latex_str.startswith(r"\ensuremath{") and out_latex_str.endswith("}"):
486
+ out_latex_str = out_latex_str[len(r"\ensuremath{") : -1]
487
+ out_latex_str = _ensure_latex_command_boundary(out_latex_str)
488
+ elif (
489
+ s.startswith("{") is False
490
+ and out_latex_str.startswith("{")
491
+ and s.endswith("}") is False
492
+ and out_latex_str.endswith("}")
493
+ ):
494
+ out_latex_str = f" {out_latex_str[1:-1]} "
495
+
496
+ # Do NOT wrap remaining content in \text{}.
497
+ # Previously this code matched any string starting with "\text" and wrapped it
498
+ # again, producing invalid constructs like \text{ \textperiodcentered } for
499
+ # textcomp symbols. Characters that truly need text mode should be mapped in
500
+ # the T dictionary above; for all others we keep the pylatexenc output as-is.
501
+
502
+ return out_latex_str
503
+
504
+ def do_r(self, elm):
505
+ """
506
+ Get text from 'r' element,And try convert them to latex symbols
507
+ @todo text style support , (sty)
508
+ @todo \text (latex pure text support)
509
+ """
510
+ _str = []
511
+ _base_str = []
512
+ found_text = elm.findtext(f"./{OMML_NS}t")
513
+ if found_text:
514
+ for s in found_text:
515
+ out_latex_str = self.process_unicode(s)
516
+ _str.append(out_latex_str)
517
+ _base_str.append(s)
518
+
519
+ proc_str = escape_latex(BLANK.join(_str))
520
+ base_proc_str = BLANK.join(_base_str)
521
+
522
+ if "{" not in base_proc_str and "\\{" in proc_str:
523
+ proc_str = proc_str.replace("\\{", "{")
524
+
525
+ if "}" not in base_proc_str and "\\}" in proc_str:
526
+ proc_str = proc_str.replace("\\}", "}")
527
+
528
+ # Handle <m:scr> math font style (script, fraktur, double-struck, etc.)
529
+ # OMML encodes math alphabets via <m:rPr><m:scr m:val="..."/> rather than
530
+ # Unicode math-alphabet codepoints, so we must apply the LaTeX wrapper here.
531
+ rPr = elm.find(f"{OMML_NS}rPr")
532
+ if rPr is not None:
533
+ scr_elem = rPr.find(f"{OMML_NS}scr")
534
+ if scr_elem is not None:
535
+ scr_val = scr_elem.get(f"{OMML_NS}val")
536
+ latex_template = SCR_TO_LATEX.get(scr_val)
537
+ if latex_template and proc_str.strip():
538
+ proc_str = latex_template.format(proc_str.strip())
539
+
540
+ return proc_str
541
+
542
+ tag2meth = {
543
+ "acc": do_acc,
544
+ "r": do_r,
545
+ "bar": do_bar,
546
+ "sub": do_sub,
547
+ "sup": do_sup,
548
+ "f": do_f,
549
+ "func": do_func,
550
+ "fName": do_fname,
551
+ "groupChr": do_groupchr,
552
+ "d": do_d,
553
+ "rad": do_rad,
554
+ "eqArr": do_eqarr,
555
+ "limLow": do_limlow,
556
+ "limUpp": do_limupp,
557
+ "lim": do_lim,
558
+ "m": do_m,
559
+ "mr": do_mr,
560
+ "nary": do_nary,
561
+ }
@@ -0,0 +1,62 @@
1
+ """现代 Office OOXML 包中的 MathType/Equation OLE 公式解码适配器。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ import hashlib
7
+
8
+ from ..errors import LegacyOfficeResourceLimitError
9
+ from ..limits import MAX_ASSET_TOTAL_BYTES, MAX_ENTRY_BYTES
10
+ from .mtef import decode_equation_object
11
+
12
+ CFB_MAGIC = b"\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1"
13
+ EQUATION_PROG_ID = "equation"
14
+ EQUATION_PROG_ID_PREFIX = "equation."
15
+
16
+
17
+ def is_mathtype_equation_prog_id(prog_id: object | None) -> bool:
18
+ """判断 OLE ProgID 是否为 Equation 或带非空版本后缀的 Equation.*。"""
19
+
20
+ if not isinstance(prog_id, str):
21
+ return False
22
+ normalized = prog_id.strip().casefold()
23
+ return normalized == EQUATION_PROG_ID or (
24
+ normalized.startswith(EQUATION_PROG_ID_PREFIX) and len(normalized) > len(EQUATION_PROG_ID_PREFIX)
25
+ )
26
+
27
+
28
+ @dataclass(slots=True)
29
+ class OoxmlEquationDecoder:
30
+ """按共享资源上限缓存并解码 OOXML 中的公式 OLE 对象。"""
31
+
32
+ total_bytes: int = 0
33
+ _cache: dict[bytes, str | None] = field(default_factory=dict)
34
+
35
+ def decode(
36
+ self,
37
+ blob: bytes | None,
38
+ *,
39
+ prog_id: object | None,
40
+ show_as_icon: bool = False,
41
+ ) -> str | None:
42
+ """校验公式 ProgID、图标模式、CFB 头和资源预算后返回 LaTeX。"""
43
+
44
+ if show_as_icon or not is_mathtype_equation_prog_id(prog_id) or blob is None:
45
+ return None
46
+ if not isinstance(blob, bytes):
47
+ return None
48
+ if len(blob) > MAX_ENTRY_BYTES:
49
+ raise LegacyOfficeResourceLimitError(f"OOXML equation object exceeds max_entry_bytes={MAX_ENTRY_BYTES}")
50
+ if not blob.startswith(CFB_MAGIC):
51
+ return None
52
+
53
+ digest = hashlib.sha256(blob).digest()
54
+ if digest in self._cache:
55
+ return self._cache[digest]
56
+ if self.total_bytes + len(blob) > MAX_ASSET_TOTAL_BYTES:
57
+ raise LegacyOfficeResourceLimitError(f"OOXML equation objects exceed max_asset_total_bytes={MAX_ASSET_TOTAL_BYTES}")
58
+
59
+ self.total_bytes += len(blob)
60
+ latex = decode_equation_object(blob)
61
+ self._cache[digest] = latex
62
+ return latex
@@ -0,0 +1,33 @@
1
+ """Flash Office 二进制、嵌入对象与 RTF 解析共享的稳定错误类型。"""
2
+
3
+ from __future__ import annotations
4
+
5
+
6
+ class LegacyOfficeError(ValueError):
7
+ """旧版 Office 解析错误基类,并携带稳定错误码。"""
8
+
9
+ code = "legacy_office_error"
10
+
11
+
12
+ class LegacyOfficeMalformedError(LegacyOfficeError):
13
+ """输入容器或核心二进制记录无法形成有效文档。"""
14
+
15
+ code = "malformed"
16
+
17
+
18
+ class LegacyOfficeMissingPartError(LegacyOfficeError):
19
+ """缺少完成解析所必需的 OLE stream。"""
20
+
21
+ code = "missing_part"
22
+
23
+
24
+ class LegacyOfficeEncryptedError(LegacyOfficeError):
25
+ """输入使用了当前纯 Python 解析链不支持的加密。"""
26
+
27
+ code = "encrypted"
28
+
29
+
30
+ class LegacyOfficeResourceLimitError(LegacyOfficeError):
31
+ """输入超过固定安全限制。"""
32
+
33
+ code = "resource_limit"