numbers-parser 4.16.1__tar.gz → 4.16.3__tar.gz

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 (117) hide show
  1. {numbers_parser-4.16.1/src/numbers_parser.egg-info → numbers_parser-4.16.3}/PKG-INFO +8 -3
  2. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/README.md +4 -0
  3. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/pyproject.toml +12 -15
  4. numbers_parser-4.16.3/src/numbers_parser/data/empty.numbers +0 -0
  5. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/model.py +5 -3
  6. {numbers_parser-4.16.1 → numbers_parser-4.16.3/src/numbers_parser.egg-info}/PKG-INFO +8 -3
  7. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser.egg-info/SOURCES.txt +1 -18
  8. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser.egg-info/requires.txt +3 -2
  9. numbers_parser-4.16.1/src/build/extract_functions.py +0 -104
  10. numbers_parser-4.16.1/src/build/extract_mapping.py +0 -102
  11. numbers_parser-4.16.1/src/build/generate_fontmap.py +0 -22
  12. numbers_parser-4.16.1/src/build/generate_mapping.py +0 -70
  13. numbers_parser-4.16.1/src/build/protodump.py +0 -353
  14. numbers_parser-4.16.1/src/build/rename_proto_files.py +0 -26
  15. numbers_parser-4.16.1/src/build/replace_paths.py +0 -15
  16. numbers_parser-4.16.1/src/debug/dump_formats.py +0 -29
  17. numbers_parser-4.16.1/src/debug/dump_formula_nodes.py +0 -117
  18. numbers_parser-4.16.1/src/debug/dump_formulas.py +0 -50
  19. numbers_parser-4.16.1/src/debug/dump_metadata.py +0 -39
  20. numbers_parser-4.16.1/src/debug/dump_strokes.py +0 -75
  21. numbers_parser-4.16.1/src/debug/dump_tree.py +0 -113
  22. numbers_parser-4.16.1/src/debug/dump_uids.py +0 -31
  23. numbers_parser-4.16.1/src/debug/lldbutil.py +0 -1451
  24. numbers_parser-4.16.1/src/debug/profile_large_read.py +0 -23
  25. numbers_parser-4.16.1/src/debug/profile_large_write.py +0 -20
  26. numbers_parser-4.16.1/src/debug/sdiff-no-ids.py +0 -69
  27. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/LICENSE.rst +0 -0
  28. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/setup.cfg +0 -0
  29. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/__init__.py +0 -0
  30. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/_cat_numbers.py +0 -0
  31. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/_csv2numbers.py +0 -0
  32. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/_unpack_numbers.py +0 -0
  33. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/bullets.py +0 -0
  34. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/cell.py +0 -0
  35. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/constants.py +0 -0
  36. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/containers.py +0 -0
  37. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/currencies.py +0 -0
  38. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/document.py +0 -0
  39. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/exceptions.py +0 -0
  40. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/experimental.py +0 -0
  41. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/formula.py +0 -0
  42. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TNArchives_pb2.py +0 -0
  43. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TNArchives_sos_pb2.py +0 -0
  44. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TNCommandArchives_pb2.py +0 -0
  45. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TNCommandArchives_sos_pb2.py +0 -0
  46. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSAArchives_pb2.py +0 -0
  47. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSAArchives_sos_pb2.py +0 -0
  48. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSACommandArchives_sos_pb2.py +0 -0
  49. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSCEArchives_pb2.py +0 -0
  50. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSCH3DArchives_pb2.py +0 -0
  51. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSCHArchives_Common_pb2.py +0 -0
  52. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSCHArchives_GEN_pb2.py +0 -0
  53. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSCHArchives_pb2.py +0 -0
  54. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSCHArchives_sos_pb2.py +0 -0
  55. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSCHCommandArchives_pb2.py +0 -0
  56. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSCHPreUFFArchives_pb2.py +0 -0
  57. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSCKArchives_pb2.py +0 -0
  58. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSCKArchives_sos_pb2.py +0 -0
  59. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSDArchives_pb2.py +0 -0
  60. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSDArchives_sos_pb2.py +0 -0
  61. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSDCommandArchives_pb2.py +0 -0
  62. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSKArchives_pb2.py +0 -0
  63. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSPArchiveMessages_pb2.py +0 -0
  64. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSPDatabaseMessages_pb2.py +0 -0
  65. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSPMessages_pb2.py +0 -0
  66. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSSArchives_pb2.py +0 -0
  67. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSSArchives_sos_pb2.py +0 -0
  68. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSTArchives_pb2.py +0 -0
  69. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSTArchives_sos_pb2.py +0 -0
  70. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSTCommandArchives_pb2.py +0 -0
  71. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSTStylePropertyArchiving_pb2.py +0 -0
  72. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSWPArchives_pb2.py +0 -0
  73. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSWPArchives_sos_pb2.py +0 -0
  74. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/TSWPCommandArchives_pb2.py +0 -0
  75. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/__init__.py +0 -0
  76. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/fontmap.py +0 -0
  77. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/functionmap.py +0 -0
  78. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/generated/mapping.py +0 -0
  79. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/iwafile.py +0 -0
  80. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/iwork.py +0 -0
  81. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/numbers_cache.py +0 -0
  82. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/numbers_uuid.py +0 -0
  83. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/roman.py +0 -0
  84. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/tokenizer.py +0 -0
  85. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser/xrefs.py +0 -0
  86. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser.egg-info/dependency_links.txt +0 -0
  87. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser.egg-info/entry_points.txt +0 -0
  88. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/src/numbers_parser.egg-info/top_level.txt +0 -0
  89. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_all_formulas.py +0 -0
  90. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_api_change.py +0 -0
  91. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_borders.py +0 -0
  92. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_bullets.py +0 -0
  93. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_cat_numbers.py +0 -0
  94. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_categories.py +0 -0
  95. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_coverage.py +0 -0
  96. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_create_cells.py +0 -0
  97. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_csv2numbers.py +0 -0
  98. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_currency.py +0 -0
  99. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_folder.py +0 -0
  100. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_formatting.py +0 -0
  101. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_formulas.py +0 -0
  102. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_issues.py +0 -0
  103. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_large.py +0 -0
  104. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_memory_leaks.py +0 -0
  105. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_merges.py +0 -0
  106. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_package.py +0 -0
  107. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_properties.py +0 -0
  108. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_roman.py +0 -0
  109. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_save.py +0 -0
  110. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_slices.py +0 -0
  111. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_styles.py +0 -0
  112. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_table_size.py +0 -0
  113. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_tables.py +0 -0
  114. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_unpack_numbers.py +0 -0
  115. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_unsupported.py +0 -0
  116. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_uuids.py +0 -0
  117. {numbers_parser-4.16.1 → numbers_parser-4.16.3}/tests/test_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: numbers-parser
3
- Version: 4.16.1
3
+ Version: 4.16.3
4
4
  Summary: Read and write Apple Numbers spreadsheets
5
5
  Author-email: Jon Connell <python@figsandfudge.com>
6
6
  License-Expression: MIT
@@ -13,8 +13,9 @@ Requires-Python: <4.0,>=3.9
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE.rst
15
15
  Requires-Dist: compact-json<2.0.0,>=1.1.3
16
- Requires-Dist: protobuf<6.0,>=4.0
17
- Requires-Dist: python-snappy<1.0,>=0.7
16
+ Requires-Dist: protobuf>=6.0
17
+ Requires-Dist: python-snappy>=0.7
18
+ Requires-Dist: cramjam>=2.11.0
18
19
  Requires-Dist: sigfig<2.0.0,>=1.3.3
19
20
  Requires-Dist: setuptools>=70.0.0
20
21
  Requires-Dist: importlib-resources>=6.1
@@ -484,6 +485,10 @@ The following limitations are expected to always remain:
484
485
  (introduced in `numbers-parser` version 4.16) is supported only for documents
485
486
  created by Numbers 12.0 and later. No warnings are issued for earlier
486
487
  Numbers documents.
488
+ - Only standard macOS fonts are not supported. If a document includes a non-standard
489
+ font, numbers-parser will issue a UnsupportedWarning and default styles to
490
+ Helvetica Neue. Reading font names from the system would add additional system-specific
491
+ dependencies to the package and so this is not planned to changed.
487
492
 
488
493
  ## License
489
494
 
@@ -460,6 +460,10 @@ The following limitations are expected to always remain:
460
460
  (introduced in `numbers-parser` version 4.16) is supported only for documents
461
461
  created by Numbers 12.0 and later. No warnings are issued for earlier
462
462
  Numbers documents.
463
+ - Only standard macOS fonts are not supported. If a document includes a non-standard
464
+ font, numbers-parser will issue a UnsupportedWarning and default styles to
465
+ Helvetica Neue. Reading font names from the system would add additional system-specific
466
+ dependencies to the package and so this is not planned to changed.
463
467
 
464
468
  ## License
465
469
 
@@ -6,8 +6,9 @@ license = "MIT"
6
6
  requires-python = "<4.0,>=3.9"
7
7
  dependencies = [
8
8
  "compact-json<2.0.0,>=1.1.3",
9
- "protobuf<6.0,>=4.0",
10
- "python-snappy<1.0,>=0.7",
9
+ "protobuf>=6.0",
10
+ "python-snappy>=0.7",
11
+ "cramjam>=2.11.0",
11
12
  "sigfig<2.0.0,>=1.3.3",
12
13
  "setuptools>=70.0.0",
13
14
  "importlib-resources>=6.1",
@@ -22,7 +23,7 @@ classifiers = [
22
23
  description = "Read and write Apple Numbers spreadsheets"
23
24
  name = "numbers-parser"
24
25
  readme = "README.md"
25
- version = "4.16.1"
26
+ version = "4.16.3"
26
27
 
27
28
  [project.urls]
28
29
  repository = "https://github.com/masaccio/numbers-parser"
@@ -36,7 +37,7 @@ csv2numbers = "numbers_parser._csv2numbers:main"
36
37
  [dependency-groups]
37
38
  dev = [
38
39
  "gprof2dot<2023.0.0,>=2022.7.29",
39
- "line-profiler<5.0.0,>=4.0.3",
40
+ "line-profiler>=5.0.0",
40
41
  "mock>=5.1.0",
41
42
  "pytest>=7.2.0",
42
43
  "pytest-check>=1.0",
@@ -68,18 +69,14 @@ bootstrap = [
68
69
  requires = ["setuptools >= 61.0"]
69
70
  build-backend = "setuptools.build_meta"
70
71
 
71
- # [tool.setuptools]
72
- # exclude-package-data = { "*" = ["tests*"]}
73
- # include-package-data = false
74
- # packages.find.include = ['numbers-parser/src*']
75
- # packages.find.exclude = ['tests*']
76
- # package-dir = { "" = "src" }
77
-
78
72
  [tool.setuptools.packages.find]
79
- where = ["src"] # list of folders that contain the packages (["."] by default)
80
- include = ["numbers_parser*"] # package names should match these glob patterns (["*"] by default)
81
- exclude = ["*tests*"] # exclude packages matching these glob patterns (empty by default)
82
- namespaces = false # to disable scanning PEP 420 namespaces (true by default)
73
+ where = ["src"]
74
+ include = ["numbers_parser*"]
75
+ exclude = ["*tests*"]
76
+ namespaces = false # disable scanning PEP 420 namespaces
77
+
78
+ [tool.setuptools.package-data]
79
+ "numbers_parser" = ["data/*"]
83
80
 
84
81
  [tool.coverage.run]
85
82
  branch = true
@@ -790,9 +790,11 @@ class _NumbersModel(Cacheable):
790
790
  # Map table IDs to the base_owner_uids of the formula owners that match
791
791
  # the table model's haunted owner
792
792
  self._table_id_to_base_id = {
793
- table_id: formula_owner_to_base_owner_map[
794
- uuid_to_hex(self.objects[table_id].haunted_owner.owner_uid)
795
- ]
793
+ table_id: formula_owner_to_base_owner_map.get(
794
+ uuid_to_hex(self.objects[table_id].haunted_owner.owner_uid),
795
+ # Some older documents do not have this mapping
796
+ None,
797
+ )
796
798
  for table_id in self.table_ids()
797
799
  }
798
800
  self._table_base_id_to_formula_owner_id = {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: numbers-parser
3
- Version: 4.16.1
3
+ Version: 4.16.3
4
4
  Summary: Read and write Apple Numbers spreadsheets
5
5
  Author-email: Jon Connell <python@figsandfudge.com>
6
6
  License-Expression: MIT
@@ -13,8 +13,9 @@ Requires-Python: <4.0,>=3.9
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE.rst
15
15
  Requires-Dist: compact-json<2.0.0,>=1.1.3
16
- Requires-Dist: protobuf<6.0,>=4.0
17
- Requires-Dist: python-snappy<1.0,>=0.7
16
+ Requires-Dist: protobuf>=6.0
17
+ Requires-Dist: python-snappy>=0.7
18
+ Requires-Dist: cramjam>=2.11.0
18
19
  Requires-Dist: sigfig<2.0.0,>=1.3.3
19
20
  Requires-Dist: setuptools>=70.0.0
20
21
  Requires-Dist: importlib-resources>=6.1
@@ -484,6 +485,10 @@ The following limitations are expected to always remain:
484
485
  (introduced in `numbers-parser` version 4.16) is supported only for documents
485
486
  created by Numbers 12.0 and later. No warnings are issued for earlier
486
487
  Numbers documents.
488
+ - Only standard macOS fonts are not supported. If a document includes a non-standard
489
+ font, numbers-parser will issue a UnsupportedWarning and default styles to
490
+ Helvetica Neue. Reading font names from the system would add additional system-specific
491
+ dependencies to the package and so this is not planned to changed.
487
492
 
488
493
  ## License
489
494
 
@@ -1,24 +1,6 @@
1
1
  LICENSE.rst
2
2
  README.md
3
3
  pyproject.toml
4
- src/build/extract_functions.py
5
- src/build/extract_mapping.py
6
- src/build/generate_fontmap.py
7
- src/build/generate_mapping.py
8
- src/build/protodump.py
9
- src/build/rename_proto_files.py
10
- src/build/replace_paths.py
11
- src/debug/dump_formats.py
12
- src/debug/dump_formula_nodes.py
13
- src/debug/dump_formulas.py
14
- src/debug/dump_metadata.py
15
- src/debug/dump_strokes.py
16
- src/debug/dump_tree.py
17
- src/debug/dump_uids.py
18
- src/debug/lldbutil.py
19
- src/debug/profile_large_read.py
20
- src/debug/profile_large_write.py
21
- src/debug/sdiff-no-ids.py
22
4
  src/numbers_parser/__init__.py
23
5
  src/numbers_parser/_cat_numbers.py
24
6
  src/numbers_parser/_csv2numbers.py
@@ -46,6 +28,7 @@ src/numbers_parser.egg-info/dependency_links.txt
46
28
  src/numbers_parser.egg-info/entry_points.txt
47
29
  src/numbers_parser.egg-info/requires.txt
48
30
  src/numbers_parser.egg-info/top_level.txt
31
+ src/numbers_parser/data/empty.numbers
49
32
  src/numbers_parser/generated/TNArchives_pb2.py
50
33
  src/numbers_parser/generated/TNArchives_sos_pb2.py
51
34
  src/numbers_parser/generated/TNCommandArchives_pb2.py
@@ -1,6 +1,7 @@
1
1
  compact-json<2.0.0,>=1.1.3
2
- protobuf<6.0,>=4.0
3
- python-snappy<1.0,>=0.7
2
+ protobuf>=6.0
3
+ python-snappy>=0.7
4
+ cramjam>=2.11.0
4
5
  sigfig<2.0.0,>=1.3.3
5
6
  setuptools>=70.0.0
6
7
  importlib-resources>=6.1
@@ -1,104 +0,0 @@
1
- import re
2
- import sys
3
- from subprocess import PIPE, Popen
4
-
5
- # Code pattern in AArch64:
6
- #
7
- # mov w8, #325
8
- # strh w8, [sp, #8]
9
- # str x23, [sp]
10
- # adrp x2, 2590 ; 0x14e0000
11
- # add x2, x2, #3776 ; Objc cfstring ref: @"GETPIVOTDATA"
12
- #
13
- # TSCEFunction_GETPIVOTDATA::evaluateWithContext(...
14
-
15
- # Additional required code pattern in AArch64 for Numbers 14.2:
16
- #
17
- # mov w0, #319
18
- # bl TSCEFormulaCreationMagic::function_3arg(...
19
- # ;
20
- # ; Approx. 20 lines
21
- # ;
22
- # TSCEFormulaCreationMagic::TEXTBETWEEN(...
23
-
24
- if len(sys.argv) != 3:
25
- print(f"Usage: {sys.argv[0]} framework-file output.py", file=sys.stderr)
26
- sys.exit(1)
27
-
28
- framework = sys.argv[1]
29
- output_map = sys.argv[2]
30
-
31
- if framework.endswith(".s"):
32
- with open(framework, "rb") as fh:
33
- disassembly = fh.readlines()
34
- else:
35
- objdump = Popen( # noqa: S603
36
- [ # noqa: S607
37
- "objdump",
38
- "--disassemble",
39
- "--no-addresses",
40
- "--no-print-imm-hex",
41
- "--no-show-raw-insn",
42
- "--macho",
43
- "--objc-meta-data",
44
- framework,
45
- ],
46
- stdout=PIPE,
47
- )
48
- cxxfilt = Popen(["c++filt"], stdin=objdump.stdout, stdout=PIPE) # noqa: S603, S607
49
- objdump.stdout.close()
50
- disassembly = str(cxxfilt.communicate()[0]).split("\\n")
51
-
52
- arg = None
53
- line_count = 0
54
- tsce_functions = {}
55
- function_refs = {}
56
-
57
- previous_line = ""
58
- for line in disassembly:
59
- line = str(line).replace("\\t", " ") # noqa: PLW2901
60
- if m := re.search(r"mov *w8, #(\d+)", line):
61
- arg = m.group(1)
62
- line_count = 0
63
- continue
64
-
65
- if arg is not None:
66
- line_count += 1
67
- if line_count > 30:
68
- arg = None
69
- line_count = 0
70
-
71
- if m := re.search(r'x2, x2.*Objc cfstring ref: @"([A-Z0-9\.]+)"', line):
72
- if arg is not None and line_count <= 8:
73
- func = m.group(1).replace("_", ".")
74
- print(f"Found cstring {func} = {arg}")
75
- function_refs[func] = arg
76
- arg = None
77
- line_count = 0
78
- elif m := re.search(r"bl *TSCEFormulaCreationMagic::function_3arg\(", line):
79
- if m := re.search(r"mov *w0, #(\d+)", previous_line):
80
- arg = m.group(1)
81
- line_count = 0
82
- elif (m := re.search(r"TSCEFormulaCreationMagic::(\w+)\(", line)) and arg is not None:
83
- func = m.group(1).replace("_", ".")
84
- print(f"Found TSCEFormulaCreationMagic {func} = {arg}")
85
- function_refs[func] = arg
86
- arg = None
87
- line_count = 0
88
- elif m := re.search(r"TSCEFunction_(\w+)::evaluateWithContext", line):
89
- func = m.group(1).replace("_", ".")
90
- print(f"Found TSCEFunction {func}")
91
- tsce_functions[func] = True
92
-
93
- previous_line = line
94
-
95
- function_refs = dict(sorted(function_refs.items(), key=lambda x: int(x[1])))
96
- with open(output_map, "w") as fh:
97
- fh.write("FUNCTION_MAP = {\n")
98
- if "ABS" not in function_refs:
99
- fh.write(' 1: "ABS",\n')
100
- for func_name, func_id in function_refs.items():
101
- if func in tsce_functions:
102
- fh.write(f' {func_id}: "{func_name}",\n')
103
-
104
- fh.write("}\n")
@@ -1,102 +0,0 @@
1
- """
2
- lldb script to dump TSPersistence registry mapping from iWork apps.
3
-
4
- Licensed under the MIT license.
5
-
6
- Copyright 2020-2022 Peter Sobot
7
- Copyright 2022 Jon Connell
8
- Copyright 2022 SheetJS LLC
9
- """
10
-
11
- import json
12
- import os
13
- import sys
14
-
15
- import lldb
16
-
17
- from debug.lldbutil import print_stacktrace
18
-
19
- if len(sys.argv) != 3:
20
- msg = f"Usage: {sys.argv[0]} exe-file output.json"
21
- raise (ValueError(msg))
22
-
23
- exe = sys.argv[1]
24
- output = sys.argv[2]
25
-
26
- debugger = lldb.SBDebugger.Create()
27
- debugger.SetAsync(False)
28
- target = debugger.CreateTargetWithFileAndArch(exe, None)
29
-
30
- # # Note: original script also created breakpoints on _handleAEOpenEvent
31
- # # but that is too early in Numbers 12.1
32
- # target.BreakpointCreateByName("-[NSApplication _sendFinishLaunchingNotification]")
33
- # target.BreakpointCreateByName("-[NSApplication _crashOnException:]")
34
-
35
- # # Note: original script skipped [CKContainer containerWithIdentifier:]
36
- # target.BreakpointCreateByRegex("CloudKit")
37
-
38
- target.BreakpointCreateByName("_sendFinishLaunchingNotification")
39
- target.BreakpointCreateByName("_handleAEOpenEvent:")
40
- # To get around the fact that we don't have iCloud entitlements when running re-signed code,
41
- # let's break in the CloudKit code and early exit the function before it can raise an exception:
42
- target.BreakpointCreateByName("[CKContainer containerWithIdentifier:]")
43
- # In later Keynote versions, 'containerWithIdentifier' isn't called directly, but we can break on similar methods:
44
- # Note: this __lldb_unnamed_symbol hack was determined by painstaking experimentation. It will break again for sure.
45
- target.BreakpointCreateByRegex("___lldb_unnamed_symbol[0-9]+", "CloudKit")
46
-
47
-
48
- process = target.LaunchSimple(None, None, os.getcwd())
49
- if not process:
50
- raise ValueError("Failed to launch process: " + exe)
51
-
52
- if process.GetState() == lldb.eStateExited:
53
- msg = f"LLDB was unable to stop process! {process}"
54
- raise ValueError(msg)
55
-
56
- try:
57
- while process.GetState() == lldb.eStateStopped:
58
- thread = process.GetThreadAtIndex(0)
59
- frame = thread.GetSelectedFrame()
60
- if frame.name == "-[NSApplication _crashOnException:]":
61
- msg = f"Process crashed at {frame.name}"
62
- raise ValueError(msg)
63
-
64
- stop_reason = thread.GetStopReason()
65
-
66
- if stop_reason == lldb.eStopReasonException:
67
- print_stacktrace(thread)
68
- function = frame.GetFunction()
69
- function_or_symbol = function if function else frame.GetSymbol()
70
- msg = f"Exception at {frame.name}"
71
- raise ValueError(msg)
72
- if stop_reason != lldb.eStopReasonBreakpoint:
73
- process.Continue()
74
- continue
75
- if frame.name[-8:] == "CloudKit":
76
- thread.ReturnFromFrame(
77
- thread.GetSelectedFrame(),
78
- lldb.SBValue().CreateValueFromExpression("0", ""),
79
- )
80
- process.Continue()
81
- elif frame.name == "-[NSApplication _sendFinishLaunchingNotification]":
82
- registry = frame.EvaluateExpression("[TSPRegistry sharedRegistry]")
83
- error = registry.GetError()
84
- if error.fail or registry.description is None:
85
- continue
86
- # raise (ValueError("Failed to extract registry"))
87
- split = [
88
- x.strip().split(" -> ")
89
- for x in registry.description.split("{")[1].split("}")[0].split("\n")
90
- if x.strip()
91
- ]
92
- json_str = json.dumps(
93
- dict(sorted([(int(a), b.split(" ")[-1]) for a, b in split if "null" not in b])),
94
- indent=2,
95
- )
96
- with open(output, "w") as fh:
97
- fh.write(json_str)
98
- break
99
- else:
100
- process.Continue()
101
- finally:
102
- process.Kill()
@@ -1,22 +0,0 @@
1
- import sys
2
-
3
- import Cocoa
4
-
5
- if len(sys.argv) != 2:
6
- msg = f"Usage: {sys.argv[0]} fontmap.py"
7
- raise (ValueError(msg))
8
-
9
- mapping_py = sys.argv[1]
10
-
11
- with open(mapping_py, "w") as fh:
12
- manager = Cocoa.NSFontManager.sharedFontManager()
13
- font_families = list(manager.availableFontFamilies())
14
-
15
- print("FONT_NAME_TO_FAMILY = {", file=fh)
16
- for family in sorted(font_families):
17
- fonts = manager.availableMembersOfFontFamily_(family)
18
- for font in fonts:
19
- print(f' "{font[0]}": "{family}",', file=fh)
20
- print(' "Calibri": "Calibri",', file=fh)
21
- print(' "Cambria": "Cambria",', file=fh)
22
- print("}", file=fh)
@@ -1,70 +0,0 @@
1
- import json
2
- import os
3
- import sys
4
-
5
- if len(sys.argv) != 3:
6
- msg = f"Usage: {sys.argv[0]} mapping.json mapping.py"
7
- raise (ValueError(msg))
8
-
9
- mapping_json = sys.argv[1]
10
- mapping_py = sys.argv[2]
11
-
12
- modules = []
13
- module_import_output = ""
14
- module_files_output = ""
15
- mapping_output = ""
16
- for filename in os.listdir("src/numbers_parser/generated"):
17
- if "pb2" in filename:
18
- module = filename.replace("_pb2.py", "")
19
- modules.append(module)
20
- module_import_output += f"from numbers_parser.generated import {module}_pb2 as {module}\n"
21
- module_files_output += f" {module},\n"
22
-
23
- with open(mapping_json) as fh:
24
- mappings = json.load(fh)
25
-
26
- for index, symbol in sorted(mappings.items(), key=lambda x: int(x[0])):
27
- mapping_output += f' "{index}": "{symbol}",\n'
28
-
29
- OUTPUT_CODE = f"""{module_import_output.strip()}
30
-
31
- PROTO_FILES = [
32
- {module_files_output.strip()}
33
- ]
34
-
35
- TSPRegistryMapping = {{
36
- {mapping_output.strip()}
37
- }}
38
-
39
-
40
- def compute_maps():
41
- name_class_map = {{}}
42
-
43
- def add_nested_types(message_type):
44
- for name in dict(message_type.DESCRIPTOR.nested_types_by_name):
45
- child_type = getattr(message_type, name)
46
- name_class_map[child_type.DESCRIPTOR.full_name] = child_type
47
- add_nested_types(child_type)
48
-
49
- for file in PROTO_FILES:
50
- for message_name in dict(file.DESCRIPTOR.message_types_by_name):
51
- message_type = getattr(file, message_name)
52
- name_class_map[message_type.DESCRIPTOR.full_name] = message_type
53
- add_nested_types(message_type)
54
-
55
- id_name_map = {{}}
56
- name_id_map = {{}}
57
- for k, v in list(TSPRegistryMapping.items()):
58
- if v in name_class_map: # pragma: no branch
59
- id_name_map[int(k)] = name_class_map[v]
60
- if v not in name_id_map:
61
- name_id_map[v] = int(k)
62
-
63
- return name_class_map, id_name_map, name_id_map
64
-
65
-
66
- NAME_CLASS_MAP, ID_NAME_MAP, NAME_ID_MAP = compute_maps()
67
- """
68
-
69
- with open(mapping_py, "w") as fh:
70
- fh.write(OUTPUT_CODE)