polyfile-weave 0.5.5__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.

Potentially problematic release.


This version of polyfile-weave might be problematic. Click here for more details.

Files changed (585) hide show
  1. polyfile/__init__.py +15 -0
  2. polyfile/__main__.py +394 -0
  3. polyfile/arithmetic.py +27 -0
  4. polyfile/ast.py +114 -0
  5. polyfile/debugger.py +1039 -0
  6. polyfile/expressions.py +346 -0
  7. polyfile/fileutils.py +343 -0
  8. polyfile/html.py +135 -0
  9. polyfile/http/__init__.py +1 -0
  10. polyfile/http/defacto.py +37 -0
  11. polyfile/http/deprecated.py +51 -0
  12. polyfile/http/experimental.py +67 -0
  13. polyfile/http/http_11.py +548 -0
  14. polyfile/http/matcher.py +37 -0
  15. polyfile/http/structured_headers.py +48 -0
  16. polyfile/iterators.py +72 -0
  17. polyfile/jpeg.py +24 -0
  18. polyfile/kaitai/__init__.py +0 -0
  19. polyfile/kaitai/compiler.py +156 -0
  20. polyfile/kaitai/parser.py +312 -0
  21. polyfile/kaitai/parsers/__init__.py +0 -0
  22. polyfile/kaitai/parsers/aix_utmp.py +116 -0
  23. polyfile/kaitai/parsers/allegro_dat.py +367 -0
  24. polyfile/kaitai/parsers/andes_firmware.py +64 -0
  25. polyfile/kaitai/parsers/android_bootldr_asus.py +105 -0
  26. polyfile/kaitai/parsers/android_bootldr_huawei.py +181 -0
  27. polyfile/kaitai/parsers/android_bootldr_qcom.py +217 -0
  28. polyfile/kaitai/parsers/android_dto.py +138 -0
  29. polyfile/kaitai/parsers/android_img.py +319 -0
  30. polyfile/kaitai/parsers/android_nanoapp_header.py +83 -0
  31. polyfile/kaitai/parsers/android_opengl_shaders_cache.py +151 -0
  32. polyfile/kaitai/parsers/android_sparse.py +237 -0
  33. polyfile/kaitai/parsers/android_super.py +401 -0
  34. polyfile/kaitai/parsers/apm_partition_table.py +196 -0
  35. polyfile/kaitai/parsers/apple_single_double.py +180 -0
  36. polyfile/kaitai/parsers/asn1_der.py +235 -0
  37. polyfile/kaitai/parsers/au.py +138 -0
  38. polyfile/kaitai/parsers/avantes_roh60.py +112 -0
  39. polyfile/kaitai/parsers/avi.py +296 -0
  40. polyfile/kaitai/parsers/bcd.py +111 -0
  41. polyfile/kaitai/parsers/bitcoin_transaction.py +210 -0
  42. polyfile/kaitai/parsers/blender_blend.py +334 -0
  43. polyfile/kaitai/parsers/bmp.py +780 -0
  44. polyfile/kaitai/parsers/bson.py +411 -0
  45. polyfile/kaitai/parsers/btrfs_stream.py +318 -0
  46. polyfile/kaitai/parsers/bytes_with_io.py +27 -0
  47. polyfile/kaitai/parsers/chrome_pak.py +194 -0
  48. polyfile/kaitai/parsers/code_6502.py +456 -0
  49. polyfile/kaitai/parsers/compressed_resource.py +217 -0
  50. polyfile/kaitai/parsers/cpio_old_le.py +154 -0
  51. polyfile/kaitai/parsers/cramfs.py +344 -0
  52. polyfile/kaitai/parsers/creative_voice_file.py +342 -0
  53. polyfile/kaitai/parsers/dbf.py +274 -0
  54. polyfile/kaitai/parsers/dcmp_0.py +664 -0
  55. polyfile/kaitai/parsers/dcmp_1.py +422 -0
  56. polyfile/kaitai/parsers/dcmp_2.py +312 -0
  57. polyfile/kaitai/parsers/dcmp_variable_length_integer.py +66 -0
  58. polyfile/kaitai/parsers/dex.py +1086 -0
  59. polyfile/kaitai/parsers/dicom.py +4370 -0
  60. polyfile/kaitai/parsers/dime_message.py +201 -0
  61. polyfile/kaitai/parsers/dns_packet.py +569 -0
  62. polyfile/kaitai/parsers/doom_wad.py +654 -0
  63. polyfile/kaitai/parsers/dos_datetime.py +191 -0
  64. polyfile/kaitai/parsers/dos_mz.py +172 -0
  65. polyfile/kaitai/parsers/ds_store.py +513 -0
  66. polyfile/kaitai/parsers/dtb.py +310 -0
  67. polyfile/kaitai/parsers/dune_2_pak.py +126 -0
  68. polyfile/kaitai/parsers/edid.py +472 -0
  69. polyfile/kaitai/parsers/efivar_signature_list.py +331 -0
  70. polyfile/kaitai/parsers/elf.py +2482 -0
  71. polyfile/kaitai/parsers/ethernet_frame.py +114 -0
  72. polyfile/kaitai/parsers/exif.py +723 -0
  73. polyfile/kaitai/parsers/ext2.py +537 -0
  74. polyfile/kaitai/parsers/fallout2_dat.py +187 -0
  75. polyfile/kaitai/parsers/fallout_dat.py +156 -0
  76. polyfile/kaitai/parsers/fasttracker_xm_module.py +558 -0
  77. polyfile/kaitai/parsers/ftl_dat.py +90 -0
  78. polyfile/kaitai/parsers/genmidi_op2.py +161 -0
  79. polyfile/kaitai/parsers/gettext_mo.py +541 -0
  80. polyfile/kaitai/parsers/gif.py +492 -0
  81. polyfile/kaitai/parsers/gimp_brush.py +244 -0
  82. polyfile/kaitai/parsers/glibc_utmp.py +114 -0
  83. polyfile/kaitai/parsers/gltf_binary.py +132 -0
  84. polyfile/kaitai/parsers/google_protobuf.py +151 -0
  85. polyfile/kaitai/parsers/gpt_partition_table.py +175 -0
  86. polyfile/kaitai/parsers/gran_turismo_vol.py +140 -0
  87. polyfile/kaitai/parsers/grub2_font.py +337 -0
  88. polyfile/kaitai/parsers/gzip.py +232 -0
  89. polyfile/kaitai/parsers/hashcat_restore.py +60 -0
  90. polyfile/kaitai/parsers/hccap.py +111 -0
  91. polyfile/kaitai/parsers/hccapx.py +103 -0
  92. polyfile/kaitai/parsers/heaps_pak.py +177 -0
  93. polyfile/kaitai/parsers/heroes_of_might_and_magic_agg.py +116 -0
  94. polyfile/kaitai/parsers/heroes_of_might_and_magic_bmp.py +34 -0
  95. polyfile/kaitai/parsers/icmp_packet.py +136 -0
  96. polyfile/kaitai/parsers/ico.py +129 -0
  97. polyfile/kaitai/parsers/id3v1_1.py +220 -0
  98. polyfile/kaitai/parsers/id3v2_3.py +324 -0
  99. polyfile/kaitai/parsers/id3v2_4.py +423 -0
  100. polyfile/kaitai/parsers/ines.py +282 -0
  101. polyfile/kaitai/parsers/ipv4_packet.py +158 -0
  102. polyfile/kaitai/parsers/ipv6_packet.py +55 -0
  103. polyfile/kaitai/parsers/iso9660.py +544 -0
  104. polyfile/kaitai/parsers/java_class.py +1113 -0
  105. polyfile/kaitai/parsers/jpeg.py +361 -0
  106. polyfile/kaitai/parsers/luks.py +149 -0
  107. polyfile/kaitai/parsers/lzh.py +165 -0
  108. polyfile/kaitai/parsers/mac_os_resource_snd.py +493 -0
  109. polyfile/kaitai/parsers/mach_o.py +3033 -0
  110. polyfile/kaitai/parsers/mach_o_fat.py +92 -0
  111. polyfile/kaitai/parsers/magicavoxel_vox.py +391 -0
  112. polyfile/kaitai/parsers/manifest.json +1 -0
  113. polyfile/kaitai/parsers/mbr_partition_table.py +119 -0
  114. polyfile/kaitai/parsers/mcap.py +1015 -0
  115. polyfile/kaitai/parsers/microsoft_cfb.py +293 -0
  116. polyfile/kaitai/parsers/microsoft_network_monitor_v2.py +309 -0
  117. polyfile/kaitai/parsers/microsoft_pe.py +765 -0
  118. polyfile/kaitai/parsers/mifare_classic.py +706 -0
  119. polyfile/kaitai/parsers/minecraft_nbt.py +449 -0
  120. polyfile/kaitai/parsers/monomakh_sapr_chg.py +69 -0
  121. polyfile/kaitai/parsers/mozilla_mar.py +239 -0
  122. polyfile/kaitai/parsers/mp4.py +333 -0
  123. polyfile/kaitai/parsers/msgpack.py +467 -0
  124. polyfile/kaitai/parsers/nitf.py +1189 -0
  125. polyfile/kaitai/parsers/nt_mdt_pal.py +155 -0
  126. polyfile/kaitai/parsers/ogg.py +118 -0
  127. polyfile/kaitai/parsers/openpgp_message.py +993 -0
  128. polyfile/kaitai/parsers/packet_ppi.py +515 -0
  129. polyfile/kaitai/parsers/pcap.py +344 -0
  130. polyfile/kaitai/parsers/pcf_font.py +506 -0
  131. polyfile/kaitai/parsers/pcx.py +195 -0
  132. polyfile/kaitai/parsers/pcx_dcx.py +79 -0
  133. polyfile/kaitai/parsers/phar_without_stub.py +399 -0
  134. polyfile/kaitai/parsers/php_serialized_value.py +505 -0
  135. polyfile/kaitai/parsers/png.py +721 -0
  136. polyfile/kaitai/parsers/protocol_body.py +260 -0
  137. polyfile/kaitai/parsers/psx_tim.py +104 -0
  138. polyfile/kaitai/parsers/python_pickle.py +718 -0
  139. polyfile/kaitai/parsers/python_pyc_27.py +510 -0
  140. polyfile/kaitai/parsers/quake_mdl.py +441 -0
  141. polyfile/kaitai/parsers/quake_pak.py +112 -0
  142. polyfile/kaitai/parsers/quicktime_mov.py +634 -0
  143. polyfile/kaitai/parsers/rar.py +265 -0
  144. polyfile/kaitai/parsers/regf.py +569 -0
  145. polyfile/kaitai/parsers/renderware_binary_stream.py +877 -0
  146. polyfile/kaitai/parsers/resource_fork.py +611 -0
  147. polyfile/kaitai/parsers/respack.py +57 -0
  148. polyfile/kaitai/parsers/riff.py +409 -0
  149. polyfile/kaitai/parsers/rpm.py +964 -0
  150. polyfile/kaitai/parsers/rtcp_payload.py +579 -0
  151. polyfile/kaitai/parsers/rtp_packet.py +150 -0
  152. polyfile/kaitai/parsers/rtpdump.py +115 -0
  153. polyfile/kaitai/parsers/ruby_marshal.py +423 -0
  154. polyfile/kaitai/parsers/s3m.py +493 -0
  155. polyfile/kaitai/parsers/saints_row_2_vpp_pc.py +254 -0
  156. polyfile/kaitai/parsers/shapefile_index.py +174 -0
  157. polyfile/kaitai/parsers/shapefile_main.py +893 -0
  158. polyfile/kaitai/parsers/some_ip.py +209 -0
  159. polyfile/kaitai/parsers/some_ip_container.py +37 -0
  160. polyfile/kaitai/parsers/some_ip_sd.py +86 -0
  161. polyfile/kaitai/parsers/some_ip_sd_entries.py +160 -0
  162. polyfile/kaitai/parsers/some_ip_sd_options.py +374 -0
  163. polyfile/kaitai/parsers/specpr.py +404 -0
  164. polyfile/kaitai/parsers/sqlite3.py +472 -0
  165. polyfile/kaitai/parsers/ssh_public_key.py +252 -0
  166. polyfile/kaitai/parsers/standard_midi_file.py +390 -0
  167. polyfile/kaitai/parsers/stl.py +111 -0
  168. polyfile/kaitai/parsers/sudoers_ts.py +201 -0
  169. polyfile/kaitai/parsers/swf.py +406 -0
  170. polyfile/kaitai/parsers/systemd_journal.py +361 -0
  171. polyfile/kaitai/parsers/tcp_segment.py +57 -0
  172. polyfile/kaitai/parsers/tga.py +213 -0
  173. polyfile/kaitai/parsers/tls_client_hello.py +293 -0
  174. polyfile/kaitai/parsers/tr_dos_image.py +322 -0
  175. polyfile/kaitai/parsers/tsm.py +198 -0
  176. polyfile/kaitai/parsers/ttf.py +1847 -0
  177. polyfile/kaitai/parsers/udp_datagram.py +42 -0
  178. polyfile/kaitai/parsers/uefi_te.py +236 -0
  179. polyfile/kaitai/parsers/uimage.py +198 -0
  180. polyfile/kaitai/parsers/utf8_string.py +137 -0
  181. polyfile/kaitai/parsers/vfat.py +410 -0
  182. polyfile/kaitai/parsers/vlq_base128_be.py +104 -0
  183. polyfile/kaitai/parsers/vlq_base128_le.py +129 -0
  184. polyfile/kaitai/parsers/vmware_vmdk.py +167 -0
  185. polyfile/kaitai/parsers/vp8_ivf.py +112 -0
  186. polyfile/kaitai/parsers/warcraft_2_pud.py +423 -0
  187. polyfile/kaitai/parsers/wav.py +1014 -0
  188. polyfile/kaitai/parsers/websocket.py +167 -0
  189. polyfile/kaitai/parsers/windows_evt_log.py +304 -0
  190. polyfile/kaitai/parsers/windows_lnk_file.py +467 -0
  191. polyfile/kaitai/parsers/windows_minidump.py +575 -0
  192. polyfile/kaitai/parsers/windows_resource_file.py +243 -0
  193. polyfile/kaitai/parsers/windows_shell_items.py +190 -0
  194. polyfile/kaitai/parsers/windows_systemtime.py +52 -0
  195. polyfile/kaitai/parsers/wmf.py +502 -0
  196. polyfile/kaitai/parsers/xar.py +181 -0
  197. polyfile/kaitai/parsers/xwd.py +189 -0
  198. polyfile/kaitai/parsers/zip.py +685 -0
  199. polyfile/kaitai/parsers/zisofs.py +158 -0
  200. polyfile/kaitai/parsers/zx_spectrum_tap.py +184 -0
  201. polyfile/kaitaimatcher.py +113 -0
  202. polyfile/languagematcher.py +217 -0
  203. polyfile/logger.py +135 -0
  204. polyfile/magic.py +2983 -0
  205. polyfile/magic_defs/COPYING +29 -0
  206. polyfile/magic_defs/__init__.py +0 -0
  207. polyfile/magic_defs/acorn +102 -0
  208. polyfile/magic_defs/adi +13 -0
  209. polyfile/magic_defs/adventure +122 -0
  210. polyfile/magic_defs/aes +29 -0
  211. polyfile/magic_defs/algol68 +35 -0
  212. polyfile/magic_defs/allegro +9 -0
  213. polyfile/magic_defs/alliant +18 -0
  214. polyfile/magic_defs/alpha +32 -0
  215. polyfile/magic_defs/amanda +12 -0
  216. polyfile/magic_defs/amigaos +218 -0
  217. polyfile/magic_defs/android +259 -0
  218. polyfile/magic_defs/animation +1197 -0
  219. polyfile/magic_defs/aout +46 -0
  220. polyfile/magic_defs/apache +28 -0
  221. polyfile/magic_defs/apl +7 -0
  222. polyfile/magic_defs/apple +773 -0
  223. polyfile/magic_defs/application +7 -0
  224. polyfile/magic_defs/applix +13 -0
  225. polyfile/magic_defs/apt +52 -0
  226. polyfile/magic_defs/archive +2586 -0
  227. polyfile/magic_defs/aria +38 -0
  228. polyfile/magic_defs/arm +50 -0
  229. polyfile/magic_defs/asf +132 -0
  230. polyfile/magic_defs/assembler +18 -0
  231. polyfile/magic_defs/asterix +18 -0
  232. polyfile/magic_defs/att3b +41 -0
  233. polyfile/magic_defs/audio +1291 -0
  234. polyfile/magic_defs/avm +33 -0
  235. polyfile/magic_defs/basis +18 -0
  236. polyfile/magic_defs/beetle +7 -0
  237. polyfile/magic_defs/ber +65 -0
  238. polyfile/magic_defs/bflt +14 -0
  239. polyfile/magic_defs/bhl +10 -0
  240. polyfile/magic_defs/bioinformatics +178 -0
  241. polyfile/magic_defs/biosig +154 -0
  242. polyfile/magic_defs/blackberry +8 -0
  243. polyfile/magic_defs/blcr +25 -0
  244. polyfile/magic_defs/blender +50 -0
  245. polyfile/magic_defs/blit +24 -0
  246. polyfile/magic_defs/bm +10 -0
  247. polyfile/magic_defs/bout +11 -0
  248. polyfile/magic_defs/bsdi +33 -0
  249. polyfile/magic_defs/bsi +10 -0
  250. polyfile/magic_defs/btsnoop +13 -0
  251. polyfile/magic_defs/burp +7 -0
  252. polyfile/magic_defs/bytecode +41 -0
  253. polyfile/magic_defs/c-lang +110 -0
  254. polyfile/magic_defs/c64 +531 -0
  255. polyfile/magic_defs/cad +437 -0
  256. polyfile/magic_defs/cafebabe +107 -0
  257. polyfile/magic_defs/cbor +21 -0
  258. polyfile/magic_defs/ccf +14 -0
  259. polyfile/magic_defs/cddb +12 -0
  260. polyfile/magic_defs/chord +15 -0
  261. polyfile/magic_defs/cisco +12 -0
  262. polyfile/magic_defs/citrus +12 -0
  263. polyfile/magic_defs/clarion +27 -0
  264. polyfile/magic_defs/claris +48 -0
  265. polyfile/magic_defs/clipper +65 -0
  266. polyfile/magic_defs/clojure +30 -0
  267. polyfile/magic_defs/coff +98 -0
  268. polyfile/magic_defs/commands +201 -0
  269. polyfile/magic_defs/communications +22 -0
  270. polyfile/magic_defs/compress +461 -0
  271. polyfile/magic_defs/console +1213 -0
  272. polyfile/magic_defs/convex +69 -0
  273. polyfile/magic_defs/coverage +91 -0
  274. polyfile/magic_defs/cracklib +14 -0
  275. polyfile/magic_defs/crypto +31 -0
  276. polyfile/magic_defs/csv +8 -0
  277. polyfile/magic_defs/ctags +6 -0
  278. polyfile/magic_defs/ctf +23 -0
  279. polyfile/magic_defs/cubemap +8 -0
  280. polyfile/magic_defs/cups +56 -0
  281. polyfile/magic_defs/dact +11 -0
  282. polyfile/magic_defs/database +886 -0
  283. polyfile/magic_defs/dataone +47 -0
  284. polyfile/magic_defs/dbpf +15 -0
  285. polyfile/magic_defs/der +146 -0
  286. polyfile/magic_defs/diamond +12 -0
  287. polyfile/magic_defs/dif +33 -0
  288. polyfile/magic_defs/diff +41 -0
  289. polyfile/magic_defs/digital +59 -0
  290. polyfile/magic_defs/dolby +69 -0
  291. polyfile/magic_defs/dsf +25 -0
  292. polyfile/magic_defs/dump +96 -0
  293. polyfile/magic_defs/dwarfs +45 -0
  294. polyfile/magic_defs/dyadic +61 -0
  295. polyfile/magic_defs/ebml +8 -0
  296. polyfile/magic_defs/edid +11 -0
  297. polyfile/magic_defs/editors +43 -0
  298. polyfile/magic_defs/efi +15 -0
  299. polyfile/magic_defs/elf +379 -0
  300. polyfile/magic_defs/encore +22 -0
  301. polyfile/magic_defs/epoc +62 -0
  302. polyfile/magic_defs/erlang +21 -0
  303. polyfile/magic_defs/espressif +57 -0
  304. polyfile/magic_defs/esri +28 -0
  305. polyfile/magic_defs/etf +33 -0
  306. polyfile/magic_defs/fcs +9 -0
  307. polyfile/magic_defs/filesystems +2694 -0
  308. polyfile/magic_defs/finger +16 -0
  309. polyfile/magic_defs/firmware +133 -0
  310. polyfile/magic_defs/flash +62 -0
  311. polyfile/magic_defs/flif +36 -0
  312. polyfile/magic_defs/fonts +449 -0
  313. polyfile/magic_defs/forth +82 -0
  314. polyfile/magic_defs/fortran +9 -0
  315. polyfile/magic_defs/frame +62 -0
  316. polyfile/magic_defs/freebsd +164 -0
  317. polyfile/magic_defs/fsav +128 -0
  318. polyfile/magic_defs/fusecompress +12 -0
  319. polyfile/magic_defs/games +696 -0
  320. polyfile/magic_defs/gcc +17 -0
  321. polyfile/magic_defs/gconv +10 -0
  322. polyfile/magic_defs/gentoo +85 -0
  323. polyfile/magic_defs/geo +166 -0
  324. polyfile/magic_defs/geos +20 -0
  325. polyfile/magic_defs/gimp +77 -0
  326. polyfile/magic_defs/git +13 -0
  327. polyfile/magic_defs/glibc +21 -0
  328. polyfile/magic_defs/gnome +59 -0
  329. polyfile/magic_defs/gnu +173 -0
  330. polyfile/magic_defs/gnumeric +8 -0
  331. polyfile/magic_defs/gpt +240 -0
  332. polyfile/magic_defs/gpu +28 -0
  333. polyfile/magic_defs/grace +21 -0
  334. polyfile/magic_defs/graphviz +12 -0
  335. polyfile/magic_defs/gringotts +48 -0
  336. polyfile/magic_defs/guile +13 -0
  337. polyfile/magic_defs/hardware +12 -0
  338. polyfile/magic_defs/hitachi-sh +30 -0
  339. polyfile/magic_defs/hp +433 -0
  340. polyfile/magic_defs/human68k +26 -0
  341. polyfile/magic_defs/ibm370 +52 -0
  342. polyfile/magic_defs/ibm6000 +35 -0
  343. polyfile/magic_defs/icc +214 -0
  344. polyfile/magic_defs/iff +80 -0
  345. polyfile/magic_defs/images +4210 -0
  346. polyfile/magic_defs/inform +9 -0
  347. polyfile/magic_defs/intel +310 -0
  348. polyfile/magic_defs/interleaf +9 -0
  349. polyfile/magic_defs/island +10 -0
  350. polyfile/magic_defs/ispell +63 -0
  351. polyfile/magic_defs/isz +15 -0
  352. polyfile/magic_defs/java +52 -0
  353. polyfile/magic_defs/javascript +171 -0
  354. polyfile/magic_defs/jpeg +252 -0
  355. polyfile/magic_defs/json +8 -0
  356. polyfile/magic_defs/karma +9 -0
  357. polyfile/magic_defs/kde +11 -0
  358. polyfile/magic_defs/keepass +20 -0
  359. polyfile/magic_defs/kerberos +45 -0
  360. polyfile/magic_defs/kicad +85 -0
  361. polyfile/magic_defs/kml +34 -0
  362. polyfile/magic_defs/lammps +64 -0
  363. polyfile/magic_defs/lecter +6 -0
  364. polyfile/magic_defs/lex +12 -0
  365. polyfile/magic_defs/lif +50 -0
  366. polyfile/magic_defs/linux +557 -0
  367. polyfile/magic_defs/lisp +78 -0
  368. polyfile/magic_defs/llvm +22 -0
  369. polyfile/magic_defs/locoscript +12 -0
  370. polyfile/magic_defs/lua +31 -0
  371. polyfile/magic_defs/luks +126 -0
  372. polyfile/magic_defs/m4 +11 -0
  373. polyfile/magic_defs/mach +303 -0
  374. polyfile/magic_defs/macintosh +505 -0
  375. polyfile/magic_defs/macos +7 -0
  376. polyfile/magic_defs/magic +10 -0
  377. polyfile/magic_defs/magic.mgc +0 -0
  378. polyfile/magic_defs/mail.news +132 -0
  379. polyfile/magic_defs/make +21 -0
  380. polyfile/magic_defs/map +413 -0
  381. polyfile/magic_defs/maple +109 -0
  382. polyfile/magic_defs/marc21 +30 -0
  383. polyfile/magic_defs/mathcad +8 -0
  384. polyfile/magic_defs/mathematica +188 -0
  385. polyfile/magic_defs/matroska +17 -0
  386. polyfile/magic_defs/mcrypt +52 -0
  387. polyfile/magic_defs/measure +44 -0
  388. polyfile/magic_defs/mercurial +13 -0
  389. polyfile/magic_defs/metastore +8 -0
  390. polyfile/magic_defs/meteorological +53 -0
  391. polyfile/magic_defs/microfocus +21 -0
  392. polyfile/magic_defs/mime +9 -0
  393. polyfile/magic_defs/mips +120 -0
  394. polyfile/magic_defs/mirage +8 -0
  395. polyfile/magic_defs/misctools +140 -0
  396. polyfile/magic_defs/mkid +11 -0
  397. polyfile/magic_defs/mlssa +8 -0
  398. polyfile/magic_defs/mmdf +6 -0
  399. polyfile/magic_defs/modem +92 -0
  400. polyfile/magic_defs/modulefile +9 -0
  401. polyfile/magic_defs/motorola +71 -0
  402. polyfile/magic_defs/mozilla +37 -0
  403. polyfile/magic_defs/msdos +2304 -0
  404. polyfile/magic_defs/msooxml +68 -0
  405. polyfile/magic_defs/msvc +222 -0
  406. polyfile/magic_defs/msx +309 -0
  407. polyfile/magic_defs/mup +24 -0
  408. polyfile/magic_defs/music +17 -0
  409. polyfile/magic_defs/nasa +7 -0
  410. polyfile/magic_defs/natinst +24 -0
  411. polyfile/magic_defs/ncr +49 -0
  412. polyfile/magic_defs/neko +12 -0
  413. polyfile/magic_defs/netbsd +251 -0
  414. polyfile/magic_defs/netscape +26 -0
  415. polyfile/magic_defs/netware +11 -0
  416. polyfile/magic_defs/news +13 -0
  417. polyfile/magic_defs/nifty +202 -0
  418. polyfile/magic_defs/nim-lang +29 -0
  419. polyfile/magic_defs/nitpicker +14 -0
  420. polyfile/magic_defs/numpy +9 -0
  421. polyfile/magic_defs/oasis +12 -0
  422. polyfile/magic_defs/ocaml +14 -0
  423. polyfile/magic_defs/octave +6 -0
  424. polyfile/magic_defs/ole2compounddocs +760 -0
  425. polyfile/magic_defs/olf +98 -0
  426. polyfile/magic_defs/openfst +17 -0
  427. polyfile/magic_defs/opentimestamps +16 -0
  428. polyfile/magic_defs/oric +16 -0
  429. polyfile/magic_defs/os2 +186 -0
  430. polyfile/magic_defs/os400 +39 -0
  431. polyfile/magic_defs/os9 +80 -0
  432. polyfile/magic_defs/osf1 +10 -0
  433. polyfile/magic_defs/palm +156 -0
  434. polyfile/magic_defs/parix +13 -0
  435. polyfile/magic_defs/parrot +22 -0
  436. polyfile/magic_defs/pascal +39 -0
  437. polyfile/magic_defs/pbf +11 -0
  438. polyfile/magic_defs/pbm +8 -0
  439. polyfile/magic_defs/pc88 +24 -0
  440. polyfile/magic_defs/pc98 +77 -0
  441. polyfile/magic_defs/pci_ids +116 -0
  442. polyfile/magic_defs/pcjr +8 -0
  443. polyfile/magic_defs/pdf +51 -0
  444. polyfile/magic_defs/pdp +42 -0
  445. polyfile/magic_defs/perl +100 -0
  446. polyfile/magic_defs/pgf +52 -0
  447. polyfile/magic_defs/pgp +581 -0
  448. polyfile/magic_defs/pgp-binary-keys +388 -0
  449. polyfile/magic_defs/pkgadd +7 -0
  450. polyfile/magic_defs/plan9 +25 -0
  451. polyfile/magic_defs/playdate +57 -0
  452. polyfile/magic_defs/plus5 +18 -0
  453. polyfile/magic_defs/pmem +46 -0
  454. polyfile/magic_defs/polyfile_zip +5 -0
  455. polyfile/magic_defs/polyml +23 -0
  456. polyfile/magic_defs/printer +269 -0
  457. polyfile/magic_defs/project +10 -0
  458. polyfile/magic_defs/psdbms +14 -0
  459. polyfile/magic_defs/psl +14 -0
  460. polyfile/magic_defs/pulsar +13 -0
  461. polyfile/magic_defs/puzzle +17 -0
  462. polyfile/magic_defs/pwsafe +14 -0
  463. polyfile/magic_defs/pyramid +12 -0
  464. polyfile/magic_defs/python +305 -0
  465. polyfile/magic_defs/qt +30 -0
  466. polyfile/magic_defs/revision +66 -0
  467. polyfile/magic_defs/riff +840 -0
  468. polyfile/magic_defs/rinex +44 -0
  469. polyfile/magic_defs/ringdove +45 -0
  470. polyfile/magic_defs/rpi +52 -0
  471. polyfile/magic_defs/rpm +45 -0
  472. polyfile/magic_defs/rpmsg +7 -0
  473. polyfile/magic_defs/rst +11 -0
  474. polyfile/magic_defs/rtf +94 -0
  475. polyfile/magic_defs/ruby +55 -0
  476. polyfile/magic_defs/rust +21 -0
  477. polyfile/magic_defs/sc +7 -0
  478. polyfile/magic_defs/sccs +24 -0
  479. polyfile/magic_defs/scientific +144 -0
  480. polyfile/magic_defs/securitycerts +6 -0
  481. polyfile/magic_defs/selinux +24 -0
  482. polyfile/magic_defs/sendmail +37 -0
  483. polyfile/magic_defs/sequent +42 -0
  484. polyfile/magic_defs/sereal +35 -0
  485. polyfile/magic_defs/sgi +144 -0
  486. polyfile/magic_defs/sgml +161 -0
  487. polyfile/magic_defs/sharc +23 -0
  488. polyfile/magic_defs/sinclair +40 -0
  489. polyfile/magic_defs/sisu +18 -0
  490. polyfile/magic_defs/sketch +6 -0
  491. polyfile/magic_defs/smalltalk +25 -0
  492. polyfile/magic_defs/smile +34 -0
  493. polyfile/magic_defs/sniffer +482 -0
  494. polyfile/magic_defs/softquad +40 -0
  495. polyfile/magic_defs/sosi +40 -0
  496. polyfile/magic_defs/spec +21 -0
  497. polyfile/magic_defs/spectrum +184 -0
  498. polyfile/magic_defs/sql +288 -0
  499. polyfile/magic_defs/ssh +39 -0
  500. polyfile/magic_defs/ssl +20 -0
  501. polyfile/magic_defs/statistics +45 -0
  502. polyfile/magic_defs/subtitle +38 -0
  503. polyfile/magic_defs/sun +141 -0
  504. polyfile/magic_defs/svf +5 -0
  505. polyfile/magic_defs/sylk +36 -0
  506. polyfile/magic_defs/symbos +42 -0
  507. polyfile/magic_defs/sysex +429 -0
  508. polyfile/magic_defs/tcl +29 -0
  509. polyfile/magic_defs/teapot +6 -0
  510. polyfile/magic_defs/terminfo +63 -0
  511. polyfile/magic_defs/tex +141 -0
  512. polyfile/magic_defs/tgif +7 -0
  513. polyfile/magic_defs/ti-8x +239 -0
  514. polyfile/magic_defs/timezone +42 -0
  515. polyfile/magic_defs/tplink +95 -0
  516. polyfile/magic_defs/troff +38 -0
  517. polyfile/magic_defs/tuxedo +8 -0
  518. polyfile/magic_defs/typeset +8 -0
  519. polyfile/magic_defs/uf2 +72 -0
  520. polyfile/magic_defs/unicode +15 -0
  521. polyfile/magic_defs/unisig +12 -0
  522. polyfile/magic_defs/unknown +34 -0
  523. polyfile/magic_defs/usd +21 -0
  524. polyfile/magic_defs/uterus +16 -0
  525. polyfile/magic_defs/uuencode +28 -0
  526. polyfile/magic_defs/vacuum-cleaner +54 -0
  527. polyfile/magic_defs/varied.out +46 -0
  528. polyfile/magic_defs/varied.script +21 -0
  529. polyfile/magic_defs/vax +32 -0
  530. polyfile/magic_defs/vicar +17 -0
  531. polyfile/magic_defs/virtual +307 -0
  532. polyfile/magic_defs/virtutech +12 -0
  533. polyfile/magic_defs/visx +32 -0
  534. polyfile/magic_defs/vms +30 -0
  535. polyfile/magic_defs/vmware +6 -0
  536. polyfile/magic_defs/vorbis +155 -0
  537. polyfile/magic_defs/vxl +14 -0
  538. polyfile/magic_defs/warc +16 -0
  539. polyfile/magic_defs/weak +16 -0
  540. polyfile/magic_defs/web +18 -0
  541. polyfile/magic_defs/webassembly +17 -0
  542. polyfile/magic_defs/windows +1811 -0
  543. polyfile/magic_defs/wireless +7 -0
  544. polyfile/magic_defs/wordprocessors +630 -0
  545. polyfile/magic_defs/wsdl +23 -0
  546. polyfile/magic_defs/x68000 +25 -0
  547. polyfile/magic_defs/xdelta +13 -0
  548. polyfile/magic_defs/xenix +106 -0
  549. polyfile/magic_defs/xilinx +58 -0
  550. polyfile/magic_defs/xo65 +37 -0
  551. polyfile/magic_defs/xwindows +43 -0
  552. polyfile/magic_defs/yara +17 -0
  553. polyfile/magic_defs/zfs +96 -0
  554. polyfile/magic_defs/zilog +12 -0
  555. polyfile/magic_defs/zip +126 -0
  556. polyfile/magic_defs/zyxel +17 -0
  557. polyfile/nes.py +144 -0
  558. polyfile/nitf.py +15 -0
  559. polyfile/pdf.py +1264 -0
  560. polyfile/pickles.py +45 -0
  561. polyfile/polyfile.py +409 -0
  562. polyfile/profiling.py +115 -0
  563. polyfile/repl.py +624 -0
  564. polyfile/search.py +310 -0
  565. polyfile/serialization.py +323 -0
  566. polyfile/structmatcher.py +46 -0
  567. polyfile/structs.py +281 -0
  568. polyfile/templates/download.js +162 -0
  569. polyfile/templates/hexdump.css +268 -0
  570. polyfile/templates/hexdump.js +756 -0
  571. polyfile/templates/jquery-3.4.1.min.js +2 -0
  572. polyfile/templates/template.html +119 -0
  573. polyfile/wildcards.py +62 -0
  574. polyfile/zipmatcher.py +183 -0
  575. polyfile_weave-0.5.5.dist-info/METADATA +173 -0
  576. polyfile_weave-0.5.5.dist-info/RECORD +585 -0
  577. polyfile_weave-0.5.5.dist-info/WHEEL +5 -0
  578. polyfile_weave-0.5.5.dist-info/entry_points.txt +2 -0
  579. polyfile_weave-0.5.5.dist-info/licenses/LICENSE +202 -0
  580. polyfile_weave-0.5.5.dist-info/top_level.txt +2 -0
  581. polymerge/__init__.py +1 -0
  582. polymerge/__main__.py +296 -0
  583. polymerge/cfg.py +127 -0
  584. polymerge/polymerge.py +227 -0
  585. polymerge/polytracker.py +190 -0
polyfile/pickles.py ADDED
@@ -0,0 +1,45 @@
1
+ from typing import Optional
2
+
3
+ from fickling.analysis import Analyzer, Severity
4
+ from fickling.fickle import Pickled, PickleDecodeError
5
+
6
+ from .magic import AbsoluteOffset, DynamicMagicTest, FailedTest, MagicMatcher, MatchedTest, TestResult, TestType
7
+
8
+
9
+ class PickleMatcher(DynamicMagicTest):
10
+ def __init__(self):
11
+ super().__init__(
12
+ offset=AbsoluteOffset(0),
13
+ mime="application/x-python-pickle",
14
+ extensions=("pickle", "pkl"),
15
+ default_message="Python Pickle Serialization"
16
+ )
17
+
18
+ def subtest_type(self) -> TestType:
19
+ return TestType.BINARY
20
+
21
+ def test(self, data: bytes, absolute_offset: int, parent_match: Optional[TestResult]) -> TestResult:
22
+ prev = -1
23
+ for i, c in enumerate(data):
24
+ if i >= 128:
25
+ break
26
+ elif prev == 0x80 and c in (2, 3, 4):
27
+ try:
28
+ pickled = Pickled.load(data)
29
+ results = Analyzer.default_instance.analyze(pickled)
30
+ if results.severity <= Severity.LIKELY_SAFE:
31
+ message = self.message
32
+ else:
33
+ buffer_data = results.to_string(verbosity=Severity.LIKELY_UNSAFE)
34
+ if buffer_data:
35
+ buffer_data = f"\n{buffer_data}".replace("%", "%%")
36
+ message = f"Likely Unsafe {self.default_message}{buffer_data}"
37
+ return MatchedTest(self.bind(message), value=str(message), offset=0, length=len(data))
38
+ except PickleDecodeError as e:
39
+ return FailedTest(self, offset=0, message=f"data was not decodable as a pickle file: {e!s}")
40
+ prev = c
41
+ return FailedTest(self, offset=0, message="data did not start with b\"\x80[\x02\x03\x04]\"")
42
+
43
+
44
+ DEFAULT_PICKLE_MATCHER = PickleMatcher()
45
+ MagicMatcher.DEFAULT_INSTANCE.add(DEFAULT_PICKLE_MATCHER)
polyfile/polyfile.py ADDED
@@ -0,0 +1,409 @@
1
+ from abc import ABC, abstractmethod
2
+ from collections import defaultdict
3
+ import base64
4
+ import hashlib
5
+ from json import dumps
6
+ from mimetypes import guess_extension
7
+ from pathlib import Path
8
+ import sys
9
+ from time import localtime
10
+ import traceback
11
+ from typing import Any, Callable, Dict, IO, Iterable, Iterator, List, Optional, Set, Tuple, Union
12
+
13
+ from .fileutils import FileStream
14
+ from . import logger
15
+ from .magic import MagicMatcher, Match as MagicMatch, MatchContext, TestResult
16
+
17
+ if sys.version_info >= (3, 10):
18
+ from importlib.metadata import version
19
+ __version__: str = version("polyfile")
20
+ del version
21
+ else:
22
+ import pkg_resources
23
+ __version__ = pkg_resources.require("polyfile")[0].version
24
+ del pkg_resources
25
+ mod_year = localtime(Path(__file__).stat().st_mtime).tm_year
26
+ __copyright__: str = f"Copyright ©{mod_year} Trail of Bits"
27
+ __license__: str = "Apache License Version 2.0 https://www.apache.org/licenses/"
28
+
29
+ ParserFunction = Callable[[FileStream, "Match"], Iterator["Submatch"]]
30
+
31
+
32
+ class Parser(ABC, ParserFunction):
33
+ @abstractmethod
34
+ def parse(self, stream: FileStream, match: "Match") -> Iterator["Submatch"]:
35
+ raise NotImplementedError()
36
+
37
+ def __call__(self, stream: FileStream, match: "Match") -> Iterator["Submatch"]:
38
+ yield from self.parse(stream, match)
39
+
40
+ def __hash__(self):
41
+ return id(self)
42
+
43
+ def __str__(self):
44
+ return self.__class__.__name__
45
+
46
+
47
+ class ParserFunctionWrapper(Parser):
48
+ def __init__(self, parser: ParserFunction):
49
+ self.parser: ParserFunction = parser
50
+
51
+ def __hash__(self):
52
+ return hash(self.parser)
53
+
54
+ def parse(self, stream: FileStream, match: "Match") -> Iterator["Submatch"]:
55
+ yield from self.parser(stream, match)
56
+
57
+ def __str__(self):
58
+ if hasattr(self.parser, "__qualname__"):
59
+ return self.parser.__qualname__
60
+ elif hasattr(self.parser, "__name__"):
61
+ return self.parser.__name__
62
+ else:
63
+ return self.parser.__class__.__name__
64
+
65
+
66
+ PARSERS: Dict[str, Set[Parser]] = defaultdict(set)
67
+
68
+ log = logger.getStatusLogger("polyfile")
69
+
70
+
71
+ class InvalidMatch(ValueError):
72
+ pass
73
+
74
+
75
+ class Match:
76
+ def __init__(
77
+ self,
78
+ name: str,
79
+ match_obj: Any,
80
+ relative_offset: int = 0,
81
+ length: Optional[int] = None,
82
+ parent: Optional["Match"] = None,
83
+ matcher: Optional["Matcher"] = None,
84
+ display_name: Optional[str] = None,
85
+ img_data: Optional[str] = None,
86
+ decoded: Optional[bytes] = None,
87
+ extension: Optional[str] = None
88
+ ):
89
+ self._children: List[Match] = []
90
+ self.name: str = name
91
+ self.matcher: Optional[Matcher] = None
92
+ self.match = match_obj
93
+ self.img_data: Optional[str] = img_data
94
+ self.decoded: Optional[bytes] = decoded
95
+ self._offset: int = relative_offset
96
+ self._length: Optional[int] = length
97
+ self._parent: Optional[Match] = parent
98
+ if parent is not None:
99
+ if not isinstance(parent, Match):
100
+ raise ValueError("The parent must be an instance of a Match")
101
+ parent._children.append(self)
102
+ if matcher is None:
103
+ matcher = parent.matcher
104
+ if matcher is None:
105
+ raise(ValueError("A Match must be initialized with `parent` and/or `matcher` not being None"))
106
+ self.matcher = matcher
107
+ if display_name is None:
108
+ self.display_name: str = name
109
+ else:
110
+ self.display_name = display_name
111
+ self.extension: Optional[str] = extension
112
+ if extension is None:
113
+ self.extension = guess_extension(self.name)
114
+ if self.extension is not None and self.extension.startswith("."):
115
+ # guess_extension adds a leading dot
116
+ self.extension = self.extension[1:]
117
+
118
+ @property
119
+ def children(self) -> Tuple["Match", ...]:
120
+ return tuple(self._children)
121
+
122
+ def __len__(self):
123
+ return len(self._children)
124
+
125
+ def __iter__(self) -> Iterator["Match"]:
126
+ return iter(self._children)
127
+
128
+ def __getitem__(self, index: int) -> "Match":
129
+ return self._children[index]
130
+
131
+ @property
132
+ def parent(self) -> Optional["Match"]:
133
+ return self._parent
134
+
135
+ @property
136
+ def offset(self) -> int:
137
+ """The global offset of this match with respect to the original file"""
138
+ if self.parent is not None:
139
+ return self.parent.offset + self.relative_offset
140
+ else:
141
+ return self.relative_offset
142
+
143
+ @property
144
+ def root(self) -> "Match":
145
+ if self.parent is None:
146
+ return self
147
+ else:
148
+ return self.parent.root
149
+
150
+ @property
151
+ def root_offset(self) -> int:
152
+ return self.offset - self.root.offset
153
+
154
+ @property
155
+ def relative_offset(self) -> int:
156
+ """The offset of this match relative to its parent"""
157
+ return self._offset
158
+
159
+ @property
160
+ def length(self) -> int:
161
+ """The number of bytes in the match"""
162
+ if self._length is None:
163
+ if self._children:
164
+ return max(c.offset + c.length for c in self._children) - self.offset
165
+ else:
166
+ return 0
167
+ return self._length
168
+
169
+ def to_obj(self):
170
+ ret = {
171
+ 'relative_offset': self.relative_offset,
172
+ 'offset': self.offset,
173
+ 'size': self.length,
174
+ 'type': self.name,
175
+ 'name': self.display_name,
176
+ 'value': str(self.match),
177
+ 'subEls': [c.to_obj() for c in self]
178
+ }
179
+ if self.img_data is not None:
180
+ ret['img_data'] = self.img_data
181
+ if self.decoded is not None:
182
+ ret['decoded'] = base64.b64encode(self.decoded).decode('utf-8')
183
+ if self.extension is not None:
184
+ ret['extension'] = self.extension
185
+ return ret
186
+
187
+ def json(self) -> str:
188
+ return dumps(self.to_obj())
189
+
190
+ def __repr__(self):
191
+ return f"{self.__class__.__name__}(match={self.match!r}, relative_offset={self._offset}, parent={self._parent!r})"
192
+
193
+ def __str__(self):
194
+ return f"Match<{self.match}>@{self._offset}"
195
+
196
+
197
+ class Submatch(Match):
198
+ pass
199
+
200
+
201
+ def register_parser(*filetypes: str) -> Callable[[Union[Parser, ParserFunction]], Parser]:
202
+ def wrapper(parser: Union[Parser, ParserFunction]) -> Parser:
203
+ if not isinstance(parser, Parser):
204
+ parser = ParserFunctionWrapper(parser)
205
+ for ft in filetypes:
206
+ PARSERS[ft].add(parser)
207
+ return parser
208
+ return wrapper
209
+
210
+
211
+ class Matcher:
212
+ def __init__(self, try_all_offsets: bool = False, parse: bool = True, matcher: Optional[MagicMatcher] = None):
213
+ if matcher is None:
214
+ self.magic_matcher: MagicMatcher = MagicMatcher.DEFAULT_INSTANCE
215
+ else:
216
+ self.magic_matcher = matcher
217
+ self.try_all_offsets: bool = try_all_offsets
218
+ self.parse: bool = parse
219
+
220
+ def handle_mimetype(
221
+ self, mimetype: str,
222
+ match_obj: TestResult,
223
+ data: bytes,
224
+ file_stream: Union[str, Path, IO, FileStream],
225
+ parent: Optional[Match] = None,
226
+ offset: int = 0,
227
+ length: Optional[int] = None
228
+ ) -> Iterator[Match]:
229
+ if length is None:
230
+ length = len(data) - offset
231
+ extension: Optional[str] = None
232
+ try:
233
+ extension = next(iter(match_obj.test.all_extensions()))
234
+ except StopIteration:
235
+ pass
236
+ m = Match(
237
+ mimetype,
238
+ match_obj,
239
+ offset,
240
+ length=length,
241
+ parent=parent,
242
+ matcher=self,
243
+ extension=extension
244
+ )
245
+ yield m
246
+ if self.parse:
247
+ for parser in PARSERS[mimetype]:
248
+ # Don't yield this custom match until we've tried its submatch function
249
+ # (which may throw an InvalidMatch, meaning that this match is invalid)
250
+ try:
251
+ with FileStream(file_stream, start=offset, length=length) as fs:
252
+ submatch_iter = parser(fs, m)
253
+ try:
254
+ first_submatch = next(submatch_iter)
255
+ has_first = True
256
+ except StopIteration:
257
+ has_first = False
258
+ if has_first:
259
+ yield first_submatch
260
+ yield from submatch_iter
261
+ except InvalidMatch:
262
+ pass
263
+ except Exception as e:
264
+ log.warning(f"Parser {parser!s} for MIME type {mimetype} raised an exception while "
265
+ f"parsing {match_obj!s} in {file_stream!s}: {e!s}")
266
+ if log.isEnabledFor(logger.logging.DEBUG):
267
+ traceback.print_exc()
268
+
269
+ def identify(
270
+ self, file_stream: Union[str, Path, IO, FileStream]
271
+ ) -> Iterator[MagicMatch]:
272
+ with FileStream(file_stream) as f:
273
+ context = MatchContext.load(f, only_match_mime=False)
274
+ yield from self.magic_matcher.match(context)
275
+
276
+ def match(self, file_stream: Union[str, Path, IO, FileStream], parent: Optional[Match] = None) -> Iterator[Match]:
277
+ with FileStream(file_stream) as f:
278
+ matched_mimetypes: Set[str] = set()
279
+ context = MatchContext.load(f, only_match_mime=True)
280
+ for magic_match in self.magic_matcher.match(context):
281
+ for result in magic_match:
282
+ if result.test.mime is None:
283
+ continue
284
+ mimetype = result.test.mime.resolve(context)
285
+ if mimetype in matched_mimetypes:
286
+ continue
287
+ matched_mimetypes.add(mimetype)
288
+ yield from self.handle_mimetype(mimetype, result, context.data, file_stream, parent)
289
+
290
+
291
+ class Analyzer:
292
+ def __init__(self, path: Union[str, Path], try_all_offsets: bool = False, parse: bool = True,
293
+ magic_matcher: Optional[MagicMatcher] = None):
294
+ self.path: Union[str, Path] = path
295
+ self.try_all_offsets: bool = try_all_offsets
296
+ self.parse: bool = parse
297
+ self._magic_matcher: Optional[MagicMatcher] = magic_matcher
298
+ self._matcher: Optional[Matcher] = None
299
+ self._matches: Optional[List[Match]] = None
300
+ self._match_iterator: Optional[Iterator[Match]] = None
301
+ self._magic_matches: Optional[List[MagicMatch]] = None
302
+ self._magic_match_iterator: Optional[Iterator[MagicMatch]] = None
303
+
304
+ @property
305
+ def magic_matcher(self) -> MagicMatcher:
306
+ if self._magic_matcher is None:
307
+ return MagicMatcher.DEFAULT_INSTANCE
308
+ else:
309
+ return self._magic_matcher
310
+
311
+ def mime_types(self) -> Iterator[Tuple[str, MagicMatch]]:
312
+ mimetypes: Dict[str, Set[str]] = {}
313
+ with open(self.path, "rb") as f:
314
+ for match in self.magic_matcher.match(MatchContext.load(f, only_match_mime=True)):
315
+ for mimetype in match.mimetypes:
316
+ match_text = str(match)
317
+ if mimetype not in mimetypes:
318
+ mimetypes[mimetype] = set()
319
+ if match_text not in mimetypes[mimetype]:
320
+ yield mimetype, match
321
+ mimetypes[mimetype].add(match_text)
322
+
323
+ @property
324
+ def matcher(self) -> Matcher:
325
+ if self._matcher is None:
326
+ self._matcher = Matcher(parse=self.parse, matcher=self.magic_matcher)
327
+ return self._matcher
328
+
329
+ @property
330
+ def matches_so_far(self) -> List[Match]:
331
+ return self._matches
332
+
333
+ @property
334
+ def magic_matches_so_far(self) -> List[MagicMatch]:
335
+ return self._magic_matches
336
+
337
+ def matches(self) -> Iterator[Match]:
338
+ if self._matches is None or self._match_iterator is not None:
339
+ if self._matches is None:
340
+ self._matches = []
341
+ self._match_iterator = iter(self.matcher.match(self.path))
342
+ else:
343
+ yield from self._matches
344
+ while True:
345
+ try:
346
+ match = next(self._match_iterator)
347
+ except StopIteration:
348
+ self._match_iterator = None
349
+ break
350
+ if hasattr(match.match, "filetype"):
351
+ filetype = match.match.filetype
352
+ else:
353
+ filetype = match.name
354
+ if match.parent is None:
355
+ log.info(f"Found a file of type {filetype} at byte offset {match.offset}")
356
+ self._matches.append(match)
357
+ yield match
358
+ elif isinstance(match, Submatch):
359
+ log.debug(f"Found a subregion of type {filetype} at byte offset {match.offset}")
360
+ else:
361
+ log.info(f"Found an embedded file of type {filetype} at byte offset {match.offset}")
362
+ else:
363
+ yield from self._matches
364
+
365
+ def magic_matches(self) -> Iterator[Match]:
366
+ if self._magic_matches is None or self._magic_match_iterator is not None:
367
+ if self._magic_matches is None:
368
+ self._magic_matches = []
369
+ self._magic_match_iterator = iter(self.matcher.identify(self.path))
370
+ else:
371
+ yield from self._magic_matches
372
+ while True:
373
+ try:
374
+ match = next(self._magic_match_iterator)
375
+ yield match
376
+ except StopIteration:
377
+ self._magic_match_iterator = None
378
+ break
379
+ else:
380
+ yield from self._magic_matches
381
+
382
+ def sbud(self, matches: Optional[Iterable[Match]] = None) -> Dict[str, Any]:
383
+ if matches is None:
384
+ matches = self.matches()
385
+ md5 = hashlib.md5()
386
+ sha1 = hashlib.sha1()
387
+ sha256 = hashlib.sha256()
388
+ with open(self.path, 'rb') as hash_file:
389
+ data = hash_file.read()
390
+ md5.update(data)
391
+ sha1.update(data)
392
+ sha256.update(data)
393
+ b64contents = base64.b64encode(data)
394
+ file_length = len(data)
395
+ del data
396
+ return {
397
+ 'MD5': md5.hexdigest(),
398
+ 'SHA1': sha1.hexdigest(),
399
+ 'SHA256': sha256.hexdigest(),
400
+ 'b64contents': b64contents.decode('utf-8'),
401
+ 'fileName': self.path,
402
+ 'length': file_length,
403
+ 'versions': {
404
+ 'polyfile': __version__
405
+ },
406
+ 'struc': [
407
+ match.to_obj() for match in matches
408
+ ]
409
+ }
polyfile/profiling.py ADDED
@@ -0,0 +1,115 @@
1
+ from functools import wraps
2
+ import time
3
+ from typing import Optional
4
+ from . import logger
5
+
6
+ log = logger.getStatusLogger(__file__)
7
+
8
+
9
+ def current_time_ms():
10
+ return time.process_time_ns() / 1000000.0
11
+
12
+
13
+ # Note: This assumes single-threading, but that's basically the case as long as the GIL exists
14
+ _PROFILER_STACK: ["Profiler"] = []
15
+
16
+
17
+ class Profiler:
18
+ def __init__(self, parent: Optional["Profiler"] = None):
19
+ self.start_time_ms: Optional[float] = None
20
+ self.end_time_ms: Optional[float] = None
21
+ self.parent: Optional[Profiler] = parent
22
+ self._paused_start_time_ms: [float] = []
23
+ self._paused_ms: float = 0.0
24
+
25
+ @property
26
+ def complete(self) -> bool:
27
+ return self.end_time_ms is not None
28
+
29
+ @property
30
+ def is_paused(self) -> bool:
31
+ return bool(self._paused_start_time_ms)
32
+
33
+ @property
34
+ def paused_ms(self) -> float:
35
+ if self.complete or not self.is_paused:
36
+ return self._paused_ms
37
+ return self._paused_ms + current_time_ms() - self._paused_start_time_ms[0]
38
+
39
+ def pause(self):
40
+ profiler = self
41
+ while profiler is not None:
42
+ if profiler.complete:
43
+ raise ValueError("You cannot pause a completed profiler")
44
+ profiler._paused_start_time_ms.append(current_time_ms())
45
+
46
+ def unpause(self):
47
+ profiler = self
48
+ while profiler is not None:
49
+ if profiler.complete:
50
+ raise ValueError("You cannot unpause a completed profiler")
51
+ elif not profiler.is_paused:
52
+ raise ValueError("The profiler is not currently paused")
53
+ profiler._paused_ms += current_time_ms() - profiler._paused_start_time_ms[-1]
54
+ profiler._paused_start_time_ms.pop()
55
+ profiler = profiler.parent
56
+
57
+ @property
58
+ def elapsed_ms(self) -> float:
59
+ if self.start_time_ms is None:
60
+ raise ValueError("the profiler has not been started yet")
61
+ if self.end_time_ms is None:
62
+ end_time_ms = current_time_ms()
63
+ else:
64
+ end_time_ms = self.end_time_ms
65
+ return end_time_ms - self.start_time_ms - self.paused_ms
66
+
67
+ def start(self):
68
+ self.start_time_ms = current_time_ms()
69
+ self.end_time_ms = None
70
+
71
+ def stop(self):
72
+ if self._paused_start_time_ms:
73
+ raise ValueError("A profiler cannot be stopped while it is paused")
74
+ self.end_time_ms = current_time_ms()
75
+
76
+ def __enter__(self) -> "Profiler":
77
+ self.start()
78
+ if self.parent is None and _PROFILER_STACK:
79
+ self.parent = _PROFILER_STACK[-1]
80
+ _PROFILER_STACK.append(self)
81
+ return self
82
+
83
+ def __exit__(self, exc_type, exc_val, exc_tb):
84
+ self.stop()
85
+ if _PROFILER_STACK[-1] is not self:
86
+ log.warning(f"Profiler {self!r} stopped before its children stopped!")
87
+ _PROFILER_STACK.remove(self)
88
+ else:
89
+ _PROFILER_STACK.pop()
90
+
91
+
92
+ class Unprofiled:
93
+ def __init__(self, profiler: Optional[Profiler] = None):
94
+ self.profiler: Optional[Profiler] = profiler
95
+ self._had_profiler = profiler is not None
96
+
97
+ def __enter__(self):
98
+ if not self._had_profiler and _PROFILER_STACK:
99
+ self.profiler = _PROFILER_STACK[-1]
100
+ if self.profiler is not None:
101
+ self.profiler.pause()
102
+
103
+ def __exit__(self, exc_type, exc_val, exc_tb):
104
+ if self.profiler is not None:
105
+ self.profiler.unpause()
106
+ if not self._had_profiler:
107
+ self.profiler = None
108
+
109
+
110
+ def unprofiled(func):
111
+ @wraps(func)
112
+ def wrapped(*args, **kwargs):
113
+ with Unprofiled():
114
+ return func(*args, **kwargs)
115
+ return wrapped