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,213 @@
1
+ """二进制安全、位置显式的 RTF lexer。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Iterator, TypeAlias, Union
7
+
8
+ from ..errors import LegacyOfficeMalformedError, LegacyOfficeResourceLimitError
9
+ from ..limits import MAX_RECORDS
10
+
11
+ MAX_RTF_GROUP_DEPTH = 256
12
+ MAX_RTF_CONTROL_PARAMETER_DIGITS = 10
13
+ MIN_RTF_CONTROL_PARAMETER = -(2**31)
14
+ MAX_RTF_CONTROL_PARAMETER = 2**31 - 1
15
+
16
+
17
+ @dataclass(frozen=True, slots=True)
18
+ class RtfOpen:
19
+ """表示一个左花括号。"""
20
+
21
+ start: int
22
+ end: int
23
+
24
+
25
+ @dataclass(frozen=True, slots=True)
26
+ class RtfClose:
27
+ """表示一个右花括号。"""
28
+
29
+ start: int
30
+ end: int
31
+
32
+
33
+ @dataclass(frozen=True, slots=True)
34
+ class RtfControlWord:
35
+ """表示一个可带有有符号整数参数的 control word。"""
36
+
37
+ name: str
38
+ param: int | None
39
+ start: int
40
+ end: int
41
+
42
+
43
+ @dataclass(frozen=True, slots=True)
44
+ class RtfControlSymbol:
45
+ """表示反斜杠后的单字符 control symbol。"""
46
+
47
+ symbol: str
48
+ start: int
49
+ end: int
50
+
51
+
52
+ @dataclass(frozen=True, slots=True)
53
+ class RtfHexByte:
54
+ """表示一个 ``\'hh`` 十六进制字节。"""
55
+
56
+ value: int
57
+ start: int
58
+ end: int
59
+
60
+
61
+ @dataclass(frozen=True, slots=True)
62
+ class RtfTextBytes:
63
+ """表示不含 RTF 结构字符的连续原始文本字节。"""
64
+
65
+ data: bytes
66
+ start: int
67
+ end: int
68
+
69
+
70
+ @dataclass(frozen=True, slots=True)
71
+ class RtfBinary:
72
+ """表示由 ``\binN`` 声明长度的原始二进制载荷。"""
73
+
74
+ data: bytes
75
+ start: int
76
+ end: int
77
+
78
+
79
+ RtfToken: TypeAlias = Union[
80
+ RtfOpen,
81
+ RtfClose,
82
+ RtfControlWord,
83
+ RtfControlSymbol,
84
+ RtfHexByte,
85
+ RtfTextBytes,
86
+ RtfBinary,
87
+ ]
88
+
89
+
90
+ def _is_ascii_letter(value: int) -> bool:
91
+ """判断一个字节是否是 RTF control word 使用的 ASCII 字母。"""
92
+ return 65 <= value <= 90 or 97 <= value <= 122
93
+
94
+
95
+ def _is_ascii_digit(value: int) -> bool:
96
+ """判断一个字节是否是 ASCII 十进制数字。"""
97
+ return 48 <= value <= 57
98
+
99
+
100
+ class RtfLexer:
101
+ """按字节位置迭代 RTF token,并对二进制长度和资源上限负责。"""
102
+
103
+ def __init__(self, data: bytes) -> None:
104
+ """保存不可变输入,真正的扫描在迭代时执行。"""
105
+ self._data = data
106
+
107
+ def __iter__(self) -> Iterator[RtfToken]:
108
+ """按源顺序生成 token,允许 parser 自行恢复不平衡根组。"""
109
+ data = self._data
110
+ cursor = 0
111
+ depth = 0
112
+ token_count = 0
113
+ while cursor < len(data):
114
+ token: RtfToken
115
+ start = cursor
116
+ value = data[cursor]
117
+ if value == ord("{"):
118
+ cursor += 1
119
+ depth += 1
120
+ if depth > MAX_RTF_GROUP_DEPTH:
121
+ raise LegacyOfficeResourceLimitError(f"RTF group nesting exceeds max_group_depth={MAX_RTF_GROUP_DEPTH}")
122
+ token = RtfOpen(start, cursor)
123
+ elif value == ord("}"):
124
+ cursor += 1
125
+ depth = max(depth - 1, 0)
126
+ token = RtfClose(start, cursor)
127
+ elif value != ord("\\"):
128
+ cursor += 1
129
+ while cursor < len(data) and data[cursor] not in b"{}\\":
130
+ cursor += 1
131
+ token = RtfTextBytes(data[start:cursor], start, cursor)
132
+ else:
133
+ cursor += 1
134
+ if cursor >= len(data):
135
+ token = RtfControlSymbol("\\", start, cursor)
136
+ elif data[cursor] in (10, 13):
137
+ if data[cursor] == 13 and cursor + 1 < len(data) and data[cursor + 1] == 10:
138
+ cursor += 2
139
+ else:
140
+ cursor += 1
141
+ token = RtfControlSymbol("\n", start, cursor)
142
+ elif data[cursor] == ord("'"):
143
+ cursor += 1
144
+ if cursor + 2 <= len(data):
145
+ raw_hex = data[cursor : cursor + 2]
146
+ try:
147
+ hex_value = int(raw_hex.decode("ascii"), 16)
148
+ except (UnicodeDecodeError, ValueError):
149
+ token = RtfControlSymbol("'", start, cursor)
150
+ else:
151
+ cursor += 2
152
+ token = RtfHexByte(hex_value, start, cursor)
153
+ else:
154
+ token = RtfControlSymbol("'", start, cursor)
155
+ elif _is_ascii_letter(data[cursor]):
156
+ name_start = cursor
157
+ while cursor < len(data) and _is_ascii_letter(data[cursor]):
158
+ cursor += 1
159
+ name = data[name_start:cursor].decode("ascii").lower()
160
+ sign = 1
161
+ if cursor < len(data) and data[cursor] == ord("-"):
162
+ sign = -1
163
+ cursor += 1
164
+ number_start = cursor
165
+ while cursor < len(data) and _is_ascii_digit(data[cursor]):
166
+ cursor += 1
167
+ param = None
168
+ if cursor > number_start:
169
+ digit_count = cursor - number_start
170
+ if digit_count > MAX_RTF_CONTROL_PARAMETER_DIGITS:
171
+ raise LegacyOfficeResourceLimitError(
172
+ f"RTF control parameter exceeds max_digits={MAX_RTF_CONTROL_PARAMETER_DIGITS}"
173
+ )
174
+ param = sign * int(data[number_start:cursor])
175
+ if param < MIN_RTF_CONTROL_PARAMETER or param > MAX_RTF_CONTROL_PARAMETER:
176
+ raise LegacyOfficeResourceLimitError("RTF control parameter exceeds signed 32-bit range")
177
+ if cursor < len(data) and data[cursor] == ord(" "):
178
+ cursor += 1
179
+ if name == "bin":
180
+ if param is None or param < 0:
181
+ raise LegacyOfficeMalformedError("RTF bin control requires a non-negative length")
182
+ payload_end = cursor + param
183
+ if payload_end < cursor or payload_end > len(data):
184
+ raise LegacyOfficeMalformedError(
185
+ f"RTF bin payload is truncated: declared={param}, available={len(data) - cursor}"
186
+ )
187
+ token = RtfBinary(data[cursor:payload_end], start, payload_end)
188
+ cursor = payload_end
189
+ else:
190
+ token = RtfControlWord(name, param, start, cursor)
191
+ else:
192
+ symbol = chr(data[cursor])
193
+ cursor += 1
194
+ token = RtfControlSymbol(symbol, start, cursor)
195
+
196
+ token_count += 1
197
+ if token_count > MAX_RECORDS:
198
+ raise LegacyOfficeResourceLimitError(f"RTF token count exceeds max_tokens={MAX_RECORDS}")
199
+ yield token
200
+
201
+
202
+ __all__ = [
203
+ "MAX_RTF_GROUP_DEPTH",
204
+ "RtfBinary",
205
+ "RtfClose",
206
+ "RtfControlSymbol",
207
+ "RtfControlWord",
208
+ "RtfHexByte",
209
+ "RtfLexer",
210
+ "RtfOpen",
211
+ "RtfTextBytes",
212
+ "RtfToken",
213
+ ]
@@ -0,0 +1,339 @@
1
+ """把 RTF Office Math destination 规范化为 OMML 并复用现有 LaTeX 转换器。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+
7
+ from lxml import etree # type: ignore[reportAttributeAccessIssue]
8
+ from loguru import logger
9
+
10
+ from ..equation.omml import oMath2Latex
11
+ from .lexer import RtfClose, RtfControlWord, RtfHexByte, RtfLexer, RtfOpen, RtfTextBytes
12
+
13
+ _MATH_NS = "http://schemas.openxmlformats.org/officeDocument/2006/math"
14
+ _MATH_PREFIX = f"{{{_MATH_NS}}}"
15
+
16
+ # RTF Office Math control words为 OMML local name 增加一个 m 前缀;映射保留 XML 所需大小写。
17
+ _OMML_LOCAL_NAMES = (
18
+ "acc",
19
+ "accPr",
20
+ "aln",
21
+ "alnScr",
22
+ "argPr",
23
+ "argSz",
24
+ "bar",
25
+ "barPr",
26
+ "baseJc",
27
+ "begChr",
28
+ "borderBox",
29
+ "borderBoxPr",
30
+ "box",
31
+ "boxPr",
32
+ "brk",
33
+ "brkBin",
34
+ "brkBinSub",
35
+ "cGp",
36
+ "cGpRule",
37
+ "chr",
38
+ "count",
39
+ "cSp",
40
+ "ctrlPr",
41
+ "d",
42
+ "defJc",
43
+ "deg",
44
+ "degHide",
45
+ "den",
46
+ "diff",
47
+ "dispDef",
48
+ "dPr",
49
+ "e",
50
+ "endChr",
51
+ "eqArr",
52
+ "eqArrPr",
53
+ "f",
54
+ "fName",
55
+ "fPr",
56
+ "func",
57
+ "funcPr",
58
+ "groupChr",
59
+ "groupChrPr",
60
+ "grow",
61
+ "hideBot",
62
+ "hideLeft",
63
+ "hideRight",
64
+ "hideTop",
65
+ "interSp",
66
+ "intLim",
67
+ "intraSp",
68
+ "jc",
69
+ "lim",
70
+ "limLoc",
71
+ "limLow",
72
+ "limLowPr",
73
+ "limUpp",
74
+ "limUppPr",
75
+ "lit",
76
+ "lMargin",
77
+ "m",
78
+ "mathFont",
79
+ "mathPr",
80
+ "maxDist",
81
+ "mc",
82
+ "mcJc",
83
+ "mcPr",
84
+ "mcs",
85
+ "mPr",
86
+ "mr",
87
+ "nary",
88
+ "naryLim",
89
+ "naryPr",
90
+ "noBreak",
91
+ "nor",
92
+ "num",
93
+ "objDist",
94
+ "oMath",
95
+ "oMathPara",
96
+ "oMathParaPr",
97
+ "opEmu",
98
+ "phant",
99
+ "phantPr",
100
+ "plcHide",
101
+ "pos",
102
+ "postSp",
103
+ "preSp",
104
+ "r",
105
+ "rad",
106
+ "radPr",
107
+ "rMargin",
108
+ "rPr",
109
+ "rSp",
110
+ "rSpRule",
111
+ "scr",
112
+ "sepChr",
113
+ "show",
114
+ "shp",
115
+ "smallFrac",
116
+ "sPre",
117
+ "sPrePr",
118
+ "sSub",
119
+ "sSubPr",
120
+ "sSubSup",
121
+ "sSubSupPr",
122
+ "sSup",
123
+ "sSupPr",
124
+ "strikeBLTR",
125
+ "strikeH",
126
+ "strikeTLBR",
127
+ "strikeV",
128
+ "sty",
129
+ "sub",
130
+ "subHide",
131
+ "sup",
132
+ "supHide",
133
+ "t",
134
+ "transp",
135
+ "type",
136
+ "vertJc",
137
+ "wrapIndent",
138
+ "wrapRight",
139
+ "zeroAsc",
140
+ "zeroDesc",
141
+ "zeroWid",
142
+ )
143
+ _CONTROL_TO_LOCAL = {f"m{name}".lower(): name for name in _OMML_LOCAL_NAMES}
144
+ _PROPERTY_LOCAL_NAMES = {
145
+ "baseJc",
146
+ "begChr",
147
+ "chr",
148
+ "degHide",
149
+ "endChr",
150
+ "grow",
151
+ "jc",
152
+ "limLoc",
153
+ "nor",
154
+ "pos",
155
+ "scr",
156
+ "sepChr",
157
+ "show",
158
+ "sty",
159
+ "subHide",
160
+ "supHide",
161
+ "type",
162
+ }
163
+ _SCR_VALUES = {
164
+ 0: "roman",
165
+ 1: "script",
166
+ 2: "fraktur",
167
+ 3: "double-struck",
168
+ 4: "sans-serif",
169
+ 5: "monospace",
170
+ }
171
+
172
+
173
+ @dataclass(slots=True)
174
+ class _MathGroup:
175
+ """保存一个 RTF group 对应的 Office Math 局部树。"""
176
+
177
+ local: str | None = None
178
+ text: list[str] = field(default_factory=list)
179
+ controls: list[tuple[str, int | None]] = field(default_factory=list)
180
+ children: list[_MathGroup] = field(default_factory=list)
181
+
182
+
183
+ def _append_unicode(group: _MathGroup, value: int | None, surrogate: list[int | None]) -> int:
184
+ """解码有符号 UTF-16 code unit,并返回需要跳过的 fallback 字符数占位。"""
185
+ if value is None:
186
+ return 0
187
+ unit = value + 65536 if value < 0 else value
188
+ unit &= 0xFFFF
189
+ pending = surrogate[0]
190
+ if 0xD800 <= unit <= 0xDBFF:
191
+ surrogate[0] = unit
192
+ return 1
193
+ if 0xDC00 <= unit <= 0xDFFF and pending is not None:
194
+ codepoint = 0x10000 + ((pending - 0xD800) << 10) + (unit - 0xDC00)
195
+ group.text.append(chr(codepoint))
196
+ surrogate[0] = None
197
+ return 1
198
+ if pending is not None:
199
+ group.text.append("\ufffd")
200
+ surrogate[0] = None
201
+ group.text.append(chr(unit) if not 0xD800 <= unit <= 0xDFFF else "\ufffd")
202
+ return 1
203
+
204
+
205
+ def _parse_math_groups(data: bytes, encoding: str) -> _MathGroup:
206
+ """把 math destination token 流构造成与 RTF group 同构的轻量树。"""
207
+ root = _MathGroup(local="math")
208
+ stack = [root]
209
+ uc_skip = 1
210
+ fallback_skip = 0
211
+ surrogate: list[int | None] = [None]
212
+ for token in RtfLexer(data):
213
+ if isinstance(token, RtfOpen):
214
+ group = _MathGroup()
215
+ stack[-1].children.append(group)
216
+ stack.append(group)
217
+ continue
218
+ if isinstance(token, RtfClose):
219
+ if len(stack) > 1:
220
+ stack.pop()
221
+ continue
222
+ group = stack[-1]
223
+ if isinstance(token, RtfControlWord):
224
+ if token.name == "uc":
225
+ uc_skip = max(token.param or 0, 0)
226
+ continue
227
+ if token.name == "u":
228
+ _append_unicode(group, token.param, surrogate)
229
+ fallback_skip = uc_skip
230
+ continue
231
+ local = _CONTROL_TO_LOCAL.get(token.name)
232
+ if local is not None:
233
+ if group.local is None:
234
+ group.local = local
235
+ else:
236
+ group.controls.append((local, token.param))
237
+ continue
238
+ if isinstance(token, RtfHexByte):
239
+ if fallback_skip:
240
+ fallback_skip -= 1
241
+ continue
242
+ group.text.append(bytes([token.value]).decode(encoding, errors="replace"))
243
+ continue
244
+ if isinstance(token, RtfTextBytes):
245
+ raw = token.data.replace(b"\r", b"").replace(b"\n", b"")
246
+ if fallback_skip:
247
+ skipped = min(fallback_skip, len(raw))
248
+ raw = raw[skipped:]
249
+ fallback_skip -= skipped
250
+ if raw:
251
+ group.text.append(raw.decode(encoding, errors="replace"))
252
+ if surrogate[0] is not None:
253
+ stack[-1].text.append("\ufffd")
254
+ return root
255
+
256
+
257
+ def _value_text(group: _MathGroup) -> str:
258
+ """返回属性 group 的规范化直接文本。"""
259
+ return "".join(group.text).strip()
260
+
261
+
262
+ def _build_omml_element(group: _MathGroup) -> etree._Element | None:
263
+ """把一个已命名 math group 转换为规范 OMML element。"""
264
+ if group.local is None or group.local == "math":
265
+ return None
266
+ element = etree.Element(f"{_MATH_PREFIX}{group.local}", nsmap={"m": _MATH_NS})
267
+ if group.local == "r":
268
+ properties: list[tuple[str, str]] = []
269
+ for local, param in group.controls:
270
+ if local == "scr" and param is not None:
271
+ properties.append((local, _SCR_VALUES.get(param, str(param))))
272
+ elif local in {"sty", "nor"}:
273
+ properties.append((local, str(param if param is not None else 1)))
274
+ if properties:
275
+ r_pr = etree.SubElement(element, f"{_MATH_PREFIX}rPr")
276
+ for local, value in properties:
277
+ prop = etree.SubElement(r_pr, f"{_MATH_PREFIX}{local}")
278
+ prop.set(f"{_MATH_PREFIX}val", value)
279
+ text = "".join(group.text)
280
+ if text:
281
+ etree.SubElement(element, f"{_MATH_PREFIX}t").text = text
282
+ elif group.local in _PROPERTY_LOCAL_NAMES:
283
+ value = _value_text(group)
284
+ if value:
285
+ element.set(f"{_MATH_PREFIX}val", value)
286
+ elif group.controls:
287
+ element.set(f"{_MATH_PREFIX}val", str(group.controls[-1][1] or 0))
288
+ else:
289
+ element.set(f"{_MATH_PREFIX}val", "1")
290
+ elif group.text:
291
+ text = "".join(group.text)
292
+ run = etree.SubElement(element, f"{_MATH_PREFIX}r")
293
+ etree.SubElement(run, f"{_MATH_PREFIX}t").text = text
294
+
295
+ for child in group.children:
296
+ child_element = _build_omml_element(child)
297
+ if child_element is not None:
298
+ element.append(child_element)
299
+ return element
300
+
301
+
302
+ def _find_groups(group: _MathGroup, local: str) -> list[_MathGroup]:
303
+ """按深度优先顺序收集指定 OMML local name 的 group。"""
304
+ result: list[_MathGroup] = []
305
+ pending = [group]
306
+ while pending:
307
+ current = pending.pop()
308
+ if current.local == local:
309
+ result.append(current)
310
+ pending.extend(reversed(current.children))
311
+ return result
312
+
313
+
314
+ def parse_rtf_math(data: bytes, *, encoding: str = "cp1252") -> tuple[list[str], bool]:
315
+ """解析一个 ``mmath`` group,返回 LaTeX 公式列表和行间公式标记。"""
316
+ try:
317
+ root = _parse_math_groups(data, encoding)
318
+ paragraphs = _find_groups(root, "oMathPara")
319
+ equation_groups: list[_MathGroup] = []
320
+ if paragraphs:
321
+ for paragraph in paragraphs:
322
+ equation_groups.extend(_find_groups(paragraph, "oMath"))
323
+ else:
324
+ equation_groups = _find_groups(root, "oMath")
325
+ formulas: list[str] = []
326
+ for equation_group in equation_groups:
327
+ element = _build_omml_element(equation_group)
328
+ if element is None:
329
+ continue
330
+ latex = str(oMath2Latex(element)).strip()
331
+ if latex:
332
+ formulas.append(latex)
333
+ return formulas, bool(paragraphs)
334
+ except Exception as exc:
335
+ logger.warning("RTF Office Math fallback: {}", exc)
336
+ return [], False
337
+
338
+
339
+ __all__ = ["parse_rtf_math"]