Compare commits

...

270 Commits
1.8.7 ... 1.9.1

Author SHA1 Message Date
Matt Nadareski
ce016c5eb0 Bump version 2025-09-06 08:18:43 -04:00
Matt Nadareski
2225c1f2d8 Update Nuget packages 2025-09-05 10:57:14 -04:00
Matt Nadareski
2d0c0d5845 Make a bunch of things cache more safer 2025-09-05 08:32:40 -04:00
Matt Nadareski
60f1756cbb Wrap places where ReadFrom was not being used but still could be parallel 2025-09-05 07:45:55 -04:00
Matt Nadareski
738a1d250a Add inherent locking the the data source in wrappers 2025-09-05 07:36:15 -04:00
Matt Nadareski
c8e65e1e30 Add section string lock 2025-09-03 13:46:12 -04:00
Matt Nadareski
ecb09ce6f2 Make sure source data isn't locked unnecessarily 2025-09-02 23:56:29 -04:00
Matt Nadareski
72a1484a71 More granular locks 2025-09-02 23:51:02 -04:00
Matt Nadareski
de31c10c7c Bump version 2025-09-02 19:22:47 -04:00
HeroponRikiBestest
84483c229c Final fixes. (#21) 2025-09-02 16:08:04 -04:00
Matt Nadareski
b7e35a8fa8 Virtual insanity 2025-09-02 15:53:14 -04:00
Matt Nadareski
8c190a26a5 Math.Max 2025-09-02 15:51:26 -04:00
Matt Nadareski
2e5705125b Ensure that the WISE section only reads section data 2025-09-02 15:01:28 -04:00
Matt Nadareski
daaa92def0 Deal with end offset data 2025-09-02 14:47:49 -04:00
Matt Nadareski
86ec97678e Prep for a different tomorrow 2025-09-02 14:45:00 -04:00
Matt Nadareski
d74b82dc55 Hacky hack hack 2025-09-02 14:30:20 -04:00
Matt Nadareski
821ade2006 That was funny 2025-09-02 13:27:52 -04:00
HeroponRikiBestest
3ee999dccd Fix wise version(?) check for pre-string bytes (#20)
Needed opposite range
2025-09-02 11:02:43 -04:00
Matt Nadareski
f91bda51e1 Non-nullable nullability 2025-09-02 09:01:19 -04:00
Matt Nadareski
47255fc331 Sync NE with PE Wise extraction 2025-09-02 08:00:51 -04:00
Matt Nadareski
f7488bed04 Make CExe helpers static 2025-09-02 07:56:19 -04:00
Matt Nadareski
a94b3a82c4 Update comment 2025-09-02 07:53:42 -04:00
Matt Nadareski
1c8f64f5e6 Search for MS-CAB in resources and overlay 2025-09-02 07:52:29 -04:00
Matt Nadareski
a015e4df3f Add tests for new deserializers and wrappers 2025-09-02 07:48:17 -04:00
Matt Nadareski
2489a49924 Implement Wise section header printer 2025-09-02 07:44:14 -04:00
Matt Nadareski
d418fbd60d Complete the circle of comments 2025-09-02 07:31:15 -04:00
Matt Nadareski
cc2e7704e6 Finding methods don't need debug logging 2025-09-02 07:23:16 -04:00
Matt Nadareski
a980a56dfa Make consistent with other files 2025-09-01 21:12:05 -04:00
Matt Nadareski
da588e3bc0 That was annoying 2025-09-01 21:11:54 -04:00
Matt Nadareski
8b6f45d9b7 Detangle Wise a bit more 2025-09-01 20:37:23 -04:00
Matt Nadareski
9bdfe33baf Move some Wise things around to make more sense in broader context 2025-09-01 20:27:46 -04:00
Matt Nadareski
13d338f615 Fix some issues with desynced wrappers 2025-09-01 18:56:51 -04:00
Matt Nadareski
36a8641c8d I definitely missed these 2025-09-01 18:50:31 -04:00
Matt Nadareski
7bde6f99fc Fix porting issue with Wise 2025-09-01 18:46:15 -04:00
Matt Nadareski
45428ce991 Fix limit issue 2025-09-01 18:42:40 -04:00
Matt Nadareski
8eb5898ef6 Handle some big TODOs 2025-09-01 18:38:43 -04:00
Matt Nadareski
556e1c972c Update packages and upstream changes 2025-09-01 16:43:21 -04:00
Matt Nadareski
df8f3e7122 Clean up usings 2025-08-31 22:08:03 -04:00
Matt Nadareski
da1d575806 MPQ decryption should live separately 2025-08-31 22:07:15 -04:00
Matt Nadareski
c4d40a1dde Fix a couple of missed issues in MPQ 2025-08-31 21:53:27 -04:00
Matt Nadareski
912de926d0 Fix various issues with parsing MPQ; simplify 2025-08-31 21:51:06 -04:00
Matt Nadareski
c60fc1e31f Remove outdated comments 2025-08-31 21:45:35 -04:00
Matt Nadareski
386e607887 Add BET/HET handling based on documentation, not tested 2025-08-31 01:20:33 -04:00
Matt Nadareski
94c9b8d057 Fix MPQ v1 parsing, add hash and block table decrypt 2025-08-31 01:03:15 -04:00
Matt Nadareski
5f81275b10 Add some project references 2025-08-29 14:03:25 -04:00
Matt Nadareski
37c484411b Reimplment MPQ extraction via StormLib 2025-08-29 13:37:54 -04:00
Matt Nadareski
ad1f890742 Add StormLib as submodule 2025-08-29 13:34:59 -04:00
Matt Nadareski
2924529fa7 Start bundling runtimes 2025-08-29 13:31:19 -04:00
Matt Nadareski
ebe675cae1 Add StormLib runtimes 2025-08-29 13:29:15 -04:00
Matt Nadareski
a40c666775 Bundle libraries 2025-08-29 12:59:33 -04:00
Matt Nadareski
2ea060d3b3 Readme 2025-08-29 12:55:21 -04:00
Matt Nadareski
f8a67839dd Clean up some TODOs 2025-08-29 12:34:59 -04:00
Matt Nadareski
2773b12c9b Fix odd write-size mismatches 2025-08-29 12:14:55 -04:00
Matt Nadareski
929e12f976 These values need to be signed 2025-08-29 11:48:19 -04:00
Matt Nadareski
8fbc6c4662 Remove erroneous check 2025-08-29 11:28:37 -04:00
Matt Nadareski
797378e9c8 Better error messages 2025-08-29 11:26:17 -04:00
Matt Nadareski
113464a7d1 Privatize Reader class 2025-08-29 11:09:45 -04:00
Matt Nadareski
a13c837202 Probably fix the MD5 bug in IS-CAB 2025-08-29 11:06:37 -04:00
Matt Nadareski
48765f1ae5 Fix IS-CAB deserialization bug 2025-08-29 10:44:51 -04:00
Matt Nadareski
091ee56368 Remove Extractor, finally 2025-08-29 10:20:51 -04:00
Matt Nadareski
015a971147 Be smarter about volume opening 2025-08-29 10:17:07 -04:00
Matt Nadareski
7575a01a28 Keep track of the data offset 2025-08-29 10:11:53 -04:00
Matt Nadareski
7aa14cafea This never gets set again 2025-08-29 10:10:52 -04:00
Matt Nadareski
db10721386 Privatize 2025-08-29 10:04:52 -04:00
Matt Nadareski
6112cf8d60 This needed a rename 2025-08-29 10:04:24 -04:00
Matt Nadareski
50caeba322 Sort some filename pattern stuff 2025-08-29 10:03:56 -04:00
Matt Nadareski
b3499984b3 Start porting some functionality 2025-08-29 09:58:40 -04:00
Matt Nadareski
a5609a7a82 More descriptive class name 2025-08-29 09:41:25 -04:00
Matt Nadareski
8626a87860 Start cleaning up duplicate and unnecessary code 2025-08-29 09:37:03 -04:00
Matt Nadareski
fa31cd0e98 Let's see how UnshieldSharp goes 2025-08-29 09:14:33 -04:00
Matt Nadareski
6b6b7c6289 Reduce complexity of MS-CAB extraction paths 2025-08-29 08:29:05 -04:00
Matt Nadareski
baa3b272ab Extraction tool can pretend everything works 2025-08-29 08:20:55 -04:00
Matt Nadareski
d7c4f244cc Make the if/else chain into a switch 2025-08-29 08:13:58 -04:00
Matt Nadareski
e21d226564 Use wrapper description to simplify cases 2025-08-29 08:08:02 -04:00
Matt Nadareski
6ff6a7d4a4 Uncomment MPQ, still not hooked back up 2025-08-29 08:03:01 -04:00
Matt Nadareski
daf19a561c Add UnshieldSharp to ExtractionTool directly 2025-08-29 08:01:27 -04:00
Matt Nadareski
26226a75ff Update nuget packages 2025-08-29 07:56:51 -04:00
Matt Nadareski
4473edf476 Comments cleanup 2025-08-29 07:54:20 -04:00
Matt Nadareski
54cf0a6470 Expand the search window for embedded data 2025-08-28 23:56:05 -04:00
Matt Nadareski
0eb8f7e538 Extract overlay data for NE 2025-08-28 23:52:09 -04:00
Matt Nadareski
23b72c65ba Forgot to use the resource offset 2025-08-28 23:02:25 -04:00
Matt Nadareski
db7d89600c Handle PKZIP SFX by extracting the archive portion 2025-08-28 23:01:55 -04:00
Matt Nadareski
67d51ad1d6 Handle RAR SFX by extracting the archive portion 2025-08-28 22:42:15 -04:00
Matt Nadareski
56b71cf7fe Overlay deals with real data only 2025-08-28 22:41:49 -04:00
Matt Nadareski
e0ec2a521f Handle 7z SFX by extracting the archive portion 2025-08-28 22:21:25 -04:00
Matt Nadareski
e8589ac7b5 Fix offset read issues in resource table 2025-08-28 21:52:35 -04:00
Matt Nadareski
21e425acee Split up PE parsing a bit for readability 2025-08-28 21:35:05 -04:00
Matt Nadareski
ee316052ae Add ExtractionTool to readme 2025-08-28 20:14:08 -04:00
Matt Nadareski
3463936ae0 Fix extracting SFX archives 2025-08-28 20:00:05 -04:00
Matt Nadareski
5ff947b279 Add non-model constructors for PKZIP 2025-08-28 19:59:24 -04:00
Matt Nadareski
fdf2ea84ec Fix intermittent 7z solid issues 2025-08-28 19:59:06 -04:00
Matt Nadareski
ad9b001b6a Downstream from IO 2025-08-28 19:47:34 -04:00
Matt Nadareski
1308571c10 Smarter handling 2025-08-28 15:53:16 -04:00
Matt Nadareski
b8cb3419c1 Fix odd resource parsing issues 2025-08-28 15:49:02 -04:00
Matt Nadareski
02533cf947 Somewhat add SFX support 2025-08-28 15:26:37 -04:00
Matt Nadareski
bf8bd04dc7 Fix missing package 2025-08-28 15:22:05 -04:00
Matt Nadareski
1894376ab6 Initial migration of ExtractionTool 2025-08-28 15:11:21 -04:00
Matt Nadareski
c789e4df44 Replace simpler gzip extract with more robust version 2025-08-28 14:17:15 -04:00
Matt Nadareski
884685de4a Fix GZip extraction 2025-08-28 14:15:39 -04:00
Matt Nadareski
7fda7be457 Fix significant issue with how view streams are used 2025-08-28 14:10:08 -04:00
Matt Nadareski
5daf759033 Add debug logging for tar extraction 2025-08-28 13:16:39 -04:00
Matt Nadareski
589ab0896a Replace SharpCompress with native extract for tar 2025-08-28 13:03:59 -04:00
Matt Nadareski
7645ab978f Fix obvious bug 2025-08-28 12:59:50 -04:00
Matt Nadareski
e6497289da Add experimental tar extraction 2025-08-28 12:56:43 -04:00
Matt Nadareski
95a9f4769d Workaround to read block data 2025-08-28 12:16:07 -04:00
Matt Nadareski
7917601f7a Slight formatting cleanup 2025-08-28 12:14:48 -04:00
Matt Nadareski
3400238fc5 Make tar printing a bit more comprehensive 2025-08-28 12:13:00 -04:00
Matt Nadareski
cbd335c6aa Add and update tests 2025-08-28 10:12:08 -04:00
Matt Nadareski
9feaadd32a Implement gzip parsing and printing 2025-08-28 09:56:52 -04:00
Matt Nadareski
2ec008b3b7 Add extension property to tar 2025-08-28 09:13:02 -04:00
Matt Nadareski
c9a462a1c6 Fix tar parsing and printing 2025-08-28 09:11:04 -04:00
Matt Nadareski
ab44aa7e68 Start implementing tar 2025-08-28 08:14:38 -04:00
Matt Nadareski
9b9d3176ec Slightly more work 2025-08-28 07:54:22 -04:00
Matt Nadareski
5dda3e2c81 Add shell deserializers for gzip and tar 2025-08-28 07:52:43 -04:00
Matt Nadareski
4b8dc12c98 Add PKZIP extension properties 2025-08-27 21:59:30 -04:00
Matt Nadareski
044e4c4c75 Fill out remaining models, add printing 2025-08-27 21:48:01 -04:00
Matt Nadareski
2149630865 Fill in the remaining extras that have models 2025-08-27 20:40:56 -04:00
Matt Nadareski
3d435a1d7e Start parsing some PKZIP extras 2025-08-27 19:20:07 -04:00
Matt Nadareski
f2d993a958 Fix UTF-8 encoded strings 2025-08-27 18:14:11 -04:00
Matt Nadareski
7bf75b8dc5 Minor cleanup 2025-08-27 17:59:11 -04:00
Matt Nadareski
dfbdce1dc8 Be more strictly correct about ZIP64 reading 2025-08-27 17:54:35 -04:00
Matt Nadareski
63f5566e65 Minor formatting fix 2025-08-27 16:45:20 -04:00
Matt Nadareski
4b0f43f6c0 Clean up PKZIP printing 2025-08-27 16:41:00 -04:00
Matt Nadareski
98e1ef7362 Rearrange code to make models updates easier 2025-08-27 15:49:31 -04:00
Matt Nadareski
4e0ffcb3c8 Return nothing and be happy 2025-08-27 13:04:01 -04:00
Matt Nadareski
a93a46d6c0 Start fixing PKZIP deserializing
This does a forward-reading approach on the archive instead of the "proper" way of reading from the end. This change introduces potential issues, as both "deleted" entries and normal ones will be included. It also makes it more difficult to determine if the archive is ZIP64 or not. But it is far more stable than the read-from-the-end approach of the old code.
2025-08-27 12:54:36 -04:00
Matt Nadareski
e163302522 Add part-finding helpers and tests 2025-08-26 21:14:25 -04:00
Matt Nadareski
838afc35c3 Order of operations 2025-08-26 06:52:47 -04:00
Matt Nadareski
3a62bfab57 Fix copy-paste 2025-08-26 06:45:21 -04:00
Matt Nadareski
560b3a246c Use file part count, not partial files 2025-08-26 06:41:01 -04:00
Matt Nadareski
4360916750 Handle archive parts 2025-08-25 22:20:24 -04:00
Matt Nadareski
3f31edc1c0 Fix return comments 2025-08-25 21:02:08 -04:00
Matt Nadareski
bd874d436b Slight renaming to be more accurate 2025-08-25 21:01:20 -04:00
Matt Nadareski
fbc47425f4 Use using to use usings 2025-08-25 20:57:35 -04:00
Matt Nadareski
c9df6ff059 Rename to be consistent 2025-08-25 20:53:25 -04:00
Matt Nadareski
ef6ff85e96 Port more PE extraction 2025-08-25 20:51:35 -04:00
Matt Nadareski
bb93792f57 Remove restriction from RAR 2025-08-25 13:25:07 -04:00
Matt Nadareski
1f7ab4fccb Simpler completeness checks 2025-08-25 13:23:49 -04:00
Matt Nadareski
2535e82618 Maybe fix multipart 7z, RAR, and PKZIP archives 2025-08-25 13:19:28 -04:00
Matt Nadareski
66d80c8523 Add basic PE extraction 2025-08-25 13:06:22 -04:00
Matt Nadareski
834a17fe82 Add region note 2025-08-25 12:50:16 -04:00
Matt Nadareski
ea85167e06 Upstream changes to string reading until IO updated 2025-08-25 12:45:45 -04:00
Matt Nadareski
e007a06dda Allow direct data source access 2025-08-23 21:31:13 -04:00
Matt Nadareski
02f9e1e935 Temporarily downstream class from IO 2025-08-23 21:29:22 -04:00
Matt Nadareski
21b7d431a7 More concise naming 2025-08-23 13:38:19 -04:00
Matt Nadareski
307b932f87 A couple more clarifications 2025-08-23 13:37:39 -04:00
Matt Nadareski
6983d1cd3c This can't be null anymore 2025-08-23 13:36:59 -04:00
Matt Nadareski
a193c9bb3c Remove unnecessary comment 2025-08-23 13:23:44 -04:00
Matt Nadareski
aa67c7ad6d Rename to be simpler 2025-08-23 13:19:26 -04:00
Matt Nadareski
70fc686249 DataSource is a Stream type now 2025-08-23 13:18:46 -04:00
Matt Nadareski
c87a456a46 Move things to base classes 2025-08-23 12:58:09 -04:00
Matt Nadareski
456bb1e95b Intermediary step for extractable shells 2025-08-23 12:23:44 -04:00
Matt Nadareski
b0b334103d Implement shell wrappers for extractable types without a current model 2025-08-23 11:55:54 -04:00
Matt Nadareski
78851e3b57 Pass through data source property, make private 2025-08-20 08:11:48 -04:00
Matt Nadareski
850a883e14 Methods to properties 2025-08-20 08:08:53 -04:00
Matt Nadareski
6e0ced5ffe One more GetEndOffset removal 2025-08-20 08:04:01 -04:00
Matt Nadareski
64cd8febaa This doesn't need private set 2025-08-20 08:00:45 -04:00
Matt Nadareski
6fbe1cffaa GetEndOffset really shouldn't be used 2025-08-20 07:54:52 -04:00
Matt Nadareski
601e781ef9 Data source shennanigans 2025-08-19 22:01:10 -04:00
Matt Nadareski
d26ad35573 Create a new DataSource helper class 2025-08-19 20:49:47 -04:00
Matt Nadareski
b70c510734 Be consistent with model 2025-08-19 20:25:56 -04:00
Matt Nadareski
29a7158488 Clarify that Matching is being used 2025-08-19 15:30:23 -04:00
Matt Nadareski
1227ca020a Fix CreateExecutableWrapper 2025-08-19 09:18:50 -04:00
Matt Nadareski
cd7e6ff98d Fix some logic bugs due to offsets 2025-08-19 09:09:33 -04:00
Matt Nadareski
510a0f77f6 Stop reinventing the wheel 2025-08-19 07:43:21 -04:00
Matt Nadareski
6d1dabb1db Handle only cases where long mattered 2025-08-19 07:41:29 -04:00
Matt Nadareski
2e337891da Fix logic bug with end of file check 2025-08-19 07:36:33 -04:00
Matt Nadareski
d49e18a83e Replace _byteArrayOffset with _initialPosition 2025-08-19 07:34:51 -04:00
Matt Nadareski
c14560ec18 Add initial position to wrapper, currently unused 2025-08-19 07:29:59 -04:00
Matt Nadareski
e3e31cd9f2 Separate files 2025-08-19 07:27:39 -04:00
Matt Nadareski
adf9627045 Stricter with COFF tables 2025-08-17 15:25:25 -04:00
Matt Nadareski
c7b03c7765 This should be a file offset 2025-08-17 15:20:51 -04:00
Matt Nadareski
b5f83215d5 Don't exit parsing unnecessarily 2025-08-17 15:04:38 -04:00
Matt Nadareski
96e3fc5533 Cleanups to PE deserialization 2025-08-17 14:53:03 -04:00
Matt Nadareski
828e7dda03 Add file-only info printing flag 2025-08-13 12:03:06 -04:00
Matt Nadareski
8ef50c30d5 Add and implement IExtractable 2025-08-11 11:39:15 -04:00
Matt Nadareski
cbe1d5b608 Resync NE overlay finding 2025-08-11 11:11:51 -04:00
Matt Nadareski
7123a9e986 Add more NE deserializers 2025-08-10 20:37:42 -04:00
Matt Nadareski
af5996b972 Fill out LE/LX methods at all 2025-08-01 09:04:30 -04:00
Matt Nadareski
15e947784b Use NE helpers 2025-08-01 08:56:14 -04:00
Matt Nadareski
1b382c201e Simplify references in NE 2025-08-01 08:43:01 -04:00
Matt Nadareski
8deca4fb0c Fill out NE methods more 2025-08-01 08:39:14 -04:00
Matt Nadareski
96c4372609 Add data-reading methods for NE 2025-08-01 08:19:41 -04:00
Matt Nadareski
ca7a109037 Add more NE extensions 2025-08-01 07:58:54 -04:00
Matt Nadareski
c54f5b3c5d Add MS-DOS stub extension for LE/LX 2025-07-31 14:35:35 -04:00
Matt Nadareski
652942ab9f Add extensions based on external need 2025-07-31 14:00:55 -04:00
Matt Nadareski
2cc19a9c36 Add some more IS-CAB extensions 2025-07-31 13:44:15 -04:00
Matt Nadareski
6ffb3f4bbd Add IS-CAB OpenVolume helper 2025-07-31 13:34:35 -04:00
Matt Nadareski
bab4278318 Better linking in IS-CAB open set 2025-07-31 13:26:10 -04:00
Matt Nadareski
013d18a426 Better file descriptor method 2025-07-31 13:23:45 -04:00
Matt Nadareski
e94e27910e Add a couple of IS-CAB extensions 2025-07-31 13:20:40 -04:00
Matt Nadareski
34cea6e74a Double-chain IS-CAB like MS-CAB 2025-07-31 13:18:29 -04:00
Matt Nadareski
640e160863 Slight cleanup to the PE deserializer 2025-07-31 12:06:51 -04:00
Matt Nadareski
3100963250 Fix build issue 2025-07-31 11:57:20 -04:00
Matt Nadareski
2086358762 Slight cleanup to the PE wrapper 2025-07-31 11:52:39 -04:00
Matt Nadareski
ae273c589d Use simpler extension where possible 2025-07-31 11:28:09 -04:00
Matt Nadareski
a229015fcd Move major version helper out of deserializer 2025-07-31 11:26:54 -04:00
Matt Nadareski
b001680674 Remove unnecessary code regions for XMID and XeMID 2025-07-31 11:12:35 -04:00
Matt Nadareski
e684133f72 Add InfoPrint to the readme 2025-07-31 11:08:11 -04:00
Matt Nadareski
2b020eecc7 Output hashes to separate file 2025-07-31 10:30:13 -04:00
Matt Nadareski
78f4d6faca Add file hashing option to InfoPrint 2025-07-31 10:26:03 -04:00
Matt Nadareski
f07b7a049e Ensure endianness of reads 2025-07-31 09:41:36 -04:00
Matt Nadareski
544637779c Exception debugging should use Error stream 2025-07-31 09:14:22 -04:00
Matt Nadareski
38b6427e4e Wire through include debug flag 2025-07-31 09:11:43 -04:00
Matt Nadareski
e36822a19c Add more extension properties; clean up 2025-07-31 08:57:35 -04:00
Matt Nadareski
e1a114976f Use correct mask for v3 CFB files 2025-07-30 16:56:15 -04:00
Matt Nadareski
5ba9ab3457 Fix DIFAT assumptions for directory entries 2025-07-30 16:28:54 -04:00
Matt Nadareski
36edf9ed54 Fix parsing of large DIFAT tables in CFB 2025-07-30 15:46:19 -04:00
Matt Nadareski
e788ffa851 Fix MS-CAB block continuation 2025-07-30 15:18:29 -04:00
Matt Nadareski
e0d819b88d Fix spanned blocks, previously skipped 2025-07-30 14:54:19 -04:00
Matt Nadareski
e3b216ad09 Wrap MS-ZIP compression in case of failure 2025-07-30 14:21:13 -04:00
Matt Nadareski
55d0fd452d Add new extension property for CFB 2025-07-30 11:33:49 -04:00
Matt Nadareski
089fd02b2e Sync remaining extraction bits for CFB 2025-07-30 11:32:25 -04:00
Matt Nadareski
8cfd820dcd Sync back extraction fixes for CFB 2025-07-30 11:29:27 -04:00
Matt Nadareski
67ed9860fe Sync back deserialization fixes for CFB 2025-07-30 11:26:04 -04:00
Matt Nadareski
ee924e3a34 Backport some CFB work 2025-07-30 11:04:25 -04:00
Matt Nadareski
9e5085ba79 Add CFB extraction placeholders 2025-07-30 08:31:00 -04:00
Matt Nadareski
dbfdbbff20 Fix CFB stream name handling 2025-07-30 08:21:20 -04:00
Matt Nadareski
21dc72bf11 Decode CFB stream names 2025-07-30 08:08:27 -04:00
Matt Nadareski
c8295c4724 Make CFB printing pretty again 2025-07-29 23:43:22 -04:00
Matt Nadareski
44b4dd3d1b Fix reading CFB v3 directory entries 2025-07-29 23:41:42 -04:00
Matt Nadareski
7e543c6acb Fix some issues with CFB deserialization 2025-07-29 23:08:37 -04:00
Matt Nadareski
63514d149f CFB directory entry names are UTF-16 2025-07-29 22:51:04 -04:00
Matt Nadareski
d7e559749d Normalize extraction methods
This does a few things:
- Ensures that all output directories are normalized for the current operating system
- Ensures that all output files are flushed in case of systematic issues
- Brings MS-CAB extraction up to the same return value quality as other extractors
2025-07-29 21:13:53 -04:00
Matt Nadareski
a2be40fcbc Add CHD version extension 2025-07-29 20:39:48 -04:00
Matt Nadareski
771df5c372 Fall back on OpenNext if needed 2025-07-29 11:52:59 -04:00
Matt Nadareski
2d3d6348ad Remove redundant code 2025-07-29 11:51:28 -04:00
Matt Nadareski
a2bf15f0bc Fix method ordering 2025-07-29 11:49:07 -04:00
Matt Nadareski
0aa25df88f More graceful handling of MS-CAB sets 2025-07-29 11:48:34 -04:00
Matt Nadareski
36afb1c0ee Split out MS-ZIP handling for cleaner code 2025-07-29 11:38:38 -04:00
Matt Nadareski
c9d61906fb Only derive the compression type once per folder 2025-07-29 11:26:23 -04:00
Matt Nadareski
d8440a01d3 Remove redundant check 2025-07-29 08:30:17 -04:00
Matt Nadareski
74d92312ef Split out MS-CAB ExtractFile logic 2025-07-29 08:26:53 -04:00
Matt Nadareski
0dc9823d2b Fix assumption about MS-CAB sets 2025-07-29 08:04:02 -04:00
Matt Nadareski
9c69737073 Fix comments to make more sense 2025-07-28 21:23:18 -04:00
Matt Nadareski
66187dcf04 Keep tweaking extraction 2025-07-28 21:20:47 -04:00
Matt Nadareski
79943560bc Keep tweaking extraction 2025-07-28 21:14:51 -04:00
Matt Nadareski
b3321f9c9a Keep tweaking extraction 2025-07-28 20:58:49 -04:00
Matt Nadareski
428c269a49 Keep tweaking extraction 2025-07-28 20:56:23 -04:00
Matt Nadareski
e84964a321 Add MS-CAB extract and decompression 2025-07-28 20:31:40 -04:00
Matt Nadareski
0394ea5356 Remove unused using 2025-07-28 19:43:53 -04:00
Matt Nadareski
852b086920 Add IS-CAB obfuscation code 2025-07-28 19:41:07 -04:00
Matt Nadareski
b7fceee2b7 Port more MS-CAB helpers from BOS 2025-07-28 15:22:28 -04:00
Matt Nadareski
ecf6c957c9 Port OpenNext/OpenPrevious from BOS 2025-07-28 15:13:19 -04:00
Matt Nadareski
5e0b0070ff Make MS-CAB doubly-linked 2025-07-28 12:45:23 -04:00
Matt Nadareski
9934bc31a3 Fix build 2025-07-28 12:31:03 -04:00
Matt Nadareski
7b4711f5cf Implement OpenSet for MS-CAB 2025-07-28 12:27:18 -04:00
Matt Nadareski
844066815d Add extension properties for MS-CAB 2025-07-28 12:09:28 -04:00
Matt Nadareski
3a6293e696 Port some code from UnshieldSharp 2025-07-28 11:57:54 -04:00
Matt Nadareski
3210b8601d Add IS-CAB CreateFilenamePattern from UnshieldSharp 2025-07-28 11:35:24 -04:00
Matt Nadareski
181788802d Move PathProcessors to the correct namespace 2025-07-28 10:27:11 -04:00
Matt Nadareski
4b627ce776 Move wrapper-specific helpers to correct namespace 2025-07-28 10:25:25 -04:00
Matt Nadareski
8b799bb5c8 Port Nitro decryption step 2025-07-28 08:47:26 -04:00
Matt Nadareski
5bc8336fce Move StringBuilderExtensions to better namespace 2025-07-27 20:56:15 -04:00
Matt Nadareski
4f9f8ddcec Fix build 2025-07-27 20:49:18 -04:00
Matt Nadareski
29f1f63ef8 Add nested dir support for Logiqx, fix existing dir support 2025-07-27 20:48:49 -04:00
Matt Nadareski
48ecdff5f7 Fix AlignToBoundary a bit 2025-07-24 10:56:31 -04:00
Matt Nadareski
411acd2d5a Add AlignToBoundary for byte arrays 2025-07-24 10:55:52 -04:00
Matt Nadareski
e6742fe889 Fix missed AlignToBoundary case 2025-07-24 10:47:21 -04:00
Matt Nadareski
b6561719a7 Add SecuROM DFA 2025-07-24 10:40:31 -04:00
Matt Nadareski
2bf3d6f9a6 Use more constants in GetFileType 2025-07-24 10:19:20 -04:00
Matt Nadareski
b2700b5975 Add MESS ListXML support 2025-07-24 09:36:37 -04:00
Matt Nadareski
95b28874da Add MESS ListXML support 2025-07-24 09:36:13 -04:00
Matt Nadareski
4934ee837c Be consistent about end-of-file newlines 2025-07-24 09:31:28 -04:00
Matt Nadareski
3cbfd5cd10 Add .NET Standard 2.0 and 2.1 2025-07-24 09:19:38 -04:00
Matt Nadareski
da28ce310b Update nuget packages 2025-07-24 09:16:11 -04:00
HeroponRikiBestest
ac6d93a3b9 Add extra validity checks for GCF (#17)
* Add extra validity checks for GCF

* Remove "for validity"
2025-07-12 15:49:35 -04:00
Matt Nadareski
104028204d Fix relocation table parsing issues (fixes #16) 2025-06-28 20:00:21 -04:00
Matt Nadareski
d3e61b42dd Attempt to fix export table name table 2025-06-24 17:14:25 -04:00
Matt Nadareski
6351cabb62 Add CMP tests for non-quote serialization 2025-05-28 09:51:45 -04:00
307 changed files with 19777 additions and 3976 deletions

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "SabreTools.Serialization/_EXTERNAL/stormlibsharp"]
path = SabreTools.Serialization/_EXTERNAL/stormlibsharp
url = https://github.com/robpaveza/stormlibsharp.git

14
.vscode/launch.json vendored
View File

@@ -4,6 +4,20 @@
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (ExtractionTool)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/ExtractionTool/bin/Debug/net9.0/ExtractionTool.dll",
"args": [],
"cwd": "${workspaceFolder}",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
"stopAtEntry": false,
"justMyCode": false
},
{
"name": ".NET Core Launch (InfoPrint)",
"type": "coreclr",

View File

@@ -0,0 +1,73 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
<OutputType>Exe</OutputType>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>1.9.1</Version>
</PropertyGroup>
<!-- Support All Frameworks -->
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net4`))">
<RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith(`netcoreapp`)) OR $(TargetFramework.StartsWith(`net5`))">
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net6`)) OR $(TargetFramework.StartsWith(`net7`)) OR $(TargetFramework.StartsWith(`net8`)) OR $(TargetFramework.StartsWith(`net9`))">
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="$(RuntimeIdentifier.StartsWith(`osx-arm`))">
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
</PropertyGroup>
<!-- Set a build flag for Windows specifically -->
<PropertyGroup Condition="'$(RuntimeIdentifier)'=='win-x86'">
<DefineConstants>$(DefineConstants);WINX86</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(RuntimeIdentifier)'=='win-x64'">
<DefineConstants>$(DefineConstants);WINX64</DefineConstants>
</PropertyGroup>
<!-- These are needed for dealing with native Windows DLLs -->
<ItemGroup Condition="'$(RuntimeIdentifier)'=='win-x86'">
<ContentWithTargetPath Include="..\SabreTools.Serialization\runtimes\win-x86\native\CascLib.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
<TargetPath>CascLib.dll</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="..\SabreTools.Serialization\runtimes\win-x86\native\StormLib.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
<TargetPath>StormLib.dll</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup Condition="'$(RuntimeIdentifier)'=='win-x64'">
<ContentWithTargetPath Include="..\SabreTools.Serialization\runtimes\win-x64\native\CascLib.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
<TargetPath>CascLib.dll</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="..\SabreTools.Serialization\runtimes\win-x64\native\StormLib.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
<TargetPath>StormLib.dll</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SabreTools.Serialization\SabreTools.Serialization.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.IO" Version="1.7.2" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.8" Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))" />
</ItemGroup>
</Project>

129
ExtractionTool/Options.cs Normal file
View File

@@ -0,0 +1,129 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace ExtractionTool
{
/// <summary>
/// Set of options for the test executable
/// </summary>
internal sealed class Options
{
#region Properties
/// <summary>
/// Enable debug output for relevant operations
/// </summary>
public bool Debug { get; private set; } = false;
/// <summary>
/// Set of input paths to use for operations
/// </summary>
public List<string> InputPaths { get; private set; } = [];
/// <summary>
/// Output path for archive extraction
/// </summary>
public string OutputPath { get; private set; } = string.Empty;
#endregion
/// <summary>
/// Parse commandline arguments into an Options object
/// </summary>
public static Options? ParseOptions(string[] args)
{
// If we have invalid arguments
if (args == null || args.Length == 0)
return null;
// Create an Options object
var options = new Options();
// Parse the options and paths
for (int index = 0; index < args.Length; index++)
{
string arg = args[index];
switch (arg)
{
case "-?":
case "-h":
case "--help":
return null;
case "-d":
case "--debug":
options.Debug = true;
break;
case "-o":
case "--outdir":
options.OutputPath = index + 1 < args.Length ? args[++index] : string.Empty;
break;
default:
options.InputPaths.Add(arg);
break;
}
}
// Validate we have any input paths to work on
if (options.InputPaths.Count == 0)
{
Console.WriteLine("At least one path is required!");
return null;
}
// Validate the output path
bool validPath = ValidateExtractionPath(options);
if (!validPath)
return null;
return options;
}
/// <summary>
/// Display help text
/// </summary>
public static void DisplayHelp()
{
Console.WriteLine("Extraction Tool");
Console.WriteLine();
Console.WriteLine("ExtractionTool.exe <options> file|directory ...");
Console.WriteLine();
Console.WriteLine("Options:");
Console.WriteLine("-?, -h, --help Display this help text and quit");
Console.WriteLine("-d, --debug Enable debug mode");
Console.WriteLine("-o, --outdir [PATH] Set output path for extraction (required)");
}
/// <summary>
/// Validate the extraction path
/// </summary>
private static bool ValidateExtractionPath(Options options)
{
// Null or empty output path
if (string.IsNullOrEmpty(options.OutputPath))
{
Console.WriteLine("Output directory required for extraction!");
Console.WriteLine();
return false;
}
// Malformed output path or invalid location
try
{
options.OutputPath = Path.GetFullPath(options.OutputPath);
Directory.CreateDirectory(options.OutputPath);
}
catch
{
Console.WriteLine("Output directory could not be created!");
Console.WriteLine();
return false;
}
return true;
}
}
}

249
ExtractionTool/Program.cs Normal file
View File

@@ -0,0 +1,249 @@
using System;
using System.IO;
using SabreTools.IO.Extensions;
using SabreTools.Serialization.Wrappers;
namespace ExtractionTool
{
class Program
{
static void Main(string[] args)
{
#if NET462_OR_GREATER || NETCOREAPP
// Register the codepages
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
#endif
// Get the options from the arguments
var options = Options.ParseOptions(args);
// If we have an invalid state
if (options == null)
{
Options.DisplayHelp();
return;
}
// Loop through the input paths
foreach (string inputPath in options.InputPaths)
{
ExtractPath(inputPath, options.OutputPath, options.Debug);
}
}
/// <summary>
/// Wrapper to extract data for a single path
/// </summary>
/// <param name="path">File or directory path</param>
/// <param name="outputDirectory">Output directory path</param>
/// <param name="includeDebug">Enable including debug information</param>
private static void ExtractPath(string path, string outputDirectory, bool includeDebug)
{
// Normalize by getting the full path
path = Path.GetFullPath(path);
Console.WriteLine($"Checking possible path: {path}");
// Check if the file or directory exists
if (File.Exists(path))
{
ExtractFile(path, outputDirectory, includeDebug);
}
else if (Directory.Exists(path))
{
foreach (string file in IOExtensions.SafeEnumerateFiles(path, "*", SearchOption.AllDirectories))
{
ExtractFile(file, outputDirectory, includeDebug);
}
}
else
{
Console.WriteLine($"{path} does not exist, skipping...");
}
}
/// <summary>
/// Print information for a single file, if possible
/// </summary>
private static void ExtractFile(string file, string outputDirectory, bool includeDebug)
{
Console.WriteLine($"Attempting to extract all files from {file}");
using Stream stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
// Get the extension for certain checks
string extension = Path.GetExtension(file).ToLower().TrimStart('.');
// Get the first 16 bytes for matching
byte[] magic = new byte[16];
try
{
int read = stream.Read(magic, 0, 16);
stream.Seek(0, SeekOrigin.Begin);
}
catch (Exception ex)
{
if (includeDebug) Console.Error.WriteLine(ex);
return;
}
// Get the file type
WrapperType ft = WrapperFactory.GetFileType(magic, extension);
var wrapper = WrapperFactory.CreateWrapper(ft, stream);
// Create the output directory
Directory.CreateDirectory(outputDirectory);
// Print the preamble
Console.WriteLine($"Attempting to extract from '{wrapper?.Description() ?? "UNKNOWN"}'");
Console.WriteLine();
switch (wrapper)
{
// 7-zip
case SevenZip sz:
sz.Extract(outputDirectory, includeDebug);
break;
// BFPK archive
case BFPK bfpk:
bfpk.Extract(outputDirectory, includeDebug);
break;
// BSP
case BSP bsp:
bsp.Extract(outputDirectory, includeDebug);
break;
// bzip2
case BZip2 bzip2:
bzip2.Extract(outputDirectory, includeDebug);
break;
// CFB
case CFB cfb:
cfb.Extract(outputDirectory, includeDebug);
break;
// GCF
case GCF gcf:
gcf.Extract(outputDirectory, includeDebug);
break;
// gzip
case GZip gzip:
gzip.Extract(outputDirectory, includeDebug);
break;
// InstallShield Archive V3 (Z)
case InstallShieldArchiveV3 isv3:
isv3.Extract(outputDirectory, includeDebug);
break;
// IS-CAB archive
case InstallShieldCabinet iscab:
iscab.Extract(outputDirectory, includeDebug);
break;
// LZ-compressed file, KWAJ variant
case LZKWAJ kwaj:
kwaj.Extract(outputDirectory, includeDebug);
break;
// LZ-compressed file, QBasic variant
case LZQBasic qbasic:
qbasic.Extract(outputDirectory, includeDebug);
break;
// LZ-compressed file, SZDD variant
case LZSZDD szdd:
szdd.Extract(outputDirectory, includeDebug);
break;
// Microsoft Cabinet archive
case MicrosoftCabinet mscab:
mscab.Extract(outputDirectory, includeDebug);
break;
// MoPaQ (MPQ) archive
case MoPaQ mpq:
mpq.Extract(outputDirectory, includeDebug);
break;
// New Executable
case NewExecutable nex:
nex.Extract(outputDirectory, includeDebug);
break;
// PAK
case PAK pak:
pak.Extract(outputDirectory, includeDebug);
break;
// PFF
case PFF pff:
pff.Extract(outputDirectory, includeDebug);
break;
// PKZIP
case PKZIP pkzip:
pkzip.Extract(outputDirectory, includeDebug);
break;
// Portable Executable
case PortableExecutable pex:
pex.Extract(outputDirectory, includeDebug);
break;
// Quantum
case Quantum quantum:
quantum.Extract(outputDirectory, includeDebug);
break;
// RAR
case RAR rar:
rar.Extract(outputDirectory, includeDebug);
break;
// SGA
case SGA sga:
sga.Extract(outputDirectory, includeDebug);
break;
// Tape Archive
case TapeArchive tar:
tar.Extract(outputDirectory, includeDebug);
break;
// VBSP
case VBSP vbsp:
vbsp.Extract(outputDirectory, includeDebug);
break;
// VPK
case VPK vpk:
vpk.Extract(outputDirectory, includeDebug);
break;
// WAD3
case WAD3 wad:
wad.Extract(outputDirectory, includeDebug);
break;
// xz
case XZ xz:
xz.Extract(outputDirectory, includeDebug);
break;
// XZP
case XZP xzp:
xzp.Extract(outputDirectory, includeDebug);
break;
// Everything else
default:
Console.WriteLine("Not a supported extractable file format, skipping...");
Console.WriteLine();
break;
}
}
}
}

View File

@@ -4,12 +4,13 @@
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
<OutputType>Exe</OutputType>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>1.8.7</Version>
<Version>1.9.1</Version>
</PropertyGroup>
<!-- Support All Frameworks -->
@@ -31,7 +32,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.IO" Version="1.6.3" />
<PackageReference Include="SabreTools.IO" Version="1.7.2" />
<PackageReference Include="SabreTools.Hashing" Version="1.5.0" />
</ItemGroup>
</Project>

View File

@@ -15,6 +15,16 @@ namespace InfoPrint
/// </summary>
public bool Debug { get; private set; } = false;
/// <summary>
/// Output information to file only, skip printing to console
/// </summary>
public bool FileOnly { get; private set; } = false;
/// <summary>
/// Print external file hashes
/// </summary>
public bool Hash { get; private set; } = false;
/// <summary>
/// Set of input paths to use for operations
/// </summary>
@@ -74,6 +84,16 @@ namespace InfoPrint
options.Debug = true;
break;
case "-c":
case "--hash":
options.Hash = true;
break;
case "-f":
case "--file":
options.FileOnly = true;
break;
case "-j":
case "--json":
#if NETCOREAPP
@@ -106,14 +126,16 @@ namespace InfoPrint
{
Console.WriteLine("Information Printing Program");
Console.WriteLine();
Console.WriteLine("infoprint.exe <options> file|directory ...");
Console.WriteLine("InfoPrint <options> file|directory ...");
Console.WriteLine();
Console.WriteLine("Options:");
Console.WriteLine("-?, -h, --help Display this help text and quit");
Console.WriteLine("-d, --debug Enable debug mode");
Console.WriteLine("-c, --hash Output file hashes");
Console.WriteLine("-f, --file Print to file only");
#if NETCOREAPP
Console.WriteLine("-j, --json Print info as JSON");
#endif
}
}
}
}

View File

@@ -1,5 +1,7 @@
using System;
using System.IO;
using System.Text;
using SabreTools.Hashing;
using SabreTools.IO.Extensions;
using SabreTools.Serialization;
using SabreTools.Serialization.Wrappers;
@@ -23,11 +25,7 @@ namespace InfoPrint
// Loop through the input paths
foreach (string inputPath in options.InputPaths)
{
#if NETFRAMEWORK
PrintPathInfo(inputPath, false, options.Debug);
#else
PrintPathInfo(inputPath, options.Json, options.Debug);
#endif
PrintPathInfo(inputPath, options);
}
}
@@ -35,22 +33,21 @@ namespace InfoPrint
/// Wrapper to print information for a single path
/// </summary>
/// <param name="path">File or directory path</param>
/// <param name="json">Enable JSON output, if supported</param>
/// <param name="debug">Enable debug output</param>
private static void PrintPathInfo(string path, bool json, bool debug)
/// <param name="options">User-defined options</param>
private static void PrintPathInfo(string path, Options options)
{
Console.WriteLine($"Checking possible path: {path}");
// Check if the file or directory exists
if (File.Exists(path))
{
PrintFileInfo(path, json, debug);
PrintFileInfo(path, options);
}
else if (Directory.Exists(path))
{
foreach (string file in IOExtensions.SafeEnumerateFiles(path, "*", SearchOption.AllDirectories))
{
PrintFileInfo(file, json, debug);
PrintFileInfo(file, options);
}
}
else
@@ -62,10 +59,31 @@ namespace InfoPrint
/// <summary>
/// Print information for a single file, if possible
/// </summary>
private static void PrintFileInfo(string file, bool json, bool debug)
/// <param name="file">File path</param>
/// <param name="options">User-defined options</param>
private static void PrintFileInfo(string file, Options options)
{
Console.WriteLine($"Attempting to print info for {file}");
// Get the base info output name
string filenameBase = $"info-{DateTime.Now:yyyy-MM-dd_HHmmss.ffff}";
// If we have the hash flag
if (options.Hash)
{
var hashBuilder = PrintHashInfo(file, options.Debug);
if (hashBuilder != null)
{
// Create the output data
string hashData = hashBuilder.ToString();
// Write the output data
using var hsw = new StreamWriter(File.OpenWrite($"{filenameBase}.hashes"));
hsw.WriteLine(hashData);
hsw.Flush();
}
}
try
{
using Stream stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
@@ -92,20 +110,17 @@ namespace InfoPrint
return;
}
// Get the base info output name
string filenameBase = $"info-{DateTime.Now:yyyy-MM-dd_HHmmss.ffff}";
#if NETCOREAPP
// If we have the JSON flag
if (json)
if (options.Json)
{
// Create the output data
string serializedData = wrapper.ExportJSON();
Console.WriteLine(serializedData);
// Write the output data
using var jsw = new StreamWriter(File.OpenWrite($"{filenameBase}.json"));
jsw.WriteLine(serializedData);
jsw.Flush();
}
#endif
@@ -117,16 +132,77 @@ namespace InfoPrint
return;
}
// Write the output data
Console.WriteLine(builder);
// Only print to console if enabled
if (!options.FileOnly)
Console.WriteLine(builder);
using var sw = new StreamWriter(File.OpenWrite($"{filenameBase}.txt"));
sw.WriteLine(builder.ToString());
sw.Flush();
}
catch (Exception ex)
{
Console.WriteLine(options.Debug ? ex : "[Exception opening file, please try again]");
Console.WriteLine();
}
}
/// <summary>
/// Print hash information for a single file, if possible
/// </summary>
/// <param name="file">File path</param>
/// <param name="debug">Enable debug output</param>
/// <returns>StringBuilder representing the hash information, if possible</returns>
private static StringBuilder? PrintHashInfo(string file, bool debug)
{
// Ignore missing files
if (!File.Exists(file))
return null;
Console.WriteLine($"Attempting to hash {file}, this may take a while...");
try
{
// Get all file hashes for flexibility
var hashes = HashTool.GetFileHashes(file);
if (hashes == null)
{
if (debug) Console.WriteLine($"Hashes for {file} could not be retrieved");
return null;
}
// Output subset of available hashes
var builder = new StringBuilder();
if (hashes.TryGetValue(HashType.CRC16, out string? crc16) && crc16 != null)
builder.AppendLine($"CRC-16 checksum: {crc16}");
if (hashes.TryGetValue(HashType.CRC32, out string? crc32) && crc32 != null)
builder.AppendLine($"CRC-32 checksum: {crc32}");
if (hashes.TryGetValue(HashType.MD2, out string? md2) && md2 != null)
builder.AppendLine($"MD2 hash: {md2}");
if (hashes.TryGetValue(HashType.MD4, out string? md4) && md4 != null)
builder.AppendLine($"MD4 hash: {md4}");
if (hashes.TryGetValue(HashType.MD5, out string? md5) && md5 != null)
builder.AppendLine($"MD5 hash: {md5}");
if (hashes.TryGetValue(HashType.RIPEMD128, out string? ripemd128) && ripemd128 != null)
builder.AppendLine($"RIPEMD-128 hash: {ripemd128}");
if (hashes.TryGetValue(HashType.RIPEMD160, out string? ripemd160) && ripemd160 != null)
builder.AppendLine($"RIPEMD-160 hash: {ripemd160}");
if (hashes.TryGetValue(HashType.SHA1, out string? sha1) && sha1 != null)
builder.AppendLine($"SHA-1 hash: {sha1}");
if (hashes.TryGetValue(HashType.SHA256, out string? sha256) && sha256 != null)
builder.AppendLine($"SHA-256 hash: {sha256}");
if (hashes.TryGetValue(HashType.SHA384, out string? sha384) && sha384 != null)
builder.AppendLine($"SHA-384 hash: {sha384}");
if (hashes.TryGetValue(HashType.SHA512, out string? sha512) && sha512 != null)
builder.AppendLine($"SHA-512 hash: {sha512}");
return builder;
}
catch (Exception ex)
{
Console.WriteLine(debug ? ex : "[Exception opening file, please try again]");
Console.WriteLine();
return null;
}
}
}
}
}

View File

@@ -6,12 +6,78 @@ This library comprises of serializers that both read and write from files and st
Find the link to the Nuget package [here](https://www.nuget.org/packages/SabreTools.Serialization).
The following non-project libraries (or ports thereof) are used for file handling:
- [SharpCompress](https://github.com/adamhathcock/sharpcompress) - Common archive format extraction
- [StormLibSharp](https://github.com/robpaveza/stormlibsharp) - MoPaQ extraction [Unused in .NET Framework 2.0/3.5/4.0, non-Windows, and non-x86 builds due to Windows-specific libraries]
The following projects have influenced this library:
- [libmspack](https://github.com/kyz/libmspack) - Documentation around the MS-CAB format and associated compression methods.
- [Unshield](https://github.com/twogood/unshield/) - InstallShield CAB extraction tool that influenced internal handling
## Releases
For the most recent stable build, download the latest release here: [Releases Page](https://github.com/SabreTools/SabreTools.Serialization/releases)
For the latest WIP build here: [Rolling Release](https://github.com/SabreTools/SabreTools.Serialization/releases/tag/rolling)
## InfoPrint
**InfoPrint** is a reference implementation for the deserialization and printing features of the library, packaged as a standalone executable for all supported platforms. It will attempt to detect and display information about many supported file types, optionally both hashing the file and outputting the information to a JSON file (.NET Core 3.1 and above only).
```
InfoPrint <options> file|directory ...
Options:
-?, -h, --help Display this help text and quit
-d, --debug Enable debug mode
-c, --hash Output file hashes
-j, --json Print info as JSON
```
## ExtractionTool
**ExtractionTool** is a reference implementation for the extraction features of the library, packaged as a standalone executable for all supported platforms. It will attempt to detect and extract many supported file types. See the table below for supported extraction functionality.
```
ExtractionTool.exe <options> file|directory ...
Options:
-?, -h, --help Display this help text and quit
-d, --debug Enable debug mode
-o, --outdir [PATH] Set output path for extraction (required)
```
| Format Name | Notes |
| --- | --- |
| 7-zip archive | .NET Framework 4.6.2 and greater |
| BFPK custom archive format | |
| bzip2 archive | .NET Framework 4.6.2 and greater |
| Compound File Binary (CFB) | Only CFB common pieces extractable. .NET Framework 4.0 and greater |
| gzip archive | |
| Half-Life Game Cache File (GCF) | |
| Half-Life Level (BSP) | |
| Half-Life Package File (PAK) | |
| Half-Life Texture Package File (WAD3) | |
| Half-Life 2 Level (VBSP) | |
| InstallShield Archive V3 (Z) | |
| InstallShield CAB | |
| Microsoft cabinet file | Does not support LZX or Quantum compression |
| Microsoft LZ-compressed files | KWAJ, QBasic, and SZDD variants |
| MoPaQ game data archive (MPQ) | Currently not working. Windows only. .NET Framework 4.5.2 and above |
| New Exectuable | Embedded archives and executables in the overlay and Wise installer |
| NovaLogic Game Archive Format (PFF) | |
| PKZIP and derived files (ZIP, etc.) | .NET Framework 4.6.2 and greater |
| Portable Executable | Embedded archives and executables in the resources and overlay, CExe-packed data, SFX archives (7-zip, PKZIP, and RAR), and Wise installer |
| Quantum archive (Q) | Currently not working |
| RAR archive (RAR) | .NET Framework 4.6.2 and greater |
| SGA game archive | |
| Tape archive (TAR) | |
| Valve Package File (VPK) | |
| XBox Package File (XZP) | |
| xz archive (XZ) | .NET Framework 4.6.2 and greater |
## Interfaces
Below is a table representing the various conversion interfaces that are implemented within this library.
@@ -32,6 +98,7 @@ Below is a table representing the various non-conversion interfaces that are imp
| Interface Name | Purpose |
| --- | --- |
| `IExtractable` | Marks a wrapper as able to be extracted |
| `IPrinter` | Provides a formatted output for a model |
| `IWrapper` / `IWrapper<T>` | Wraps a model or set of models to provide additional functionality |

View File

@@ -28,10 +28,11 @@ namespace SabreTools.Serialization.Test.CrossModel
Validate(newDf.Header);
Assert.NotNull(newDf.Game);
var newGame = Assert.Single(newDf.Game);
Validate(newGame);
Assert.Equal(2, newDf.Game.Length);
Validate(newDf.Game[0], nested: false);
Validate(newDf.Game[1], nested: true);
// TODO: Unsupported
// TODO: Unsupported for round-trip
Assert.Null(newDf.Dir);
}
@@ -59,10 +60,11 @@ namespace SabreTools.Serialization.Test.CrossModel
Validate(newDf.Header);
Assert.NotNull(newDf.Game);
var newGame = Assert.Single(newDf.Game);
Validate(newGame);
Assert.Equal(2, newDf.Game.Length);
Validate(newDf.Game[0], nested: false);
Validate(newDf.Game[1], nested: true);
// TODO: Unsupported
// TODO: Unsupported for round-trip
Assert.Null(newDf.Dir);
}
@@ -253,6 +255,18 @@ namespace SabreTools.Serialization.Test.CrossModel
gameBase.Driver = driver;
gameBase.SoftwareList = [softwarelist];
var subdir = new Models.Logiqx.Dir
{
Name = "XXXXXX",
Game = [gameBase],
};
var dir = new Models.Logiqx.Dir
{
Name = "XXXXXX",
Subdir = [subdir],
};
return new Models.Logiqx.Datafile
{
Build = "XXXXXX",
@@ -260,7 +274,7 @@ namespace SabreTools.Serialization.Test.CrossModel
SchemaLocation = "XXXXXX",
Header = header,
Game = [gameBase],
// Dir = [dir], // TODO: Unsupported
Dir = [dir],
};
}
@@ -317,10 +331,13 @@ namespace SabreTools.Serialization.Test.CrossModel
/// <summary>
/// Validate a GameBase
/// </summary>
private static void Validate(Models.Logiqx.GameBase? gb)
private static void Validate(Models.Logiqx.GameBase? gb, bool nested)
{
Assert.NotNull(gb);
Assert.Equal("XXXXXX", gb.Name);
if (nested)
Assert.Equal("XXXXXX\\XXXXXX\\XXXXXX", gb.Name);
else
Assert.Equal("XXXXXX", gb.Name);
Assert.Equal("XXXXXX", gb.SourceFile);
Assert.Equal("XXXXXX", gb.IsBios);
Assert.Equal("XXXXXX", gb.IsDevice);

View File

@@ -0,0 +1,872 @@
using Xunit;
namespace SabreTools.Serialization.Test.CrossModel
{
public class MessTests
{
[Fact]
public void RoundTripGameTest()
{
// Get the cross-model serializer
var serializer = new Serialization.CrossModel.Mess();
// Build the data
Models.Listxml.Mess m1 = Build(game: true);
// Serialize to generic model
Models.Metadata.MetadataFile? metadata = serializer.Serialize(m1);
Assert.NotNull(metadata);
// Serialize back to original model
Models.Listxml.Mess? newMess = serializer.Deserialize(metadata);
// Validate the data
Assert.NotNull(newMess);
Assert.Equal("XXXXXX", newMess.Version);
Assert.NotNull(newMess.Game);
var newGame = Assert.Single(newMess.Game);
Validate(newGame);
}
[Fact]
public void RoundTripMachineTest()
{
// Get the cross-model serializer
var serializer = new Serialization.CrossModel.Mess();
// Build the data
Models.Listxml.Mess m1 = Build(game: false);
// Serialize to generic model
Models.Metadata.MetadataFile? metadata = serializer.Serialize(m1);
Assert.NotNull(metadata);
// Serialize back to original model
Models.Listxml.Mess? newMess = serializer.Deserialize(metadata);
// Validate the data
Assert.NotNull(newMess);
Assert.Equal("XXXXXX", newMess.Version);
Assert.NotNull(newMess.Game);
var newGame = Assert.Single(newMess.Game);
Validate(newGame);
}
/// <summary>
/// Build model for serialization and deserialization
/// </summary>
private static Models.Listxml.Mess Build(bool game)
{
var biosset = new Models.Listxml.BiosSet
{
Name = "XXXXXX",
Description = "XXXXXX",
Default = "XXXXXX",
};
var rom = new Models.Listxml.Rom
{
Name = "XXXXXX",
Bios = "XXXXXX",
Size = "XXXXXX",
CRC = "XXXXXX",
SHA1 = "XXXXXX",
Merge = "XXXXXX",
Region = "XXXXXX",
Offset = "XXXXXX",
Status = "XXXXXX",
Optional = "XXXXXX",
Dispose = "XXXXXX",
SoundOnly = "XXXXXX",
};
var disk = new Models.Listxml.Disk
{
Name = "XXXXXX",
MD5 = "XXXXXX",
SHA1 = "XXXXXX",
Merge = "XXXXXX",
Region = "XXXXXX",
Index = "XXXXXX",
Writable = "XXXXXX",
Status = "XXXXXX",
Optional = "XXXXXX",
};
var deviceref = new Models.Listxml.DeviceRef
{
Name = "XXXXXX",
};
var sample = new Models.Listxml.Sample
{
Name = "XXXXXX",
};
var chip = new Models.Listxml.Chip
{
Name = "XXXXXX",
Tag = "XXXXXX",
Type = "XXXXXX",
SoundOnly = "XXXXXX",
Clock = "XXXXXX",
};
var display = new Models.Listxml.Display
{
Tag = "XXXXXX",
Type = "XXXXXX",
Rotate = "XXXXXX",
FlipX = "XXXXXX",
Width = "XXXXXX",
Height = "XXXXXX",
Refresh = "XXXXXX",
PixClock = "XXXXXX",
HTotal = "XXXXXX",
HBEnd = "XXXXXX",
HBStart = "XXXXXX",
VTotal = "XXXXXX",
VBEnd = "XXXXXX",
VBStart = "XXXXXX",
};
var video = new Models.Listxml.Video
{
Screen = "XXXXXX",
Orientation = "XXXXXX",
Width = "XXXXXX",
Height = "XXXXXX",
AspectX = "XXXXXX",
AspectY = "XXXXXX",
Refresh = "XXXXXX",
};
var sound = new Models.Listxml.Sound
{
Channels = "XXXXXX",
};
var control = new Models.Listxml.Control
{
Type = "XXXXXX",
Player = "XXXXXX",
Buttons = "XXXXXX",
ReqButtons = "XXXXXX",
Minimum = "XXXXXX",
Maximum = "XXXXXX",
Sensitivity = "XXXXXX",
KeyDelta = "XXXXXX",
Reverse = "XXXXXX",
Ways = "XXXXXX",
Ways2 = "XXXXXX",
Ways3 = "XXXXXX",
};
var input = new Models.Listxml.Input
{
Service = "XXXXXX",
Tilt = "XXXXXX",
Players = "XXXXXX",
//ControlAttr = "XXXXXX", // Mututally exclusive with input.Control
Buttons = "XXXXXX",
Coins = "XXXXXX",
Control = [control],
};
var condition = new Models.Listxml.Condition
{
Tag = "XXXXXX",
Mask = "XXXXXX",
Relation = "XXXXXX",
Value = "XXXXXX",
};
var diplocation = new Models.Listxml.DipLocation
{
Name = "XXXXXX",
Number = "XXXXXX",
Inverted = "XXXXXX",
};
var dipvalue = new Models.Listxml.DipValue
{
Name = "XXXXXX",
Value = "XXXXXX",
Default = "XXXXXX",
Condition = condition,
};
var dipswitch = new Models.Listxml.DipSwitch
{
Name = "XXXXXX",
Tag = "XXXXXX",
Mask = "XXXXXX",
Condition = condition,
DipLocation = [diplocation],
DipValue = [dipvalue],
};
var conflocation = new Models.Listxml.ConfLocation
{
Name = "XXXXXX",
Number = "XXXXXX",
Inverted = "XXXXXX",
};
var confsetting = new Models.Listxml.ConfSetting
{
Name = "XXXXXX",
Value = "XXXXXX",
Default = "XXXXXX",
Condition = condition,
};
var configuration = new Models.Listxml.Configuration
{
Name = "XXXXXX",
Tag = "XXXXXX",
Mask = "XXXXXX",
Condition = condition,
ConfLocation = [conflocation],
ConfSetting = [confsetting],
};
var analog = new Models.Listxml.Analog
{
Mask = "XXXXXX",
};
var port = new Models.Listxml.Port
{
Tag = "XXXXXX",
Analog = [analog],
};
var adjuster = new Models.Listxml.Adjuster
{
Name = "XXXXXX",
Default = "XXXXXX",
Condition = condition,
};
var driver = new Models.Listxml.Driver
{
Status = "XXXXXX",
Color = "XXXXXX",
Sound = "XXXXXX",
PaletteSize = "XXXXXX",
Emulation = "XXXXXX",
Cocktail = "XXXXXX",
SaveState = "XXXXXX",
RequiresArtwork = "XXXXXX",
Unofficial = "XXXXXX",
NoSoundHardware = "XXXXXX",
Incomplete = "XXXXXX",
};
var feature = new Models.Listxml.Feature
{
Type = "XXXXXX",
Status = "XXXXXX",
Overall = "XXXXXX",
};
var instance = new Models.Listxml.Instance
{
Name = "XXXXXX",
BriefName = "XXXXXX",
};
var extension = new Models.Listxml.Extension
{
Name = "XXXXXX",
};
var device = new Models.Listxml.Device
{
Type = "XXXXXX",
Tag = "XXXXXX",
FixedImage = "XXXXXX",
Mandatory = "XXXXXX",
Interface = "XXXXXX",
Instance = instance,
Extension = [extension],
};
var slotOption = new Models.Listxml.SlotOption
{
Name = "XXXXXX",
DevName = "XXXXXX",
Default = "XXXXXX",
};
var slot = new Models.Listxml.Slot
{
Name = "XXXXXX",
SlotOption = [slotOption],
};
var softwarelist = new Models.Listxml.SoftwareList
{
Tag = "XXXXXX",
Name = "XXXXXX",
Status = "XXXXXX",
Filter = "XXXXXX",
};
var ramoption = new Models.Listxml.RamOption
{
Name = "XXXXXX",
Default = "XXXXXX",
Content = "XXXXXX",
};
Models.Listxml.GameBase gameBase = game
? new Models.Listxml.Game()
: new Models.Listxml.Machine();
gameBase.Name = "XXXXXX";
gameBase.SourceFile = "XXXXXX";
gameBase.IsBios = "XXXXXX";
gameBase.IsDevice = "XXXXXX";
gameBase.IsMechanical = "XXXXXX";
gameBase.Runnable = "XXXXXX";
gameBase.CloneOf = "XXXXXX";
gameBase.RomOf = "XXXXXX";
gameBase.SampleOf = "XXXXXX";
gameBase.Description = "XXXXXX";
gameBase.Year = "XXXXXX";
gameBase.Manufacturer = "XXXXXX";
gameBase.History = "XXXXXX";
gameBase.BiosSet = [biosset];
gameBase.Rom = [rom];
gameBase.Disk = [disk];
gameBase.DeviceRef = [deviceref];
gameBase.Sample = [sample];
gameBase.Chip = [chip];
gameBase.Display = [display];
gameBase.Video = [video];
gameBase.Sound = sound;
gameBase.Input = input;
gameBase.DipSwitch = [dipswitch];
gameBase.Configuration = [configuration];
gameBase.Port = [port];
gameBase.Adjuster = [adjuster];
gameBase.Driver = driver;
gameBase.Feature = [feature];
gameBase.Device = [device];
gameBase.Slot = [slot];
gameBase.SoftwareList = [softwarelist];
gameBase.RamOption = [ramoption];
return new Models.Listxml.Mess
{
Version = "XXXXXX",
Game = [gameBase],
};
}
/// <summary>
/// Validate a GameBase
/// </summary>
private static void Validate(Models.Listxml.GameBase? gb)
{
Assert.NotNull(gb);
Assert.Equal("XXXXXX", gb.Name);
Assert.Equal("XXXXXX", gb.SourceFile);
Assert.Equal("XXXXXX", gb.IsBios);
Assert.Equal("XXXXXX", gb.IsDevice);
Assert.Equal("XXXXXX", gb.IsMechanical);
Assert.Equal("XXXXXX", gb.Runnable);
Assert.Equal("XXXXXX", gb.CloneOf);
Assert.Equal("XXXXXX", gb.RomOf);
Assert.Equal("XXXXXX", gb.SampleOf);
Assert.Equal("XXXXXX", gb.Description);
Assert.Equal("XXXXXX", gb.Year);
Assert.Equal("XXXXXX", gb.Manufacturer);
Assert.Equal("XXXXXX", gb.History);
Assert.NotNull(gb.BiosSet);
var biosset = Assert.Single(gb.BiosSet);
Validate(biosset);
Assert.NotNull(gb.Rom);
var rom = Assert.Single(gb.Rom);
Validate(rom);
Assert.NotNull(gb.Disk);
var disk = Assert.Single(gb.Disk);
Validate(disk);
Assert.NotNull(gb.DeviceRef);
var deviceref = Assert.Single(gb.DeviceRef);
Validate(deviceref);
Assert.NotNull(gb.Sample);
var sample = Assert.Single(gb.Sample);
Validate(sample);
Assert.NotNull(gb.Chip);
var chip = Assert.Single(gb.Chip);
Validate(chip);
Assert.NotNull(gb.Display);
var display = Assert.Single(gb.Display);
Validate(display);
Assert.NotNull(gb.Video);
var video = Assert.Single(gb.Video);
Validate(video);
Validate(gb.Sound);
Validate(gb.Input);
Assert.NotNull(gb.DipSwitch);
var dipswitch = Assert.Single(gb.DipSwitch);
Validate(dipswitch);
Assert.NotNull(gb.Configuration);
var configuration = Assert.Single(gb.Configuration);
Validate(configuration);
Assert.NotNull(gb.Port);
var port = Assert.Single(gb.Port);
Validate(port);
Assert.NotNull(gb.Adjuster);
var adjuster = Assert.Single(gb.Adjuster);
Validate(adjuster);
Validate(gb.Driver);
Assert.NotNull(gb.Feature);
var feature = Assert.Single(gb.Feature);
Validate(feature);
Assert.NotNull(gb.Device);
var device = Assert.Single(gb.Device);
Validate(device);
Assert.NotNull(gb.Slot);
var slot = Assert.Single(gb.Slot);
Validate(slot);
Assert.NotNull(gb.SoftwareList);
var softwarelist = Assert.Single(gb.SoftwareList);
Validate(softwarelist);
Assert.NotNull(gb.RamOption);
var ramoption = Assert.Single(gb.RamOption);
Validate(ramoption);
}
/// <summary>
/// Validate a BiosSet
/// </summary>
private static void Validate(Models.Listxml.BiosSet? biosset)
{
Assert.NotNull(biosset);
Assert.Equal("XXXXXX", biosset.Name);
Assert.Equal("XXXXXX", biosset.Description);
Assert.Equal("XXXXXX", biosset.Default);
}
/// <summary>
/// Validate a Rom
/// </summary>
private static void Validate(Models.Listxml.Rom? rom)
{
Assert.NotNull(rom);
Assert.Equal("XXXXXX", rom.Name);
Assert.Equal("XXXXXX", rom.Bios);
Assert.Equal("XXXXXX", rom.Size);
Assert.Equal("XXXXXX", rom.CRC);
Assert.Equal("XXXXXX", rom.SHA1);
Assert.Equal("XXXXXX", rom.Merge);
Assert.Equal("XXXXXX", rom.Region);
Assert.Equal("XXXXXX", rom.Offset);
Assert.Equal("XXXXXX", rom.Status);
Assert.Equal("XXXXXX", rom.Optional);
Assert.Equal("XXXXXX", rom.Dispose);
Assert.Equal("XXXXXX", rom.SoundOnly);
}
/// <summary>
/// Validate a Disk
/// </summary>
private static void Validate(Models.Listxml.Disk? disk)
{
Assert.NotNull(disk);
Assert.Equal("XXXXXX", disk.Name);
Assert.Equal("XXXXXX", disk.MD5);
Assert.Equal("XXXXXX", disk.SHA1);
Assert.Equal("XXXXXX", disk.Merge);
Assert.Equal("XXXXXX", disk.Region);
Assert.Equal("XXXXXX", disk.Index);
Assert.Equal("XXXXXX", disk.Writable);
Assert.Equal("XXXXXX", disk.Status);
Assert.Equal("XXXXXX", disk.Optional);
}
/// <summary>
/// Validate a DeviceRef
/// </summary>
private static void Validate(Models.Listxml.DeviceRef? deviceref)
{
Assert.NotNull(deviceref);
Assert.Equal("XXXXXX", deviceref.Name);
}
/// <summary>
/// Validate a Sample
/// </summary>
private static void Validate(Models.Listxml.Sample? sample)
{
Assert.NotNull(sample);
Assert.Equal("XXXXXX", sample.Name);
}
/// <summary>
/// Validate a Chip
/// </summary>
private static void Validate(Models.Listxml.Chip? chip)
{
Assert.NotNull(chip);
Assert.Equal("XXXXXX", chip.Name);
Assert.Equal("XXXXXX", chip.Tag);
Assert.Equal("XXXXXX", chip.Type);
Assert.Equal("XXXXXX", chip.SoundOnly);
Assert.Equal("XXXXXX", chip.Clock);
}
/// <summary>
/// Validate a Display
/// </summary>
private static void Validate(Models.Listxml.Display? display)
{
Assert.NotNull(display);
Assert.Equal("XXXXXX", display.Tag);
Assert.Equal("XXXXXX", display.Type);
Assert.Equal("XXXXXX", display.Rotate);
Assert.Equal("XXXXXX", display.FlipX);
Assert.Equal("XXXXXX", display.Width);
Assert.Equal("XXXXXX", display.Height);
Assert.Equal("XXXXXX", display.Refresh);
Assert.Equal("XXXXXX", display.PixClock);
Assert.Equal("XXXXXX", display.HTotal);
Assert.Equal("XXXXXX", display.HBEnd);
Assert.Equal("XXXXXX", display.HBStart);
Assert.Equal("XXXXXX", display.VTotal);
Assert.Equal("XXXXXX", display.VBEnd);
Assert.Equal("XXXXXX", display.VBStart);
}
/// <summary>
/// Validate a Video
/// </summary>
private static void Validate(Models.Listxml.Video? video)
{
Assert.NotNull(video);
Assert.Equal("XXXXXX", video.Screen);
Assert.Equal("XXXXXX", video.Orientation);
Assert.Equal("XXXXXX", video.Width);
Assert.Equal("XXXXXX", video.Height);
Assert.Equal("XXXXXX", video.AspectX);
Assert.Equal("XXXXXX", video.AspectY);
Assert.Equal("XXXXXX", video.Refresh);
}
/// <summary>
/// Validate a Sound
/// </summary>
private static void Validate(Models.Listxml.Sound? sound)
{
Assert.NotNull(sound);
Assert.Equal("XXXXXX", sound.Channels);
}
/// <summary>
/// Validate a Input
/// </summary>
private static void Validate(Models.Listxml.Input? input)
{
Assert.NotNull(input);
Assert.Equal("XXXXXX", input.Service);
Assert.Equal("XXXXXX", input.Tilt);
Assert.Equal("XXXXXX", input.Players);
//Assert.Equal("XXXXXX", input.ControlAttr); // Mututally exclusive with input.Control
Assert.Equal("XXXXXX", input.Buttons);
Assert.Equal("XXXXXX", input.Coins);
Assert.NotNull(input.Control);
var control = Assert.Single(input.Control);
Validate(control);
}
/// <summary>
/// Validate a Control
/// </summary>
private static void Validate(Models.Listxml.Control? control)
{
Assert.NotNull(control);
Assert.Equal("XXXXXX", control.Type);
Assert.Equal("XXXXXX", control.Player);
Assert.Equal("XXXXXX", control.Buttons);
Assert.Equal("XXXXXX", control.ReqButtons);
Assert.Equal("XXXXXX", control.Minimum);
Assert.Equal("XXXXXX", control.Maximum);
Assert.Equal("XXXXXX", control.Sensitivity);
Assert.Equal("XXXXXX", control.KeyDelta);
Assert.Equal("XXXXXX", control.Reverse);
Assert.Equal("XXXXXX", control.Ways);
Assert.Equal("XXXXXX", control.Ways2);
Assert.Equal("XXXXXX", control.Ways3);
}
/// <summary>
/// Validate a DipSwitch
/// </summary>
private static void Validate(Models.Listxml.DipSwitch? dipswitch)
{
Assert.NotNull(dipswitch);
Assert.Equal("XXXXXX", dipswitch.Name);
Assert.Equal("XXXXXX", dipswitch.Tag);
Assert.Equal("XXXXXX", dipswitch.Mask);
Validate(dipswitch.Condition);
Assert.NotNull(dipswitch.DipLocation);
var diplocation = Assert.Single(dipswitch.DipLocation);
Validate(diplocation);
Assert.NotNull(dipswitch.DipValue);
var dipvalue = Assert.Single(dipswitch.DipValue);
Validate(dipvalue);
}
/// <summary>
/// Validate a Condition
/// </summary>
private static void Validate(Models.Listxml.Condition? condition)
{
Assert.NotNull(condition);
Assert.Equal("XXXXXX", condition.Tag);
Assert.Equal("XXXXXX", condition.Mask);
Assert.Equal("XXXXXX", condition.Relation);
Assert.Equal("XXXXXX", condition.Value);
}
/// <summary>
/// Validate a DipLocation
/// </summary>
private static void Validate(Models.Listxml.DipLocation? diplocation)
{
Assert.NotNull(diplocation);
Assert.Equal("XXXXXX", diplocation.Name);
Assert.Equal("XXXXXX", diplocation.Number);
Assert.Equal("XXXXXX", diplocation.Inverted);
}
/// <summary>
/// Validate a DipValue
/// </summary>
private static void Validate(Models.Listxml.DipValue? dipvalue)
{
Assert.NotNull(dipvalue);
Assert.Equal("XXXXXX", dipvalue.Name);
Assert.Equal("XXXXXX", dipvalue.Value);
Assert.Equal("XXXXXX", dipvalue.Default);
Validate(dipvalue.Condition);
}
/// <summary>
/// Validate a Configuration
/// </summary>
private static void Validate(Models.Listxml.Configuration? configuration)
{
Assert.NotNull(configuration);
Assert.Equal("XXXXXX", configuration.Name);
Assert.Equal("XXXXXX", configuration.Tag);
Assert.Equal("XXXXXX", configuration.Mask);
Validate(configuration.Condition);
Assert.NotNull(configuration.ConfLocation);
var conflocation = Assert.Single(configuration.ConfLocation);
Validate(conflocation);
Assert.NotNull(configuration.ConfSetting);
var confsetting = Assert.Single(configuration.ConfSetting);
Validate(confsetting);
}
/// <summary>
/// Validate a ConfLocation
/// </summary>
private static void Validate(Models.Listxml.ConfLocation? conflocation)
{
Assert.NotNull(conflocation);
Assert.Equal("XXXXXX", conflocation.Name);
Assert.Equal("XXXXXX", conflocation.Number);
Assert.Equal("XXXXXX", conflocation.Inverted);
}
/// <summary>
/// Validate a ConfSetting
/// </summary>
private static void Validate(Models.Listxml.ConfSetting? confsetting)
{
Assert.NotNull(confsetting);
Assert.Equal("XXXXXX", confsetting.Name);
Assert.Equal("XXXXXX", confsetting.Value);
Assert.Equal("XXXXXX", confsetting.Default);
Validate(confsetting.Condition);
}
/// <summary>
/// Validate a Port
/// </summary>
private static void Validate(Models.Listxml.Port? port)
{
Assert.NotNull(port);
Assert.Equal("XXXXXX", port.Tag);
Assert.NotNull(port.Analog);
var analog = Assert.Single(port.Analog);
Validate(analog);
}
/// <summary>
/// Validate a Analog
/// </summary>
private static void Validate(Models.Listxml.Analog? analog)
{
Assert.NotNull(analog);
Assert.Equal("XXXXXX", analog.Mask);
}
/// <summary>
/// Validate a Adjuster
/// </summary>
private static void Validate(Models.Listxml.Adjuster? adjuster)
{
Assert.NotNull(adjuster);
Assert.Equal("XXXXXX", adjuster.Name);
Assert.Equal("XXXXXX", adjuster.Default);
Validate(adjuster.Condition);
}
/// <summary>
/// Validate a Driver
/// </summary>
private static void Validate(Models.Listxml.Driver? driver)
{
Assert.NotNull(driver);
Assert.Equal("XXXXXX", driver.Status);
Assert.Equal("XXXXXX", driver.Color);
Assert.Equal("XXXXXX", driver.Sound);
Assert.Equal("XXXXXX", driver.PaletteSize);
Assert.Equal("XXXXXX", driver.Emulation);
Assert.Equal("XXXXXX", driver.Cocktail);
Assert.Equal("XXXXXX", driver.SaveState);
Assert.Equal("XXXXXX", driver.RequiresArtwork);
Assert.Equal("XXXXXX", driver.Unofficial);
Assert.Equal("XXXXXX", driver.NoSoundHardware);
Assert.Equal("XXXXXX", driver.Incomplete);
}
/// <summary>
/// Validate a Feature
/// </summary>
private static void Validate(Models.Listxml.Feature? feature)
{
Assert.NotNull(feature);
Assert.Equal("XXXXXX", feature.Type);
Assert.Equal("XXXXXX", feature.Status);
Assert.Equal("XXXXXX", feature.Overall);
}
/// <summary>
/// Validate a Device
/// </summary>
private static void Validate(Models.Listxml.Device? device)
{
Assert.NotNull(device);
Assert.Equal("XXXXXX", device.Type);
Assert.Equal("XXXXXX", device.Tag);
Assert.Equal("XXXXXX", device.FixedImage);
Assert.Equal("XXXXXX", device.Mandatory);
Assert.Equal("XXXXXX", device.Interface);
Validate(device.Instance);
Assert.NotNull(device.Extension);
var extension = Assert.Single(device.Extension);
Validate(extension);
}
/// <summary>
/// Validate a Instance
/// </summary>
private static void Validate(Models.Listxml.Instance? instance)
{
Assert.NotNull(instance);
Assert.Equal("XXXXXX", instance.Name);
Assert.Equal("XXXXXX", instance.BriefName);
}
/// <summary>
/// Validate a Extension
/// </summary>
private static void Validate(Models.Listxml.Extension? extension)
{
Assert.NotNull(extension);
Assert.Equal("XXXXXX", extension.Name);
}
/// <summary>
/// Validate a Slot
/// </summary>
private static void Validate(Models.Listxml.Slot? slot)
{
Assert.NotNull(slot);
Assert.Equal("XXXXXX", slot.Name);
Assert.NotNull(slot.SlotOption);
var slotoption = Assert.Single(slot.SlotOption);
Validate(slotoption);
}
/// <summary>
/// Validate a SlotOption
/// </summary>
private static void Validate(Models.Listxml.SlotOption? slotoption)
{
Assert.NotNull(slotoption);
Assert.Equal("XXXXXX", slotoption.Name);
Assert.Equal("XXXXXX", slotoption.DevName);
Assert.Equal("XXXXXX", slotoption.Default);
}
/// <summary>
/// Validate a SoftwareList
/// </summary>
private static void Validate(Models.Listxml.SoftwareList? softwarelist)
{
Assert.NotNull(softwarelist);
Assert.Equal("XXXXXX", softwarelist.Tag);
Assert.Equal("XXXXXX", softwarelist.Name);
Assert.Equal("XXXXXX", softwarelist.Status);
Assert.Equal("XXXXXX", softwarelist.Filter);
}
/// <summary>
/// Validate a RamOption
/// </summary>
private static void Validate(Models.Listxml.RamOption? ramoption)
{
Assert.NotNull(ramoption);
Assert.Equal("XXXXXX", ramoption.Name);
Assert.Equal("XXXXXX", ramoption.Default);
Assert.Equal("XXXXXX", ramoption.Content);
}
}
}

View File

@@ -1,4 +1,3 @@
using System;
using System.IO;
using System.Linq;
using SabreTools.Serialization.Deserializers;
@@ -96,6 +95,31 @@ namespace SabreTools.Serialization.Test.Deserializers
Validate(newGame);
}
[Fact]
public void RoundTripGameWithoutQuotesTest()
{
// Get the serializer and deserializer
var deserializer = new Serialization.Deserializers.ClrMamePro();
var serializer = new Serialization.Serializers.ClrMamePro();
// Build the data
Models.ClrMamePro.MetadataFile mf = Build(game: true);
// Serialize to stream
Stream? actual = serializer.Serialize(mf, quotes: false);
Assert.NotNull(actual);
// Serialize back to original model
Models.ClrMamePro.MetadataFile? newMf = deserializer.Deserialize(actual);
// Validate the data
Assert.NotNull(newMf);
Validate(newMf.ClrMamePro);
Assert.NotNull(newMf.Game);
var newGame = Assert.Single(newMf.Game);
Validate(newGame);
}
[Fact]
public void RoundTripMachineTest()
{
@@ -121,6 +145,31 @@ namespace SabreTools.Serialization.Test.Deserializers
Validate(newGame);
}
[Fact]
public void RoundTripMachineWithoutQuotesTest()
{
// Get the serializer and deserializer
var deserializer = new Serialization.Deserializers.ClrMamePro();
var serializer = new Serialization.Serializers.ClrMamePro();
// Build the data
Models.ClrMamePro.MetadataFile mf = Build(game: false);
// Serialize to stream
Stream? actual = serializer.Serialize(mf, quotes: false);
Assert.NotNull(actual);
// Serialize back to original model
Models.ClrMamePro.MetadataFile? newMf = deserializer.Deserialize(actual);
// Validate the data
Assert.NotNull(newMf);
Validate(newMf.ClrMamePro);
Assert.NotNull(newMf.Game);
var newGame = Assert.Single(newMf.Game);
Validate(newGame);
}
/// <summary>
/// Build model for serialization and deserialization
/// </summary>

View File

@@ -0,0 +1,73 @@
using System.IO;
using System.Linq;
using SabreTools.Serialization.Deserializers;
using Xunit;
namespace SabreTools.Serialization.Test.Deserializers
{
public class GZipTests
{
[Fact]
public void NullArray_Null()
{
byte[]? data = null;
int offset = 0;
var deserializer = new GZip();
var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
}
[Fact]
public void EmptyArray_Null()
{
byte[]? data = [];
int offset = 0;
var deserializer = new GZip();
var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
}
[Fact]
public void InvalidArray_Null()
{
byte[]? data = [.. Enumerable.Repeat<byte>(0xFF, 1024)];
int offset = 0;
var deserializer = new GZip();
var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
}
[Fact]
public void NullStream_Null()
{
Stream? data = null;
var deserializer = new GZip();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}
[Fact]
public void EmptyStream_Null()
{
Stream? data = new MemoryStream([]);
var deserializer = new GZip();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}
[Fact]
public void InvalidStream_Null()
{
Stream? data = new MemoryStream([.. Enumerable.Repeat<byte>(0xFF, 1024)]);
var deserializer = new GZip();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}
}
}

View File

@@ -0,0 +1,940 @@
using System.IO;
using System.Linq;
using SabreTools.Serialization.Deserializers;
using Xunit;
namespace SabreTools.Serialization.Test.Deserializers
{
public class MessTests
{
[Fact]
public void NullArray_Null()
{
byte[]? data = null;
int offset = 0;
var deserializer = new Mess();
var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
}
[Fact]
public void EmptyArray_Null()
{
byte[]? data = [];
int offset = 0;
var deserializer = new Mess();
var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
}
[Fact]
public void InvalidArray_Null()
{
byte[]? data = [.. Enumerable.Repeat<byte>(0xFF, 1024)];
int offset = 0;
var deserializer = new Mess();
var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
}
[Fact]
public void NullStream_Null()
{
Stream? data = null;
var deserializer = new Mess();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}
[Fact]
public void EmptyStream_Null()
{
Stream? data = new MemoryStream([]);
var deserializer = new Mess();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}
[Fact]
public void InvalidStream_Null()
{
Stream? data = new MemoryStream([.. Enumerable.Repeat<byte>(0xFF, 1024)]);
var deserializer = new Mess();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}
[Fact]
public void RoundTripGameTest()
{
// Get the serializer and deserializer
var deserializer = new Serialization.Deserializers.Mess();
var serializer = new Serialization.Serializers.Mess();
// Build the data
Models.Listxml.Mess m1 = Build(game: true);
// Serialize to generic model
Stream? metadata = serializer.Serialize(m1);
Assert.NotNull(metadata);
// Serialize to stream
Models.Listxml.Mess? newMess = deserializer.Deserialize(metadata);
// Validate the data
Assert.NotNull(newMess);
Assert.Equal("XXXXXX", newMess.Version);
Assert.NotNull(newMess.Game);
var newGame = Assert.Single(newMess.Game);
Validate(newGame);
}
[Fact]
public void RoundTripMachineTest()
{
// Get the serializer and deserializer
var deserializer = new Serialization.Deserializers.Mess();
var serializer = new Serialization.Serializers.Mess();
// Build the data
Models.Listxml.Mess m1 = Build(game: false);
// Serialize to generic model
Stream? metadata = serializer.Serialize(m1);
Assert.NotNull(metadata);
// Serialize to stream
Models.Listxml.Mess? newMess = deserializer.Deserialize(metadata);
// Validate the data
Assert.NotNull(newMess);
Assert.Equal("XXXXXX", newMess.Version);
Assert.NotNull(newMess.Game);
var newGame = Assert.Single(newMess.Game);
Validate(newGame);
}
/// <summary>
/// Build model for serialization and deserialization
/// </summary>
private static Models.Listxml.Mess Build(bool game)
{
var biosset = new Models.Listxml.BiosSet
{
Name = "XXXXXX",
Description = "XXXXXX",
Default = "XXXXXX",
};
var rom = new Models.Listxml.Rom
{
Name = "XXXXXX",
Bios = "XXXXXX",
Size = "XXXXXX",
CRC = "XXXXXX",
SHA1 = "XXXXXX",
Merge = "XXXXXX",
Region = "XXXXXX",
Offset = "XXXXXX",
Status = "XXXXXX",
Optional = "XXXXXX",
Dispose = "XXXXXX",
SoundOnly = "XXXXXX",
};
var disk = new Models.Listxml.Disk
{
Name = "XXXXXX",
MD5 = "XXXXXX",
SHA1 = "XXXXXX",
Merge = "XXXXXX",
Region = "XXXXXX",
Index = "XXXXXX",
Writable = "XXXXXX",
Status = "XXXXXX",
Optional = "XXXXXX",
};
var deviceref = new Models.Listxml.DeviceRef
{
Name = "XXXXXX",
};
var sample = new Models.Listxml.Sample
{
Name = "XXXXXX",
};
var chip = new Models.Listxml.Chip
{
Name = "XXXXXX",
Tag = "XXXXXX",
Type = "XXXXXX",
SoundOnly = "XXXXXX",
Clock = "XXXXXX",
};
var display = new Models.Listxml.Display
{
Tag = "XXXXXX",
Type = "XXXXXX",
Rotate = "XXXXXX",
FlipX = "XXXXXX",
Width = "XXXXXX",
Height = "XXXXXX",
Refresh = "XXXXXX",
PixClock = "XXXXXX",
HTotal = "XXXXXX",
HBEnd = "XXXXXX",
HBStart = "XXXXXX",
VTotal = "XXXXXX",
VBEnd = "XXXXXX",
VBStart = "XXXXXX",
};
var video = new Models.Listxml.Video
{
Screen = "XXXXXX",
Orientation = "XXXXXX",
Width = "XXXXXX",
Height = "XXXXXX",
AspectX = "XXXXXX",
AspectY = "XXXXXX",
Refresh = "XXXXXX",
};
var sound = new Models.Listxml.Sound
{
Channels = "XXXXXX",
};
var control = new Models.Listxml.Control
{
Type = "XXXXXX",
Player = "XXXXXX",
Buttons = "XXXXXX",
ReqButtons = "XXXXXX",
Minimum = "XXXXXX",
Maximum = "XXXXXX",
Sensitivity = "XXXXXX",
KeyDelta = "XXXXXX",
Reverse = "XXXXXX",
Ways = "XXXXXX",
Ways2 = "XXXXXX",
Ways3 = "XXXXXX",
};
var input = new Models.Listxml.Input
{
Service = "XXXXXX",
Tilt = "XXXXXX",
Players = "XXXXXX",
//ControlAttr = "XXXXXX", // Mututally exclusive with input.Control
Buttons = "XXXXXX",
Coins = "XXXXXX",
Control = [control],
};
var condition = new Models.Listxml.Condition
{
Tag = "XXXXXX",
Mask = "XXXXXX",
Relation = "XXXXXX",
Value = "XXXXXX",
};
var diplocation = new Models.Listxml.DipLocation
{
Name = "XXXXXX",
Number = "XXXXXX",
Inverted = "XXXXXX",
};
var dipvalue = new Models.Listxml.DipValue
{
Name = "XXXXXX",
Value = "XXXXXX",
Default = "XXXXXX",
Condition = condition,
};
var dipswitch = new Models.Listxml.DipSwitch
{
Name = "XXXXXX",
Tag = "XXXXXX",
Mask = "XXXXXX",
Condition = condition,
DipLocation = [diplocation],
DipValue = [dipvalue],
};
var conflocation = new Models.Listxml.ConfLocation
{
Name = "XXXXXX",
Number = "XXXXXX",
Inverted = "XXXXXX",
};
var confsetting = new Models.Listxml.ConfSetting
{
Name = "XXXXXX",
Value = "XXXXXX",
Default = "XXXXXX",
Condition = condition,
};
var configuration = new Models.Listxml.Configuration
{
Name = "XXXXXX",
Tag = "XXXXXX",
Mask = "XXXXXX",
Condition = condition,
ConfLocation = [conflocation],
ConfSetting = [confsetting],
};
var analog = new Models.Listxml.Analog
{
Mask = "XXXXXX",
};
var port = new Models.Listxml.Port
{
Tag = "XXXXXX",
Analog = [analog],
};
var adjuster = new Models.Listxml.Adjuster
{
Name = "XXXXXX",
Default = "XXXXXX",
Condition = condition,
};
var driver = new Models.Listxml.Driver
{
Status = "XXXXXX",
Color = "XXXXXX",
Sound = "XXXXXX",
PaletteSize = "XXXXXX",
Emulation = "XXXXXX",
Cocktail = "XXXXXX",
SaveState = "XXXXXX",
RequiresArtwork = "XXXXXX",
Unofficial = "XXXXXX",
NoSoundHardware = "XXXXXX",
Incomplete = "XXXXXX",
};
var feature = new Models.Listxml.Feature
{
Type = "XXXXXX",
Status = "XXXXXX",
Overall = "XXXXXX",
};
var instance = new Models.Listxml.Instance
{
Name = "XXXXXX",
BriefName = "XXXXXX",
};
var extension = new Models.Listxml.Extension
{
Name = "XXXXXX",
};
var device = new Models.Listxml.Device
{
Type = "XXXXXX",
Tag = "XXXXXX",
FixedImage = "XXXXXX",
Mandatory = "XXXXXX",
Interface = "XXXXXX",
Instance = instance,
Extension = [extension],
};
var slotOption = new Models.Listxml.SlotOption
{
Name = "XXXXXX",
DevName = "XXXXXX",
Default = "XXXXXX",
};
var slot = new Models.Listxml.Slot
{
Name = "XXXXXX",
SlotOption = [slotOption],
};
var softwarelist = new Models.Listxml.SoftwareList
{
Tag = "XXXXXX",
Name = "XXXXXX",
Status = "XXXXXX",
Filter = "XXXXXX",
};
var ramoption = new Models.Listxml.RamOption
{
Name = "XXXXXX",
Default = "XXXXXX",
Content = "XXXXXX",
};
Models.Listxml.GameBase gameBase = game
? new Models.Listxml.Game()
: new Models.Listxml.Machine();
gameBase.Name = "XXXXXX";
gameBase.SourceFile = "XXXXXX";
gameBase.IsBios = "XXXXXX";
gameBase.IsDevice = "XXXXXX";
gameBase.IsMechanical = "XXXXXX";
gameBase.Runnable = "XXXXXX";
gameBase.CloneOf = "XXXXXX";
gameBase.RomOf = "XXXXXX";
gameBase.SampleOf = "XXXXXX";
gameBase.Description = "XXXXXX";
gameBase.Year = "XXXXXX";
gameBase.Manufacturer = "XXXXXX";
gameBase.History = "XXXXXX";
gameBase.BiosSet = [biosset];
gameBase.Rom = [rom];
gameBase.Disk = [disk];
gameBase.DeviceRef = [deviceref];
gameBase.Sample = [sample];
gameBase.Chip = [chip];
gameBase.Display = [display];
gameBase.Video = [video];
gameBase.Sound = sound;
gameBase.Input = input;
gameBase.DipSwitch = [dipswitch];
gameBase.Configuration = [configuration];
gameBase.Port = [port];
gameBase.Adjuster = [adjuster];
gameBase.Driver = driver;
gameBase.Feature = [feature];
gameBase.Device = [device];
gameBase.Slot = [slot];
gameBase.SoftwareList = [softwarelist];
gameBase.RamOption = [ramoption];
return new Models.Listxml.Mess
{
Version = "XXXXXX",
Game = [gameBase],
};
}
/// <summary>
/// Validate a GameBase
/// </summary>
private static void Validate(Models.Listxml.GameBase? gb)
{
Assert.NotNull(gb);
Assert.Equal("XXXXXX", gb.Name);
Assert.Equal("XXXXXX", gb.SourceFile);
Assert.Equal("XXXXXX", gb.IsBios);
Assert.Equal("XXXXXX", gb.IsDevice);
Assert.Equal("XXXXXX", gb.IsMechanical);
Assert.Equal("XXXXXX", gb.Runnable);
Assert.Equal("XXXXXX", gb.CloneOf);
Assert.Equal("XXXXXX", gb.RomOf);
Assert.Equal("XXXXXX", gb.SampleOf);
Assert.Equal("XXXXXX", gb.Description);
Assert.Equal("XXXXXX", gb.Year);
Assert.Equal("XXXXXX", gb.Manufacturer);
Assert.Equal("XXXXXX", gb.History);
Assert.NotNull(gb.BiosSet);
var biosset = Assert.Single(gb.BiosSet);
Validate(biosset);
Assert.NotNull(gb.Rom);
var rom = Assert.Single(gb.Rom);
Validate(rom);
Assert.NotNull(gb.Disk);
var disk = Assert.Single(gb.Disk);
Validate(disk);
Assert.NotNull(gb.DeviceRef);
var deviceref = Assert.Single(gb.DeviceRef);
Validate(deviceref);
Assert.NotNull(gb.Sample);
var sample = Assert.Single(gb.Sample);
Validate(sample);
Assert.NotNull(gb.Chip);
var chip = Assert.Single(gb.Chip);
Validate(chip);
Assert.NotNull(gb.Display);
var display = Assert.Single(gb.Display);
Validate(display);
Assert.NotNull(gb.Video);
var video = Assert.Single(gb.Video);
Validate(video);
Validate(gb.Sound);
Validate(gb.Input);
Assert.NotNull(gb.DipSwitch);
var dipswitch = Assert.Single(gb.DipSwitch);
Validate(dipswitch);
Assert.NotNull(gb.Configuration);
var configuration = Assert.Single(gb.Configuration);
Validate(configuration);
Assert.NotNull(gb.Port);
var port = Assert.Single(gb.Port);
Validate(port);
Assert.NotNull(gb.Adjuster);
var adjuster = Assert.Single(gb.Adjuster);
Validate(adjuster);
Validate(gb.Driver);
Assert.NotNull(gb.Feature);
var feature = Assert.Single(gb.Feature);
Validate(feature);
Assert.NotNull(gb.Device);
var device = Assert.Single(gb.Device);
Validate(device);
Assert.NotNull(gb.Slot);
var slot = Assert.Single(gb.Slot);
Validate(slot);
Assert.NotNull(gb.SoftwareList);
var softwarelist = Assert.Single(gb.SoftwareList);
Validate(softwarelist);
Assert.NotNull(gb.RamOption);
var ramoption = Assert.Single(gb.RamOption);
Validate(ramoption);
}
/// <summary>
/// Validate a BiosSet
/// </summary>
private static void Validate(Models.Listxml.BiosSet? biosset)
{
Assert.NotNull(biosset);
Assert.Equal("XXXXXX", biosset.Name);
Assert.Equal("XXXXXX", biosset.Description);
Assert.Equal("XXXXXX", biosset.Default);
}
/// <summary>
/// Validate a Rom
/// </summary>
private static void Validate(Models.Listxml.Rom? rom)
{
Assert.NotNull(rom);
Assert.Equal("XXXXXX", rom.Name);
Assert.Equal("XXXXXX", rom.Bios);
Assert.Equal("XXXXXX", rom.Size);
Assert.Equal("XXXXXX", rom.CRC);
Assert.Equal("XXXXXX", rom.SHA1);
Assert.Equal("XXXXXX", rom.Merge);
Assert.Equal("XXXXXX", rom.Region);
Assert.Equal("XXXXXX", rom.Offset);
Assert.Equal("XXXXXX", rom.Status);
Assert.Equal("XXXXXX", rom.Optional);
Assert.Equal("XXXXXX", rom.Dispose);
Assert.Equal("XXXXXX", rom.SoundOnly);
}
/// <summary>
/// Validate a Disk
/// </summary>
private static void Validate(Models.Listxml.Disk? disk)
{
Assert.NotNull(disk);
Assert.Equal("XXXXXX", disk.Name);
Assert.Equal("XXXXXX", disk.MD5);
Assert.Equal("XXXXXX", disk.SHA1);
Assert.Equal("XXXXXX", disk.Merge);
Assert.Equal("XXXXXX", disk.Region);
Assert.Equal("XXXXXX", disk.Index);
Assert.Equal("XXXXXX", disk.Writable);
Assert.Equal("XXXXXX", disk.Status);
Assert.Equal("XXXXXX", disk.Optional);
}
/// <summary>
/// Validate a DeviceRef
/// </summary>
private static void Validate(Models.Listxml.DeviceRef? deviceref)
{
Assert.NotNull(deviceref);
Assert.Equal("XXXXXX", deviceref.Name);
}
/// <summary>
/// Validate a Sample
/// </summary>
private static void Validate(Models.Listxml.Sample? sample)
{
Assert.NotNull(sample);
Assert.Equal("XXXXXX", sample.Name);
}
/// <summary>
/// Validate a Chip
/// </summary>
private static void Validate(Models.Listxml.Chip? chip)
{
Assert.NotNull(chip);
Assert.Equal("XXXXXX", chip.Name);
Assert.Equal("XXXXXX", chip.Tag);
Assert.Equal("XXXXXX", chip.Type);
Assert.Equal("XXXXXX", chip.SoundOnly);
Assert.Equal("XXXXXX", chip.Clock);
}
/// <summary>
/// Validate a Display
/// </summary>
private static void Validate(Models.Listxml.Display? display)
{
Assert.NotNull(display);
Assert.Equal("XXXXXX", display.Tag);
Assert.Equal("XXXXXX", display.Type);
Assert.Equal("XXXXXX", display.Rotate);
Assert.Equal("XXXXXX", display.FlipX);
Assert.Equal("XXXXXX", display.Width);
Assert.Equal("XXXXXX", display.Height);
Assert.Equal("XXXXXX", display.Refresh);
Assert.Equal("XXXXXX", display.PixClock);
Assert.Equal("XXXXXX", display.HTotal);
Assert.Equal("XXXXXX", display.HBEnd);
Assert.Equal("XXXXXX", display.HBStart);
Assert.Equal("XXXXXX", display.VTotal);
Assert.Equal("XXXXXX", display.VBEnd);
Assert.Equal("XXXXXX", display.VBStart);
}
/// <summary>
/// Validate a Video
/// </summary>
private static void Validate(Models.Listxml.Video? video)
{
Assert.NotNull(video);
Assert.Equal("XXXXXX", video.Screen);
Assert.Equal("XXXXXX", video.Orientation);
Assert.Equal("XXXXXX", video.Width);
Assert.Equal("XXXXXX", video.Height);
Assert.Equal("XXXXXX", video.AspectX);
Assert.Equal("XXXXXX", video.AspectY);
Assert.Equal("XXXXXX", video.Refresh);
}
/// <summary>
/// Validate a Sound
/// </summary>
private static void Validate(Models.Listxml.Sound? sound)
{
Assert.NotNull(sound);
Assert.Equal("XXXXXX", sound.Channels);
}
/// <summary>
/// Validate a Input
/// </summary>
private static void Validate(Models.Listxml.Input? input)
{
Assert.NotNull(input);
Assert.Equal("XXXXXX", input.Service);
Assert.Equal("XXXXXX", input.Tilt);
Assert.Equal("XXXXXX", input.Players);
//Assert.Equal("XXXXXX", input.ControlAttr); // Mututally exclusive with input.Control
Assert.Equal("XXXXXX", input.Buttons);
Assert.Equal("XXXXXX", input.Coins);
Assert.NotNull(input.Control);
var control = Assert.Single(input.Control);
Validate(control);
}
/// <summary>
/// Validate a Control
/// </summary>
private static void Validate(Models.Listxml.Control? control)
{
Assert.NotNull(control);
Assert.Equal("XXXXXX", control.Type);
Assert.Equal("XXXXXX", control.Player);
Assert.Equal("XXXXXX", control.Buttons);
Assert.Equal("XXXXXX", control.ReqButtons);
Assert.Equal("XXXXXX", control.Minimum);
Assert.Equal("XXXXXX", control.Maximum);
Assert.Equal("XXXXXX", control.Sensitivity);
Assert.Equal("XXXXXX", control.KeyDelta);
Assert.Equal("XXXXXX", control.Reverse);
Assert.Equal("XXXXXX", control.Ways);
Assert.Equal("XXXXXX", control.Ways2);
Assert.Equal("XXXXXX", control.Ways3);
}
/// <summary>
/// Validate a DipSwitch
/// </summary>
private static void Validate(Models.Listxml.DipSwitch? dipswitch)
{
Assert.NotNull(dipswitch);
Assert.Equal("XXXXXX", dipswitch.Name);
Assert.Equal("XXXXXX", dipswitch.Tag);
Assert.Equal("XXXXXX", dipswitch.Mask);
Validate(dipswitch.Condition);
Assert.NotNull(dipswitch.DipLocation);
var diplocation = Assert.Single(dipswitch.DipLocation);
Validate(diplocation);
Assert.NotNull(dipswitch.DipValue);
var dipvalue = Assert.Single(dipswitch.DipValue);
Validate(dipvalue);
}
/// <summary>
/// Validate a Condition
/// </summary>
private static void Validate(Models.Listxml.Condition? condition)
{
Assert.NotNull(condition);
Assert.Equal("XXXXXX", condition.Tag);
Assert.Equal("XXXXXX", condition.Mask);
Assert.Equal("XXXXXX", condition.Relation);
Assert.Equal("XXXXXX", condition.Value);
}
/// <summary>
/// Validate a DipLocation
/// </summary>
private static void Validate(Models.Listxml.DipLocation? diplocation)
{
Assert.NotNull(diplocation);
Assert.Equal("XXXXXX", diplocation.Name);
Assert.Equal("XXXXXX", diplocation.Number);
Assert.Equal("XXXXXX", diplocation.Inverted);
}
/// <summary>
/// Validate a DipValue
/// </summary>
private static void Validate(Models.Listxml.DipValue? dipvalue)
{
Assert.NotNull(dipvalue);
Assert.Equal("XXXXXX", dipvalue.Name);
Assert.Equal("XXXXXX", dipvalue.Value);
Assert.Equal("XXXXXX", dipvalue.Default);
Validate(dipvalue.Condition);
}
/// <summary>
/// Validate a Configuration
/// </summary>
private static void Validate(Models.Listxml.Configuration? configuration)
{
Assert.NotNull(configuration);
Assert.Equal("XXXXXX", configuration.Name);
Assert.Equal("XXXXXX", configuration.Tag);
Assert.Equal("XXXXXX", configuration.Mask);
Validate(configuration.Condition);
Assert.NotNull(configuration.ConfLocation);
var conflocation = Assert.Single(configuration.ConfLocation);
Validate(conflocation);
Assert.NotNull(configuration.ConfSetting);
var confsetting = Assert.Single(configuration.ConfSetting);
Validate(confsetting);
}
/// <summary>
/// Validate a ConfLocation
/// </summary>
private static void Validate(Models.Listxml.ConfLocation? conflocation)
{
Assert.NotNull(conflocation);
Assert.Equal("XXXXXX", conflocation.Name);
Assert.Equal("XXXXXX", conflocation.Number);
Assert.Equal("XXXXXX", conflocation.Inverted);
}
/// <summary>
/// Validate a ConfSetting
/// </summary>
private static void Validate(Models.Listxml.ConfSetting? confsetting)
{
Assert.NotNull(confsetting);
Assert.Equal("XXXXXX", confsetting.Name);
Assert.Equal("XXXXXX", confsetting.Value);
Assert.Equal("XXXXXX", confsetting.Default);
Validate(confsetting.Condition);
}
/// <summary>
/// Validate a Port
/// </summary>
private static void Validate(Models.Listxml.Port? port)
{
Assert.NotNull(port);
Assert.Equal("XXXXXX", port.Tag);
Assert.NotNull(port.Analog);
var analog = Assert.Single(port.Analog);
Validate(analog);
}
/// <summary>
/// Validate a Analog
/// </summary>
private static void Validate(Models.Listxml.Analog? analog)
{
Assert.NotNull(analog);
Assert.Equal("XXXXXX", analog.Mask);
}
/// <summary>
/// Validate a Adjuster
/// </summary>
private static void Validate(Models.Listxml.Adjuster? adjuster)
{
Assert.NotNull(adjuster);
Assert.Equal("XXXXXX", adjuster.Name);
Assert.Equal("XXXXXX", adjuster.Default);
Validate(adjuster.Condition);
}
/// <summary>
/// Validate a Driver
/// </summary>
private static void Validate(Models.Listxml.Driver? driver)
{
Assert.NotNull(driver);
Assert.Equal("XXXXXX", driver.Status);
Assert.Equal("XXXXXX", driver.Color);
Assert.Equal("XXXXXX", driver.Sound);
Assert.Equal("XXXXXX", driver.PaletteSize);
Assert.Equal("XXXXXX", driver.Emulation);
Assert.Equal("XXXXXX", driver.Cocktail);
Assert.Equal("XXXXXX", driver.SaveState);
Assert.Equal("XXXXXX", driver.RequiresArtwork);
Assert.Equal("XXXXXX", driver.Unofficial);
Assert.Equal("XXXXXX", driver.NoSoundHardware);
Assert.Equal("XXXXXX", driver.Incomplete);
}
/// <summary>
/// Validate a Feature
/// </summary>
private static void Validate(Models.Listxml.Feature? feature)
{
Assert.NotNull(feature);
Assert.Equal("XXXXXX", feature.Type);
Assert.Equal("XXXXXX", feature.Status);
Assert.Equal("XXXXXX", feature.Overall);
}
/// <summary>
/// Validate a Device
/// </summary>
private static void Validate(Models.Listxml.Device? device)
{
Assert.NotNull(device);
Assert.Equal("XXXXXX", device.Type);
Assert.Equal("XXXXXX", device.Tag);
Assert.Equal("XXXXXX", device.FixedImage);
Assert.Equal("XXXXXX", device.Mandatory);
Assert.Equal("XXXXXX", device.Interface);
Validate(device.Instance);
Assert.NotNull(device.Extension);
var extension = Assert.Single(device.Extension);
Validate(extension);
}
/// <summary>
/// Validate a Instance
/// </summary>
private static void Validate(Models.Listxml.Instance? instance)
{
Assert.NotNull(instance);
Assert.Equal("XXXXXX", instance.Name);
Assert.Equal("XXXXXX", instance.BriefName);
}
/// <summary>
/// Validate a Extension
/// </summary>
private static void Validate(Models.Listxml.Extension? extension)
{
Assert.NotNull(extension);
Assert.Equal("XXXXXX", extension.Name);
}
/// <summary>
/// Validate a Slot
/// </summary>
private static void Validate(Models.Listxml.Slot? slot)
{
Assert.NotNull(slot);
Assert.Equal("XXXXXX", slot.Name);
Assert.NotNull(slot.SlotOption);
var slotoption = Assert.Single(slot.SlotOption);
Validate(slotoption);
}
/// <summary>
/// Validate a SlotOption
/// </summary>
private static void Validate(Models.Listxml.SlotOption? slotoption)
{
Assert.NotNull(slotoption);
Assert.Equal("XXXXXX", slotoption.Name);
Assert.Equal("XXXXXX", slotoption.DevName);
Assert.Equal("XXXXXX", slotoption.Default);
}
/// <summary>
/// Validate a SoftwareList
/// </summary>
private static void Validate(Models.Listxml.SoftwareList? softwarelist)
{
Assert.NotNull(softwarelist);
Assert.Equal("XXXXXX", softwarelist.Tag);
Assert.Equal("XXXXXX", softwarelist.Name);
Assert.Equal("XXXXXX", softwarelist.Status);
Assert.Equal("XXXXXX", softwarelist.Filter);
}
/// <summary>
/// Validate a RamOption
/// </summary>
private static void Validate(Models.Listxml.RamOption? ramoption)
{
Assert.NotNull(ramoption);
Assert.Equal("XXXXXX", ramoption.Name);
Assert.Equal("XXXXXX", ramoption.Default);
Assert.Equal("XXXXXX", ramoption.Content);
}
}
}

View File

@@ -0,0 +1,73 @@
using System.IO;
using System.Linq;
using SabreTools.Serialization.Deserializers;
using Xunit;
namespace SabreTools.Serialization.Test.Deserializers
{
public class TapeArchiveTests
{
[Fact]
public void NullArray_Null()
{
byte[]? data = null;
int offset = 0;
var deserializer = new TapeArchive();
var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
}
[Fact]
public void EmptyArray_Null()
{
byte[]? data = [];
int offset = 0;
var deserializer = new TapeArchive();
var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
}
[Fact]
public void InvalidArray_Null()
{
byte[]? data = [.. Enumerable.Repeat<byte>(0xFF, 1024)];
int offset = 0;
var deserializer = new TapeArchive();
var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
}
[Fact]
public void NullStream_Null()
{
Stream? data = null;
var deserializer = new TapeArchive();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}
[Fact]
public void EmptyStream_Null()
{
Stream? data = new MemoryStream([]);
var deserializer = new TapeArchive();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}
[Fact]
public void InvalidStream_Null()
{
Stream? data = new MemoryStream([.. Enumerable.Repeat<byte>(0xFF, 1024)]);
var deserializer = new TapeArchive();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}
}
}

View File

@@ -0,0 +1,73 @@
using System.IO;
using System.Linq;
using SabreTools.Serialization.Deserializers;
using Xunit;
namespace SabreTools.Serialization.Test.Deserializers
{
public class WiseOverlayHeaderTests
{
[Fact]
public void NullArray_Null()
{
byte[]? data = null;
int offset = 0;
var deserializer = new WiseOverlayHeader();
var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
}
[Fact]
public void EmptyArray_Null()
{
byte[]? data = [];
int offset = 0;
var deserializer = new WiseOverlayHeader();
var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
}
[Fact]
public void InvalidArray_Null()
{
byte[]? data = [.. Enumerable.Repeat<byte>(0xFF, 1024)];
int offset = 0;
var deserializer = new WiseOverlayHeader();
var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
}
[Fact]
public void NullStream_Null()
{
Stream? data = null;
var deserializer = new WiseOverlayHeader();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}
[Fact]
public void EmptyStream_Null()
{
Stream? data = new MemoryStream([]);
var deserializer = new WiseOverlayHeader();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}
[Fact]
public void InvalidStream_Null()
{
Stream? data = new MemoryStream([.. Enumerable.Repeat<byte>(0xFF, 1024)]);
var deserializer = new WiseOverlayHeader();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}
}
}

View File

@@ -0,0 +1,73 @@
using System.IO;
using System.Linq;
using SabreTools.Serialization.Deserializers;
using Xunit;
namespace SabreTools.Serialization.Test.Deserializers
{
public class WiseScriptTests
{
[Fact]
public void NullArray_Null()
{
byte[]? data = null;
int offset = 0;
var deserializer = new WiseScript();
var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
}
[Fact]
public void EmptyArray_Null()
{
byte[]? data = [];
int offset = 0;
var deserializer = new WiseScript();
var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
}
[Fact]
public void InvalidArray_Null()
{
byte[]? data = [.. Enumerable.Repeat<byte>(0xFF, 1024)];
int offset = 0;
var deserializer = new WiseScript();
var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
}
[Fact]
public void NullStream_Null()
{
Stream? data = null;
var deserializer = new WiseScript();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}
[Fact]
public void EmptyStream_Null()
{
Stream? data = new MemoryStream([]);
var deserializer = new WiseScript();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}
[Fact]
public void InvalidStream_Null()
{
Stream? data = new MemoryStream([.. Enumerable.Repeat<byte>(0xFF, 1024)]);
var deserializer = new WiseScript();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}
}
}

View File

@@ -0,0 +1,73 @@
using System.IO;
using System.Linq;
using SabreTools.Serialization.Deserializers;
using Xunit;
namespace SabreTools.Serialization.Test.Deserializers
{
public class WiseSectionHeaderTests
{
[Fact]
public void NullArray_Null()
{
byte[]? data = null;
int offset = 0;
var deserializer = new WiseSectionHeader();
var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
}
[Fact]
public void EmptyArray_Null()
{
byte[]? data = [];
int offset = 0;
var deserializer = new WiseSectionHeader();
var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
}
[Fact]
public void InvalidArray_Null()
{
byte[]? data = [.. Enumerable.Repeat<byte>(0xFF, 1024)];
int offset = 0;
var deserializer = new WiseSectionHeader();
var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
}
[Fact]
public void NullStream_Null()
{
Stream? data = null;
var deserializer = new WiseSectionHeader();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}
[Fact]
public void EmptyStream_Null()
{
Stream? data = new MemoryStream([]);
var deserializer = new WiseSectionHeader();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}
[Fact]
public void InvalidStream_Null()
{
Stream? data = new MemoryStream([.. Enumerable.Repeat<byte>(0xFF, 1024)]);
var deserializer = new WiseSectionHeader();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}
}
}

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0;net8.0;net9.0</TargetFrameworks>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<IsPackable>false</IsPackable>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
@@ -12,11 +12,11 @@
</ItemGroup>
<ItemGroup>
<None Remove="TestData\*" />
<None Remove="TestData\**" />
</ItemGroup>
<ItemGroup>
<Content Include="TestData\*">
<Content Include="TestData\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
@@ -26,11 +26,11 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="SabreTools.Hashing" Version="1.4.2" />
<PackageReference Include="SabreTools.Models" Version="1.5.8" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="SabreTools.Hashing" Version="1.5.0" />
<PackageReference Include="SabreTools.Models" Version="1.7.1" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.2">
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>

View File

@@ -0,0 +1,25 @@
using System.IO;
using SabreTools.Serialization.Serializers;
using Xunit;
namespace SabreTools.Serialization.Test.Serializers
{
public class MessTests
{
[Fact]
public void SerializeArray_Null_Null()
{
var serializer = new Mess();
byte[]? actual = serializer.SerializeArray(null);
Assert.Null(actual);
}
[Fact]
public void SerializeStream_Null_Null()
{
var serializer = new Mess();
Stream? actual = serializer.Serialize(null);
Assert.Null(actual);
}
}
}

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1 @@
This is a fake file for testing

View File

@@ -0,0 +1,61 @@
using System.IO;
using System.Linq;
using SabreTools.Serialization.Wrappers;
using Xunit;
namespace SabreTools.Serialization.Test.Wrappers
{
public class BZip2Tests
{
[Fact]
public void NullArray_Null()
{
byte[]? data = null;
int offset = 0;
var actual = BZip2.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void EmptyArray_Null()
{
byte[]? data = [];
int offset = 0;
var actual = BZip2.Create(data, offset);
Assert.Null(actual);
}
[Fact(Skip = "This will never pass with the current code")]
public void InvalidArray_Null()
{
byte[]? data = [.. Enumerable.Repeat<byte>(0xFF, 1024)];
int offset = 0;
var actual = BZip2.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void NullStream_Null()
{
Stream? data = null;
var actual = BZip2.Create(data);
Assert.Null(actual);
}
[Fact(Skip = "This will never pass with the current code")]
public void EmptyStream_Null()
{
Stream? data = new MemoryStream([]);
var actual = BZip2.Create(data);
Assert.Null(actual);
}
[Fact(Skip = "This will never pass with the current code")]
public void InvalidStream_Null()
{
Stream? data = new MemoryStream([.. Enumerable.Repeat<byte>(0xFF, 1024)]);
var actual = BZip2.Create(data);
Assert.Null(actual);
}
}
}

View File

@@ -0,0 +1,61 @@
using System.IO;
using System.Linq;
using SabreTools.Serialization.Wrappers;
using Xunit;
namespace SabreTools.Serialization.Test.Wrappers
{
public class GZipTests
{
[Fact]
public void NullArray_Null()
{
byte[]? data = null;
int offset = 0;
var actual = GZip.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void EmptyArray_Null()
{
byte[]? data = [];
int offset = 0;
var actual = GZip.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void InvalidArray_Null()
{
byte[]? data = [.. Enumerable.Repeat<byte>(0xFF, 1024)];
int offset = 0;
var actual = GZip.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void NullStream_Null()
{
Stream? data = null;
var actual = GZip.Create(data);
Assert.Null(actual);
}
[Fact]
public void EmptyStream_Null()
{
Stream? data = new MemoryStream([]);
var actual = GZip.Create(data);
Assert.Null(actual);
}
[Fact]
public void InvalidStream_Null()
{
Stream? data = new MemoryStream([.. Enumerable.Repeat<byte>(0xFF, 1024)]);
var actual = GZip.Create(data);
Assert.Null(actual);
}
}
}

View File

@@ -1,3 +1,4 @@
using System;
using System.IO;
using System.Linq;
using SabreTools.Serialization.Wrappers;
@@ -57,5 +58,22 @@ namespace SabreTools.Serialization.Test.Wrappers
var actual = PKZIP.Create(data);
Assert.Null(actual);
}
#region FindParts
[Theory]
[InlineData("single.zip", 1)]
[InlineData("single.zipx", 1)]
[InlineData("multi.zip", 4)]
[InlineData("multix.zipx", 4)]
[InlineData("multi-split.zip.001", 3)]
public void FindPartsTest(string filename, int expectedParts)
{
string firstPart = Path.Combine(Environment.CurrentDirectory, "TestData", "PKZIP", filename);
var actual = PKZIP.FindParts(firstPart);
Assert.Equal(expectedParts, actual.Count);
}
#endregion
}
}

View File

@@ -0,0 +1,78 @@
using System;
using System.IO;
using System.Linq;
using SabreTools.Serialization.Wrappers;
using Xunit;
namespace SabreTools.Serialization.Test.Wrappers
{
public class RARTests
{
[Fact]
public void NullArray_Null()
{
byte[]? data = null;
int offset = 0;
var actual = RAR.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void EmptyArray_Null()
{
byte[]? data = [];
int offset = 0;
var actual = RAR.Create(data, offset);
Assert.Null(actual);
}
[Fact(Skip = "This will never pass with the current code")]
public void InvalidArray_Null()
{
byte[]? data = [.. Enumerable.Repeat<byte>(0xFF, 1024)];
int offset = 0;
var actual = RAR.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void NullStream_Null()
{
Stream? data = null;
var actual = RAR.Create(data);
Assert.Null(actual);
}
[Fact(Skip = "This will never pass with the current code")]
public void EmptyStream_Null()
{
Stream? data = new MemoryStream([]);
var actual = RAR.Create(data);
Assert.Null(actual);
}
[Fact(Skip = "This will never pass with the current code")]
public void InvalidStream_Null()
{
Stream? data = new MemoryStream([.. Enumerable.Repeat<byte>(0xFF, 1024)]);
var actual = RAR.Create(data);
Assert.Null(actual);
}
#region FindParts
[Theory]
[InlineData("single.rar", 1)]
[InlineData("multi-old.rar", 4)]
[InlineData("multi-new.part01.rar", 3)]
[InlineData("multi-split.rar.001", 3)]
public void FindPartsTest(string filename, int expectedParts)
{
string firstPart = Path.Combine(Environment.CurrentDirectory, "TestData", "RAR", filename);
var actual = RAR.FindParts(firstPart);
Assert.Equal(expectedParts, actual.Count);
}
#endregion
}
}

View File

@@ -0,0 +1,76 @@
using System;
using System.IO;
using System.Linq;
using SabreTools.Serialization.Wrappers;
using Xunit;
namespace SabreTools.Serialization.Test.Wrappers
{
public class SevenZipTests
{
[Fact]
public void NullArray_Null()
{
byte[]? data = null;
int offset = 0;
var actual = SevenZip.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void EmptyArray_Null()
{
byte[]? data = [];
int offset = 0;
var actual = SevenZip.Create(data, offset);
Assert.Null(actual);
}
[Fact(Skip = "This will never pass with the current code")]
public void InvalidArray_Null()
{
byte[]? data = [.. Enumerable.Repeat<byte>(0xFF, 1024)];
int offset = 0;
var actual = SevenZip.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void NullStream_Null()
{
Stream? data = null;
var actual = SevenZip.Create(data);
Assert.Null(actual);
}
[Fact(Skip = "This will never pass with the current code")]
public void EmptyStream_Null()
{
Stream? data = new MemoryStream([]);
var actual = SevenZip.Create(data);
Assert.Null(actual);
}
[Fact(Skip = "This will never pass with the current code")]
public void InvalidStream_Null()
{
Stream? data = new MemoryStream([.. Enumerable.Repeat<byte>(0xFF, 1024)]);
var actual = SevenZip.Create(data);
Assert.Null(actual);
}
#region FindParts
[Theory]
[InlineData("single.7z", 1)]
[InlineData("multi.7z.001", 3)]
public void FindPartsTest(string filename, int expectedParts)
{
string firstPart = Path.Combine(Environment.CurrentDirectory, "TestData", "SevenZip", filename);
var actual = SevenZip.FindParts(firstPart);
Assert.Equal(expectedParts, actual.Count);
}
#endregion
}
}

View File

@@ -0,0 +1,61 @@
using System.IO;
using System.Linq;
using SabreTools.Serialization.Wrappers;
using Xunit;
namespace SabreTools.Serialization.Test.Wrappers
{
public class TapeArchiveTests
{
[Fact]
public void NullArray_Null()
{
byte[]? data = null;
int offset = 0;
var actual = TapeArchive.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void EmptyArray_Null()
{
byte[]? data = [];
int offset = 0;
var actual = TapeArchive.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void InvalidArray_Null()
{
byte[]? data = [.. Enumerable.Repeat<byte>(0xFF, 1024)];
int offset = 0;
var actual = TapeArchive.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void NullStream_Null()
{
Stream? data = null;
var actual = TapeArchive.Create(data);
Assert.Null(actual);
}
[Fact]
public void EmptyStream_Null()
{
Stream? data = new MemoryStream([]);
var actual = TapeArchive.Create(data);
Assert.Null(actual);
}
[Fact]
public void InvalidStream_Null()
{
Stream? data = new MemoryStream([.. Enumerable.Repeat<byte>(0xFF, 1024)]);
var actual = TapeArchive.Create(data);
Assert.Null(actual);
}
}
}

View File

@@ -0,0 +1,61 @@
using System.IO;
using System.Linq;
using SabreTools.Serialization.Wrappers;
using Xunit;
namespace SabreTools.Serialization.Test.Wrappers
{
public class WiseOverlayHeaderTests
{
[Fact]
public void NullArray_Null()
{
byte[]? data = null;
int offset = 0;
var actual = WiseOverlayHeader.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void EmptyArray_Null()
{
byte[]? data = [];
int offset = 0;
var actual = WiseOverlayHeader.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void InvalidArray_Null()
{
byte[]? data = [.. Enumerable.Repeat<byte>(0xFF, 1024)];
int offset = 0;
var actual = WiseOverlayHeader.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void NullStream_Null()
{
Stream? data = null;
var actual = WiseOverlayHeader.Create(data);
Assert.Null(actual);
}
[Fact]
public void EmptyStream_Null()
{
Stream? data = new MemoryStream([]);
var actual = WiseOverlayHeader.Create(data);
Assert.Null(actual);
}
[Fact]
public void InvalidStream_Null()
{
Stream? data = new MemoryStream([.. Enumerable.Repeat<byte>(0xFF, 1024)]);
var actual = WiseOverlayHeader.Create(data);
Assert.Null(actual);
}
}
}

View File

@@ -0,0 +1,61 @@
using System.IO;
using System.Linq;
using SabreTools.Serialization.Wrappers;
using Xunit;
namespace SabreTools.Serialization.Test.Wrappers
{
public class WiseScriptTests
{
[Fact]
public void NullArray_Null()
{
byte[]? data = null;
int offset = 0;
var actual = WiseScript.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void EmptyArray_Null()
{
byte[]? data = [];
int offset = 0;
var actual = WiseScript.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void InvalidArray_Null()
{
byte[]? data = [.. Enumerable.Repeat<byte>(0xFF, 1024)];
int offset = 0;
var actual = WiseScript.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void NullStream_Null()
{
Stream? data = null;
var actual = WiseScript.Create(data);
Assert.Null(actual);
}
[Fact]
public void EmptyStream_Null()
{
Stream? data = new MemoryStream([]);
var actual = WiseScript.Create(data);
Assert.Null(actual);
}
[Fact]
public void InvalidStream_Null()
{
Stream? data = new MemoryStream([.. Enumerable.Repeat<byte>(0xFF, 1024)]);
var actual = WiseScript.Create(data);
Assert.Null(actual);
}
}
}

View File

@@ -0,0 +1,61 @@
using System.IO;
using System.Linq;
using SabreTools.Serialization.Wrappers;
using Xunit;
namespace SabreTools.Serialization.Test.Wrappers
{
public class WiseSectionHeaderTests
{
[Fact]
public void NullArray_Null()
{
byte[]? data = null;
int offset = 0;
var actual = WiseSectionHeader.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void EmptyArray_Null()
{
byte[]? data = [];
int offset = 0;
var actual = WiseSectionHeader.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void InvalidArray_Null()
{
byte[]? data = [.. Enumerable.Repeat<byte>(0xFF, 1024)];
int offset = 0;
var actual = WiseSectionHeader.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void NullStream_Null()
{
Stream? data = null;
var actual = WiseSectionHeader.Create(data);
Assert.Null(actual);
}
[Fact]
public void EmptyStream_Null()
{
Stream? data = new MemoryStream([]);
var actual = WiseSectionHeader.Create(data);
Assert.Null(actual);
}
[Fact]
public void InvalidStream_Null()
{
Stream? data = new MemoryStream([.. Enumerable.Repeat<byte>(0xFF, 1024)]);
var actual = WiseSectionHeader.Create(data);
Assert.Null(actual);
}
}
}

View File

@@ -0,0 +1,61 @@
using System.IO;
using System.Linq;
using SabreTools.Serialization.Wrappers;
using Xunit;
namespace SabreTools.Serialization.Test.Wrappers
{
public class XZTests
{
[Fact]
public void NullArray_Null()
{
byte[]? data = null;
int offset = 0;
var actual = XZ.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void EmptyArray_Null()
{
byte[]? data = [];
int offset = 0;
var actual = XZ.Create(data, offset);
Assert.Null(actual);
}
[Fact(Skip = "This will never pass with the current code")]
public void InvalidArray_Null()
{
byte[]? data = [.. Enumerable.Repeat<byte>(0xFF, 1024)];
int offset = 0;
var actual = XZ.Create(data, offset);
Assert.Null(actual);
}
[Fact]
public void NullStream_Null()
{
Stream? data = null;
var actual = XZ.Create(data);
Assert.Null(actual);
}
[Fact(Skip = "This will never pass with the current code")]
public void EmptyStream_Null()
{
Stream? data = new MemoryStream([]);
var actual = XZ.Create(data);
Assert.Null(actual);
}
[Fact(Skip = "This will never pass with the current code")]
public void InvalidStream_Null()
{
Stream? data = new MemoryStream([.. Enumerable.Repeat<byte>(0xFF, 1024)]);
var actual = XZ.Create(data);
Assert.Null(actual);
}
}
}

View File

@@ -9,26 +9,68 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InfoPrint", "InfoPrint\Info
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SabreTools.Serialization.Test", "SabreTools.Serialization.Test\SabreTools.Serialization.Test.csproj", "{B8A04C5E-A14F-4842-9035-2F6871A1DA10}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExtractionTool", "ExtractionTool\ExtractionTool.csproj", "{1565A8FD-1399-4CA7-A806-11FCD11EC687}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5B688801-5F36-483E-B2E8-F219BA5923A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5B688801-5F36-483E-B2E8-F219BA5923A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5B688801-5F36-483E-B2E8-F219BA5923A2}.Debug|x64.ActiveCfg = Debug|Any CPU
{5B688801-5F36-483E-B2E8-F219BA5923A2}.Debug|x64.Build.0 = Debug|Any CPU
{5B688801-5F36-483E-B2E8-F219BA5923A2}.Debug|x86.ActiveCfg = Debug|Any CPU
{5B688801-5F36-483E-B2E8-F219BA5923A2}.Debug|x86.Build.0 = Debug|Any CPU
{5B688801-5F36-483E-B2E8-F219BA5923A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5B688801-5F36-483E-B2E8-F219BA5923A2}.Release|Any CPU.Build.0 = Release|Any CPU
{5B688801-5F36-483E-B2E8-F219BA5923A2}.Release|x64.ActiveCfg = Release|Any CPU
{5B688801-5F36-483E-B2E8-F219BA5923A2}.Release|x64.Build.0 = Release|Any CPU
{5B688801-5F36-483E-B2E8-F219BA5923A2}.Release|x86.ActiveCfg = Release|Any CPU
{5B688801-5F36-483E-B2E8-F219BA5923A2}.Release|x86.Build.0 = Release|Any CPU
{F3DEE31A-4726-464C-A90C-C19D78F51898}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F3DEE31A-4726-464C-A90C-C19D78F51898}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F3DEE31A-4726-464C-A90C-C19D78F51898}.Debug|x64.ActiveCfg = Debug|Any CPU
{F3DEE31A-4726-464C-A90C-C19D78F51898}.Debug|x64.Build.0 = Debug|Any CPU
{F3DEE31A-4726-464C-A90C-C19D78F51898}.Debug|x86.ActiveCfg = Debug|Any CPU
{F3DEE31A-4726-464C-A90C-C19D78F51898}.Debug|x86.Build.0 = Debug|Any CPU
{F3DEE31A-4726-464C-A90C-C19D78F51898}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F3DEE31A-4726-464C-A90C-C19D78F51898}.Release|Any CPU.Build.0 = Release|Any CPU
{F3DEE31A-4726-464C-A90C-C19D78F51898}.Release|x64.ActiveCfg = Release|Any CPU
{F3DEE31A-4726-464C-A90C-C19D78F51898}.Release|x64.Build.0 = Release|Any CPU
{F3DEE31A-4726-464C-A90C-C19D78F51898}.Release|x86.ActiveCfg = Release|Any CPU
{F3DEE31A-4726-464C-A90C-C19D78F51898}.Release|x86.Build.0 = Release|Any CPU
{B8A04C5E-A14F-4842-9035-2F6871A1DA10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B8A04C5E-A14F-4842-9035-2F6871A1DA10}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B8A04C5E-A14F-4842-9035-2F6871A1DA10}.Debug|x64.ActiveCfg = Debug|Any CPU
{B8A04C5E-A14F-4842-9035-2F6871A1DA10}.Debug|x64.Build.0 = Debug|Any CPU
{B8A04C5E-A14F-4842-9035-2F6871A1DA10}.Debug|x86.ActiveCfg = Debug|Any CPU
{B8A04C5E-A14F-4842-9035-2F6871A1DA10}.Debug|x86.Build.0 = Debug|Any CPU
{B8A04C5E-A14F-4842-9035-2F6871A1DA10}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B8A04C5E-A14F-4842-9035-2F6871A1DA10}.Release|Any CPU.Build.0 = Release|Any CPU
{B8A04C5E-A14F-4842-9035-2F6871A1DA10}.Release|x64.ActiveCfg = Release|Any CPU
{B8A04C5E-A14F-4842-9035-2F6871A1DA10}.Release|x64.Build.0 = Release|Any CPU
{B8A04C5E-A14F-4842-9035-2F6871A1DA10}.Release|x86.ActiveCfg = Release|Any CPU
{B8A04C5E-A14F-4842-9035-2F6871A1DA10}.Release|x86.Build.0 = Release|Any CPU
{1565A8FD-1399-4CA7-A806-11FCD11EC687}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1565A8FD-1399-4CA7-A806-11FCD11EC687}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1565A8FD-1399-4CA7-A806-11FCD11EC687}.Debug|x64.ActiveCfg = Debug|Any CPU
{1565A8FD-1399-4CA7-A806-11FCD11EC687}.Debug|x64.Build.0 = Debug|Any CPU
{1565A8FD-1399-4CA7-A806-11FCD11EC687}.Debug|x86.ActiveCfg = Debug|Any CPU
{1565A8FD-1399-4CA7-A806-11FCD11EC687}.Debug|x86.Build.0 = Debug|Any CPU
{1565A8FD-1399-4CA7-A806-11FCD11EC687}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1565A8FD-1399-4CA7-A806-11FCD11EC687}.Release|Any CPU.Build.0 = Release|Any CPU
{1565A8FD-1399-4CA7-A806-11FCD11EC687}.Release|x64.ActiveCfg = Release|Any CPU
{1565A8FD-1399-4CA7-A806-11FCD11EC687}.Release|x64.Build.0 = Release|Any CPU
{1565A8FD-1399-4CA7-A806-11FCD11EC687}.Release|x86.ActiveCfg = Release|Any CPU
{1565A8FD-1399-4CA7-A806-11FCD11EC687}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -111,4 +111,4 @@ namespace SabreTools.Serialization.CrossModel
return file;
}
}
}
}

View File

@@ -128,4 +128,4 @@ namespace SabreTools.Serialization.CrossModel
return rom;
}
}
}
}

View File

@@ -84,4 +84,4 @@ namespace SabreTools.Serialization.CrossModel
return row;
}
}
}
}

View File

@@ -11,7 +11,7 @@ namespace SabreTools.Serialization.CrossModel
{
if (obj == null)
return null;
var metadataFile = new Models.Metadata.MetadataFile
{
[Models.Metadata.MetadataFile.HeaderKey] = ConvertHeaderToInternalModel(obj),
@@ -87,4 +87,4 @@ namespace SabreTools.Serialization.CrossModel
return rom;
}
}
}
}

View File

@@ -339,4 +339,4 @@ namespace SabreTools.Serialization.CrossModel
return video;
}
}
}
}

View File

@@ -355,4 +355,4 @@ namespace SabreTools.Serialization.CrossModel
return video;
}
}
}
}

View File

@@ -76,4 +76,4 @@ namespace SabreTools.Serialization.CrossModel
return file;
}
}
}
}

View File

@@ -11,7 +11,7 @@ namespace SabreTools.Serialization.CrossModel
{
if (obj == null)
return null;
var metadataFile = new Models.Metadata.MetadataFile();
if (obj?.DosCenter != null)
@@ -79,4 +79,4 @@ namespace SabreTools.Serialization.CrossModel
return rom;
}
}
}
}

View File

@@ -56,4 +56,4 @@ namespace SabreTools.Serialization.CrossModel
return row;
}
}
}
}

View File

@@ -67,4 +67,4 @@ namespace SabreTools.Serialization.CrossModel
return rom;
}
}
}
}

View File

@@ -238,4 +238,4 @@ namespace SabreTools.Serialization.CrossModel
return spamsum;
}
}
}
}

View File

@@ -11,7 +11,7 @@ namespace SabreTools.Serialization.CrossModel
{
if (obj == null)
return null;
var metadataFile = new Models.Metadata.MetadataFile
{
[Models.Metadata.MetadataFile.HeaderKey] = ConvertHeaderToInternalModel(),
@@ -181,4 +181,4 @@ namespace SabreTools.Serialization.CrossModel
return rom;
}
}
}
}

View File

@@ -18,7 +18,7 @@ namespace SabreTools.Serialization.CrossModel
var machines = obj.Read<Models.Metadata.Machine[]>(Models.Metadata.MetadataFile.MachineKey);
if (machines != null && machines.Length > 0)
metadataFile.Set = Array.ConvertAll(machines, ConvertMachineFromInternalModel);
return metadataFile;
}
@@ -90,4 +90,4 @@ namespace SabreTools.Serialization.CrossModel
return row;
}
}
}
}

View File

@@ -12,7 +12,7 @@ namespace SabreTools.Serialization.CrossModel
{
if (obj == null)
return null;
var metadataFile = new Models.Metadata.MetadataFile
{
[Models.Metadata.MetadataFile.HeaderKey] = ConvertHeaderToInternalModel(),
@@ -117,4 +117,4 @@ namespace SabreTools.Serialization.CrossModel
}
}
}
}
}

View File

@@ -670,4 +670,4 @@ namespace SabreTools.Serialization.CrossModel
return video;
}
}
}
}

View File

@@ -711,4 +711,4 @@ namespace SabreTools.Serialization.CrossModel
return video;
}
}
}
}

View File

@@ -26,7 +26,6 @@ namespace SabreTools.Serialization.CrossModel
datafile.Header = ConvertHeaderFromInternalModel(header);
}
// TODO: Handle Dir items - Currently need to be generated from the machines
var machines = obj.Read<Models.Metadata.Machine[]>(Models.Metadata.MetadataFile.MachineKey);
if (machines != null && machines.Length > 0)
datafile.Game = Array.ConvertAll(machines, m => ConvertMachineFromInternalModel(m, game));
@@ -349,4 +348,4 @@ namespace SabreTools.Serialization.CrossModel
return softwareList;
}
}
}
}

View File

@@ -20,7 +20,7 @@ namespace SabreTools.Serialization.CrossModel
var machines = new List<Models.Metadata.Machine>();
if (item.Game != null && item.Game.Length > 0)
machines.AddRange(Array.ConvertAll(item.Game, ConvertMachineToInternalModel));
machines.AddRange(Array.ConvertAll(item.Game, g => ConvertMachineToInternalModel(g)));
foreach (var dir in item.Dir ?? [])
{
@@ -94,27 +94,40 @@ namespace SabreTools.Serialization.CrossModel
/// <summary>
/// Convert from <see cref="Models.Logiqx.Dir"/> to an array of <see cref="Models.Metadata.Machine"/>
/// </summary>
private static Models.Metadata.Machine[] ConvertDirToInternalModel(Dir item)
private static Models.Metadata.Machine[] ConvertDirToInternalModel(Dir item, string? parent = null)
{
if (item.Game == null || item.Game.Length == 0)
return [];
// Get the directory name
string? dirName = item.Name;
if (parent != null)
dirName = $"{parent}\\{item.Name}";
return Array.ConvertAll(item.Game, g =>
{
var machine = ConvertMachineToInternalModel(g);
machine[Models.Metadata.Machine.DirNameKey] = item.Name;
return machine;
});
// Handle machine items
Models.Metadata.Machine[] machines = [];
if (item.Game != null && item.Game.Length > 0)
machines = Array.ConvertAll(item.Game, g => ConvertMachineToInternalModel(g, dirName));
// Handle dir items
List<Models.Metadata.Machine> dirs = [];
foreach (var subdir in item.Subdir ?? [])
{
dirs.AddRange(ConvertDirToInternalModel(subdir, dirName));
}
return [.. machines, .. dirs];
}
/// <summary>
/// Convert from <see cref="Models.Logiqx.GameBase"/> to <see cref="Models.Metadata.Machine"/>
/// </summary>
private static Models.Metadata.Machine ConvertMachineToInternalModel(GameBase item)
private static Models.Metadata.Machine ConvertMachineToInternalModel(GameBase item, string? dir = null)
{
string? machineName = item.Name;
if (machineName != null && dir != null)
machineName = $"{dir}\\{machineName}";
var machine = new Models.Metadata.Machine
{
[Models.Metadata.Machine.NameKey] = item.Name,
[Models.Metadata.Machine.NameKey] = machineName,
[Models.Metadata.Machine.SourceFileKey] = item.SourceFile,
[Models.Metadata.Machine.IsBiosKey] = item.IsBios,
[Models.Metadata.Machine.IsDeviceKey] = item.IsDevice,
@@ -331,4 +344,4 @@ namespace SabreTools.Serialization.CrossModel
return softwareList;
}
}
}
}

View File

@@ -33,4 +33,4 @@ namespace SabreTools.Serialization.CrossModel
return m1;
}
}
}
}

View File

@@ -37,4 +37,4 @@ namespace SabreTools.Serialization.CrossModel
return header;
}
}
}
}

View File

@@ -0,0 +1,36 @@
using System;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{
public partial class Mess : IModelSerializer<Models.Listxml.Mess, Models.Metadata.MetadataFile>
{
/// <inheritdoc/>
public Models.Listxml.Mess? Deserialize(Models.Metadata.MetadataFile? obj)
{
if (obj == null)
return null;
var header = obj.Read<Models.Metadata.Header>(Models.Metadata.MetadataFile.HeaderKey);
var m1 = header != null ? ConvertMessFromInternalModel(header) : new Models.Listxml.Mess();
var machines = obj.Read<Models.Metadata.Machine[]>(Models.Metadata.MetadataFile.MachineKey);
if (machines != null && machines.Length > 0)
m1.Game = Array.ConvertAll(machines, Listxml.ConvertMachineFromInternalModel);
return m1;
}
/// <summary>
/// Convert from <see cref="Models.Metadata.Models.Metadata.Header"/> to <see cref="Models.Listxml.Mess"/>
/// </summary>
private static Models.Listxml.Mess ConvertMessFromInternalModel(Models.Metadata.Header item)
{
var m1 = new Models.Listxml.Mess
{
Version = item.ReadString(Models.Metadata.Header.VersionKey),
};
return m1;
}
}
}

View File

@@ -0,0 +1,40 @@
using System;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{
public partial class Mess : IModelSerializer<Models.Listxml.Mess, Models.Metadata.MetadataFile>
{
/// <inheritdoc/>
public Models.Metadata.MetadataFile? Serialize(Models.Listxml.Mess? item)
{
if (item == null)
return null;
var metadataFile = new Models.Metadata.MetadataFile
{
[Models.Metadata.MetadataFile.HeaderKey] = ConvertHeaderToInternalModel(item),
};
if (item?.Game != null && item.Game.Length > 0)
{
metadataFile[Models.Metadata.MetadataFile.MachineKey]
= Array.ConvertAll(item.Game, Listxml.ConvertMachineToInternalModel);
}
return metadataFile;
}
/// <summary>
/// Convert from <see cref="Models.Listxml.Mess"/> to <see cref="Models.Metadata.Header"/>
/// </summary>
private static Models.Metadata.Header ConvertHeaderToInternalModel(Models.Listxml.Mess item)
{
var header = new Models.Metadata.Header
{
[Models.Metadata.Header.VersionKey] = item.Version,
};
return header;
}
}
}

View File

@@ -123,4 +123,4 @@ namespace SabreTools.Serialization.CrossModel
return fileRomCRC;
}
}
}
}

View File

@@ -107,4 +107,4 @@ namespace SabreTools.Serialization.CrossModel
return rom;
}
}
}
}

View File

@@ -18,7 +18,7 @@ namespace SabreTools.Serialization.CrossModel
var machines = obj.Read<Models.Metadata.Machine[]>(Models.Metadata.MetadataFile.MachineKey);
if (machines != null && machines.Length > 0)
softwareDb.Software = Array.ConvertAll(machines, ConvertMachineFromInternalModel);
return softwareDb;
}
@@ -140,4 +140,4 @@ namespace SabreTools.Serialization.CrossModel
return sccPlusCart;
}
}
}
}

View File

@@ -121,4 +121,4 @@ namespace SabreTools.Serialization.CrossModel
return rom;
}
}
}
}

View File

@@ -112,4 +112,4 @@ namespace SabreTools.Serialization.CrossModel
return row;
}
}
}
}

View File

@@ -11,7 +11,7 @@ namespace SabreTools.Serialization.CrossModel
{
if (obj == null)
return null;
var metadataFile = new Models.Metadata.MetadataFile
{
[Models.Metadata.MetadataFile.HeaderKey] = ConvertHeaderToInternalModel(obj),
@@ -97,4 +97,4 @@ namespace SabreTools.Serialization.CrossModel
return rom;
}
}
}
}

View File

@@ -153,4 +153,4 @@ namespace SabreTools.Serialization.CrossModel
return row;
}
}
}
}

View File

@@ -116,4 +116,4 @@ namespace SabreTools.Serialization.CrossModel
};
}
}
}
}

View File

@@ -82,7 +82,7 @@ namespace SabreTools.Serialization.CrossModel
var roms = item.Read<Models.Metadata.Rom[]>(Models.Metadata.DataArea.RomKey);
if (roms != null && roms.Length > 0)
dataArea.Rom = Array.ConvertAll(roms,ConvertFromInternalModel);
dataArea.Rom = Array.ConvertAll(roms, ConvertFromInternalModel);
return dataArea;
}
@@ -242,4 +242,4 @@ namespace SabreTools.Serialization.CrossModel
return sharedFeat;
}
}
}
}

View File

@@ -236,4 +236,4 @@ namespace SabreTools.Serialization.CrossModel
return sharedFeat;
}
}
}
}

View File

@@ -106,7 +106,7 @@ namespace SabreTools.Serialization.Deserializers
return obj;
}
/// <summary>
/// Parse a Stream into a DriveRevocationListEntry
/// </summary>
@@ -411,4 +411,4 @@ namespace SabreTools.Serialization.Deserializers
return obj;
}
}
}
}

View File

@@ -76,4 +76,4 @@ namespace SabreTools.Serialization.Deserializers
}
}
}
}
}

View File

@@ -4,4 +4,4 @@ namespace SabreTools.Serialization.Deserializers
{
// All logic taken care of in the base class
}
}
}

View File

@@ -124,4 +124,4 @@ namespace SabreTools.Serialization.Deserializers
#endregion
}
}
}

View File

@@ -49,4 +49,4 @@ namespace SabreTools.Serialization.Deserializers
}
}
}
}
}

View File

@@ -17,6 +17,9 @@ namespace SabreTools.Serialization.Deserializers
try
{
// Cache the current offset
long initialOffset = data.Position;
// Create a new archive to fill
var archive = new Archive();
@@ -40,7 +43,7 @@ namespace SabreTools.Serialization.Deserializers
// Read all entries in turn
for (int i = 0; i < header.Files; i++)
{
files[i] = ParseFileEntry(data);
files[i] = ParseFileEntry(data, initialOffset);
}
// Set the files
@@ -61,8 +64,9 @@ namespace SabreTools.Serialization.Deserializers
/// Parse a Stream into a FileEntry
/// </summary>
/// <param name="data">Stream to parse</param>
/// <param name="initialOffset">Initial offset to use in address comparisons</param>
/// <returns>Filled FileEntry on success, null on error</returns>
public static FileEntry ParseFileEntry(Stream data)
public static FileEntry ParseFileEntry(Stream data, long initialOffset)
{
var fileEntry = new FileEntry();
@@ -78,7 +82,7 @@ namespace SabreTools.Serialization.Deserializers
if (fileEntry.Offset > 0)
{
long currentOffset = data.Position;
data.Seek(fileEntry.Offset, SeekOrigin.Begin);
data.Seek(initialOffset + fileEntry.Offset, SeekOrigin.Begin);
fileEntry.CompressedSize = data.ReadInt32LittleEndian();
data.Seek(currentOffset, SeekOrigin.Begin);
}
@@ -103,4 +107,4 @@ namespace SabreTools.Serialization.Deserializers
return obj;
}
}
}
}

View File

@@ -19,6 +19,9 @@ namespace SabreTools.Serialization.Deserializers
try
{
// Cache the current offset
long initialOffset = data.Position;
// Create a new Half-Life Level to fill
var file = new BspFile();
@@ -46,7 +49,7 @@ namespace SabreTools.Serialization.Deserializers
continue;
// Seek to the lump offset
data.Seek(lumpEntry.Offset, SeekOrigin.Begin);
data.Seek(initialOffset + lumpEntry.Offset, SeekOrigin.Begin);
// Read according to the lump type
switch ((LumpType)l)
@@ -674,4 +677,4 @@ namespace SabreTools.Serialization.Deserializers
return new BspModelsLump { Models = [.. models] };
}
}
}
}

View File

@@ -163,4 +163,4 @@ namespace SabreTools.Serialization.Deserializers
#endregion
}
}
}

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using SabreTools.IO.Extensions;
using SabreTools.Models.CFB;
@@ -20,6 +19,9 @@ namespace SabreTools.Serialization.Deserializers
try
{
// Cache the current offset
long initialOffset = data.Position;
// Create a new binary to fill
var binary = new Binary();
@@ -58,28 +60,32 @@ namespace SabreTools.Serialization.Deserializers
var currentSector = (SectorNumber?)fileHeader.FirstDIFATSectorLocation;
for (int i = 0; i < fileHeader.NumberOfDIFATSectors; i++)
{
// If we have a readable sector
if (currentSector <= SectorNumber.MAXREGSECT)
// If we have an unreadable sector
if (currentSector > SectorNumber.MAXREGSECT)
break;
// Get the new next sector information
long sectorOffset = initialOffset
+ (long)((long)(currentSector + 1) * Math.Pow(2, fileHeader.SectorShift));
if (sectorOffset < initialOffset || sectorOffset >= data.Length)
return null;
// Seek to the next sector
data.Seek(sectorOffset, SeekOrigin.Begin);
// Try to parse the sectors
var sectorNumbers = ParseSectorNumbers(data, fileHeader.SectorShift);
if (sectorNumbers == null)
return null;
// Add all but the last sector number that was parsed
for (int j = 0; j < sectorNumbers.Length - 1; j++)
{
// Get the new next sector information
long sectorOffset = (long)((long)(currentSector + 1) * Math.Pow(2, fileHeader.SectorShift));
if (sectorOffset < 0 || sectorOffset >= data.Length)
return null;
// Seek to the next sector
data.Seek(sectorOffset, SeekOrigin.Begin);
// Try to parse the sectors
var sectorNumbers = ParseSectorNumbers(data, fileHeader.SectorShift);
if (sectorNumbers == null)
return null;
// Add the sector shifts
difatSectors.AddRange(sectorNumbers);
difatSectors.Add(sectorNumbers[j]);
}
// Get the next sector from the DIFAT
currentSector = difatSectors[i];
// Get the next sector from the final sector number
currentSector = sectorNumbers[sectorNumbers.Length - 1];
}
// Assign the DIFAT sectors table
@@ -93,31 +99,31 @@ namespace SabreTools.Serialization.Deserializers
var fatSectors = new List<SectorNumber>();
// Loop through and add the FAT sectors
currentSector = binary.DIFATSectorNumbers[0];
for (int i = 0; i < fileHeader.NumberOfFATSectors; i++)
{
// If we have a readable sector
if (currentSector <= SectorNumber.MAXREGSECT)
{
// Get the new next sector information
long sectorOffset = (long)((long)(currentSector + 1) * Math.Pow(2, fileHeader.SectorShift));
if (sectorOffset < 0 || sectorOffset >= data.Length)
return null;
// Seek to the next sector
data.Seek(sectorOffset, SeekOrigin.Begin);
// Try to parse the sectors
var sectorNumbers = ParseSectorNumbers(data, fileHeader.SectorShift);
if (sectorNumbers == null)
return null;
// Add the sector shifts
fatSectors.AddRange(sectorNumbers);
}
// Get the next sector from the DIFAT
currentSector = binary.DIFATSectorNumbers[i];
// If we have an unreadable sector
if (currentSector > SectorNumber.MAXREGSECT)
break;
// Get the new next sector information
long sectorOffset = initialOffset
+ (long)((long)(currentSector + 1) * Math.Pow(2, fileHeader.SectorShift));
if (sectorOffset < initialOffset || sectorOffset >= data.Length)
return null;
// Seek to the next sector
data.Seek(sectorOffset, SeekOrigin.Begin);
// Try to parse the sectors
var sectorNumbers = ParseSectorNumbers(data, fileHeader.SectorShift);
if (sectorNumbers == null)
return null;
// Add the sector shifts
fatSectors.AddRange(sectorNumbers);
}
// Assign the FAT sectors table
@@ -134,28 +140,29 @@ namespace SabreTools.Serialization.Deserializers
currentSector = (SectorNumber)fileHeader.FirstMiniFATSectorLocation;
for (int i = 0; i < fileHeader.NumberOfMiniFATSectors; i++)
{
// If we have a readable sector
if (currentSector <= SectorNumber.MAXREGSECT)
{
// Get the new next sector information
long sectorOffset = (long)((long)(currentSector + 1) * Math.Pow(2, fileHeader.SectorShift));
if (sectorOffset < 0 || sectorOffset >= data.Length)
return null;
// If we have an unreadable sector
if (currentSector > SectorNumber.MAXREGSECT)
break;
// Seek to the next sector
data.Seek(sectorOffset, SeekOrigin.Begin);
// Get the new next sector information
long sectorOffset = initialOffset
+ (long)((long)(currentSector + 1) * Math.Pow(2, fileHeader.SectorShift));
if (sectorOffset < initialOffset || sectorOffset >= data.Length)
return null;
// Try to parse the sectors
var sectorNumbers = ParseSectorNumbers(data, fileHeader.SectorShift);
if (sectorNumbers == null)
return null;
// Seek to the next sector
data.Seek(sectorOffset, SeekOrigin.Begin);
// Add the sector shifts
miniFatSectors.AddRange(sectorNumbers);
}
// Try to parse the sectors
var sectorNumbers = ParseSectorNumbers(data, fileHeader.SectorShift);
if (sectorNumbers == null)
return null;
// Get the next sector from the DIFAT
currentSector = binary.DIFATSectorNumbers[i];
// Add the sector shifts
miniFatSectors.AddRange(sectorNumbers);
// Get the next sector from the FAT
currentSector = binary.FATSectorNumbers[(int)currentSector];
}
// Assign the mini FAT sectors table
@@ -165,14 +172,6 @@ namespace SabreTools.Serialization.Deserializers
#region Directory Entries
// Get the offset of the first directory sector
long firstDirectoryOffset = (long)(fileHeader.FirstDirectorySectorLocation * Math.Pow(2, fileHeader.SectorShift));
if (firstDirectoryOffset < 0 || firstDirectoryOffset >= data.Length)
return null;
// Seek to the first directory sector
data.Seek(firstDirectoryOffset, SeekOrigin.Begin);
// Create a directory sector table
var directorySectors = new List<DirectoryEntry>();
@@ -196,32 +195,29 @@ namespace SabreTools.Serialization.Deserializers
if (currentSector == SectorNumber.ENDOFCHAIN)
break;
// If we have a free sector for a version 3 filie
if (directorySectorCount == int.MaxValue && currentSector == SectorNumber.FREESECT)
// If we have an unusable sector for a version 3 file
if (directorySectorCount == int.MaxValue && currentSector > SectorNumber.MAXREGSECT)
break;
// If we have a readable sector
if (currentSector <= SectorNumber.MAXREGSECT)
{
// Get the new next sector information
long sectorOffset = (long)((long)(currentSector + 1) * Math.Pow(2, fileHeader.SectorShift));
if (sectorOffset < 0 || sectorOffset >= data.Length)
return null;
// Get the new next sector information
long sectorOffset = initialOffset
+ (long)((long)(currentSector + 1) * Math.Pow(2, fileHeader.SectorShift));
if (sectorOffset < initialOffset || sectorOffset >= data.Length)
return null;
// Seek to the next sector
data.Seek(sectorOffset, SeekOrigin.Begin);
// Seek to the next sector
data.Seek(sectorOffset, SeekOrigin.Begin);
// Try to parse the sectors
var directoryEntries = ParseDirectoryEntries(data, fileHeader.SectorShift, fileHeader.MajorVersion);
if (directoryEntries == null)
return null;
// Try to parse the sectors
var directoryEntries = ParseDirectoryEntries(data, fileHeader.SectorShift, fileHeader.MajorVersion);
if (directoryEntries == null)
return null;
// Add the sector shifts
directorySectors.AddRange(directoryEntries);
}
// Add the sector shifts
directorySectors.AddRange(directoryEntries);
// Get the next sector from the DIFAT
currentSector = binary.DIFATSectorNumbers[i];
// Get the next sector from the FAT
currentSector = binary.FATSectorNumbers[(int)currentSector];
}
// Assign the Directory sectors table
@@ -247,8 +243,8 @@ namespace SabreTools.Serialization.Deserializers
{
var obj = new DirectoryEntry();
byte[] name = data.ReadBytes(32);
obj.Name = Encoding.ASCII.GetString(name).TrimEnd('\0');
byte[] name = data.ReadBytes(64);
obj.Name = Encoding.Unicode.GetString(name).DecodeStreamName()?.TrimEnd('\0');
obj.NameLength = data.ReadUInt16LittleEndian();
obj.ObjectType = (ObjectType)data.ReadByteValue();
obj.ColorFlag = (ColorFlag)data.ReadByteValue();
@@ -332,13 +328,11 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled sector full of directory entries on success, null on error</returns>
private static DirectoryEntry[]? ParseDirectoryEntries(Stream data, ushort sectorShift, ushort majorVersion)
{
#if NET20 || NET35 || NET40
int directoryEntrySize = Marshal.SizeOf(new DirectoryEntry());
#else
int directoryEntrySize = Marshal.SizeOf<DirectoryEntry>();
#endif
int sectorCount = (int)(Math.Pow(2, sectorShift) / directoryEntrySize);
var directoryEntries = new DirectoryEntry[sectorCount];
// <see href="https://winprotocoldoc.z19.web.core.windows.net/MS-CFB/%5bMS-CFB%5d.pdf"/>
int directoryEntrySize = 128;
int dirsPerSector = (int)(Math.Pow(2, sectorShift) / directoryEntrySize);
var directoryEntries = new DirectoryEntry[dirsPerSector];
for (int i = 0; i < directoryEntries.Length; i++)
{
@@ -346,7 +340,7 @@ namespace SabreTools.Serialization.Deserializers
// Handle version 3 entries
if (majorVersion == 3)
directoryEntry.StreamSize &= 0x0000FFFF;
directoryEntry.StreamSize &= 0x00000000FFFFFFFF;
directoryEntries[i] = directoryEntry;
}
@@ -354,4 +348,4 @@ namespace SabreTools.Serialization.Deserializers
return directoryEntries;
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More