Compare commits

..

128 Commits
1.5.6 ... 1.7.3

Author SHA1 Message Date
Matt Nadareski
1fcf44fb8d Bump version 2024-11-14 11:32:17 -05:00
Matt Nadareski
a2a472baf9 Fix top level printing issue 2024-11-14 11:24:08 -05:00
Matt Nadareski
b5b4a50d94 Fix deserialization of NCCH extended header
The actual fix to this is somewhere in the conversion code where an array of Enum values somehow just... fails? I'm not totally sure how that's happening but this is the easiest way around it until that auto stuff can be fixed.
2024-11-14 11:20:46 -05:00
Matt Nadareski
f1b5464052 Extend N3DS wrapper further 2024-11-14 03:17:11 -05:00
Matt Nadareski
2c0224db22 Fix byte order for N3DS IV 2024-11-14 00:12:35 -05:00
Matt Nadareski
1e78eecb40 Bump version 2024-11-13 23:13:55 -05:00
Matt Nadareski
3626faea60 Fix building N3DS cart image 2024-11-13 23:05:26 -05:00
Matt Nadareski
a0177f1174 Add bitmasks helper method 2024-11-13 21:29:43 -05:00
Matt Nadareski
db5fe4a2cd Add extension property for backup header 2024-11-13 21:25:46 -05:00
Matt Nadareski
5716143168 Bump version 2024-11-13 20:48:55 -05:00
Matt Nadareski
2a59b23149 Add more extensions to N3DS wrapper 2024-11-13 20:47:25 -05:00
Matt Nadareski
bdbec4ed02 Update Models to 1.5.1 2024-11-13 20:41:13 -05:00
Matt Nadareski
25193f1805 Start making fixes to N3DS 2024-11-13 20:21:32 -05:00
Matt Nadareski
4840c816a2 Bump version 2024-11-13 02:51:46 -05:00
Matt Nadareski
d0a8e3770b Fix serialization issue 2024-11-13 02:48:38 -05:00
Matt Nadareski
1cf3d50864 Add .NET 9 to target frameworks 2024-11-13 02:42:14 -05:00
Matt Nadareski
d1b98f7d6d HashSet does what I need 2024-11-12 19:41:04 -05:00
Matt Nadareski
4bc87ff812 Use list sorting instead of Linq sorting 2024-11-12 19:35:08 -05:00
Matt Nadareski
e1df11b360 Build cached strings differently 2024-11-12 19:30:28 -05:00
Matt Nadareski
34606a4f04 Easier to read archive count in VPK 2024-11-12 17:05:10 -05:00
Matt Nadareski
c4c5fc4bf6 Array.Find works differently than I thought 2024-11-12 16:58:21 -05:00
Matt Nadareski
cd87ce5373 Unrolling Linq is more efficient 2024-11-12 16:44:41 -05:00
Matt Nadareski
90fc16b888 Reduce more Linq steps 2024-11-12 16:29:47 -05:00
Matt Nadareski
c2d0b71d22 Generic types all have ToString 2024-11-12 16:18:56 -05:00
Matt Nadareski
e54473682c Use TrueForAll 2024-11-12 16:11:15 -05:00
Matt Nadareski
1c8d64d98c Clean up usings 2024-11-12 16:07:31 -05:00
Matt Nadareski
a19437f42f More efficient checks 2024-11-12 16:07:27 -05:00
Matt Nadareski
855e2f2c77 Another overload I never knew about 2024-11-12 16:02:21 -05:00
Matt Nadareski
bd3cf88123 As I said, they're fun 2024-11-12 16:00:05 -05:00
Matt Nadareski
e4578ad3fc Match collections are fun 2024-11-12 15:56:31 -05:00
Matt Nadareski
39e56ef864 Remove one more unnecessary cast 2024-11-12 15:47:49 -05:00
Matt Nadareski
51b77da760 Reduce use of Cast 2024-11-12 15:46:36 -05:00
Matt Nadareski
4b83219a9b Fix conversion 2024-11-12 15:33:48 -05:00
Matt Nadareski
3ed07dd299 Linq is good, but it can be better 2024-11-12 15:30:33 -05:00
Matt Nadareski
bb7daed7f6 Reduce Linq steps 2024-11-12 15:06:28 -05:00
Matt Nadareski
0c84c47752 Explicitly add Linq library 2024-11-12 15:03:28 -05:00
Matt Nadareski
c18a185474 Fix old .NET 2024-11-12 14:56:53 -05:00
Matt Nadareski
8ff66b04d8 Reduce Linq to better query 2024-11-12 14:49:42 -05:00
Matt Nadareski
94d6556e04 Ignore additional elements 2024-11-12 14:40:43 -05:00
Matt Nadareski
6d960265e4 Minor Linq reduction 2024-11-12 14:27:34 -05:00
Matt Nadareski
cf4ca76e10 Select 2024-11-12 14:10:00 -05:00
Matt Nadareski
c7760e9903 Any 2024-11-12 13:10:47 -05:00
Matt Nadareski
d51bedceb6 ToArray 2024-11-12 13:03:06 -05:00
Matt Nadareski
125dc021d5 Disallow CRC-32 variants 2024-11-12 12:37:42 -05:00
Matt Nadareski
5bce481648 Update Hashing to 1.3.0 2024-11-12 12:36:46 -05:00
Matt Nadareski
20153f62cf Update Hashing to 1.2.3 2024-11-06 21:56:44 -05:00
Matt Nadareski
e302dfccf1 Attempt to reduce nesting in GHA builds 2024-11-05 13:53:34 -05:00
Matt Nadareski
594b841490 Make GitHub action Debug-only 2024-11-04 15:09:10 -05:00
Matt Nadareski
40c354f79f Add releases links for convenience 2024-11-04 13:17:55 -05:00
Matt Nadareski
b77959f300 Rename test executable 2024-11-04 12:14:28 -05:00
Matt Nadareski
59d6026a2b Create helper method for string reading; add UTF-8 2024-11-02 20:23:20 -04:00
Matt Nadareski
14226d1270 Completely reset cached data 2024-11-02 19:53:21 -04:00
Matt Nadareski
955f4da708 Fix minor formatting issue 2024-11-02 19:42:32 -04:00
Matt Nadareski
700b0359ea Limit fully repeating strings 2024-11-02 19:40:02 -04:00
Matt Nadareski
fe95b894d7 Bump version 2024-10-31 15:23:59 -04:00
Matt Nadareski
38a2712a8f Fake readable compressor names 2024-10-31 13:51:29 -04:00
Matt Nadareski
d1ea091574 Remove "press enter" on failure 2024-10-31 13:49:08 -04:00
Matt Nadareski
6bc812fc2f Fix formatting for CHD printing 2024-10-31 13:38:42 -04:00
Matt Nadareski
61b89fbd72 Fix typo in N3DS 2024-10-31 12:10:53 -04:00
Matt Nadareski
a2c065bdf2 Add CHD to factory 2024-10-31 12:09:36 -04:00
Matt Nadareski
88479f674b Add CHD printer 2024-10-31 12:06:25 -04:00
Matt Nadareski
5edbacde74 Add CHD printer 2024-10-31 12:03:34 -04:00
Matt Nadareski
67fc51224b Fix lack of ValueTuple in switch 2024-10-31 11:51:14 -04:00
Matt Nadareski
101f3294b4 Add CHD wrapper 2024-10-31 11:47:58 -04:00
Matt Nadareski
6c5622f732 Add CHD header deserialization 2024-10-31 11:40:50 -04:00
Matt Nadareski
f2a6fe1445 Update Models to 1.4.11 2024-10-31 11:34:45 -04:00
Matt Nadareski
b0b593443f Update packages 2024-10-24 17:27:55 -04:00
Matt Nadareski
9b05185add Fix old .NET compatibility 2024-10-14 00:20:02 -04:00
Matt Nadareski
17316da536 Port numerous extensions from NDecrypt 2024-10-14 00:15:14 -04:00
Matt Nadareski
f3ca4dd989 Port logic from UnshieldSharp 2024-10-03 11:14:41 -04:00
Matt Nadareski
e2b7bdac8c Temporary fix for IS-CAB file group parsing 2024-10-03 02:51:37 -04:00
Matt Nadareski
f86f6dc438 Bump version 2024-10-01 14:08:18 -04:00
Matt Nadareski
2bac0ed505 Update packages 2024-10-01 14:06:53 -04:00
Matt Nadareski
ae4078bb7f Fix inconsistencies in build and publish 2024-08-08 20:17:42 -04:00
Matt Nadareski
afaffbd9a2 Fix 3DS serialization and printing 2024-08-08 19:46:05 -04:00
TheRogueArchivist
b878e59e2e Fix typo in PortableExecutable Printer (#11) 2024-07-12 11:08:50 -04:00
Matt Nadareski
4bb3f625dd Make PE debug table parsing safer 2024-06-20 11:23:28 -04:00
Matt Nadareski
b7978cafa5 Bump version 2024-06-13 11:12:40 -04:00
Matt Nadareski
17f376c76f Remove all instances of this. 2024-06-05 22:49:27 -04:00
Matt Nadareski
2774fdf158 Clean up enumerables and namespace use 2024-06-05 22:48:42 -04:00
Matt Nadareski
11081efcb0 Make PE header reading even saferer 2024-06-05 22:22:22 -04:00
TheRogueArchivist
1b412c3027 Add header length safeguards to PortableExecutable wrapper (#9) 2024-06-05 22:19:35 -04:00
Matt Nadareski
73ec66e627 Fix ISv3 deserialization 2024-06-03 11:55:12 -04:00
Matt Nadareski
4ae4cd80b1 Bump version 2024-05-30 21:07:04 -04:00
Matt Nadareski
6eb27c66fc Merge pull request #8 from TheRogueArchivist/streamdatalock
Add lock for reading data from stream
2024-05-30 12:30:33 -04:00
TheRogueArchivist
f96fd17fd3 Add lock for reading data from stream 2024-05-27 15:36:04 -06:00
Matt Nadareski
c255a2494d Fix IS-CAB file group name parsing 2024-05-18 21:27:09 -04:00
Matt Nadareski
86a9846300 Bump version 2024-05-15 15:10:58 -04:00
Matt Nadareski
db877d253c Update Models, fix build 2024-05-15 14:59:55 -04:00
Matt Nadareski
0acf1e3b08 Handle bounds-defying reads 2024-05-15 13:38:44 -04:00
Matt Nadareski
362ed3a9b6 Protect against odd end-of-stream issues 2024-05-15 13:08:51 -04:00
Matt Nadareski
758878a229 Bump version 2024-05-15 12:02:21 -04:00
Matt Nadareski
ffb6dfc333 Update packages 2024-05-13 16:29:53 -04:00
Matt Nadareski
66da74e00a Fix resource table issues with NE 2024-05-12 11:46:05 -04:00
Matt Nadareski
d41a0045cb Fix input paths for test program 2024-05-09 21:54:30 -04:00
Matt Nadareski
b65629ba0e Combine magic and extension checks; helps with complex situations 2024-05-09 21:34:58 -04:00
Matt Nadareski
9518e6d1a0 Unicode (UTF-16) not UTF-8 2024-05-08 12:09:11 -04:00
Matt Nadareski
4f374ee885 Only read resources that are valid 2024-05-08 12:02:48 -04:00
Matt Nadareski
afa239056e Handle future model fix 2024-05-07 08:55:54 -04:00
Matt Nadareski
886825af11 Bump version 2024-05-07 05:17:06 -04:00
Matt Nadareski
198de925aa Update IO 2024-05-07 05:13:30 -04:00
Matt Nadareski
3f7b71e9a5 Bump version 2024-05-06 22:23:45 -04:00
Matt Nadareski
95baaf8603 Update SabreTools.IO 2024-05-06 22:12:14 -04:00
Matt Nadareski
3673264bab Bump version 2024-04-28 19:37:10 -04:00
Matt Nadareski
64fb5a6b63 Update SabreTools.IO 2024-04-28 19:32:06 -04:00
Matt Nadareski
e9c959ccdb Update SabreTools.IO 2024-04-28 17:39:30 -04:00
Matt Nadareski
4b7487e92e More rudimentary ZIP64 fixes 2024-04-28 00:24:35 -04:00
Matt Nadareski
52dbcffd8e Add shortcut if any other valid PKZIP blocks found 2024-04-27 23:57:32 -04:00
Matt Nadareski
24ae354bc2 Fix an indicator for ZIP64 2024-04-27 23:50:03 -04:00
Matt Nadareski
b30b91fd91 Remove redunant fix in StringBuilderExtensions 2024-04-27 23:48:55 -04:00
Matt Nadareski
efb63afc74 Fix PKZIP data printing 2024-04-27 23:45:33 -04:00
Matt Nadareski
16706f7169 Force writing values with proper width 2024-04-27 23:42:37 -04:00
Matt Nadareski
d7c32676b5 Add PKZIP printer implementation 2024-04-27 23:40:02 -04:00
Matt Nadareski
c8c45446bc Add PKZIP archive extra data record parsing 2024-04-27 23:01:50 -04:00
Matt Nadareski
f4de2e27d7 Notes cleanup 2024-04-27 22:49:09 -04:00
Matt Nadareski
970fcbd93b Add PKZIP shell wrapper 2024-04-27 22:45:49 -04:00
Matt Nadareski
57d1cd7f1e Initial code for PKZIP deserialization 2024-04-27 22:41:22 -04:00
Matt Nadareski
522fc372fa Fix instance of wrong extension 2024-04-27 22:23:33 -04:00
Matt Nadareski
7141690fcb Add override for compression handling 2024-04-27 22:04:52 -04:00
Matt Nadareski
c7d9177e68 Allow decompression to be skipped 2024-04-27 22:04:38 -04:00
Matt Nadareski
00b3ea40d9 Bump version 2024-04-26 21:33:56 -04:00
Matt Nadareski
c9afe939dc Update packages 2024-04-26 21:32:55 -04:00
Matt Nadareski
4171ae6516 Update build scripts, action 2024-04-26 21:27:58 -04:00
Matt Nadareski
35a42c49d5 Uncomment large amount of items but return null explicitly 2024-04-24 19:18:38 -04:00
Matt Nadareski
e4dbf56b49 Integrate test program data into main library 2024-04-24 19:15:28 -04:00
Matt Nadareski
76eeb10c47 Update README 2024-04-24 19:04:05 -04:00
Matt Nadareski
9fa73ad54f Rename PrintExtensions to Printer 2024-04-24 19:04:01 -04:00
Matt Nadareski
6034a4fd06 Port Printing into Serialization 2024-04-24 18:53:10 -04:00
141 changed files with 15151 additions and 2915 deletions

View File

@@ -16,10 +16,16 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
dotnet-version: 9.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build library
run: dotnet build
- name: Run tests
run: dotnet test
- name: Pack
run: dotnet pack

55
.github/workflows/build_test.yml vendored Normal file
View File

@@ -0,0 +1,55 @@
name: Build InfoPrint
on:
push:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
project: [InfoPrint]
runtime: [win-x86, win-x64, win-arm64, linux-x64, linux-arm64, osx-x64]
framework: [net9.0] #[net20, net35, net40, net452, net472, net48, netcoreapp3.1, net5.0, net6.0, net7.0, net8.0, net9.0]
conf: [Debug] #[Release, Debug]
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet publish ${{ matrix.project }}/${{ matrix.project }}.csproj -f ${{ matrix.framework }} -r ${{ matrix.runtime }} -c ${{ matrix.conf == 'Release' && 'Release -p:DebugType=None -p:DebugSymbols=false' || 'Debug'}} --self-contained true --version-suffix ${{ github.sha }} ${{ (startsWith(matrix.framework, 'net5') || startsWith(matrix.framework, 'net6') || startsWith(matrix.framework, 'net7') || startsWith(matrix.framework, 'net8') || startsWith(matrix.framework, 'net9')) && '-p:PublishSingleFile=true' || ''}}
- name: Archive build
run: |
cd ${{ matrix.project }}/bin/Debug/${{ matrix.framework }}/${{ matrix.runtime }}/publish/
zip -r ${{ github.workspace }}/${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}.zip ./
- name: Upload build
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}
path: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}.zip
- name: Upload to rolling
uses: ncipollo/release-action@v1.14.0
with:
allowUpdates: True
artifacts: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}.zip
body: 'Last built commit: ${{ github.sha }}'
name: 'Rolling Release'
prerelease: True
replacesArtifacts: True
tag: "rolling"
updateOnlyUnreleased: True

View File

@@ -11,7 +11,10 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
dotnet-version: 9.0.x
- name: Build
run: dotnet build
run: dotnet build
- name: Run tests
run: dotnet test

328
.gitignore vendored
View File

@@ -1,15 +1,7 @@
*.swp
*.*~
project.lock.json
.DS_Store
*.pyc
nupkg/
# Visual Studio Code
.vscode
# Rider
.idea
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.suo
@@ -17,6 +9,9 @@ nupkg/
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
@@ -24,15 +19,312 @@ nupkg/
[Rr]eleases/
x64/
x86/
build/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
msbuild.log
msbuild.err
msbuild.wrn
[Ll]og/
# Visual Studio 2015
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/

28
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,28 @@
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (InfoPrint)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/InfoPrint/bin/Debug/net9.0/InfoPrint.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 Attach",
"type": "coreclr",
"request": "attach",
"processId": "${command:pickProcess}"
}
]
}

24
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,24 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "shell",
"args": [
"build",
// Ask dotnet build to generate full paths for file names.
"/property:GenerateFullPaths=true",
// Do not generate summary otherwise it leads to duplicate errors in Problems panel
"/consoleloggerparameters:NoSummary"
],
"group": "build",
"presentation": {
"reveal": "silent"
},
"problemMatcher": "$msCompile"
}
]
}

View File

@@ -0,0 +1,33 @@
<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>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>1.7.3</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>
<ItemGroup>
<ProjectReference Include="..\SabreTools.Serialization\SabreTools.Serialization.csproj" />
</ItemGroup>
</Project>

119
InfoPrint/Options.cs Normal file
View File

@@ -0,0 +1,119 @@
using System;
using System.Collections.Generic;
namespace InfoPrint
{
/// <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; } = [];
#if NETCOREAPP3_1_OR_GREATER
/// <summary>
/// Enable JSON output
/// </summary>
public bool Json { get; private set; } = false;
#endif
#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 features
int index = 0;
for (; index < args.Length; index++)
{
string arg = args[index];
bool featureFound = false;
switch (arg)
{
case "-?":
case "-h":
case "--help":
return null;
default:
break;
}
// If the flag wasn't a feature
if (!featureFound)
break;
}
// Parse the options and paths
for (; index < args.Length; index++)
{
string arg = args[index];
switch (arg)
{
case "-d":
case "--debug":
options.Debug = true;
break;
case "-j":
case "--json":
#if NET6_0_OR_GREATER
options.Json = true;
#else
Console.WriteLine("JSON output not available in .NET Framework");
#endif
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;
}
return options;
}
/// <summary>
/// Display help text
/// </summary>
public static void DisplayHelp()
{
Console.WriteLine("Information Printing Program");
Console.WriteLine();
Console.WriteLine("infoprint.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");
#if NET6_0_OR_GREATER
Console.WriteLine("-j, --json Print info as JSON");
#endif
}
}
}

136
InfoPrint/Program.cs Normal file
View File

@@ -0,0 +1,136 @@
using System;
using System.IO;
using SabreTools.IO.Extensions;
using SabreTools.Serialization;
using SabreTools.Serialization.Wrappers;
namespace InfoPrint
{
public static class Program
{
public static void Main(string[] args)
{
// 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)
{
#if NETFRAMEWORK
PrintPathInfo(inputPath, false, options.Debug);
#else
PrintPathInfo(inputPath, options.Json, options.Debug);
#endif
}
}
/// <summary>
/// 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)
{
Console.WriteLine($"Checking possible path: {path}");
// Check if the file or directory exists
if (File.Exists(path))
{
PrintFileInfo(path, json, debug);
}
else if (Directory.Exists(path))
{
#if NET20 || NET35
foreach (string file in Directory.GetFiles(path, "*", SearchOption.AllDirectories))
#else
foreach (string file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories))
#endif
{
PrintFileInfo(file, json, debug);
}
}
else
{
Console.WriteLine($"{path} does not exist, skipping...");
}
}
/// <summary>
/// Print information for a single file, if possible
/// </summary>
private static void PrintFileInfo(string file, bool json, bool debug)
{
Console.WriteLine($"Attempting to print info for {file}");
try
{
using Stream stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
// Read the first 8 bytes
byte[]? magic = stream.ReadBytes(8);
stream.Seek(0, SeekOrigin.Begin);
// Get the file type
string extension = Path.GetExtension(file).TrimStart('.');
WrapperType ft = WrapperFactory.GetFileType(magic ?? [], extension);
// Print out the file format
Console.WriteLine($"File format found: {ft}");
// Setup the wrapper to print
var wrapper = WrapperFactory.CreateWrapper(ft, stream);
// If we don't have a wrapper
if (wrapper == null)
{
Console.WriteLine($"Either {ft} is not supported or something went wrong during parsing!");
Console.WriteLine();
return;
}
// Get the base info output name
string filenameBase = $"info-{DateTime.Now:yyyy-MM-dd_HHmmss.ffff}";
#if NET6_0_OR_GREATER
// If we have the JSON flag
if (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);
}
#endif
// Create the output data
var builder = wrapper.ExportStringBuilder();
if (builder == null)
{
Console.WriteLine("No item information could be generated");
return;
}
// Write the output data
Console.WriteLine(builder);
using var sw = new StreamWriter(File.OpenWrite($"{filenameBase}.txt"));
sw.WriteLine(builder.ToString());
}
catch (Exception ex)
{
Console.WriteLine(debug ? ex : "[Exception opening file, please try again]");
Console.WriteLine();
}
}
}
}

View File

@@ -4,9 +4,15 @@ 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).
## 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)
## Interfaces
Below is a table representing the various interfaces that are implemented within this library.
Below is a table representing the various conversion interfaces that are implemented within this library.
| Interface Name | Source Type | Destination Type |
| --- | --- | --- |
@@ -19,7 +25,13 @@ Below is a table representing the various interfaces that are implemented within
| `IStreamSerializer` | Model | `Stream?` |
| `IStringDeserializer` | `string?` representation | Model |
| `IStringSerializer` | Model | `string?` representation |
| `IWrapper` | N/A | N/A |
Below is a table representing the various non-conversion interfaces that are implemented within this library.
| Interface Name | Purpose |
| --- | --- |
| `IPrinter` | Provides a formatted output for a model |
| `IWrapper` / `IWrapper<T>` | Wraps a model or set of models to provide additional functionality |
## Namespaces
@@ -29,5 +41,6 @@ Below is a table of all namespaces within the library and what they represent
| --- | --- |
| `SabreTools.Serialization.CrossModel` | Convert between models; mainly used for metadata files converting to and from a common, `Dictionary`-based model |
| `SabreTools.Serialization.Deserializers` | Convert from external sources to models |
| `SabreTools.Serialization.Printers` | Export model information in a formatted manner |
| `SabreTools.Serialization.Serializers` | Convert from models to external sources |
| `SabreTools.Serialization.Wrappers` | Classes that wrap serialization and models to allow for including extension properties |

View File

@@ -31,13 +31,9 @@ namespace SabreTools.Serialization.Test
Assert.Equal(count, dat.File.Length);
// Validate we're not missing any attributes or elements
Assert.Null(dat.ADDITIONAL_ATTRIBUTES);
Assert.Null(dat.ADDITIONAL_ELEMENTS);
foreach (var file in dat.File)
{
Assert.NotNull(file);
Assert.Null(file.ADDITIONAL_ATTRIBUTES);
Assert.Null(file.ADDITIONAL_ELEMENTS);
}
}
@@ -59,7 +55,6 @@ namespace SabreTools.Serialization.Test
foreach (var file in dat.Row)
{
Assert.NotNull(file);
Assert.Null(file.ADDITIONAL_ELEMENTS);
}
}
@@ -76,103 +71,12 @@ namespace SabreTools.Serialization.Test
// Validate the values
if (expectHeader)
{
Assert.NotNull(dat?.ClrMamePro);
Assert.Null(dat.ClrMamePro.ADDITIONAL_ELEMENTS);
}
else
{
Assert.Null(dat?.ClrMamePro);
}
Assert.NotNull(dat?.Game);
Assert.Equal(count, dat.Game.Length);
// Validate we're not missing any attributes or elements
Assert.NotNull(dat?.ADDITIONAL_ELEMENTS);
Assert.Empty(dat.ADDITIONAL_ELEMENTS);
foreach (var game in dat.Game)
{
Assert.NotNull(game?.ADDITIONAL_ELEMENTS);
Assert.Empty(game.ADDITIONAL_ELEMENTS);
foreach (var release in game.Release ?? Array.Empty<Models.ClrMamePro.Release>())
{
Assert.NotNull(release?.ADDITIONAL_ELEMENTS);
Assert.Empty(release.ADDITIONAL_ELEMENTS);
}
foreach (var biosset in game.BiosSet ?? Array.Empty<Models.ClrMamePro.BiosSet>())
{
Assert.NotNull(biosset?.ADDITIONAL_ELEMENTS);
Assert.Empty(biosset.ADDITIONAL_ELEMENTS);
}
foreach (var rom in game.Rom ?? Array.Empty<Models.ClrMamePro.Rom>())
{
Assert.NotNull(rom?.ADDITIONAL_ELEMENTS);
Assert.Empty(rom.ADDITIONAL_ELEMENTS);
}
foreach (var disk in game.Disk ?? Array.Empty<Models.ClrMamePro.Disk>())
{
Assert.NotNull(disk?.ADDITIONAL_ELEMENTS);
Assert.Empty(disk.ADDITIONAL_ELEMENTS);
}
foreach (var media in game.Media ?? Array.Empty<Models.ClrMamePro.Media>())
{
Assert.NotNull(media?.ADDITIONAL_ELEMENTS);
Assert.Empty(media.ADDITIONAL_ELEMENTS);
}
foreach (var sample in game.Sample ?? Array.Empty<Models.ClrMamePro.Sample>())
{
Assert.NotNull(sample?.ADDITIONAL_ELEMENTS);
Assert.Empty(sample.ADDITIONAL_ELEMENTS);
}
foreach (var archive in game.Archive ?? Array.Empty<Models.ClrMamePro.Archive>())
{
Assert.NotNull(archive?.ADDITIONAL_ELEMENTS);
Assert.Empty(archive.ADDITIONAL_ELEMENTS);
}
foreach (var chip in game.Chip ?? Array.Empty<Models.ClrMamePro.Chip>())
{
Assert.NotNull(chip?.ADDITIONAL_ELEMENTS);
Assert.Empty(chip.ADDITIONAL_ELEMENTS);
}
foreach (var video in game.Video ?? Array.Empty<Models.ClrMamePro.Video>())
{
Assert.NotNull(video?.ADDITIONAL_ELEMENTS);
Assert.Empty(video.ADDITIONAL_ELEMENTS);
}
if (game.Sound != null)
{
Assert.NotNull(game.Sound?.ADDITIONAL_ELEMENTS);
Assert.Empty(game.Sound.ADDITIONAL_ELEMENTS);
}
if (game.Input != null)
{
Assert.NotNull(game.Input?.ADDITIONAL_ELEMENTS);
Assert.Empty(game.Input.ADDITIONAL_ELEMENTS);
}
foreach (var dipswitch in game.DipSwitch ?? Array.Empty<Models.ClrMamePro.DipSwitch>())
{
Assert.NotNull(dipswitch?.ADDITIONAL_ELEMENTS);
Assert.Empty(dipswitch.ADDITIONAL_ELEMENTS);
}
if (game.Driver != null)
{
Assert.NotNull(game.Driver?.ADDITIONAL_ELEMENTS);
Assert.Empty(game.Driver.ADDITIONAL_ELEMENTS);
}
}
}
[Theory]
@@ -192,23 +96,9 @@ namespace SabreTools.Serialization.Test
Assert.NotNull(dat?.Game);
Assert.Equal(count, dat.Game.Length);
// Validate we're not missing any attributes or elements
Assert.NotNull(dat?.ADDITIONAL_ELEMENTS);
Assert.Empty(dat.ADDITIONAL_ELEMENTS);
Assert.NotNull(dat.DosCenter?.ADDITIONAL_ELEMENTS);
Assert.Empty(dat.DosCenter.ADDITIONAL_ELEMENTS);
foreach (var game in dat.Game)
{
Assert.NotNull(game?.ADDITIONAL_ELEMENTS);
Assert.Empty(game.ADDITIONAL_ELEMENTS);
Assert.NotNull(game.File);
foreach (var file in game.File)
{
Assert.NotNull(file?.ADDITIONAL_ELEMENTS);
Assert.Empty(file.ADDITIONAL_ELEMENTS);
}
}
}
@@ -225,20 +115,10 @@ namespace SabreTools.Serialization.Test
// Validate the values
Assert.NotNull(dat?.Row);
Assert.Equal(count, dat.Row.Length);
// Validate we're not missing any attributes or elements
foreach (var file in dat.Row)
{
Assert.Null(file.ADDITIONAL_ELEMENTS);
}
}
[Theory]
[InlineData("test-sfv-files.sfv", HashType.CRC32, 100)]
[InlineData("test-sfv-files.sfv", HashType.CRC32_ISO, 100)]
[InlineData("test-sfv-files.sfv", HashType.CRC32_Naive, 100)]
[InlineData("test-sfv-files.sfv", HashType.CRC32_Optimized, 100)]
[InlineData("test-sfv-files.sfv", HashType.CRC32_Parallel, 100)]
[InlineData("test-md5-files.md5", HashType.MD5, 100)]
[InlineData("test-sha1-files.sha1", HashType.SHA1, 100)]
[InlineData("test-sha256.sha256", HashType.SHA256, 1)]
@@ -259,10 +139,6 @@ namespace SabreTools.Serialization.Test
switch (hash)
{
case HashType.CRC32:
case HashType.CRC32_ISO:
case HashType.CRC32_Naive:
case HashType.CRC32_Optimized:
case HashType.CRC32_Parallel:
Assert.NotNull(dat.SFV);
Assert.Equal(count, dat.SFV.Length);
break;
@@ -308,10 +184,6 @@ namespace SabreTools.Serialization.Test
// Validate the values
Assert.NotNull(dat?.Set);
Assert.Equal(count, dat.Set.Length);
// Validate we're not missing any attributes or elements
Assert.NotNull(dat.ADDITIONAL_ELEMENTS);
Assert.Empty(dat.ADDITIONAL_ELEMENTS);
}
[Theory]
@@ -328,219 +200,6 @@ namespace SabreTools.Serialization.Test
// Validate the values
Assert.NotNull(dat?.Game);
Assert.Equal(count, dat.Game.Length);
// Validate we're not missing any attributes or elements
Assert.Null(dat.ADDITIONAL_ATTRIBUTES);
Assert.Null(dat.ADDITIONAL_ELEMENTS);
foreach (var game in dat.Game)
{
Assert.Null(game.ADDITIONAL_ATTRIBUTES);
Assert.Null(game.ADDITIONAL_ELEMENTS);
foreach (var biosset in game.BiosSet ?? Array.Empty<Models.Listxml.BiosSet>())
{
Assert.Null(biosset.ADDITIONAL_ATTRIBUTES);
Assert.Null(biosset.ADDITIONAL_ELEMENTS);
}
foreach (var rom in game.Rom ?? Array.Empty<Models.Listxml.Rom>())
{
Assert.Null(rom.ADDITIONAL_ATTRIBUTES);
Assert.Null(rom.ADDITIONAL_ELEMENTS);
}
foreach (var disk in game.Disk ?? Array.Empty<Models.Listxml.Disk>())
{
Assert.Null(disk.ADDITIONAL_ATTRIBUTES);
Assert.Null(disk.ADDITIONAL_ELEMENTS);
}
foreach (var deviceRef in game.DeviceRef ?? Array.Empty<Models.Listxml.DeviceRef>())
{
Assert.Null(deviceRef.ADDITIONAL_ATTRIBUTES);
Assert.Null(deviceRef.ADDITIONAL_ELEMENTS);
}
foreach (var sample in game.Sample ?? Array.Empty<Models.Listxml.Sample>())
{
Assert.Null(sample.ADDITIONAL_ATTRIBUTES);
Assert.Null(sample.ADDITIONAL_ELEMENTS);
}
foreach (var chip in game.Chip ?? Array.Empty<Models.Listxml.Chip>())
{
Assert.Null(chip.ADDITIONAL_ATTRIBUTES);
Assert.Null(chip.ADDITIONAL_ELEMENTS);
}
foreach (var display in game.Display ?? Array.Empty<Models.Listxml.Display>())
{
Assert.Null(display.ADDITIONAL_ATTRIBUTES);
Assert.Null(display.ADDITIONAL_ELEMENTS);
}
foreach (var video in game.Video ?? Array.Empty<Models.Listxml.Video>())
{
Assert.Null(video.ADDITIONAL_ATTRIBUTES);
Assert.Null(video.ADDITIONAL_ELEMENTS);
}
if (game.Sound != null)
{
Assert.Null(game.Sound.ADDITIONAL_ATTRIBUTES);
Assert.Null(game.Sound.ADDITIONAL_ELEMENTS);
}
if (game.Input != null)
{
Assert.Null(game.Input.ADDITIONAL_ATTRIBUTES);
Assert.Null(game.Input.ADDITIONAL_ELEMENTS);
foreach (var control in game.Input.Control ?? Array.Empty<Models.Listxml.Control>())
{
Assert.Null(control.ADDITIONAL_ATTRIBUTES);
Assert.Null(control.ADDITIONAL_ELEMENTS);
}
}
foreach (var dipswitch in game.DipSwitch ?? Array.Empty<Models.Listxml.DipSwitch>())
{
Assert.Null(dipswitch.ADDITIONAL_ATTRIBUTES);
Assert.Null(dipswitch.ADDITIONAL_ELEMENTS);
if (dipswitch.Condition != null)
{
Assert.Null(dipswitch.Condition.ADDITIONAL_ATTRIBUTES);
Assert.Null(dipswitch.Condition.ADDITIONAL_ELEMENTS);
}
foreach (var diplocation in dipswitch.DipLocation ?? Array.Empty<Models.Listxml.DipLocation>())
{
Assert.Null(diplocation.ADDITIONAL_ATTRIBUTES);
Assert.Null(diplocation.ADDITIONAL_ELEMENTS);
}
foreach (var dipvalue in dipswitch.DipValue ?? Array.Empty<Models.Listxml.DipValue>())
{
Assert.Null(dipvalue.ADDITIONAL_ATTRIBUTES);
Assert.Null(dipvalue.ADDITIONAL_ELEMENTS);
if (dipvalue.Condition != null)
{
Assert.Null(dipvalue.Condition.ADDITIONAL_ATTRIBUTES);
Assert.Null(dipvalue.Condition.ADDITIONAL_ELEMENTS);
}
}
}
foreach (var configuration in game.Configuration ?? Array.Empty<Models.Listxml.Configuration>())
{
Assert.Null(configuration.ADDITIONAL_ATTRIBUTES);
Assert.Null(configuration.ADDITIONAL_ELEMENTS);
if (configuration.Condition != null)
{
Assert.Null(configuration.Condition.ADDITIONAL_ATTRIBUTES);
Assert.Null(configuration.Condition.ADDITIONAL_ELEMENTS);
}
foreach (var conflocation in configuration.ConfLocation ?? Array.Empty<Models.Listxml.ConfLocation>())
{
Assert.Null(conflocation.ADDITIONAL_ATTRIBUTES);
Assert.Null(conflocation.ADDITIONAL_ELEMENTS);
}
foreach (var confsetting in configuration.ConfSetting ?? Array.Empty<Models.Listxml.ConfSetting>())
{
Assert.Null(confsetting.ADDITIONAL_ATTRIBUTES);
Assert.Null(confsetting.ADDITIONAL_ELEMENTS);
if (confsetting.Condition != null)
{
Assert.Null(confsetting.Condition.ADDITIONAL_ATTRIBUTES);
Assert.Null(confsetting.Condition.ADDITIONAL_ELEMENTS);
}
}
}
foreach (var port in game.Port ?? Array.Empty<Models.Listxml.Port>())
{
Assert.Null(port.ADDITIONAL_ATTRIBUTES);
Assert.Null(port.ADDITIONAL_ELEMENTS);
foreach (var analog in port.Analog ?? Array.Empty<Models.Listxml.Analog>())
{
Assert.Null(analog.ADDITIONAL_ATTRIBUTES);
Assert.Null(analog.ADDITIONAL_ELEMENTS);
}
}
foreach (var adjuster in game.Adjuster ?? Array.Empty<Models.Listxml.Adjuster>())
{
Assert.Null(adjuster.ADDITIONAL_ATTRIBUTES);
Assert.Null(adjuster.ADDITIONAL_ELEMENTS);
if (adjuster.Condition != null)
{
Assert.Null(adjuster.Condition.ADDITIONAL_ATTRIBUTES);
Assert.Null(adjuster.Condition.ADDITIONAL_ELEMENTS);
}
}
if (game.Driver != null)
{
Assert.Null(game.Driver.ADDITIONAL_ATTRIBUTES);
Assert.Null(game.Driver.ADDITIONAL_ELEMENTS);
}
foreach (var feature in game.Feature ?? Array.Empty<Models.Listxml.Feature>())
{
Assert.Null(feature.ADDITIONAL_ATTRIBUTES);
Assert.Null(feature.ADDITIONAL_ELEMENTS);
}
foreach (var device in game.Device ?? Array.Empty<Models.Listxml.Device>())
{
Assert.Null(device.ADDITIONAL_ATTRIBUTES);
Assert.Null(device.ADDITIONAL_ELEMENTS);
if (device.Instance != null)
{
Assert.Null(device.Instance.ADDITIONAL_ATTRIBUTES);
Assert.Null(device.Instance.ADDITIONAL_ELEMENTS);
}
foreach (var extension in device.Extension ?? Array.Empty<Models.Listxml.Extension>())
{
Assert.Null(extension.ADDITIONAL_ATTRIBUTES);
Assert.Null(extension.ADDITIONAL_ELEMENTS);
}
}
foreach (var slot in game.Slot ?? Array.Empty<Models.Listxml.Slot>())
{
Assert.Null(slot.ADDITIONAL_ATTRIBUTES);
Assert.Null(slot.ADDITIONAL_ELEMENTS);
foreach (var slotoption in slot.SlotOption ?? Array.Empty<Models.Listxml.SlotOption>())
{
Assert.Null(slotoption.ADDITIONAL_ATTRIBUTES);
Assert.Null(slotoption.ADDITIONAL_ELEMENTS);
}
}
foreach (var softwarelist in game.SoftwareList ?? Array.Empty<Models.Listxml.SoftwareList>())
{
Assert.Null(softwarelist.ADDITIONAL_ATTRIBUTES);
Assert.Null(softwarelist.ADDITIONAL_ELEMENTS);
}
foreach (var ramoption in game.RamOption ?? Array.Empty<Models.Listxml.RamOption>())
{
Assert.Null(ramoption.ADDITIONAL_ATTRIBUTES);
Assert.Null(ramoption.ADDITIONAL_ELEMENTS);
}
}
}
[Theory]
@@ -557,180 +216,6 @@ namespace SabreTools.Serialization.Test
// Validate the values
Assert.NotNull(dat?.Game);
Assert.Equal(count, dat.Game.Length);
// Validate we're not missing any attributes or elements
Assert.Null(dat.ADDITIONAL_ATTRIBUTES);
Assert.Null(dat.ADDITIONAL_ELEMENTS);
if (dat.Header != null)
{
var header = dat.Header;
Assert.Null(header.ADDITIONAL_ATTRIBUTES);
Assert.Null(header.ADDITIONAL_ELEMENTS);
if (header.ClrMamePro != null)
{
var cmp = header.ClrMamePro;
Assert.Null(cmp.ADDITIONAL_ATTRIBUTES);
Assert.Null(cmp.ADDITIONAL_ELEMENTS);
}
if (header.RomCenter != null)
{
var rc = header.RomCenter;
Assert.Null(rc.ADDITIONAL_ATTRIBUTES);
Assert.Null(rc.ADDITIONAL_ELEMENTS);
}
}
foreach (var game in dat.Game)
{
Assert.Null(game.ADDITIONAL_ATTRIBUTES);
Assert.Null(game.ADDITIONAL_ELEMENTS);
foreach (var item in game.Release ?? Array.Empty<Models.Logiqx.Release>())
{
Assert.Null(item.ADDITIONAL_ATTRIBUTES);
Assert.Null(item.ADDITIONAL_ELEMENTS);
}
foreach (var item in game.BiosSet ?? Array.Empty<Models.Logiqx.BiosSet>())
{
Assert.Null(item.ADDITIONAL_ATTRIBUTES);
Assert.Null(item.ADDITIONAL_ELEMENTS);
}
foreach (var item in game.Rom ?? Array.Empty<Models.Logiqx.Rom>())
{
Assert.Null(item.ADDITIONAL_ATTRIBUTES);
Assert.Null(item.ADDITIONAL_ELEMENTS);
}
foreach (var item in game.Disk ?? Array.Empty<Models.Logiqx.Disk>())
{
Assert.Null(item.ADDITIONAL_ATTRIBUTES);
Assert.Null(item.ADDITIONAL_ELEMENTS);
}
foreach (var item in game.Media ?? Array.Empty<Models.Logiqx.Media>())
{
Assert.Null(item.ADDITIONAL_ATTRIBUTES);
Assert.Null(item.ADDITIONAL_ELEMENTS);
}
foreach (var item in game.DeviceRef ?? Array.Empty<Models.Logiqx.DeviceRef>())
{
Assert.Null(item.ADDITIONAL_ATTRIBUTES);
Assert.Null(item.ADDITIONAL_ELEMENTS);
}
foreach (var item in game.Sample ?? Array.Empty<Models.Logiqx.Sample>())
{
Assert.Null(item.ADDITIONAL_ATTRIBUTES);
Assert.Null(item.ADDITIONAL_ELEMENTS);
}
foreach (var item in game.Archive ?? Array.Empty<Models.Logiqx.Archive>())
{
Assert.Null(item.ADDITIONAL_ATTRIBUTES);
Assert.Null(item.ADDITIONAL_ELEMENTS);
}
if (game.Driver != null)
{
Assert.Null(game.Driver.ADDITIONAL_ATTRIBUTES);
Assert.Null(game.Driver.ADDITIONAL_ELEMENTS);
}
foreach (var item in game.SoftwareList ?? Array.Empty<Models.Logiqx.SoftwareList>())
{
Assert.Null(item.ADDITIONAL_ATTRIBUTES);
Assert.Null(item.ADDITIONAL_ELEMENTS);
}
if (game.Trurip != null)
{
var trurip = game.Trurip;
Assert.Null(trurip.ADDITIONAL_ATTRIBUTES);
Assert.Null(trurip.ADDITIONAL_ELEMENTS);
}
}
foreach (var dir in dat.Dir ?? Array.Empty<Models.Logiqx.Dir>())
{
Assert.NotNull(dir.Game);
foreach (var game in dir.Game)
{
Assert.Null(game.ADDITIONAL_ATTRIBUTES);
Assert.Null(game.ADDITIONAL_ELEMENTS);
foreach (var item in game.Release ?? Array.Empty<Models.Logiqx.Release>())
{
Assert.Null(item.ADDITIONAL_ATTRIBUTES);
Assert.Null(item.ADDITIONAL_ELEMENTS);
}
foreach (var item in game.BiosSet ?? Array.Empty<Models.Logiqx.BiosSet>())
{
Assert.Null(item.ADDITIONAL_ATTRIBUTES);
Assert.Null(item.ADDITIONAL_ELEMENTS);
}
foreach (var item in game.Rom ?? Array.Empty<Models.Logiqx.Rom>())
{
Assert.Null(item.ADDITIONAL_ATTRIBUTES);
Assert.Null(item.ADDITIONAL_ELEMENTS);
}
foreach (var item in game.Disk ?? Array.Empty<Models.Logiqx.Disk>())
{
Assert.Null(item.ADDITIONAL_ATTRIBUTES);
Assert.Null(item.ADDITIONAL_ELEMENTS);
}
foreach (var item in game.Media ?? Array.Empty<Models.Logiqx.Media>())
{
Assert.Null(item.ADDITIONAL_ATTRIBUTES);
Assert.Null(item.ADDITIONAL_ELEMENTS);
}
foreach (var item in game.DeviceRef ?? Array.Empty<Models.Logiqx.DeviceRef>())
{
Assert.Null(item.ADDITIONAL_ATTRIBUTES);
Assert.Null(item.ADDITIONAL_ELEMENTS);
}
foreach (var item in game.Sample ?? Array.Empty<Models.Logiqx.Sample>())
{
Assert.Null(item.ADDITIONAL_ATTRIBUTES);
Assert.Null(item.ADDITIONAL_ELEMENTS);
}
foreach (var item in game.Archive ?? Array.Empty<Models.Logiqx.Archive>())
{
Assert.Null(item.ADDITIONAL_ATTRIBUTES);
Assert.Null(item.ADDITIONAL_ELEMENTS);
}
if (game.Driver != null)
{
Assert.Null(game.Driver.ADDITIONAL_ATTRIBUTES);
Assert.Null(game.Driver.ADDITIONAL_ELEMENTS);
}
foreach (var item in game.SoftwareList ?? Array.Empty<Models.Logiqx.SoftwareList>())
{
Assert.Null(item.ADDITIONAL_ATTRIBUTES);
Assert.Null(item.ADDITIONAL_ELEMENTS);
}
if (game.Trurip != null)
{
var trurip = game.Trurip;
Assert.Null(trurip.ADDITIONAL_ATTRIBUTES);
Assert.Null(trurip.ADDITIONAL_ELEMENTS);
}
}
}
}
[Theory]
@@ -746,196 +231,6 @@ namespace SabreTools.Serialization.Test
// Validate the values
Assert.NotNull(dat?.Games?.Game);
Assert.Equal(count, dat.Games.Game.Length);
// Validate we're not missing any attributes or elements
Assert.Null(dat.ADDITIONAL_ATTRIBUTES);
Assert.Null(dat.ADDITIONAL_ELEMENTS);
if (dat.Configuration != null)
{
var configuration = dat.Configuration;
Assert.Null(configuration.ADDITIONAL_ATTRIBUTES);
Assert.Null(configuration.ADDITIONAL_ELEMENTS);
if (configuration.Infos != null)
{
var infos = configuration.Infos;
Assert.Null(infos.ADDITIONAL_ATTRIBUTES);
Assert.Null(infos.ADDITIONAL_ELEMENTS);
if (infos.Title != null)
{
var title = infos.Title;
Assert.Null(title.ADDITIONAL_ATTRIBUTES);
Assert.Null(title.ADDITIONAL_ELEMENTS);
}
if (infos.Location != null)
{
var location = infos.Location;
Assert.Null(location.ADDITIONAL_ATTRIBUTES);
Assert.Null(location.ADDITIONAL_ELEMENTS);
}
if (infos.Publisher != null)
{
var publisher = infos.Publisher;
Assert.Null(publisher.ADDITIONAL_ATTRIBUTES);
Assert.Null(publisher.ADDITIONAL_ELEMENTS);
}
if (infos.SourceRom != null)
{
var sourceRom = infos.SourceRom;
Assert.Null(sourceRom.ADDITIONAL_ATTRIBUTES);
Assert.Null(sourceRom.ADDITIONAL_ELEMENTS);
}
if (infos.SaveType != null)
{
var saveType = infos.SaveType;
Assert.Null(saveType.ADDITIONAL_ATTRIBUTES);
Assert.Null(saveType.ADDITIONAL_ELEMENTS);
}
if (infos.RomSize != null)
{
var romSize = infos.RomSize;
Assert.Null(romSize.ADDITIONAL_ATTRIBUTES);
Assert.Null(romSize.ADDITIONAL_ELEMENTS);
}
if (infos.ReleaseNumber != null)
{
var releaseNumber = infos.ReleaseNumber;
Assert.Null(releaseNumber.ADDITIONAL_ATTRIBUTES);
Assert.Null(releaseNumber.ADDITIONAL_ELEMENTS);
}
if (infos.LanguageNumber != null)
{
var languageNumber = infos.LanguageNumber;
Assert.Null(languageNumber.ADDITIONAL_ATTRIBUTES);
Assert.Null(languageNumber.ADDITIONAL_ELEMENTS);
}
if (infos.Comment != null)
{
var comment = infos.Comment;
Assert.Null(comment.ADDITIONAL_ATTRIBUTES);
Assert.Null(comment.ADDITIONAL_ELEMENTS);
}
if (infos.RomCRC != null)
{
var romCRC = infos.RomCRC;
Assert.Null(romCRC.ADDITIONAL_ATTRIBUTES);
Assert.Null(romCRC.ADDITIONAL_ELEMENTS);
}
if (infos.Im1CRC != null)
{
var im1CRC = infos.Im1CRC;
Assert.Null(im1CRC.ADDITIONAL_ATTRIBUTES);
Assert.Null(im1CRC.ADDITIONAL_ELEMENTS);
}
if (infos.Im2CRC != null)
{
var im2CRC = infos.Im2CRC;
Assert.Null(im2CRC.ADDITIONAL_ATTRIBUTES);
Assert.Null(im2CRC.ADDITIONAL_ELEMENTS);
}
if (infos.Languages != null)
{
var languages = infos.Languages;
Assert.Null(languages.ADDITIONAL_ATTRIBUTES);
Assert.Null(languages.ADDITIONAL_ELEMENTS);
}
}
if (configuration.CanOpen != null)
{
var canOpen = configuration.CanOpen;
Assert.Null(canOpen.ADDITIONAL_ATTRIBUTES);
Assert.Null(canOpen.ADDITIONAL_ELEMENTS);
}
if (configuration.NewDat != null)
{
var newDat = configuration.NewDat;
Assert.Null(newDat.ADDITIONAL_ATTRIBUTES);
Assert.Null(newDat.ADDITIONAL_ELEMENTS);
if (newDat.DatUrl != null)
{
var datURL = newDat.DatUrl;
Assert.Null(datURL.ADDITIONAL_ATTRIBUTES);
Assert.Null(datURL.ADDITIONAL_ELEMENTS);
}
}
if (configuration.Search != null)
{
var search = configuration.Search;
Assert.Null(search.ADDITIONAL_ATTRIBUTES);
Assert.Null(search.ADDITIONAL_ELEMENTS);
foreach (var to in search.To ?? Array.Empty<Models.OfflineList.To>())
{
Assert.Null(to.ADDITIONAL_ATTRIBUTES);
Assert.Null(to.ADDITIONAL_ELEMENTS);
foreach (var find in to.Find ?? Array.Empty<Models.OfflineList.Find>())
{
Assert.Null(find.ADDITIONAL_ATTRIBUTES);
Assert.Null(find.ADDITIONAL_ELEMENTS);
}
}
}
}
Assert.Null(dat.Games.ADDITIONAL_ATTRIBUTES);
Assert.Null(dat.Games.ADDITIONAL_ELEMENTS);
foreach (var game in dat.Games.Game)
{
Assert.Null(game.ADDITIONAL_ATTRIBUTES);
//Assert.Null(game.ADDITIONAL_ELEMENTS); // TODO: Re-enable line when Models is fixed again
if (game.Files != null)
{
var files = game.Files;
Assert.Null(files.ADDITIONAL_ATTRIBUTES);
Assert.Null(files.ADDITIONAL_ELEMENTS);
foreach (var romCRC in files.RomCRC ?? Array.Empty<Models.OfflineList.FileRomCRC>())
{
Assert.Null(romCRC.ADDITIONAL_ATTRIBUTES);
Assert.Null(romCRC.ADDITIONAL_ELEMENTS);
}
}
}
if (dat.GUI != null)
{
var gui = dat.GUI;
Assert.Null(gui.ADDITIONAL_ATTRIBUTES);
Assert.Null(gui.ADDITIONAL_ELEMENTS);
if (gui.Images != null)
{
var images = gui.Images;
Assert.Null(images.ADDITIONAL_ATTRIBUTES);
Assert.Null(images.ADDITIONAL_ELEMENTS);
foreach (var image in images.Image ?? Array.Empty<Models.OfflineList.Image>())
{
Assert.Null(image.ADDITIONAL_ATTRIBUTES);
Assert.Null(image.ADDITIONAL_ELEMENTS);
}
}
}
}
[Theory]
@@ -952,33 +247,6 @@ namespace SabreTools.Serialization.Test
Assert.NotNull(dat);
Assert.NotNull(dat.Software);
Assert.Equal(count, dat.Software.Length);
// Validate we're not missing any attributes or elements
Assert.Null(dat.ADDITIONAL_ATTRIBUTES);
Assert.Null(dat.ADDITIONAL_ELEMENTS);
foreach (var software in dat.Software)
{
Assert.Null(software.ADDITIONAL_ATTRIBUTES);
Assert.Null(software.ADDITIONAL_ELEMENTS);
foreach (var dump in software.Dump ?? Array.Empty<Models.OpenMSX.Dump>())
{
Assert.Null(dump.ADDITIONAL_ATTRIBUTES);
Assert.Null(dump.ADDITIONAL_ELEMENTS);
if (dump.Original != null)
{
Assert.Null(dump.Original.ADDITIONAL_ATTRIBUTES);
Assert.Null(dump.Original.ADDITIONAL_ELEMENTS);
}
if (dump.Rom != null)
{
Assert.Null(dump.Rom.ADDITIONAL_ATTRIBUTES);
Assert.Null(dump.Rom.ADDITIONAL_ELEMENTS);
}
}
}
}
[Theory]
@@ -994,37 +262,6 @@ namespace SabreTools.Serialization.Test
// Validate the values
Assert.NotNull(dat?.Games?.Rom);
Assert.Equal(count, dat.Games.Rom.Length);
// Validate we're not missing any attributes or elements
Assert.NotNull(dat.ADDITIONAL_ELEMENTS);
Assert.Empty(dat.ADDITIONAL_ELEMENTS);
if (dat.Credits != null)
{
Assert.NotNull(dat.Credits.ADDITIONAL_ELEMENTS);
Assert.Empty(dat.Credits.ADDITIONAL_ELEMENTS);
}
if (dat.Dat != null)
{
Assert.NotNull(dat.Dat.ADDITIONAL_ELEMENTS);
Assert.Empty(dat.Dat.ADDITIONAL_ELEMENTS);
}
if (dat.Emulator != null)
{
Assert.NotNull(dat.Emulator.ADDITIONAL_ELEMENTS);
Assert.Empty(dat.Emulator.ADDITIONAL_ELEMENTS);
}
if (dat.Games != null)
{
Assert.NotNull(dat.Games.ADDITIONAL_ELEMENTS);
Assert.Empty(dat.Games.ADDITIONAL_ELEMENTS);
foreach (var rom in dat.Games.Rom ?? Array.Empty<Models.RomCenter.Rom>())
{
Assert.Null(rom.ADDITIONAL_ELEMENTS);
}
}
}
[Theory]
@@ -1045,12 +282,6 @@ namespace SabreTools.Serialization.Test
// Validate the values
Assert.NotNull(dat?.Row);
Assert.Equal(count, dat.Row.Length);
// Validate we're not missing any attributes or elements
foreach (var rom in dat.Row ?? Array.Empty<Models.SeparatedValue.Row>())
{
Assert.Null(rom.ADDITIONAL_ELEMENTS);
}
}
[Theory]
@@ -1069,77 +300,8 @@ namespace SabreTools.Serialization.Test
Assert.NotNull(dat);
Assert.NotNull(dat.Software);
Assert.Equal(count, dat.Software.Length);
// Validate we're not missing any attributes or elements
Assert.Null(dat.ADDITIONAL_ATTRIBUTES);
Assert.Null(dat.ADDITIONAL_ELEMENTS);
foreach (var software in dat.Software)
{
Assert.Null(software.ADDITIONAL_ATTRIBUTES);
Assert.Null(software.ADDITIONAL_ELEMENTS);
foreach (var info in software.Info ?? Array.Empty<Models.SoftwareList.Info>())
{
Assert.Null(info.ADDITIONAL_ATTRIBUTES);
Assert.Null(info.ADDITIONAL_ELEMENTS);
}
foreach (var sharedfeat in software.SharedFeat ?? Array.Empty<Models.SoftwareList.SharedFeat>())
{
Assert.Null(sharedfeat.ADDITIONAL_ATTRIBUTES);
Assert.Null(sharedfeat.ADDITIONAL_ELEMENTS);
}
foreach (var part in software.Part ?? Array.Empty<Models.SoftwareList.Part>())
{
Assert.Null(part.ADDITIONAL_ATTRIBUTES);
Assert.Null(part.ADDITIONAL_ELEMENTS);
foreach (var feature in part.Feature ?? Array.Empty<Models.SoftwareList.Feature>())
{
Assert.Null(feature.ADDITIONAL_ATTRIBUTES);
Assert.Null(feature.ADDITIONAL_ELEMENTS);
}
foreach (var dataarea in part.DataArea ?? Array.Empty<Models.SoftwareList.DataArea>())
{
Assert.Null(dataarea.ADDITIONAL_ATTRIBUTES);
Assert.Null(dataarea.ADDITIONAL_ELEMENTS);
foreach (var rom in dataarea.Rom ?? Array.Empty<Models.SoftwareList.Rom>())
{
Assert.Null(rom.ADDITIONAL_ATTRIBUTES);
Assert.Null(rom.ADDITIONAL_ELEMENTS);
}
}
foreach (var diskarea in part.DiskArea ?? Array.Empty<Models.SoftwareList.DiskArea>())
{
Assert.Null(diskarea.ADDITIONAL_ATTRIBUTES);
Assert.Null(diskarea.ADDITIONAL_ELEMENTS);
foreach (var disk in diskarea.Disk ?? Array.Empty<Models.SoftwareList.Disk>())
{
Assert.Null(disk.ADDITIONAL_ATTRIBUTES);
Assert.Null(disk.ADDITIONAL_ELEMENTS);
}
}
foreach (var dipswitch in part.DipSwitch ?? Array.Empty<Models.SoftwareList.DipSwitch>())
{
Assert.Null(dipswitch.ADDITIONAL_ATTRIBUTES);
Assert.Null(dipswitch.ADDITIONAL_ELEMENTS);
foreach (var dipvalue in dipswitch.DipValue ?? Array.Empty<Models.SoftwareList.DipValue>())
{
Assert.Null(dipvalue.ADDITIONAL_ATTRIBUTES);
Assert.Null(dipvalue.ADDITIONAL_ELEMENTS);
}
}
}
}
}
/// <summary>
/// Get the path to the test file
/// </summary>

View File

@@ -63,9 +63,9 @@ namespace SabreTools.Serialization.Test
var dump = new Models.OpenMSX.Dump[]
{
new Models.OpenMSX.Dump { Original = original, Rom = rom },
new Models.OpenMSX.Dump { Rom = megaRom },
new Models.OpenMSX.Dump { Rom = sccPlusCart },
new() { Original = original, Rom = rom },
new() { Rom = megaRom },
new() { Rom = sccPlusCart },
};
var software = new Models.OpenMSX.Software

View File

@@ -1,38 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
<IsPackable>false</IsPackable>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<TargetFrameworks>net6.0;net8.0;net9.0</TargetFrameworks>
<IsPackable>false</IsPackable>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\SabreTools.Serialization\SabreTools.Serialization.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SabreTools.Serialization\SabreTools.Serialization.csproj" />
</ItemGroup>
<ItemGroup>
<None Remove="TestData\*" />
</ItemGroup>
<ItemGroup>
<None Remove="TestData\*" />
</ItemGroup>
<ItemGroup>
<Content Include="TestData\*">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Content Include="TestData\*">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="SabreTools.Models" Version="1.4.5" />
<PackageReference Include="xunit" Version="2.7.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.8">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="SabreTools.Models" Version="1.5.1" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
</Project>
</Project>

View File

@@ -5,7 +5,7 @@ VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SabreTools.Serialization", "SabreTools.Serialization\SabreTools.Serialization.csproj", "{5B688801-5F36-483E-B2E8-F219BA5923A2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{F3DEE31A-4726-464C-A90C-C19D78F51898}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InfoPrint", "InfoPrint\InfoPrint.csproj", "{F3DEE31A-4726-464C-A90C-C19D78F51898}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SabreTools.Serialization.Test", "SabreTools.Serialization.Test\SabreTools.Serialization.Test.csproj", "{B8A04C5E-A14F-4842-9035-2F6871A1DA10}"
EndProject

View File

@@ -1,6 +1,5 @@
using System;
using System.Linq;
using SabreTools.Models.ArchiveDotOrg;
using System.Collections.Generic;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
@@ -16,14 +15,13 @@ namespace SabreTools.Serialization.CrossModel
var files = new Models.ArchiveDotOrg.Files();
var machines = obj.Read<Models.Metadata.Machine[]>(Models.Metadata.MetadataFile.MachineKey);
if (machines != null && machines.Any())
var items = new List<Models.ArchiveDotOrg.File>();
foreach (var machine in machines ?? [])
{
files.File = machines
.Where(m => m != null)
.SelectMany(ConvertFromInternalModel)
.ToArray();
items.AddRange(ConvertFromInternalModel(machine));
}
files.File = [.. items];
return files;
}
@@ -36,9 +34,7 @@ namespace SabreTools.Serialization.CrossModel
if (roms == null)
return [];
return roms
.Where(r => r != null)
.Select(ConvertFromInternalModel).ToArray();
return Array.ConvertAll(roms, ConvertFromInternalModel);
}
/// <summary>

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
@@ -16,13 +16,10 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.MetadataFile.HeaderKey] = ConvertHeaderToInternalModel(item),
};
if (item?.File != null && item.File.Any())
if (item?.File != null && item.File.Length > 0)
{
metadataFile[Models.Metadata.MetadataFile.MachineKey] = item.File
.Where(f => f != null)
.Select(ConvertMachineToInternalModel)
.Where(m => m != null)
.ToArray();
metadataFile[Models.Metadata.MetadataFile.MachineKey]
= Array.ConvertAll(item.File, ConvertMachineToInternalModel);
}
return metadataFile;

View File

@@ -1,5 +1,5 @@
using System;
using System.Linq;
using System.Collections.Generic;
using SabreTools.Models.AttractMode;
using SabreTools.Serialization.Interfaces;
@@ -17,14 +17,13 @@ namespace SabreTools.Serialization.CrossModel
var metadataFile = header != null ? ConvertHeaderFromInternalModel(header) : new MetadataFile();
var machines = obj.Read<Models.Metadata.Machine[]>(Models.Metadata.MetadataFile.MachineKey);
if (machines != null && machines.Any())
var items = new List<Row>();
foreach (var machine in machines ?? [])
{
metadataFile.Row = machines
.Where(m => m != null)
.SelectMany(ConvertMachineFromInternalModel)
.ToArray();
items.AddRange(ConvertMachineFromInternalModel(machine));
}
metadataFile.Row = [.. items];
return metadataFile;
}
@@ -46,13 +45,10 @@ namespace SabreTools.Serialization.CrossModel
private static Row[] ConvertMachineFromInternalModel(Models.Metadata.Machine item)
{
var roms = item.Read<Models.Metadata.Rom[]>(Models.Metadata.Machine.RomKey);
if (roms == null || !roms.Any())
if (roms == null || roms.Length == 0)
return [];
return roms
.Where(r => r != null)
.Select(rom => ConvertFromInternalModel(rom, item))
.ToArray();
return Array.ConvertAll(roms, r => ConvertFromInternalModel(r, item));
}
/// <summary>

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using SabreTools.Models.AttractMode;
using SabreTools.Serialization.Interfaces;
@@ -17,13 +17,10 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.MetadataFile.HeaderKey] = ConvertHeaderToInternalModel(obj),
};
if (obj?.Row != null && obj.Row.Any())
if (obj?.Row != null && obj.Row.Length > 0)
{
metadataFile[Models.Metadata.MetadataFile.MachineKey] = obj.Row
.Where(r => r != null)
.Select(ConvertMachineToInternalModel)
.Where(m => m != null)
.ToArray();
metadataFile[Models.Metadata.MetadataFile.MachineKey]
= Array.ConvertAll(obj.Row, ConvertMachineToInternalModel);
}
return metadataFile;

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using SabreTools.Models.ClrMamePro;
using SabreTools.Serialization.Interfaces;
@@ -22,12 +22,10 @@ namespace SabreTools.Serialization.CrossModel
metadataFile.ClrMamePro = ConvertHeaderFromInternalModel(header);
var machines = obj.Read<Models.Metadata.Machine[]>(Models.Metadata.MetadataFile.MachineKey);
if (machines != null && machines.Any())
if (machines != null && machines.Length > 0)
{
metadataFile.Game = machines
.Where(m => m != null)
.Select(machine => ConvertMachineFromInternalModel(machine, game))
.ToArray();
metadataFile.Game
= Array.ConvertAll(machines, m => ConvertMachineFromInternalModel(m));
}
return metadataFile;
@@ -76,85 +74,40 @@ namespace SabreTools.Serialization.CrossModel
gameBase.SampleOf = item.ReadString(Models.Metadata.Machine.SampleOfKey);
var releases = item.Read<Models.Metadata.Release[]>(Models.Metadata.Machine.ReleaseKey);
if (releases != null && releases.Any())
{
gameBase.Release = releases
.Where(r => r != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (releases != null && releases.Length > 0)
gameBase.Release = Array.ConvertAll(releases, ConvertFromInternalModel);
var biosSets = item.Read<Models.Metadata.BiosSet[]>(Models.Metadata.Machine.BiosSetKey);
if (biosSets != null && biosSets.Any())
{
gameBase.BiosSet = biosSets
.Where(r => r != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (biosSets != null && biosSets.Length > 0)
gameBase.BiosSet = Array.ConvertAll(biosSets, ConvertFromInternalModel);
var roms = item.Read<Models.Metadata.Rom[]>(Models.Metadata.Machine.RomKey);
if (roms != null && roms.Any())
{
gameBase.Rom = roms
.Where(r => r != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (roms != null && roms.Length > 0)
gameBase.Rom = Array.ConvertAll(roms, ConvertFromInternalModel);
var disks = item.Read<Models.Metadata.Disk[]>(Models.Metadata.Machine.DiskKey);
if (disks != null && disks.Any())
{
gameBase.Disk = disks
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (disks != null && disks.Length > 0)
gameBase.Disk = Array.ConvertAll(disks, ConvertFromInternalModel);
var medias = item.Read<Models.Metadata.Media[]>(Models.Metadata.Machine.MediaKey);
if (medias != null && medias.Any())
{
gameBase.Media = medias
.Where(m => m != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (medias != null && medias.Length > 0)
gameBase.Media = Array.ConvertAll(medias, ConvertFromInternalModel);
var samples = item.Read<Models.Metadata.Sample[]>(Models.Metadata.Machine.SampleKey);
if (samples != null && samples.Any())
{
gameBase.Sample = samples
.Where(m => m != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (samples != null && samples.Length > 0)
gameBase.Sample = Array.ConvertAll(samples, ConvertFromInternalModel);
var archives = item.Read<Models.Metadata.Archive[]>(Models.Metadata.Machine.ArchiveKey);
if (archives != null && archives.Any())
{
gameBase.Archive = archives
.Where(m => m != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (archives != null && archives.Length > 0)
gameBase.Archive = Array.ConvertAll(archives, ConvertFromInternalModel);
var chips = item.Read<Models.Metadata.Chip[]>(Models.Metadata.Machine.ChipKey);
if (chips != null && chips.Any())
{
gameBase.Chip = chips
.Where(m => m != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (chips != null && chips.Length > 0)
gameBase.Chip = Array.ConvertAll(chips, ConvertFromInternalModel);
var videos = item.Read<Models.Metadata.Video[]>(Models.Metadata.Machine.VideoKey);
if (videos != null && videos.Any())
{
gameBase.Video = videos
.Where(m => m != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (videos != null && videos.Length > 0)
gameBase.Video = Array.ConvertAll(videos, ConvertFromInternalModel);
var sound = item.Read<Models.Metadata.Sound>(Models.Metadata.Machine.SoundKey);
if (sound != null)
@@ -165,13 +118,8 @@ namespace SabreTools.Serialization.CrossModel
gameBase.Input = ConvertFromInternalModel(input);
var dipSwitches = item.Read<Models.Metadata.DipSwitch[]>(Models.Metadata.Machine.DipSwitchKey);
if (dipSwitches != null && dipSwitches.Any())
{
gameBase.DipSwitch = dipSwitches
.Where(m => m != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (dipSwitches != null && dipSwitches.Length > 0)
gameBase.DipSwitch = Array.ConvertAll(dipSwitches, ConvertFromInternalModel);
var driver = item.Read<Models.Metadata.Driver>(Models.Metadata.Machine.DriverKey);
if (driver != null)

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using SabreTools.Models.ClrMamePro;
using SabreTools.Serialization.Interfaces;
@@ -17,13 +17,10 @@ namespace SabreTools.Serialization.CrossModel
if (obj?.ClrMamePro != null)
metadataFile[Models.Metadata.MetadataFile.HeaderKey] = ConvertHeaderToInternalModel(obj.ClrMamePro);
if (obj?.Game != null && obj.Game.Any())
if (obj?.Game != null && obj.Game.Length > 0)
{
metadataFile[Models.Metadata.MetadataFile.MachineKey] = obj.Game
.Where(g => g != null)
.Select(ConvertMachineToInternalModel)
.Where(m => m != null)
.ToArray();
metadataFile[Models.Metadata.MetadataFile.MachineKey]
= Array.ConvertAll(obj.Game, ConvertMachineToInternalModel);
}
return metadataFile;
@@ -75,76 +72,58 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.Machine.SampleOfKey] = item.SampleOf,
};
if (item.Release != null && item.Release.Any())
if (item.Release != null && item.Release.Length > 0)
{
machine[Models.Metadata.Machine.ReleaseKey] = item.Release
.Where(r => r != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.ReleaseKey]
= Array.ConvertAll(item.Release, ConvertToInternalModel);
}
if (item.BiosSet != null && item.BiosSet.Any())
if (item.BiosSet != null && item.BiosSet.Length > 0)
{
machine[Models.Metadata.Machine.BiosSetKey] = item.BiosSet
.Where(b => b != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.BiosSetKey]
= Array.ConvertAll(item.BiosSet, ConvertToInternalModel);
}
if (item.Rom != null && item.Rom.Any())
if (item.Rom != null && item.Rom.Length > 0)
{
machine[Models.Metadata.Machine.RomKey] = item.Rom
.Where(r => r != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.RomKey]
= Array.ConvertAll(item.Rom, ConvertToInternalModel);
}
if (item.Disk != null && item.Disk.Any())
if (item.Disk != null && item.Disk.Length > 0)
{
machine[Models.Metadata.Machine.DiskKey] = item.Disk
.Where(d => d != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.DiskKey]
= Array.ConvertAll(item.Disk, ConvertToInternalModel);
}
if (item.Media != null && item.Media.Any())
if (item.Media != null && item.Media.Length > 0)
{
machine[Models.Metadata.Machine.MediaKey] = item.Media
.Where(m => m != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.MediaKey]
= Array.ConvertAll(item.Media, ConvertToInternalModel);
}
if (item.Sample != null && item.Sample.Any())
if (item.Sample != null && item.Sample.Length > 0)
{
machine[Models.Metadata.Machine.SampleKey] = item.Sample
.Where(s => s != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.SampleKey]
= Array.ConvertAll(item.Sample, ConvertToInternalModel);
}
if (item.Archive != null && item.Archive.Any())
if (item.Archive != null && item.Archive.Length > 0)
{
machine[Models.Metadata.Machine.ArchiveKey] = item.Archive
.Where(a => a != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.ArchiveKey]
= Array.ConvertAll(item.Archive, ConvertToInternalModel);
}
if (item.Chip != null && item.Chip.Any())
if (item.Chip != null && item.Chip.Length > 0)
{
machine[Models.Metadata.Machine.ChipKey] = item.Chip
.Where(c => c != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.ChipKey]
= Array.ConvertAll(item.Chip, ConvertToInternalModel);
}
if (item.Video != null)
{
machine[Models.Metadata.Machine.VideoKey] = item.Video
.Where(v => v != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.VideoKey]
= Array.ConvertAll(item.Video, ConvertToInternalModel);
}
if (item.Sound != null)
@@ -153,12 +132,10 @@ namespace SabreTools.Serialization.CrossModel
if (item.Input != null)
machine[Models.Metadata.Machine.InputKey] = ConvertToInternalModel(item.Input);
if (item.DipSwitch != null && item.DipSwitch.Any())
if (item.DipSwitch != null && item.DipSwitch.Length > 0)
{
machine[Models.Metadata.Machine.DipSwitchKey] = item.DipSwitch
.Where(d => d != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.DipSwitchKey]
= Array.ConvertAll(item.DipSwitch, ConvertToInternalModel);
}
if (item.Driver != null)

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using SabreTools.Models.DosCenter;
using SabreTools.Serialization.Interfaces;
@@ -19,13 +19,8 @@ namespace SabreTools.Serialization.CrossModel
metadataFile.DosCenter = ConvertHeaderFromInternalModel(header);
var machines = obj.Read<Models.Metadata.Machine[]>(Models.Metadata.MetadataFile.MachineKey);
if (machines != null && machines.Any())
{
metadataFile.Game = machines
.Where(m => m != null)
.Select(ConvertMachineFromInternalModel)
.ToArray();
}
if (machines != null && machines.Length > 0)
metadataFile.Game = Array.ConvertAll(machines, ConvertMachineFromInternalModel);
return metadataFile;
}
@@ -59,13 +54,8 @@ namespace SabreTools.Serialization.CrossModel
};
var roms = item.Read<Models.Metadata.Rom[]>(Models.Metadata.Machine.RomKey);
if (roms != null && roms.Any())
{
game.File = roms
.Where(r => r != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (roms != null && roms.Length > 0)
game.File = Array.ConvertAll(roms, ConvertFromInternalModel);
return game;
}

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using SabreTools.Models.DosCenter;
using SabreTools.Serialization.Interfaces;
@@ -17,12 +17,10 @@ namespace SabreTools.Serialization.CrossModel
if (obj?.DosCenter != null)
metadataFile[Models.Metadata.MetadataFile.HeaderKey] = ConvertHeaderToInternalModel(obj.DosCenter);
if (obj?.Game != null && obj.Game.Any())
if (obj?.Game != null && obj.Game.Length > 0)
{
metadataFile[Models.Metadata.MetadataFile.MachineKey] = obj.Game
.Where(g => g != null)
.Select(ConvertMachineToInternalModel)
.ToArray();
metadataFile[Models.Metadata.MetadataFile.MachineKey]
= Array.ConvertAll(obj.Game, ConvertMachineToInternalModel);
}
return metadataFile;
@@ -56,12 +54,10 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.Machine.NameKey] = item.Name,
};
if (item.File != null && item.File.Any())
if (item.File != null && item.File.Length > 0)
{
machine[Models.Metadata.Machine.RomKey] = item.File
.Where(f => f != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.RomKey]
= Array.ConvertAll(item.File, ConvertToInternalModel);
}
return machine;

View File

@@ -1,5 +1,5 @@
using System;
using System.Linq;
using System.Collections.Generic;
using SabreTools.Models.EverdriveSMDB;
using SabreTools.Serialization.Interfaces;
@@ -16,13 +16,13 @@ namespace SabreTools.Serialization.CrossModel
var metadataFile = new MetadataFile();
var machines = obj.Read<Models.Metadata.Machine[]>(Models.Metadata.MetadataFile.MachineKey);
if (machines != null && machines.Any())
{
metadataFile.Row = machines
.Where(m => m != null)
.SelectMany(ConvertMachineFromInternalModel)
.ToArray();
}
var items = new List<Row>();
foreach (var machine in machines ?? [])
{
items.AddRange(ConvertMachineFromInternalModel(machine));
}
metadataFile.Row = [.. items];
return metadataFile;
}
@@ -33,13 +33,10 @@ namespace SabreTools.Serialization.CrossModel
private static Row[] ConvertMachineFromInternalModel(Models.Metadata.Machine item)
{
var roms = item.Read<Models.Metadata.Rom[]>(Models.Metadata.Machine.RomKey);
if (roms == null || !roms.Any())
if (roms == null || roms.Length == 0)
return [];
return roms
.Where(r => r != null)
.Select(ConvertFromInternalModel)
.ToArray();
return Array.ConvertAll(roms, ConvertFromInternalModel);
}
/// <summary>

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using SabreTools.Models.EverdriveSMDB;
using SabreTools.Serialization.Interfaces;
@@ -17,12 +17,10 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.MetadataFile.HeaderKey] = ConvertHeaderToInternalModel(),
};
if (obj?.Row != null && obj.Row.Any())
if (obj?.Row != null && obj.Row.Length > 0)
{
metadataFile[Models.Metadata.MetadataFile.MachineKey] = obj.Row
.Where(r => r != null)
.Select(ConvertMachineToInternalModel)
.ToArray();
metadataFile[Models.Metadata.MetadataFile.MachineKey]
= Array.ConvertAll(obj.Row, ConvertMachineToInternalModel);
}
return metadataFile;

View File

@@ -1,5 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SabreTools.Hashing;
using SabreTools.Models.Hashfile;
using SabreTools.Serialization.Interfaces;
@@ -18,12 +18,10 @@ namespace SabreTools.Serialization.CrossModel
return null;
var machines = obj.Read<Models.Metadata.Machine[]>(Models.Metadata.MetadataFile.MachineKey);
if (machines == null || !machines.Any())
if (machines == null || machines.Length == 0)
return null;
var hashfiles = machines
.Where(m => m != null)
.Select(machine => ConvertMachineFromInternalModel(machine, hash));
var hashfiles = Array.ConvertAll(machines, m => ConvertMachineFromInternalModel(m, hash));
var sfvs = new List<SFV>();
var md5s = new List<MD5>();
@@ -35,38 +33,38 @@ namespace SabreTools.Serialization.CrossModel
foreach (var hashfile in hashfiles)
{
if (hashfile.SFV != null && hashfile.SFV.Any())
if (hashfile.SFV != null && hashfile.SFV.Length > 0)
sfvs.AddRange(hashfile.SFV);
if (hashfile.MD5 != null && hashfile.MD5.Any())
if (hashfile.MD5 != null && hashfile.MD5.Length > 0)
md5s.AddRange(hashfile.MD5);
if (hashfile.SHA1 != null && hashfile.SHA1.Any())
if (hashfile.SHA1 != null && hashfile.SHA1.Length > 0)
sha1s.AddRange(hashfile.SHA1);
if (hashfile.SHA256 != null && hashfile.SHA256.Any())
if (hashfile.SHA256 != null && hashfile.SHA256.Length > 0)
sha256s.AddRange(hashfile.SHA256);
if (hashfile.SHA384 != null && hashfile.SHA384.Any())
if (hashfile.SHA384 != null && hashfile.SHA384.Length > 0)
sha384s.AddRange(hashfile.SHA384);
if (hashfile.SHA512 != null && hashfile.SHA512.Any())
if (hashfile.SHA512 != null && hashfile.SHA512.Length > 0)
sha512s.AddRange(hashfile.SHA512);
if (hashfile.SpamSum != null && hashfile.SpamSum.Any())
if (hashfile.SpamSum != null && hashfile.SpamSum.Length > 0)
spamsums.AddRange(hashfile.SpamSum);
}
var hashfileItem = new Models.Hashfile.Hashfile();
if (sfvs.Any())
hashfileItem.SFV = sfvs.ToArray();
if (md5s.Any())
hashfileItem.MD5 = md5s.ToArray();
if (sha1s.Any())
hashfileItem.SHA1 = sha1s.ToArray();
if (sha256s.Any())
hashfileItem.SHA256 = sha256s.ToArray();
if (sha384s.Any())
hashfileItem.SHA384 = sha384s.ToArray();
if (sha512s.Any())
hashfileItem.SHA512 = sha512s.ToArray();
if (spamsums.Any())
hashfileItem.SpamSum = spamsums.ToArray();
if (sfvs.Count > 0)
hashfileItem.SFV = [.. sfvs];
if (md5s.Count > 0)
hashfileItem.MD5 = [.. md5s];
if (sha1s.Count > 0)
hashfileItem.SHA1 = [.. sha1s];
if (sha256s.Count > 0)
hashfileItem.SHA256 = [.. sha256s];
if (sha384s.Count > 0)
hashfileItem.SHA384 = [.. sha384s];
if (sha512s.Count > 0)
hashfileItem.SHA512 = [.. sha512s];
if (spamsums.Count > 0)
hashfileItem.SpamSum = [.. spamsums];
return hashfileItem;
}
@@ -80,13 +78,8 @@ namespace SabreTools.Serialization.CrossModel
return null;
var machines = item.Read<Models.Metadata.Machine[]>(Models.Metadata.MetadataFile.MachineKey);
if (machines != null && machines.Any())
{
return machines
.Where(m => m != null)
.Select(machine => ConvertMachineFromInternalModel(machine, hash))
.ToArray();
}
if (machines != null && machines.Length > 0)
return Array.ConvertAll(machines, m => ConvertMachineFromInternalModel(m, hash));
return null;
}
@@ -102,47 +95,26 @@ namespace SabreTools.Serialization.CrossModel
return new Models.Hashfile.Hashfile
{
SFV = hash == HashType.CRC32 || hash == HashType.CRC32_ISO || hash == HashType.CRC32_Naive || hash == HashType.CRC32_Optimized || hash == HashType.CRC32_Parallel
? roms
.Where(r => r != null)
.Select(ConvertToSFV)
.ToArray()
SFV = hash == HashType.CRC32
? Array.ConvertAll(roms, ConvertToSFV)
: null,
MD5 = hash == HashType.MD5
? roms
.Where(r => r != null)
.Select(ConvertToMD5)
.ToArray()
? Array.ConvertAll(roms, ConvertToMD5)
: null,
SHA1 = hash == HashType.SHA1
? roms
.Where(r => r != null)
.Select(ConvertToSHA1)
.ToArray()
? Array.ConvertAll(roms, ConvertToSHA1)
: null,
SHA256 = hash == HashType.SHA256
? roms
.Where(r => r != null)
.Select(ConvertToSHA256)
.ToArray()
? Array.ConvertAll(roms, ConvertToSHA256)
: null,
SHA384 = hash == HashType.SHA384
? roms
.Where(r => r != null)
.Select(ConvertToSHA384)
.ToArray()
? Array.ConvertAll(roms, ConvertToSHA384)
: null,
SHA512 = hash == HashType.SHA512
? roms
.Where(r => r != null)
.Select(ConvertToSHA512)
.ToArray()
? Array.ConvertAll(roms, ConvertToSHA512)
: null,
SpamSum = hash == HashType.SpamSum
? roms
.Where(r => r != null)
.Select(ConvertToSpamSum)
.ToArray()
? Array.ConvertAll(roms, ConvertToSpamSum)
: null,
};
}

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using SabreTools.Models.Hashfile;
using SabreTools.Serialization.Interfaces;
@@ -42,20 +42,20 @@ namespace SabreTools.Serialization.CrossModel
{
var machine = new Models.Metadata.Machine();
if (item.SFV != null && item.SFV.Any())
machine[Models.Metadata.Machine.RomKey] = item.SFV.Select(ConvertToInternalModel).ToArray();
else if (item.MD5 != null && item.MD5.Any())
machine[Models.Metadata.Machine.RomKey] = item.MD5.Select(ConvertToInternalModel).ToArray();
else if (item.SHA1 != null && item.SHA1.Any())
machine[Models.Metadata.Machine.RomKey] = item.SHA1.Select(ConvertToInternalModel).ToArray();
else if (item.SHA256 != null && item.SHA256.Any())
machine[Models.Metadata.Machine.RomKey] = item.SHA256.Select(ConvertToInternalModel).ToArray();
else if (item.SHA384 != null && item.SHA384.Any())
machine[Models.Metadata.Machine.RomKey] = item.SHA384.Select(ConvertToInternalModel).ToArray();
else if (item.SHA512 != null && item.SHA512.Any())
machine[Models.Metadata.Machine.RomKey] = item.SHA512.Select(ConvertToInternalModel).ToArray();
else if (item.SpamSum != null && item.SpamSum.Any())
machine[Models.Metadata.Machine.RomKey] = item.SpamSum.Select(ConvertToInternalModel).ToArray();
if (item.SFV != null && item.SFV.Length > 0)
machine[Models.Metadata.Machine.RomKey] = Array.ConvertAll(item.SFV, ConvertToInternalModel);
else if (item.MD5 != null && item.MD5.Length > 0)
machine[Models.Metadata.Machine.RomKey] = Array.ConvertAll(item.MD5, ConvertToInternalModel);
else if (item.SHA1 != null && item.SHA1.Length > 0)
machine[Models.Metadata.Machine.RomKey] = Array.ConvertAll(item.SHA1, ConvertToInternalModel);
else if (item.SHA256 != null && item.SHA256.Length > 0)
machine[Models.Metadata.Machine.RomKey] = Array.ConvertAll(item.SHA256, ConvertToInternalModel);
else if (item.SHA384 != null && item.SHA384.Length > 0)
machine[Models.Metadata.Machine.RomKey] = Array.ConvertAll(item.SHA384, ConvertToInternalModel);
else if (item.SHA512 != null && item.SHA512.Length > 0)
machine[Models.Metadata.Machine.RomKey] = Array.ConvertAll(item.SHA512, ConvertToInternalModel);
else if (item.SpamSum != null && item.SpamSum.Length > 0)
machine[Models.Metadata.Machine.RomKey] = Array.ConvertAll(item.SpamSum, ConvertToInternalModel);
return machine;
}

View File

@@ -1,5 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SabreTools.Models.Listrom;
using SabreTools.Serialization.Interfaces;
@@ -16,13 +16,8 @@ namespace SabreTools.Serialization.CrossModel
var metadataFile = new MetadataFile();
var machines = obj.Read<Models.Metadata.Machine[]>(Models.Metadata.MetadataFile.MachineKey);
if (machines != null && machines.Any())
{
metadataFile.Set = machines
.Where(m => m != null)
.Select(ConvertMachineFromInternalModel)
.ToArray();
}
if (machines != null && machines.Length > 0)
metadataFile.Set = Array.ConvertAll(machines, ConvertMachineFromInternalModel);
return metadataFile;
}
@@ -43,14 +38,14 @@ namespace SabreTools.Serialization.CrossModel
var roms = item.Read<Models.Metadata.Rom[]>(Models.Metadata.Machine.RomKey);
if (roms != null)
{
rowItems.AddRange(roms.Where(r => r != null).Select(ConvertFromInternalModel));
rowItems.AddRange(Array.ConvertAll(roms, ConvertFromInternalModel));
}
var disks = item.Read<Models.Metadata.Disk[]>(Models.Metadata.Machine.DiskKey);
if (disks != null)
rowItems.AddRange(disks.Where(d => d != null).Select(ConvertFromInternalModel));
rowItems.AddRange(Array.ConvertAll(disks, ConvertFromInternalModel));
set.Row = rowItems.ToArray();
set.Row = [.. rowItems];
return set;
}

View File

@@ -1,5 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SabreTools.Models.Listrom;
using SabreTools.Serialization.Interfaces;
@@ -18,12 +18,10 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.MetadataFile.HeaderKey] = ConvertHeaderToInternalModel(),
};
if (obj?.Set != null && obj.Set.Any())
if (obj?.Set != null && obj.Set.Length > 0)
{
metadataFile[Models.Metadata.MetadataFile.MachineKey] = obj.Set
.Where(s => s != null)
.Select(ConvertMachineToInternalModel)
.ToArray();
metadataFile[Models.Metadata.MetadataFile.MachineKey]
= Array.ConvertAll(obj.Set, ConvertMachineToInternalModel);
}
return metadataFile;
@@ -57,16 +55,21 @@ namespace SabreTools.Serialization.CrossModel
machine[Models.Metadata.Machine.NameKey] = item.Driver;
}
if (item.Row != null && item.Row.Any())
if (item.Row != null && item.Row.Length > 0)
{
var datItems = new List<Models.Metadata.DatItem>();
var disks = new List<Models.Metadata.Disk>();
var roms = new List<Models.Metadata.Rom>();
foreach (var file in item.Row)
{
datItems.Add(ConvertToInternalModel(file));
var datItem = ConvertToInternalModel(file);
if (datItem is Models.Metadata.Disk disk)
disks.Add(disk);
else if (datItem is Models.Metadata.Rom rom)
roms.Add(rom);
}
machine[Models.Metadata.Machine.DiskKey] = datItems.Where(i => i.ReadString(Models.Metadata.DatItem.TypeKey) == "disk").Select(d => d as Models.Metadata.Disk).ToArray();
machine[Models.Metadata.Machine.RomKey] = datItems.Where(i => i.ReadString(Models.Metadata.DatItem.TypeKey) == "rom").Select(d => d as Models.Metadata.Rom).ToArray();
machine[Models.Metadata.Machine.DiskKey] = disks.ToArray();
machine[Models.Metadata.Machine.RomKey] = roms.ToArray();
}
return machine;

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using SabreTools.Models.Listxml;
using SabreTools.Serialization.Interfaces;
@@ -16,13 +16,8 @@ namespace SabreTools.Serialization.CrossModel
var mame = header != null ? ConvertMameFromInternalModel(header) : new Mame();
var machines = obj.Read<Models.Metadata.Machine[]>(Models.Metadata.MetadataFile.MachineKey);
if (machines != null && machines.Any())
{
mame.Game = machines
.Where(m => m != null)
.Select(ConvertMachineFromInternalModel)
.ToArray();
}
if (machines != null && machines.Length > 0)
mame.Game = Array.ConvertAll(machines, ConvertMachineFromInternalModel);
return mame;
}
@@ -39,13 +34,8 @@ namespace SabreTools.Serialization.CrossModel
var mame = header != null ? ConvertMameFromInternalModel(header) : new Mame();
var machines = item.Read<Models.Metadata.Machine[]>(Models.Metadata.MetadataFile.MachineKey);
if (machines != null && machines.Any())
{
mame.Game = machines
.Where(m => m != null)
.Select(ConvertMachineFromInternalModel)
.ToArray();
}
if (machines != null && machines.Length > 0)
mame.Game = Array.ConvertAll(machines, ConvertMachineFromInternalModel);
return mame;
}
@@ -88,76 +78,36 @@ namespace SabreTools.Serialization.CrossModel
};
var biosSets = item.Read<Models.Metadata.BiosSet[]>(Models.Metadata.Machine.BiosSetKey);
if (biosSets != null && biosSets.Any())
{
machine.BiosSet = biosSets
.Where(b => b != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (biosSets != null && biosSets.Length > 0)
machine.BiosSet = Array.ConvertAll(biosSets, ConvertFromInternalModel);
var roms = item.Read<Models.Metadata.Rom[]>(Models.Metadata.Machine.RomKey);
if (roms != null && roms.Any())
{
machine.Rom = roms
.Where(r => r != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (roms != null && roms.Length > 0)
machine.Rom = Array.ConvertAll(roms, ConvertFromInternalModel);
var disks = item.Read<Models.Metadata.Disk[]>(Models.Metadata.Machine.DiskKey);
if (disks != null && disks.Any())
{
machine.Disk = disks
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (disks != null && disks.Length > 0)
machine.Disk = Array.ConvertAll(disks, ConvertFromInternalModel);
var deviceRefs = item.Read<Models.Metadata.DeviceRef[]>(Models.Metadata.Machine.DeviceRefKey);
if (deviceRefs != null && deviceRefs.Any())
{
machine.DeviceRef = deviceRefs
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (deviceRefs != null && deviceRefs.Length > 0)
machine.DeviceRef = Array.ConvertAll(deviceRefs, ConvertFromInternalModel);
var samples = item.Read<Models.Metadata.Sample[]>(Models.Metadata.Machine.SampleKey);
if (samples != null && samples.Any())
{
machine.Sample = samples
.Where(s => s != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (samples != null && samples.Length > 0)
machine.Sample = Array.ConvertAll(samples, ConvertFromInternalModel);
var chips = item.Read<Models.Metadata.Chip[]>(Models.Metadata.Machine.ChipKey);
if (chips != null && chips.Any())
{
machine.Chip = chips
.Where(c => c != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (chips != null && chips.Length > 0)
machine.Chip = Array.ConvertAll(chips, ConvertFromInternalModel);
var displays = item.Read<Models.Metadata.Display[]>(Models.Metadata.Machine.DisplayKey);
if (displays != null && displays.Any())
{
machine.Display = displays
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (displays != null && displays.Length > 0)
machine.Display = Array.ConvertAll(displays, ConvertFromInternalModel);
var videos = item.Read<Models.Metadata.Video[]>(Models.Metadata.Machine.VideoKey);
if (videos != null && videos.Any())
{
machine.Video = videos
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (videos != null && videos.Length > 0)
machine.Video = Array.ConvertAll(videos, ConvertFromInternalModel);
var sound = item.Read<Models.Metadata.Sound>(Models.Metadata.Machine.SoundKey);
if (sound != null)
@@ -168,89 +118,44 @@ namespace SabreTools.Serialization.CrossModel
machine.Input = ConvertFromInternalModel(input);
var dipSwitches = item.Read<Models.Metadata.DipSwitch[]>(Models.Metadata.Machine.DipSwitchKey);
if (dipSwitches != null && dipSwitches.Any())
{
machine.DipSwitch = dipSwitches
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (dipSwitches != null && dipSwitches.Length > 0)
machine.DipSwitch = Array.ConvertAll(dipSwitches, ConvertFromInternalModel);
var configurations = item.Read<Models.Metadata.Configuration[]>(Models.Metadata.Machine.ConfigurationKey);
if (configurations != null && configurations.Any())
{
machine.Configuration = configurations
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (configurations != null && configurations.Length > 0)
machine.Configuration = Array.ConvertAll(configurations, ConvertFromInternalModel);
var ports = item.Read<Models.Metadata.Port[]>(Models.Metadata.Machine.PortKey);
if (ports != null && ports.Any())
{
machine.Port = ports
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (ports != null && ports.Length > 0)
machine.Port = Array.ConvertAll(ports, ConvertFromInternalModel);
var adjusters = item.Read<Models.Metadata.Adjuster[]>(Models.Metadata.Machine.AdjusterKey);
if (adjusters != null && adjusters.Any())
{
machine.Adjuster = adjusters
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (adjusters != null && adjusters.Length > 0)
machine.Adjuster = Array.ConvertAll(adjusters, ConvertFromInternalModel);
var driver = item.Read<Models.Metadata.Driver>(Models.Metadata.Machine.DriverKey);
if (driver != null)
machine.Driver = ConvertFromInternalModel(driver);
var features = item.Read<Models.Metadata.Feature[]>(Models.Metadata.Machine.FeatureKey);
if (features != null && features.Any())
{
machine.Feature = features
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (features != null && features.Length > 0)
machine.Feature = Array.ConvertAll(features, ConvertFromInternalModel);
var devices = item.Read<Models.Metadata.Device[]>(Models.Metadata.Machine.DeviceKey);
if (devices != null && devices.Any())
{
machine.Device = devices
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (devices != null && devices.Length > 0)
machine.Device = Array.ConvertAll(devices, ConvertFromInternalModel);
var slots = item.Read<Models.Metadata.Slot[]>(Models.Metadata.Machine.SlotKey);
if (slots != null && slots.Any())
{
machine.Slot = slots
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (slots != null && slots.Length > 0)
machine.Slot = Array.ConvertAll(slots, ConvertFromInternalModel);
var softwareLists = item.Read<Models.Metadata.SoftwareList[]>(Models.Metadata.Machine.SoftwareListKey);
if (softwareLists != null && softwareLists.Any())
{
machine.SoftwareList = softwareLists
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (softwareLists != null && softwareLists.Length > 0)
machine.SoftwareList = Array.ConvertAll(softwareLists, ConvertFromInternalModel);
var ramOptions = item.Read<Models.Metadata.RamOption[]>(Models.Metadata.Machine.RamOptionKey);
if (ramOptions != null && ramOptions.Any())
{
machine.RamOption = ramOptions
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (ramOptions != null && ramOptions.Length > 0)
machine.RamOption = Array.ConvertAll(ramOptions, ConvertFromInternalModel);
return machine;
}
@@ -347,22 +252,12 @@ namespace SabreTools.Serialization.CrossModel
configuration.Condition = ConvertFromInternalModel(condition);
var confLocations = item.Read<Models.Metadata.ConfLocation[]>(Models.Metadata.Configuration.ConfLocationKey);
if (confLocations != null && confLocations.Any())
{
configuration.ConfLocation = confLocations
.Where(c => c != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (confLocations != null && confLocations.Length > 0)
configuration.ConfLocation = Array.ConvertAll(confLocations, ConvertFromInternalModel);
var confSettings = item.Read<Models.Metadata.ConfSetting[]>(Models.Metadata.Configuration.ConfSettingKey);
if (confSettings != null && confSettings.Any())
{
configuration.ConfSetting = confSettings
.Where(c => c != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (confSettings != null && confSettings.Length > 0)
configuration.ConfSetting = Array.ConvertAll(confSettings, ConvertFromInternalModel);
return configuration;
}
@@ -442,13 +337,8 @@ namespace SabreTools.Serialization.CrossModel
device.Instance = ConvertFromInternalModel(instance);
var extensions = item.Read<Models.Metadata.Extension[]>(Models.Metadata.Device.ExtensionKey);
if (extensions != null && extensions.Any())
{
device.Extension = extensions
.Where(e => e != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (extensions != null && extensions.Length > 0)
device.Extension = Array.ConvertAll(extensions, ConvertFromInternalModel);
return device;
}
@@ -496,22 +386,12 @@ namespace SabreTools.Serialization.CrossModel
dipSwitch.Condition = ConvertFromInternalModel(condition);
var dipLocations = item.Read<Models.Metadata.DipLocation[]>(Models.Metadata.DipSwitch.DipLocationKey);
if (dipLocations != null && dipLocations.Any())
{
dipSwitch.DipLocation = dipLocations
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (dipLocations != null && dipLocations.Length > 0)
dipSwitch.DipLocation = Array.ConvertAll(dipLocations, ConvertFromInternalModel);
var dipValues = item.Read<Models.Metadata.DipValue[]>(Models.Metadata.DipSwitch.DipValueKey);
if (dipValues != null && dipValues.Any())
{
dipSwitch.DipValue = dipValues
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (dipValues != null && dipValues.Length > 0)
dipSwitch.DipValue = Array.ConvertAll(dipValues, ConvertFromInternalModel);
return dipSwitch;
}
@@ -644,13 +524,8 @@ namespace SabreTools.Serialization.CrossModel
};
var controls = item.Read<Models.Metadata.Control[]>(Models.Metadata.Input.ControlKey);
if (controls != null && controls.Any())
{
input.Control = controls
.Where(c => c != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (controls != null && controls.Length > 0)
input.Control = Array.ConvertAll(controls, ConvertFromInternalModel);
return input;
}
@@ -679,13 +554,8 @@ namespace SabreTools.Serialization.CrossModel
};
var analogs = item.Read<Models.Metadata.Analog[]>(Models.Metadata.Port.AnalogKey);
if (analogs != null && analogs.Any())
{
port.Analog = analogs
.Where(a => a != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (analogs != null && analogs.Length > 0)
port.Analog = Array.ConvertAll(analogs, ConvertFromInternalModel);
return port;
}
@@ -750,13 +620,8 @@ namespace SabreTools.Serialization.CrossModel
};
var slotOptions = item.Read<Models.Metadata.SlotOption[]>(Models.Metadata.Slot.SlotOptionKey);
if (slotOptions != null && slotOptions.Any())
{
slot.SlotOption = slotOptions
.Where(s => s != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (slotOptions != null && slotOptions.Length > 0)
slot.SlotOption = Array.ConvertAll(slotOptions, ConvertFromInternalModel);
return slot;
}

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using SabreTools.Models.Listxml;
using SabreTools.Serialization.Interfaces;
@@ -17,12 +17,10 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.MetadataFile.HeaderKey] = ConvertHeaderToInternalModel(item),
};
if (item?.Game != null && item.Game.Any())
if (item?.Game != null && item.Game.Length > 0)
{
metadataFile[Models.Metadata.MetadataFile.MachineKey] = item.Game
.Where(g => g != null)
.Select(ConvertMachineToInternalModel)
.ToArray();
metadataFile[Models.Metadata.MetadataFile.MachineKey]
= Array.ConvertAll(item.Game, ConvertMachineToInternalModel);
}
return metadataFile;
@@ -64,68 +62,52 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.Machine.HistoryKey] = item.History,
};
if (item.BiosSet != null && item.BiosSet.Any())
if (item.BiosSet != null && item.BiosSet.Length > 0)
{
machine[Models.Metadata.Machine.BiosSetKey] = item.BiosSet
.Where(b => b != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.BiosSetKey]
= Array.ConvertAll(item.BiosSet, ConvertToInternalModel);
}
if (item.Rom != null && item.Rom.Any())
if (item.Rom != null && item.Rom.Length > 0)
{
machine[Models.Metadata.Machine.RomKey] = item.Rom
.Where(r => r != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.RomKey]
= Array.ConvertAll(item.Rom, ConvertToInternalModel);
}
if (item.Disk != null && item.Disk.Any())
if (item.Disk != null && item.Disk.Length > 0)
{
machine[Models.Metadata.Machine.DiskKey] = item.Disk
.Where(d => d != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.DiskKey]
= Array.ConvertAll(item.Disk, ConvertToInternalModel);
}
if (item.DeviceRef != null && item.DeviceRef.Any())
if (item.DeviceRef != null && item.DeviceRef.Length > 0)
{
machine[Models.Metadata.Machine.DeviceRefKey] = item.DeviceRef
.Where(d => d != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.DeviceRefKey]
= Array.ConvertAll(item.DeviceRef, ConvertToInternalModel);
}
if (item.Sample != null && item.Sample.Any())
if (item.Sample != null && item.Sample.Length > 0)
{
machine[Models.Metadata.Machine.SampleKey] = item.Sample
.Where(s => s != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.SampleKey]
= Array.ConvertAll(item.Sample, ConvertToInternalModel);
}
if (item.Chip != null && item.Chip.Any())
if (item.Chip != null && item.Chip.Length > 0)
{
machine[Models.Metadata.Machine.ChipKey] = item.Chip
.Where(c => c != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.ChipKey]
= Array.ConvertAll(item.Chip, ConvertToInternalModel);
}
if (item.Display != null && item.Display.Any())
if (item.Display != null && item.Display.Length > 0)
{
machine[Models.Metadata.Machine.DisplayKey] = item.Display
.Where(d => d != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.DisplayKey]
= Array.ConvertAll(item.Display, ConvertToInternalModel);
}
if (item.Video != null && item.Video.Any())
if (item.Video != null && item.Video.Length > 0)
{
machine[Models.Metadata.Machine.VideoKey] = item.Video
.Where(v => v != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.VideoKey]
= Array.ConvertAll(item.Video, ConvertToInternalModel);
}
if (item.Sound != null)
@@ -134,79 +116,61 @@ namespace SabreTools.Serialization.CrossModel
if (item.Input != null)
machine[Models.Metadata.Machine.InputKey] = ConvertToInternalModel(item.Input);
if (item.DipSwitch != null && item.DipSwitch.Any())
if (item.DipSwitch != null && item.DipSwitch.Length > 0)
{
machine[Models.Metadata.Machine.DipSwitchKey] = item.DipSwitch
.Where(d => d != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.DipSwitchKey]
= Array.ConvertAll(item.DipSwitch, ConvertToInternalModel);
}
if (item.Configuration != null && item.Configuration.Any())
if (item.Configuration != null && item.Configuration.Length > 0)
{
machine[Models.Metadata.Machine.ConfigurationKey] = item.Configuration
.Where(c => c != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.ConfigurationKey]
= Array.ConvertAll(item.Configuration, ConvertToInternalModel);
}
if (item.Port != null && item.Port.Any())
if (item.Port != null && item.Port.Length > 0)
{
machine[Models.Metadata.Machine.PortKey] = item.Port
.Where(p => p != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.PortKey]
= Array.ConvertAll(item.Port, ConvertToInternalModel);
}
if (item.Adjuster != null && item.Adjuster.Any())
if (item.Adjuster != null && item.Adjuster.Length > 0)
{
machine[Models.Metadata.Machine.AdjusterKey] = item.Adjuster
.Where(a => a != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.AdjusterKey]
= Array.ConvertAll(item.Adjuster, ConvertToInternalModel);
}
if (item.Driver != null)
machine[Models.Metadata.Machine.DriverKey] = ConvertToInternalModel(item.Driver);
if (item.Feature != null && item.Feature.Any())
if (item.Feature != null && item.Feature.Length > 0)
{
machine[Models.Metadata.Machine.FeatureKey] = item.Feature
.Where(f => f != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.FeatureKey]
= Array.ConvertAll(item.Feature, ConvertToInternalModel);
}
if (item.Device != null && item.Device.Any())
if (item.Device != null && item.Device.Length > 0)
{
machine[Models.Metadata.Machine.DeviceKey] = item.Device
.Where(d => d != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.DeviceKey]
= Array.ConvertAll(item.Device, ConvertToInternalModel);
}
if (item.Slot != null && item.Slot.Any())
if (item.Slot != null && item.Slot.Length > 0)
{
machine[Models.Metadata.Machine.SlotKey] = item.Slot
.Where(s => s != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.SlotKey]
= Array.ConvertAll(item.Slot, ConvertToInternalModel);
}
if (item.SoftwareList != null && item.SoftwareList.Any())
if (item.SoftwareList != null && item.SoftwareList.Length > 0)
{
machine[Models.Metadata.Machine.SoftwareListKey] = item.SoftwareList
.Where(s => s != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.SoftwareListKey]
= Array.ConvertAll(item.SoftwareList, ConvertToInternalModel);
}
if (item.RamOption != null && item.RamOption.Any())
if (item.RamOption != null && item.RamOption.Length > 0)
{
machine[Models.Metadata.Machine.RamOptionKey] = item.RamOption
.Where(r => r != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.RamOptionKey]
= Array.ConvertAll(item.RamOption, ConvertToInternalModel);
}
return machine;
@@ -301,20 +265,16 @@ namespace SabreTools.Serialization.CrossModel
if (item.Condition != null)
configuration[Models.Metadata.Configuration.ConditionKey] = ConvertToInternalModel(item.Condition);
if (item.ConfLocation != null && item.ConfLocation.Any())
if (item.ConfLocation != null && item.ConfLocation.Length > 0)
{
configuration[Models.Metadata.Configuration.ConfLocationKey] = item.ConfLocation
.Where(c => c != null)
.Select(ConvertToInternalModel)
.ToArray();
configuration[Models.Metadata.Configuration.ConfLocationKey]
= Array.ConvertAll(item.ConfLocation, ConvertToInternalModel);
}
if (item.ConfSetting != null && item.ConfSetting.Any())
if (item.ConfSetting != null && item.ConfSetting.Length > 0)
{
configuration[Models.Metadata.Configuration.ConfSettingKey] = item.ConfSetting
.Where(c => c != null)
.Select(ConvertToInternalModel)
.ToArray();
configuration[Models.Metadata.Configuration.ConfSettingKey]
= Array.ConvertAll(item.ConfSetting, ConvertToInternalModel);
}
return configuration;
@@ -392,12 +352,10 @@ namespace SabreTools.Serialization.CrossModel
if (item.Instance != null)
device[Models.Metadata.Device.InstanceKey] = ConvertToInternalModel(item.Instance);
if (item.Extension != null && item.Extension.Any())
if (item.Extension != null && item.Extension.Length > 0)
{
device[Models.Metadata.Device.ExtensionKey] = item.Extension
.Where(e => e != null)
.Select(ConvertToInternalModel)
.ToArray();
device[Models.Metadata.Device.ExtensionKey]
= Array.ConvertAll(item.Extension, ConvertToInternalModel);
}
return device;
@@ -444,20 +402,16 @@ namespace SabreTools.Serialization.CrossModel
if (item.Condition != null)
dipSwitch[Models.Metadata.DipSwitch.ConditionKey] = ConvertToInternalModel(item.Condition);
if (item.DipLocation != null && item.DipLocation.Any())
if (item.DipLocation != null && item.DipLocation.Length > 0)
{
dipSwitch[Models.Metadata.DipSwitch.DipLocationKey] = item.DipLocation
.Where(d => d != null)
.Select(ConvertToInternalModel)
.ToArray();
dipSwitch[Models.Metadata.DipSwitch.DipLocationKey]
= Array.ConvertAll(item.DipLocation, ConvertToInternalModel);
}
if (item.DipValue != null && item.DipValue.Any())
if (item.DipValue != null && item.DipValue.Length > 0)
{
dipSwitch[Models.Metadata.DipSwitch.DipValueKey] = item.DipValue
.Where(d => d != null)
.Select(ConvertToInternalModel)
.ToArray();
dipSwitch[Models.Metadata.DipSwitch.DipValueKey]
= Array.ConvertAll(item.DipValue, ConvertToInternalModel);
}
return dipSwitch;
@@ -589,12 +543,10 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.Input.CoinsKey] = item.Coins,
};
if (item.Control != null && item.Control.Any())
if (item.Control != null && item.Control.Length > 0)
{
input[Models.Metadata.Input.ControlKey] = item.Control
.Where(c => c != null)
.Select(ConvertToInternalModel)
.ToArray();
input[Models.Metadata.Input.ControlKey]
= Array.ConvertAll(item.Control, ConvertToInternalModel);
}
return input;
@@ -623,12 +575,10 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.Port.TagKey] = item.Tag,
};
if (item.Analog != null && item.Analog.Any())
if (item.Analog != null && item.Analog.Length > 0)
{
port[Models.Metadata.Port.AnalogKey] = item.Analog
.Where(a => a != null)
.Select(ConvertToInternalModel)
.ToArray();
port[Models.Metadata.Port.AnalogKey]
= Array.ConvertAll(item.Analog, ConvertToInternalModel);
}
return port;
@@ -693,12 +643,10 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.Slot.NameKey] = item.Name,
};
if (item.SlotOption != null && item.SlotOption.Any())
if (item.SlotOption != null && item.SlotOption.Length > 0)
{
slot[Models.Metadata.Slot.SlotOptionKey] = item.SlotOption
.Where(s => s != null)
.Select(ConvertToInternalModel)
.ToArray();
slot[Models.Metadata.Slot.SlotOptionKey]
= Array.ConvertAll(item.SlotOption, ConvertToInternalModel);
}
return slot;

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using SabreTools.Models.Logiqx;
using SabreTools.Serialization.Interfaces;
@@ -28,13 +28,8 @@ namespace SabreTools.Serialization.CrossModel
// 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.Any())
{
datafile.Game = machines
.Where(m => m != null)
.Select(machine => ConvertMachineFromInternalModel(machine, game))
.ToArray();
}
if (machines != null && machines.Length > 0)
datafile.Game = Array.ConvertAll(machines, m => ConvertMachineFromInternalModel(m, game));
return datafile;
}
@@ -130,89 +125,44 @@ namespace SabreTools.Serialization.CrossModel
gameBase.Trurip = trurip;
var releases = item.Read<Models.Metadata.Release[]>(Models.Metadata.Machine.ReleaseKey);
if (releases != null && releases.Any())
{
gameBase.Release = releases
.Where(r => r != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (releases != null && releases.Length > 0)
gameBase.Release = Array.ConvertAll(releases, ConvertFromInternalModel);
var biosSets = item.Read<Models.Metadata.BiosSet[]>(Models.Metadata.Machine.BiosSetKey);
if (biosSets != null && biosSets.Any())
{
gameBase.BiosSet = biosSets
.Where(b => b != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (biosSets != null && biosSets.Length > 0)
gameBase.BiosSet = Array.ConvertAll(biosSets, ConvertFromInternalModel);
var roms = item.Read<Models.Metadata.Rom[]>(Models.Metadata.Machine.RomKey);
if (roms != null && roms.Any())
{
gameBase.Rom = roms
.Where(r => r != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (roms != null && roms.Length > 0)
gameBase.Rom = Array.ConvertAll(roms, ConvertFromInternalModel);
var disks = item.Read<Models.Metadata.Disk[]>(Models.Metadata.Machine.DiskKey);
if (disks != null && disks.Any())
{
gameBase.Disk = disks
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (disks != null && disks.Length > 0)
gameBase.Disk = Array.ConvertAll(disks, ConvertFromInternalModel);
var medias = item.Read<Models.Metadata.Media[]>(Models.Metadata.Machine.MediaKey);
if (medias != null && medias.Any())
{
gameBase.Media = medias
.Where(m => m != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (medias != null && medias.Length > 0)
gameBase.Media = Array.ConvertAll(medias, ConvertFromInternalModel);
var deviceRefs = item.Read<Models.Metadata.DeviceRef[]>(Models.Metadata.Machine.DeviceRefKey);
if (deviceRefs != null && deviceRefs.Any())
{
gameBase.DeviceRef = deviceRefs
.Where(m => m != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (deviceRefs != null && deviceRefs.Length > 0)
gameBase.DeviceRef = Array.ConvertAll(deviceRefs, ConvertFromInternalModel);
var samples = item.Read<Models.Metadata.Sample[]>(Models.Metadata.Machine.SampleKey);
if (samples != null && samples.Any())
{
gameBase.Sample = samples
.Where(m => m != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (samples != null && samples.Length > 0)
gameBase.Sample = Array.ConvertAll(samples, ConvertFromInternalModel);
var archives = item.Read<Models.Metadata.Archive[]>(Models.Metadata.Machine.ArchiveKey);
if (archives != null && archives.Any())
{
gameBase.Archive = archives
.Where(m => m != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (archives != null && archives.Length > 0)
gameBase.Archive = Array.ConvertAll(archives, ConvertFromInternalModel);
var driver = item.Read<Models.Metadata.Driver>(Models.Metadata.Machine.DriverKey);
if (driver != null)
gameBase.Driver = ConvertFromInternalModel(driver);
var softwareLists = item.Read<Models.Metadata.SoftwareList[]>(Models.Metadata.Machine.SoftwareListKey);
if (softwareLists != null && softwareLists.Any())
{
gameBase.SoftwareList = softwareLists
.Where(m => m != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (softwareLists != null && softwareLists.Length > 0)
gameBase.SoftwareList = Array.ConvertAll(softwareLists, ConvertFromInternalModel);
return gameBase;
}

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SabreTools.Models.Logiqx;
using SabreTools.Serialization.Interfaces;
@@ -20,21 +19,15 @@ namespace SabreTools.Serialization.CrossModel
var machines = new List<Models.Metadata.Machine>();
if (item.Game != null && item.Game.Any())
if (item.Game != null && item.Game.Length > 0)
machines.AddRange(Array.ConvertAll(item.Game, ConvertMachineToInternalModel));
foreach (var dir in item.Dir ?? [])
{
machines.AddRange(item.Game
.Where(g => g != null)
.Select(ConvertMachineToInternalModel));
machines.AddRange(ConvertDirToInternalModel(dir));
}
if (item.Dir != null && item.Dir.Any())
{
machines.AddRange(item.Dir
.Where(d => d != null)
.SelectMany(ConvertDirToInternalModel));
}
if (machines.Any())
if (machines.Count > 0)
metadataFile[Models.Metadata.MetadataFile.MachineKey] = machines.ToArray();
return metadataFile;
@@ -103,18 +96,15 @@ namespace SabreTools.Serialization.CrossModel
/// </summary>
private static Models.Metadata.Machine[] ConvertDirToInternalModel(Dir item)
{
if (item.Game == null || !item.Game.Any())
if (item.Game == null || item.Game.Length == 0)
return [];
return item.Game
.Where(g => g != null)
.Select(game =>
return Array.ConvertAll(item.Game, g =>
{
var machine = ConvertMachineToInternalModel(game);
var machine = ConvertMachineToInternalModel(g);
machine[Models.Metadata.Machine.DirNameKey] = item.Name;
return machine;
})
.ToArray();
});
}
/// <summary>
@@ -146,35 +136,35 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.Machine.TruripKey] = item.Trurip,
};
if (item.Release != null && item.Release.Any())
machine[Models.Metadata.Machine.ReleaseKey] = item.Release.Select(ConvertToInternalModel).ToArray();
if (item.Release != null && item.Release.Length > 0)
machine[Models.Metadata.Machine.ReleaseKey] = Array.ConvertAll(item.Release, ConvertToInternalModel);
if (item.BiosSet != null && item.BiosSet.Any())
machine[Models.Metadata.Machine.BiosSetKey] = item.BiosSet.Select(ConvertToInternalModel).ToArray();
if (item.BiosSet != null && item.BiosSet.Length > 0)
machine[Models.Metadata.Machine.BiosSetKey] = Array.ConvertAll(item.BiosSet, ConvertToInternalModel);
if (item.Rom != null && item.Rom.Any())
machine[Models.Metadata.Machine.RomKey] = item.Rom.Select(ConvertToInternalModel).ToArray();
if (item.Rom != null && item.Rom.Length > 0)
machine[Models.Metadata.Machine.RomKey] = Array.ConvertAll(item.Rom, ConvertToInternalModel);
if (item.Disk != null && item.Disk.Any())
machine[Models.Metadata.Machine.DiskKey] = item.Disk.Select(ConvertToInternalModel).ToArray();
if (item.Disk != null && item.Disk.Length > 0)
machine[Models.Metadata.Machine.DiskKey] = Array.ConvertAll(item.Disk, ConvertToInternalModel);
if (item.Media != null && item.Media.Any())
machine[Models.Metadata.Machine.MediaKey] = item.Media.Select(ConvertToInternalModel).ToArray();
if (item.Media != null && item.Media.Length > 0)
machine[Models.Metadata.Machine.MediaKey] = Array.ConvertAll(item.Media, ConvertToInternalModel);
if (item.DeviceRef != null && item.DeviceRef.Any())
machine[Models.Metadata.Machine.DeviceRefKey] = item.DeviceRef.Select(ConvertToInternalModel).ToArray();
if (item.DeviceRef != null && item.DeviceRef.Length > 0)
machine[Models.Metadata.Machine.DeviceRefKey] = Array.ConvertAll(item.DeviceRef, ConvertToInternalModel);
if (item.Sample != null && item.Sample.Any())
machine[Models.Metadata.Machine.SampleKey] = item.Sample.Select(ConvertToInternalModel).ToArray();
if (item.Sample != null && item.Sample.Length > 0)
machine[Models.Metadata.Machine.SampleKey] = Array.ConvertAll(item.Sample, ConvertToInternalModel);
if (item.Archive != null && item.Archive.Any())
machine[Models.Metadata.Machine.ArchiveKey] = item.Archive.Select(ConvertToInternalModel).ToArray();
if (item.Archive != null && item.Archive.Length > 0)
machine[Models.Metadata.Machine.ArchiveKey] = Array.ConvertAll(item.Archive, ConvertToInternalModel);
if (item.Driver != null)
machine[Models.Metadata.Machine.DriverKey] = ConvertToInternalModel(item.Driver);
if (item.SoftwareList != null && item.SoftwareList.Any())
machine[Models.Metadata.Machine.SoftwareListKey] = item.SoftwareList.Select(ConvertToInternalModel).ToArray();
if (item.SoftwareList != null && item.SoftwareList.Length > 0)
machine[Models.Metadata.Machine.SoftwareListKey] = Array.ConvertAll(item.SoftwareList, ConvertToInternalModel);
return machine;
}

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
@@ -15,13 +15,8 @@ namespace SabreTools.Serialization.CrossModel
var m1 = header != null ? ConvertM1FromInternalModel(header) : new Models.Listxml.M1();
var machines = obj.Read<Models.Metadata.Machine[]>(Models.Metadata.MetadataFile.MachineKey);
if (machines != null && machines.Any())
{
m1.Game = machines
.Where(m => m != null)
.Select(Listxml.ConvertMachineFromInternalModel)
.ToArray();
}
if (machines != null && machines.Length > 0)
m1.Game = Array.ConvertAll(machines, Listxml.ConvertMachineFromInternalModel);
return m1;
}

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
@@ -16,12 +16,10 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.MetadataFile.HeaderKey] = ConvertHeaderToInternalModel(item),
};
if (item?.Game != null && item.Game.Any())
if (item?.Game != null && item.Game.Length > 0)
{
metadataFile[Models.Metadata.MetadataFile.MachineKey] = item.Game
.Where(g => g != null)
.Select(Listxml.ConvertMachineToInternalModel)
.ToArray();
metadataFile[Models.Metadata.MetadataFile.MachineKey]
= Array.ConvertAll(item.Game, Listxml.ConvertMachineToInternalModel);
}
return metadataFile;

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using SabreTools.Models.OfflineList;
using SabreTools.Serialization.Interfaces;
@@ -16,14 +16,11 @@ namespace SabreTools.Serialization.CrossModel
var dat = header != null ? ConvertHeaderFromInternalModel(header) : new Dat();
var machines = obj.Read<Models.Metadata.Machine[]>(Models.Metadata.MetadataFile.MachineKey);
if (machines != null && machines.Any())
if (machines != null && machines.Length > 0)
{
dat.Games = new Games
{
Game = machines
.Where(m => m != null)
.Select(ConvertMachineFromInternalModel)
.ToArray()
Game = Array.ConvertAll(machines, ConvertMachineFromInternalModel),
};
}
@@ -101,17 +98,12 @@ namespace SabreTools.Serialization.CrossModel
};
var roms = item.Read<Models.Metadata.Rom[]>(Models.Metadata.Machine.RomKey);
if (roms != null && roms.Any())
if (roms != null && roms.Length > 0)
{
game.RomSize = roms
.Select(rom => rom.ReadString(Models.Metadata.Rom.SizeKey))
.FirstOrDefault(s => s != null);
var romCRCs = roms
.Where(r => r != null)
.Select(ConvertFromInternalModel)
.ToArray();
var romSizes = Array.ConvertAll(roms, r => r.ReadLong(Models.Metadata.Rom.SizeKey) ?? -1);
game.RomSize = Array.Find(romSizes, s => s > -1).ToString();
var romCRCs = Array.ConvertAll(roms, ConvertFromInternalModel);;
game.Files = new Models.OfflineList.Files { RomCRC = romCRCs };
}

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using SabreTools.Models.OfflineList;
using SabreTools.Serialization.Interfaces;
@@ -17,12 +17,10 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.MetadataFile.HeaderKey] = ConvertHeaderToInternalModel(item),
};
if (item?.Games?.Game != null && item.Games.Game.Any())
if (item?.Games?.Game != null && item.Games.Game.Length > 0)
{
metadataFile[Models.Metadata.MetadataFile.MachineKey] = item.Games.Game
.Where(g => g != null)
.Select(ConvertMachineToInternalModel)
.ToArray();
metadataFile[Models.Metadata.MetadataFile.MachineKey]
= Array.ConvertAll(item.Games.Game, ConvertMachineToInternalModel);
}
return metadataFile;
@@ -82,17 +80,15 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.Machine.DuplicateIDKey] = item.DuplicateID,
};
if (item.Files?.RomCRC != null && item.Files.RomCRC.Any())
if (item.Files?.RomCRC != null && item.Files.RomCRC.Length > 0)
{
machine[Models.Metadata.Machine.RomKey] = item.Files.RomCRC
.Where(r => r != null)
.Select(romCRC =>
{
var rom = ConvertToInternalModel(romCRC);
rom[Models.Metadata.Rom.SizeKey] = item.RomSize;
return rom;
})
.ToArray();
machine[Models.Metadata.Machine.RomKey]
= Array.ConvertAll(item.Files.RomCRC, romCRC =>
{
var rom = ConvertToInternalModel(romCRC);
rom[Models.Metadata.Rom.SizeKey] = item.RomSize;
return rom;
});
}
return machine;

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using SabreTools.Models.OpenMSX;
using SabreTools.Serialization.Interfaces;
@@ -16,13 +16,8 @@ namespace SabreTools.Serialization.CrossModel
var softwareDb = header != null ? ConvertHeaderFromInternalModel(header) : new SoftwareDb();
var machines = obj.Read<Models.Metadata.Machine[]>(Models.Metadata.MetadataFile.MachineKey);
if (machines != null && machines.Any())
{
softwareDb.Software = machines
.Where(m => m != null)
.Select(ConvertMachineFromInternalModel)
.ToArray();
}
if (machines != null && machines.Length > 0)
softwareDb.Software = Array.ConvertAll(machines, ConvertMachineFromInternalModel);
return softwareDb;
}
@@ -55,13 +50,8 @@ namespace SabreTools.Serialization.CrossModel
};
var dumps = item.Read<Models.Metadata.Dump[]>(Models.Metadata.Machine.DumpKey);
if (dumps != null && dumps.Any())
{
game.Dump = dumps
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (dumps != null && dumps.Length > 0)
game.Dump = Array.ConvertAll(dumps, ConvertFromInternalModel);
return game;
}

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using SabreTools.Models.OpenMSX;
using SabreTools.Serialization.Interfaces;
@@ -17,12 +17,10 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.MetadataFile.HeaderKey] = ConvertHeaderToInternalModel(item),
};
if (item?.Software != null && item.Software.Any())
if (item?.Software != null && item.Software.Length > 0)
{
metadataFile[Models.Metadata.MetadataFile.MachineKey] = item.Software
.Where(s => s != null)
.Select(ConvertMachineToInternalModel)
.ToArray();
metadataFile[Models.Metadata.MetadataFile.MachineKey]
= Array.ConvertAll(item.Software, ConvertMachineToInternalModel);
}
return metadataFile;
@@ -55,12 +53,10 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.Machine.CountryKey] = item.Country,
};
if (item.Dump != null && item.Dump.Any())
if (item.Dump != null && item.Dump.Length > 0)
{
machine[Models.Metadata.Machine.DumpKey] = item.Dump
.Where(d => d != null)
.Select(ConvertToInternalModel)
.ToArray();
machine[Models.Metadata.Machine.DumpKey]
= Array.ConvertAll(item.Dump, ConvertToInternalModel);
}
return machine;

View File

@@ -1,5 +1,5 @@
using System;
using System.Linq;
using System.Collections.Generic;
using SabreTools.Models.RomCenter;
using SabreTools.Serialization.Interfaces;
@@ -17,17 +17,13 @@ namespace SabreTools.Serialization.CrossModel
var metadataFile = header != null ? ConvertHeaderFromInternalModel(header) : new MetadataFile();
var machines = obj.Read<Models.Metadata.Machine[]>(Models.Metadata.MetadataFile.MachineKey);
if (machines != null && machines.Any())
var items = new List<Rom>();
foreach (var machine in machines ?? [])
{
metadataFile.Games = new Games
{
Rom = machines
.Where(m => m != null)
.SelectMany(ConvertMachineFromInternalModel)
.ToArray()
};
items.AddRange(ConvertMachineFromInternalModel(machine));
}
metadataFile.Games = new Games { Rom = [.. items] };
return metadataFile;
}
@@ -93,10 +89,7 @@ namespace SabreTools.Serialization.CrossModel
if (roms == null)
return [];
return roms
.Where(r => r != null)
.Select(rom => ConvertFromInternalModel(rom, item))
.ToArray();
return Array.ConvertAll(roms, r => ConvertFromInternalModel(r, item));
}
/// <summary>

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using SabreTools.Models.RomCenter;
using SabreTools.Serialization.Interfaces;
@@ -17,11 +17,10 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.MetadataFile.HeaderKey] = ConvertHeaderToInternalModel(obj),
};
if (obj?.Games?.Rom != null && obj.Games.Rom.Any())
if (obj?.Games?.Rom != null && obj.Games.Rom.Length > 0)
{
metadataFile[Models.Metadata.MetadataFile.MachineKey] = obj.Games.Rom
.Where(r => r != null)
.Select(ConvertMachineToInternalModel).ToArray();
metadataFile[Models.Metadata.MetadataFile.MachineKey]
= Array.ConvertAll(obj.Games.Rom, ConvertMachineToInternalModel);
}
return metadataFile;

View File

@@ -1,5 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SabreTools.Models.SeparatedValue;
using SabreTools.Serialization.Interfaces;
@@ -17,14 +17,13 @@ namespace SabreTools.Serialization.CrossModel
var metadataFile = header != null ? ConvertHeaderFromInternalModel(header) : new MetadataFile();
var machines = obj.Read<Models.Metadata.Machine[]>(Models.Metadata.MetadataFile.MachineKey);
if (machines != null && machines.Any())
var items = new List<Row>();
foreach (var machine in machines ?? [])
{
metadataFile.Row = machines
.Where(m => m != null)
.SelectMany(m => ConvertMachineFromInternalModel(m, header))
.ToArray();
items.AddRange(ConvertMachineFromInternalModel(machine, header));
}
metadataFile.Row = [.. items];
return metadataFile;
}
@@ -48,27 +47,24 @@ namespace SabreTools.Serialization.CrossModel
var rowItems = new List<Row>();
var roms = item.Read<Models.Metadata.Rom[]>(Models.Metadata.Machine.RomKey);
if (roms != null && roms.Any())
if (roms != null && roms.Length > 0)
{
rowItems.AddRange(roms
.Where(r => r != null)
.Select(rom => ConvertFromInternalModel(rom, item, header)));
rowItems.AddRange(
Array.ConvertAll(roms, r => ConvertFromInternalModel(r, item, header)));
}
var disks = item.Read<Models.Metadata.Disk[]>(Models.Metadata.Machine.DiskKey);
if (disks != null && disks.Any())
if (disks != null && disks.Length > 0)
{
rowItems.AddRange(disks
.Where(d => d != null)
.Select(disk => ConvertFromInternalModel(disk, item, header)));
rowItems.AddRange(
Array.ConvertAll(disks, d => ConvertFromInternalModel(d, item, header)));
}
var media = item.Read<Models.Metadata.Media[]>(Models.Metadata.Machine.MediaKey);
if (media != null && media.Any())
if (media != null && media.Length > 0)
{
rowItems.AddRange(media
.Where(m => m != null)
.Select(medium => ConvertFromInternalModel(medium, item, header)));
rowItems.AddRange(
Array.ConvertAll(media, m => ConvertFromInternalModel(m, item, header)));
}
return rowItems.ToArray();

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using SabreTools.Models.SeparatedValue;
using SabreTools.Serialization.Interfaces;
@@ -17,8 +17,11 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.MetadataFile.HeaderKey] = ConvertHeaderToInternalModel(obj),
};
if (obj?.Row != null && obj.Row.Any())
metadataFile[Models.Metadata.MetadataFile.MachineKey] = obj.Row.Select(ConvertMachineToInternalModel).ToArray();
if (obj?.Row != null && obj.Row.Length > 0)
{
metadataFile[Models.Metadata.MetadataFile.MachineKey]
= Array.ConvertAll(obj.Row, ConvertMachineToInternalModel);
}
return metadataFile;
}
@@ -33,7 +36,7 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.Header.HeaderKey] = item.Header,
};
if (item.Row != null && item.Row.Any())
if (item.Row != null && item.Row.Length > 0)
{
var first = item.Row[0];
//header[Models.Metadata.Header.FileNameKey] = first.FileName; // Not possible to map

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using SabreTools.Models.SoftwareList;
using SabreTools.Serialization.Interfaces;
@@ -16,13 +16,8 @@ namespace SabreTools.Serialization.CrossModel
var metadataFile = header != null ? ConvertHeaderFromInternalModel(header) : new Models.SoftwareList.SoftwareList();
var machines = obj.Read<Models.Metadata.Machine[]>(Models.Metadata.MetadataFile.MachineKey);
if (machines != null && machines.Any())
{
metadataFile.Software = machines
.Where(m => m != null)
.Select(ConvertMachineFromInternalModel)
.ToArray();
}
if (machines != null && machines.Length > 0)
metadataFile.Software = Array.ConvertAll(machines, ConvertMachineFromInternalModel);
return metadataFile;
}
@@ -58,31 +53,16 @@ namespace SabreTools.Serialization.CrossModel
};
var infos = item.Read<Models.Metadata.Info[]>(Models.Metadata.Machine.InfoKey);
if (infos != null && infos.Any())
{
software.Info = infos
.Where(i => i != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (infos != null && infos.Length > 0)
software.Info = Array.ConvertAll(infos, ConvertFromInternalModel);
var sharedFeats = item.Read<Models.Metadata.SharedFeat[]>(Models.Metadata.Machine.SharedFeatKey);
if (sharedFeats != null && sharedFeats.Any())
{
software.SharedFeat = sharedFeats
.Where(s => s != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (sharedFeats != null && sharedFeats.Length > 0)
software.SharedFeat = Array.ConvertAll(sharedFeats, ConvertFromInternalModel);
var parts = item.Read<Models.Metadata.Part[]>(Models.Metadata.Machine.PartKey);
if (parts != null && parts.Any())
{
software.Part = parts
.Where(p => p != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (parts != null && parts.Length > 0)
software.Part = Array.ConvertAll(parts, ConvertFromInternalModel);
return software;
}
@@ -101,13 +81,8 @@ namespace SabreTools.Serialization.CrossModel
};
var roms = item.Read<Models.Metadata.Rom[]>(Models.Metadata.DataArea.RomKey);
if (roms != null && roms.Any())
{
dataArea.Rom = roms
.Where(r => r != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (roms != null && roms.Length > 0)
dataArea.Rom = Array.ConvertAll(roms,ConvertFromInternalModel);
return dataArea;
}
@@ -125,13 +100,8 @@ namespace SabreTools.Serialization.CrossModel
};
var dipValues = item.Read<Models.Metadata.DipValue[]>(Models.Metadata.DipSwitch.DipValueKey);
if (dipValues != null && dipValues.Any())
{
dipSwitch.DipValue = dipValues
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (dipValues != null && dipValues.Length > 0)
dipSwitch.DipValue = Array.ConvertAll(dipValues, ConvertFromInternalModel);
return dipSwitch;
}
@@ -177,13 +147,8 @@ namespace SabreTools.Serialization.CrossModel
};
var disks = item.Read<Models.Metadata.Disk[]>(Models.Metadata.DiskArea.DiskKey);
if (disks != null && disks.Any())
{
diskArea.Disk = disks
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (disks != null && disks.Length > 0)
diskArea.Disk = Array.ConvertAll(disks, ConvertFromInternalModel);
return diskArea;
}
@@ -226,40 +191,20 @@ namespace SabreTools.Serialization.CrossModel
};
var features = item.Read<Models.Metadata.Feature[]>(Models.Metadata.Part.FeatureKey);
if (features != null && features.Any())
{
part.Feature = features
.Where(f => f != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (features != null && features.Length > 0)
part.Feature = Array.ConvertAll(features, ConvertFromInternalModel);
var dataAreas = item.Read<Models.Metadata.DataArea[]>(Models.Metadata.Part.DataAreaKey);
if (dataAreas != null && dataAreas.Any())
{
part.DataArea = dataAreas
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (dataAreas != null && dataAreas.Length > 0)
part.DataArea = Array.ConvertAll(dataAreas, ConvertFromInternalModel);
var diskAreas = item.Read<Models.Metadata.DiskArea[]>(Models.Metadata.Part.DiskAreaKey);
if (diskAreas != null && diskAreas.Any())
{
part.DiskArea = diskAreas
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (diskAreas != null && diskAreas.Length > 0)
part.DiskArea = Array.ConvertAll(diskAreas, ConvertFromInternalModel);
var dipSwitches = item.Read<Models.Metadata.DipSwitch[]>(Models.Metadata.Part.DipSwitchKey);
if (dipSwitches != null && dipSwitches.Any())
{
part.DipSwitch = dipSwitches
.Where(d => d != null)
.Select(ConvertFromInternalModel)
.ToArray();
}
if (dipSwitches != null && dipSwitches.Length > 0)
part.DipSwitch = Array.ConvertAll(dipSwitches, ConvertFromInternalModel);
return part;
}

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using SabreTools.Models.SoftwareList;
using SabreTools.Serialization.Interfaces;
@@ -17,12 +17,10 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.MetadataFile.HeaderKey] = ConvertHeaderToInternalModel(item),
};
if (item?.Software != null && item.Software.Any())
if (item?.Software != null && item.Software.Length > 0)
{
metadataFile[Models.Metadata.MetadataFile.MachineKey] = item.Software
.Where(s => s != null)
.Select(ConvertMachineToInternalModel)
.ToArray();
metadataFile[Models.Metadata.MetadataFile.MachineKey]
= Array.ConvertAll(item.Software, ConvertMachineToInternalModel);
}
return metadataFile;
@@ -58,14 +56,14 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.Machine.NotesKey] = item.Notes,
};
if (item.Info != null && item.Info.Any())
machine[Models.Metadata.Machine.InfoKey] = item.Info.Select(ConvertToInternalModel).ToArray();
if (item.Info != null && item.Info.Length > 0)
machine[Models.Metadata.Machine.InfoKey] = Array.ConvertAll(item.Info, ConvertToInternalModel);
if (item.SharedFeat != null && item.SharedFeat.Any())
machine[Models.Metadata.Machine.SharedFeatKey] = item.SharedFeat.Select(ConvertToInternalModel).ToArray();
if (item.SharedFeat != null && item.SharedFeat.Length > 0)
machine[Models.Metadata.Machine.SharedFeatKey] = Array.ConvertAll(item.SharedFeat, ConvertToInternalModel);
if (item.Part != null && item.Part.Any())
machine[Models.Metadata.Machine.PartKey] = item.Part.Select(ConvertToInternalModel).ToArray();
if (item.Part != null && item.Part.Length > 0)
machine[Models.Metadata.Machine.PartKey] = Array.ConvertAll(item.Part, ConvertToInternalModel);
return machine;
}
@@ -83,8 +81,8 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.DataArea.EndiannessKey] = item.Endianness,
};
if (item.Rom != null && item.Rom.Any())
dataArea[Models.Metadata.DataArea.RomKey] = item.Rom.Select(ConvertToInternalModel).ToArray();
if (item.Rom != null && item.Rom.Length > 0)
dataArea[Models.Metadata.DataArea.RomKey] = Array.ConvertAll(item.Rom, ConvertToInternalModel);
return dataArea;
}
@@ -101,8 +99,8 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.DipSwitch.MaskKey] = item.Mask,
};
if (item.DipValue != null && item.DipValue.Any())
dipSwitch[Models.Metadata.DipSwitch.DipValueKey] = item.DipValue.Select(ConvertToInternalModel).ToArray();
if (item.DipValue != null && item.DipValue.Length > 0)
dipSwitch[Models.Metadata.DipSwitch.DipValueKey] = Array.ConvertAll(item.DipValue, ConvertToInternalModel);
return dipSwitch;
}
@@ -147,8 +145,8 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.DiskArea.NameKey] = item.Name,
};
if (item.Disk != null && item.Disk.Any())
diskArea[Models.Metadata.DiskArea.DiskKey] = item.Disk.Select(ConvertToInternalModel).ToArray();
if (item.Disk != null && item.Disk.Length > 0)
diskArea[Models.Metadata.DiskArea.DiskKey] = Array.ConvertAll(item.Disk, ConvertToInternalModel);
return diskArea;
}
@@ -190,17 +188,17 @@ namespace SabreTools.Serialization.CrossModel
[Models.Metadata.Part.InterfaceKey] = item.Interface,
};
if (item.Feature != null && item.Feature.Any())
part[Models.Metadata.Part.FeatureKey] = item.Feature.Select(ConvertToInternalModel).ToArray();
if (item.Feature != null && item.Feature.Length > 0)
part[Models.Metadata.Part.FeatureKey] = Array.ConvertAll(item.Feature, ConvertToInternalModel);
if (item.DataArea != null && item.DataArea.Any())
part[Models.Metadata.Part.DataAreaKey] = item.DataArea.Select(ConvertToInternalModel).ToArray();
if (item.DataArea != null && item.DataArea.Length > 0)
part[Models.Metadata.Part.DataAreaKey] = Array.ConvertAll(item.DataArea, ConvertToInternalModel);
if (item.DiskArea != null && item.DiskArea.Any())
part[Models.Metadata.Part.DiskAreaKey] = item.DiskArea.Select(ConvertToInternalModel).ToArray();
if (item.DiskArea != null && item.DiskArea.Length > 0)
part[Models.Metadata.Part.DiskAreaKey] = Array.ConvertAll(item.DiskArea, ConvertToInternalModel);
if (item.DipSwitch != null && item.DipSwitch.Any())
part[Models.Metadata.Part.DipSwitchKey] = item.DipSwitch.Select(ConvertToInternalModel).ToArray();
if (item.DipSwitch != null && item.DipSwitch.Length > 0)
part[Models.Metadata.Part.DipSwitchKey] = Array.ConvertAll(item.DipSwitch, ConvertToInternalModel);
return part;
}

View File

@@ -59,7 +59,7 @@ namespace SabreTools.Serialization.Deserializers
}
// Set the records
mediaKeyBlock.Records = records.ToArray();
mediaKeyBlock.Records = [.. records];
#endregion
@@ -164,7 +164,7 @@ namespace SabreTools.Serialization.Deserializers
}
// Set the subset differences
record.SubsetDifferences = subsetDifferences.ToArray();
record.SubsetDifferences = [.. subsetDifferences];
// If there's any data left, discard it
if (data.Position < initialOffset + length)
@@ -205,7 +205,7 @@ namespace SabreTools.Serialization.Deserializers
}
// Set the media keys
record.MediaKeyData = mediaKeys.ToArray();
record.MediaKeyData = [.. mediaKeys];
return record;
}
@@ -243,7 +243,7 @@ namespace SabreTools.Serialization.Deserializers
}
// Set the offsets
record.Offsets = offsets.ToArray();
record.Offsets = [.. offsets];
return record;
}
@@ -322,7 +322,7 @@ namespace SabreTools.Serialization.Deserializers
}
// Set the signature blocks
record.SignatureBlocks = blocks.ToArray();
record.SignatureBlocks = [.. blocks];
// If there's any data left, discard it
if (data.Position < initialOffset + length)
@@ -383,7 +383,7 @@ namespace SabreTools.Serialization.Deserializers
}
// Set the signature blocks
record.SignatureBlocks = blocks.ToArray();
record.SignatureBlocks = [.. blocks];
// If there's any data left, discard it
if (data.Position < initialOffset + length)

View File

@@ -1,6 +1,5 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using SabreTools.IO.Readers;
using SabreTools.Models.AttractMode;
@@ -38,7 +37,7 @@ namespace SabreTools.Serialization.Deserializers
if (!reader.ReadHeader() || reader.HeaderValues == null)
return null;
dat.Header = reader.HeaderValues.ToArray();
dat.Header = [.. reader.HeaderValues];
// Loop through the rows and parse out values
var rows = new List<Row>();
@@ -72,10 +71,6 @@ namespace SabreTools.Serialization.Deserializers
Extra = reader.Line[15],
Buttons = reader.Line[16],
};
// If we have additional fields
if (reader.Line.Count > HeaderWithoutRomnameCount)
row.ADDITIONAL_ELEMENTS = reader.Line.Skip(HeaderWithoutRomnameCount).ToArray();
}
else
{
@@ -99,17 +94,13 @@ namespace SabreTools.Serialization.Deserializers
Extra = reader.Line[15],
Buttons = reader.Line[16],
};
// If we have additional fields
if (reader.Line.Count > HeaderWithRomnameCount)
row.ADDITIONAL_ELEMENTS = reader.Line.Skip(HeaderWithRomnameCount).ToArray();
}
rows.Add(row);
}
// Assign the rows to the Dat and return
dat.Row = rows.ToArray();
dat.Row = [.. rows];
return dat;
}

View File

@@ -1,5 +1,4 @@
using System.IO;
using System.Linq;
using System.Text;
using SabreTools.IO.Extensions;
using SabreTools.Models.BSP;
@@ -165,9 +164,9 @@ namespace SabreTools.Serialization.Deserializers
// TODO: Use marshalling here instead of building
var texture = new Texture();
byte[]? name = data.ReadBytes(16)?.TakeWhile(c => c != '\0')?.ToArray();
byte[]? name = data.ReadBytes(16);
if (name != null)
texture.Name = Encoding.ASCII.GetString(name);
texture.Name = Encoding.ASCII.GetString(name).TrimEnd('\0');
texture.Width = data.ReadUInt32();
texture.Height = data.ReadUInt32();
texture.Offsets = new uint[4];

View File

@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using SabreTools.Serialization.Interfaces;
@@ -17,6 +15,11 @@ namespace SabreTools.Serialization.Deserializers
IFileDeserializer<TModel>,
IStreamDeserializer<TModel>
{
/// <summary>
/// Indicates if compressed files should be decompressed before processing
/// </summary>
protected virtual bool SkipCompression => false;
#region IByteDeserializer
/// <inheritdoc/>
@@ -42,7 +45,7 @@ namespace SabreTools.Serialization.Deserializers
/// <inheritdoc/>
public virtual TModel? Deserialize(string? path)
{
using var stream = PathProcessor.OpenStream(path);
using var stream = PathProcessor.OpenStream(path, SkipCompression);
return DeserializeStream(stream);
}
@@ -103,12 +106,13 @@ namespace SabreTools.Serialization.Deserializers
if (deserializerName == null)
return default;
// If the deserializer has no model type
Type? modelType = typeof(TDeserializer).GetGenericArguments()?.FirstOrDefault();
if (modelType == null)
// If the deserializer has no generic arguments
var genericArgs = typeof(TDeserializer).GetGenericArguments();
if (genericArgs.Length == 0)
return default;
// Loop through all loaded assemblies
Type modelType = genericArgs[0];
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
// If the assembly is invalid
@@ -116,19 +120,23 @@ namespace SabreTools.Serialization.Deserializers
return default;
// If not all types can be loaded, use the ones that could be
List<Type> assemblyTypes = [];
Type?[] assemblyTypes = [];
try
{
assemblyTypes = assembly.GetTypes().ToList<Type>();
assemblyTypes = assembly.GetTypes();
}
catch (ReflectionTypeLoadException rtle)
{
assemblyTypes = rtle.Types.Where(t => t != null)!.ToList<Type>();
assemblyTypes = rtle.Types ?? [];
}
// Loop through all types
foreach (Type type in assemblyTypes)
foreach (Type? type in assemblyTypes)
{
// If the type is invalid
if (type == null)
continue;
// If the type isn't a class
if (!type.IsClass)
continue;

View File

@@ -77,7 +77,7 @@ namespace SabreTools.Serialization.Deserializers
}
// Assign the DIFAT sectors table
binary.DIFATSectorNumbers = difatSectors.ToArray();
binary.DIFATSectorNumbers = [.. difatSectors];
#endregion
@@ -115,7 +115,7 @@ namespace SabreTools.Serialization.Deserializers
}
// Assign the FAT sectors table
binary.FATSectorNumbers = fatSectors.ToArray();
binary.FATSectorNumbers = [.. fatSectors];
#endregion
@@ -153,7 +153,7 @@ namespace SabreTools.Serialization.Deserializers
}
// Assign the mini FAT sectors table
binary.MiniFATSectorNumbers = miniFatSectors.ToArray();
binary.MiniFATSectorNumbers = [.. miniFatSectors];
#endregion
@@ -219,7 +219,7 @@ namespace SabreTools.Serialization.Deserializers
}
// Assign the Directory sectors table
binary.DirectoryEntries = directorySectors.ToArray();
binary.DirectoryEntries = [.. directorySectors];
#endregion

View File

@@ -0,0 +1,253 @@
using System;
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
using SabreTools.Models.CHD;
namespace SabreTools.Serialization.Deserializers
{
// TODO: Expand this to full CHD files eventually
public class CHD : BaseBinaryDeserializer<Header>
{
/// <inheritdoc/>
public override Header? Deserialize(Stream? data)
{
// If the data is invalid
if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead)
return null;
// If the offset is out of bounds
if (data.Position < 0 || data.Position >= data.Length)
return null;
// Cache the current offset
int initialOffset = (int)data.Position;
// Determine the header version
uint version = GetVersion(data);
// Read and return the current CHD
return version switch
{
1 => ParseHeaderV1(data),
2 => ParseHeaderV2(data),
3 => ParseHeaderV3(data),
4 => ParseHeaderV4(data),
5 => ParseHeaderV5(data),
_ => null,
};
}
/// <summary>
/// Get the matching CHD version, if possible
/// </summary>
/// <returns>Matching version, 0 if none</returns>
private static uint GetVersion(Stream data)
{
// Read the header values
byte[] tagBytes = data.ReadBytes(8);
string tag = Encoding.ASCII.GetString(tagBytes);
uint length = data.ReadUInt32BigEndian();
uint version = data.ReadUInt32BigEndian();
// Seek back to start
data.SeekIfPossible();
// Check the signature
if (!string.Equals(tag, Constants.SignatureString, StringComparison.Ordinal))
return 0;
// Match the version to header length
#if NET472_OR_GREATER || NETCOREAPP
return (version, length) switch
{
(1, Constants.HeaderV1Size) => version,
(2, Constants.HeaderV2Size) => version,
(3, Constants.HeaderV3Size) => version,
(4, Constants.HeaderV4Size) => version,
(5, Constants.HeaderV5Size) => version,
_ => 0,
};
#else
return version switch
{
1 => length == Constants.HeaderV1Size ? version : 0,
2 => length == Constants.HeaderV2Size ? version : 0,
3 => length == Constants.HeaderV3Size ? version : 0,
4 => length == Constants.HeaderV4Size ? version : 0,
5 => length == Constants.HeaderV5Size ? version : 0,
_ => 0,
};
#endif
}
/// <summary>
/// Parse a Stream into a V1 header
/// </summary>
private static HeaderV1? ParseHeaderV1(Stream data)
{
var header = new HeaderV1();
byte[] tagBytes = data.ReadBytes(8);
header.Tag = Encoding.ASCII.GetString(tagBytes);
if (header.Tag != Constants.SignatureString)
return null;
header.Length = data.ReadUInt32BigEndian();
if (header.Length != Constants.HeaderV1Size)
return null;
header.Version = data.ReadUInt32BigEndian();
header.Flags = (Flags)data.ReadUInt32BigEndian();
header.Compression = (CompressionType)data.ReadUInt32BigEndian();
if (header.Compression > CompressionType.CHDCOMPRESSION_ZLIB)
return null;
header.HunkSize = data.ReadUInt32BigEndian();
header.TotalHunks = data.ReadUInt32BigEndian();
header.Cylinders = data.ReadUInt32BigEndian();
header.Heads = data.ReadUInt32BigEndian();
header.Sectors = data.ReadUInt32BigEndian();
header.MD5 = data.ReadBytes(16);
header.ParentMD5 = data.ReadBytes(16);
return header;
}
/// <summary>
/// Parse a Stream into a V2 header
/// </summary>
private static HeaderV2? ParseHeaderV2(Stream data)
{
var header = new HeaderV2();
byte[] tagBytes = data.ReadBytes(8);
header.Tag = Encoding.ASCII.GetString(tagBytes);
if (header.Tag != Constants.SignatureString)
return null;
header.Length = data.ReadUInt32BigEndian();
if (header.Length != Constants.HeaderV2Size)
return null;
header.Version = data.ReadUInt32BigEndian();
header.Flags = (Flags)data.ReadUInt32BigEndian();
header.Compression = (CompressionType)data.ReadUInt32BigEndian();
if (header.Compression > CompressionType.CHDCOMPRESSION_ZLIB)
return null;
header.HunkSize = data.ReadUInt32BigEndian();
header.TotalHunks = data.ReadUInt32BigEndian();
header.Cylinders = data.ReadUInt32BigEndian();
header.Heads = data.ReadUInt32BigEndian();
header.Sectors = data.ReadUInt32BigEndian();
header.MD5 = data.ReadBytes(16);
header.ParentMD5 = data.ReadBytes(16);
header.BytesPerSector = data.ReadUInt32BigEndian();
return header;
}
/// <summary>
/// Parse a Stream into a V3 header
/// </summary>
private static HeaderV3? ParseHeaderV3(Stream data)
{
var header = new HeaderV3();
byte[] tagBytes = data.ReadBytes(8);
header.Tag = Encoding.ASCII.GetString(tagBytes);
if (header.Tag != Constants.SignatureString)
return null;
header.Length = data.ReadUInt32BigEndian();
if (header.Length != Constants.HeaderV3Size)
return null;
header.Version = data.ReadUInt32BigEndian();
header.Flags = (Flags)data.ReadUInt32BigEndian();
header.Compression = (CompressionType)data.ReadUInt32BigEndian();
if (header.Compression > CompressionType.CHDCOMPRESSION_ZLIB_PLUS)
return null;
header.TotalHunks = data.ReadUInt32BigEndian();
header.LogicalBytes = data.ReadUInt64BigEndian();
header.MetaOffset = data.ReadUInt64BigEndian();
header.MD5 = data.ReadBytes(16);
header.ParentMD5 = data.ReadBytes(16);
header.HunkBytes = data.ReadUInt32BigEndian();
header.SHA1 = data.ReadBytes(20);
header.ParentSHA1 = data.ReadBytes(20);
return header;
}
/// <summary>
/// Parse a Stream into a V4 header
/// </summary>
private static HeaderV4? ParseHeaderV4(Stream data)
{
var header = new HeaderV4();
byte[] tagBytes = data.ReadBytes(8);
header.Tag = Encoding.ASCII.GetString(tagBytes);
if (header.Tag != Constants.SignatureString)
return null;
header.Length = data.ReadUInt32BigEndian();
if (header.Length != Constants.HeaderV4Size)
return null;
header.Version = data.ReadUInt32BigEndian();
header.Flags = (Flags)data.ReadUInt32BigEndian();
header.Compression = (CompressionType)data.ReadUInt32BigEndian();
if (header.Compression > CompressionType.CHDCOMPRESSION_AV)
return null;
header.TotalHunks = data.ReadUInt32BigEndian();
header.LogicalBytes = data.ReadUInt64BigEndian();
header.MetaOffset = data.ReadUInt64BigEndian();
header.HunkBytes = data.ReadUInt32BigEndian();
header.SHA1 = data.ReadBytes(20);
header.ParentSHA1 = data.ReadBytes(20);
header.RawSHA1 = data.ReadBytes(20);
return header;
}
/// <summary>
/// Parse a Stream into a V5 header
/// </summary>
private static HeaderV5? ParseHeaderV5(Stream data)
{
var header = new HeaderV5();
byte[] tagBytes = data.ReadBytes(8);
header.Tag = Encoding.ASCII.GetString(tagBytes);
if (header.Tag != Constants.SignatureString)
return null;
header.Length = data.ReadUInt32BigEndian();
if (header.Length != Constants.HeaderV5Size)
return null;
header.Version = data.ReadUInt32BigEndian();
header.Compressors = new CodecType[4];
for (int i = 0; i < header.Compressors.Length; i++)
{
header.Compressors[i] = (CodecType)data.ReadUInt32BigEndian();
}
header.LogicalBytes = data.ReadUInt64BigEndian();
header.MapOffset = data.ReadUInt64BigEndian();
header.MetaOffset = data.ReadUInt64BigEndian();
header.HunkBytes = data.ReadUInt32BigEndian();
header.UnitBytes = data.ReadUInt32BigEndian();
header.RawSHA1 = data.ReadBytes(20);
header.SHA1 = data.ReadBytes(20);
header.ParentSHA1 = data.ReadBytes(20);
return header;
}
}
}

View File

@@ -70,7 +70,7 @@ namespace SabreTools.Serialization.Deserializers
var deserializer = new ClrMamePro();
return deserializer.Deserialize(data, quotes);
}
/// <inheritdoc/>
public override MetadataFile? Deserialize(Stream? data)
=> Deserialize(data, true);
@@ -102,9 +102,6 @@ namespace SabreTools.Serialization.Deserializers
var videos = new List<Video>();
var dipSwitches = new List<DipSwitch>();
var additional = new List<string>();
var headerAdditional = new List<string>();
var gameAdditional = new List<string>();
while (!reader.EndOfStream)
{
// If we have no next line
@@ -120,12 +117,6 @@ namespace SabreTools.Serialization.Deserializers
case CmpRowType.EndTopLevel:
switch (lastTopLevel)
{
case "doscenter":
if (dat.ClrMamePro != null)
dat.ClrMamePro.ADDITIONAL_ELEMENTS = [.. headerAdditional];
headerAdditional.Clear();
break;
case "game":
case "machine":
case "resource":
@@ -142,7 +133,6 @@ namespace SabreTools.Serialization.Deserializers
game.Chip = [.. chips];
game.Video = [.. videos];
game.DipSwitch = [.. dipSwitches];
game.ADDITIONAL_ELEMENTS = [.. gameAdditional];
games.Add(game);
game = null;
@@ -158,10 +148,6 @@ namespace SabreTools.Serialization.Deserializers
chips.Clear();
videos.Clear();
dipSwitches.Clear();
gameAdditional.Clear();
break;
default:
// No-op
break;
}
continue;
@@ -188,10 +174,6 @@ namespace SabreTools.Serialization.Deserializers
case "set":
game = new Set();
break;
default:
if (reader.CurrentLine != null)
additional.Add(reader.CurrentLine);
break;
}
}
@@ -249,10 +231,6 @@ namespace SabreTools.Serialization.Deserializers
case "forcepacking":
dat.ClrMamePro.ForcePacking = reader.Standalone?.Value;
break;
default:
if (reader.CurrentLine != null)
headerAdditional.Add(reader.CurrentLine);
break;
}
}
@@ -303,14 +281,9 @@ namespace SabreTools.Serialization.Deserializers
var sample = new Sample
{
Name = reader.Standalone?.Value ?? string.Empty,
ADDITIONAL_ELEMENTS = [],
};
samples.Add(sample);
break;
default:
if (reader.CurrentLine != null)
gameAdditional.Add(reader.CurrentLine);
break;
}
}
@@ -391,22 +364,13 @@ namespace SabreTools.Serialization.Deserializers
game.Driver = driver;
break;
default:
if (reader.CurrentLine != null)
gameAdditional.Add(reader.CurrentLine);
continue;
}
}
else
{
if (reader.CurrentLine != null)
additional.Add(reader.CurrentLine);
}
}
// Add extra pieces and return
dat.Game = [.. games];
dat.ADDITIONAL_ELEMENTS = [.. additional];
return dat;
}
@@ -447,7 +411,6 @@ namespace SabreTools.Serialization.Deserializers
}
}
release.ADDITIONAL_ELEMENTS = [.. itemAdditional];
return release;
}
@@ -461,7 +424,6 @@ namespace SabreTools.Serialization.Deserializers
if (reader.Internal == null)
return null;
var itemAdditional = new List<string>();
var biosset = new BiosSet();
foreach (var kvp in reader.Internal)
{
@@ -476,13 +438,9 @@ namespace SabreTools.Serialization.Deserializers
case "default":
biosset.Default = kvp.Value;
break;
default:
itemAdditional.Add($"{kvp.Key}: {kvp.Value}");
break;
}
}
biosset.ADDITIONAL_ELEMENTS = [.. itemAdditional];
return biosset;
}
@@ -496,7 +454,6 @@ namespace SabreTools.Serialization.Deserializers
if (reader.Internal == null)
return null;
var itemAdditional = new List<string>();
var rom = new Rom();
foreach (var kvp in reader.Internal)
{
@@ -565,13 +522,9 @@ namespace SabreTools.Serialization.Deserializers
case "mia":
rom.MIA = kvp.Value;
break;
default:
itemAdditional.Add($"{kvp.Key}: {kvp.Value}");
break;
}
}
rom.ADDITIONAL_ELEMENTS = [.. itemAdditional];
return rom;
}
@@ -585,7 +538,6 @@ namespace SabreTools.Serialization.Deserializers
if (reader.Internal == null)
return null;
var itemAdditional = new List<string>();
var disk = new Disk();
foreach (var kvp in reader.Internal)
{
@@ -609,13 +561,9 @@ namespace SabreTools.Serialization.Deserializers
case "flags":
disk.Flags = kvp.Value;
break;
default:
itemAdditional.Add($"{kvp.Key}: {kvp.Value}");
break;
}
}
disk.ADDITIONAL_ELEMENTS = [.. itemAdditional];
return disk;
}
@@ -629,7 +577,6 @@ namespace SabreTools.Serialization.Deserializers
if (reader.Internal == null)
return null;
var itemAdditional = new List<string>();
var media = new Media();
foreach (var kvp in reader.Internal)
{
@@ -650,13 +597,9 @@ namespace SabreTools.Serialization.Deserializers
case "spamsum":
media.SpamSum = kvp.Value;
break;
default:
itemAdditional.Add($"{kvp.Key}: {kvp.Value}");
break;
}
}
media.ADDITIONAL_ELEMENTS = [.. itemAdditional];
return media;
}
@@ -670,7 +613,6 @@ namespace SabreTools.Serialization.Deserializers
if (reader.Internal == null)
return null;
var itemAdditional = new List<string>();
var sample = new Sample();
foreach (var kvp in reader.Internal)
{
@@ -679,13 +621,9 @@ namespace SabreTools.Serialization.Deserializers
case "name":
sample.Name = kvp.Value;
break;
default:
itemAdditional.Add($"{kvp.Key}: {kvp.Value}");
break;
}
}
sample.ADDITIONAL_ELEMENTS = [.. itemAdditional];
return sample;
}
@@ -699,7 +637,6 @@ namespace SabreTools.Serialization.Deserializers
if (reader.Internal == null)
return null;
var itemAdditional = new List<string>();
var archive = new Archive();
foreach (var kvp in reader.Internal)
{
@@ -708,13 +645,9 @@ namespace SabreTools.Serialization.Deserializers
case "name":
archive.Name = kvp.Value;
break;
default:
itemAdditional.Add($"{kvp.Key}: {kvp.Value}");
break;
}
}
archive.ADDITIONAL_ELEMENTS = [.. itemAdditional];
return archive;
}
@@ -728,7 +661,6 @@ namespace SabreTools.Serialization.Deserializers
if (reader.Internal == null)
return null;
var itemAdditional = new List<string>();
var chip = new Chip();
foreach (var kvp in reader.Internal)
{
@@ -746,13 +678,9 @@ namespace SabreTools.Serialization.Deserializers
case "clock":
chip.Clock = kvp.Value;
break;
default:
itemAdditional.Add($"{kvp.Key}: {kvp.Value}");
break;
}
}
chip.ADDITIONAL_ELEMENTS = itemAdditional.ToArray();
return chip;
}
@@ -766,7 +694,6 @@ namespace SabreTools.Serialization.Deserializers
if (reader.Internal == null)
return null;
var itemAdditional = new List<string>();
var video = new Video();
foreach (var kvp in reader.Internal)
{
@@ -793,13 +720,9 @@ namespace SabreTools.Serialization.Deserializers
case "freq":
video.Freq = kvp.Value;
break;
default:
itemAdditional.Add($"{kvp.Key}: {kvp.Value}");
break;
}
}
video.ADDITIONAL_ELEMENTS = itemAdditional.ToArray();
return video;
}
@@ -813,7 +736,6 @@ namespace SabreTools.Serialization.Deserializers
if (reader.Internal == null)
return null;
var itemAdditional = new List<string>();
var sound = new Sound();
foreach (var kvp in reader.Internal)
{
@@ -822,13 +744,9 @@ namespace SabreTools.Serialization.Deserializers
case "channels":
sound.Channels = kvp.Value;
break;
default:
itemAdditional.Add($"{kvp.Key}: {kvp.Value}");
break;
}
}
sound.ADDITIONAL_ELEMENTS = itemAdditional.ToArray();
return sound;
}
@@ -842,7 +760,6 @@ namespace SabreTools.Serialization.Deserializers
if (reader.Internal == null)
return null;
var itemAdditional = new List<string>();
var input = new Input();
foreach (var kvp in reader.Internal)
{
@@ -866,13 +783,9 @@ namespace SabreTools.Serialization.Deserializers
case "service":
input.Service = kvp.Value;
break;
default:
itemAdditional.Add($"{kvp.Key}: {kvp.Value}");
break;
}
}
input.ADDITIONAL_ELEMENTS = itemAdditional.ToArray();
return input;
}
@@ -886,7 +799,6 @@ namespace SabreTools.Serialization.Deserializers
if (reader.Internal == null)
return null;
var itemAdditional = new List<string>();
var dipswitch = new DipSwitch();
var entries = new List<string>();
foreach (var kvp in reader.Internal)
@@ -902,14 +814,10 @@ namespace SabreTools.Serialization.Deserializers
case "default":
dipswitch.Default = kvp.Value;
break;
default:
itemAdditional.Add($"{kvp.Key}: {kvp.Value}");
break;
}
}
dipswitch.Entry = [.. entries];
dipswitch.ADDITIONAL_ELEMENTS = itemAdditional.ToArray();
return dipswitch;
}
@@ -923,7 +831,6 @@ namespace SabreTools.Serialization.Deserializers
if (reader.Internal == null)
return null;
var itemAdditional = new List<string>();
var driver = new Driver();
foreach (var kvp in reader.Internal)
{
@@ -944,13 +851,9 @@ namespace SabreTools.Serialization.Deserializers
case "blit":
driver.Blit = kvp.Value;
break;
default:
itemAdditional.Add($"{kvp.Key}: {kvp.Value}");
break;
}
}
driver.ADDITIONAL_ELEMENTS = itemAdditional.ToArray();
return driver;
}

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using SabreTools.IO.Extensions;
using SabreTools.Models.CueSheets;
@@ -44,11 +43,13 @@ namespace SabreTools.Serialization.Deserializers
continue;
// http://stackoverflow.com/questions/554013/regular-expression-to-split-on-spaces-unless-in-quotes
string[] splitLine = Regex
.Matches(line, @"[^\s""]+|""[^""]*""")
.Cast<Match>()
.Select(m => m.Groups[0].Value)
.ToArray();
var matchCol = Regex.Matches(line, @"[^\s""]+|""[^""]*""");
var splitLine = new List<string>();
foreach (Match? match in matchCol)
{
if (match != null)
splitLine.Add(match.Groups[0].Value);
}
switch (splitLine[0])
{
@@ -59,7 +60,7 @@ namespace SabreTools.Serialization.Deserializers
// Read MCN
case "CATALOG":
if (splitLine.Length < 2)
if (splitLine.Count < 2)
throw new FormatException($"CATALOG line malformed: {line}");
cueSheet.Catalog = splitLine[1].Trim('"');
@@ -67,7 +68,7 @@ namespace SabreTools.Serialization.Deserializers
// Read external CD-Text file path
case "CDTEXTFILE":
if (splitLine.Length < 2)
if (splitLine.Count < 2)
throw new FormatException($"CDTEXTFILE line malformed: {line}");
cueSheet.CdTextFile = splitLine[1].Trim('"');
@@ -75,7 +76,7 @@ namespace SabreTools.Serialization.Deserializers
// Read CD-Text enhanced performer
case "PERFORMER":
if (splitLine.Length < 2)
if (splitLine.Count < 2)
throw new FormatException($"PERFORMER line malformed: {line}");
cueSheet.Performer = splitLine[1].Trim('"');
@@ -83,7 +84,7 @@ namespace SabreTools.Serialization.Deserializers
// Read CD-Text enhanced songwriter
case "SONGWRITER":
if (splitLine.Length < 2)
if (splitLine.Count < 2)
throw new FormatException($"SONGWRITER line malformed: {line}");
cueSheet.Songwriter = splitLine[1].Trim('"');
@@ -91,7 +92,7 @@ namespace SabreTools.Serialization.Deserializers
// Read CD-Text enhanced title
case "TITLE":
if (splitLine.Length < 2)
if (splitLine.Count < 2)
throw new FormatException($"TITLE line malformed: {line}");
cueSheet.Title = splitLine[1].Trim('"');
@@ -99,7 +100,7 @@ namespace SabreTools.Serialization.Deserializers
// Read file information
case "FILE":
if (splitLine.Length < 3)
if (splitLine.Count < 3)
throw new FormatException($"FILE line malformed: {line}");
var file = CreateCueFile(splitLine[1], splitLine[2], data, out lastLine);
@@ -152,11 +153,13 @@ namespace SabreTools.Serialization.Deserializers
continue;
// http://stackoverflow.com/questions/554013/regular-expression-to-split-on-spaces-unless-in-quotes
string[] splitLine = Regex
.Matches(line, @"[^\s""]+|""[^""]*""")
.Cast<Match>()
.Select(m => m.Groups[0].Value)
.ToArray();
var matchCol = Regex.Matches(line, @"[^\s""]+|""[^""]*""");
var splitLine = new List<string>();
foreach (Match? match in matchCol)
{
if (match != null)
splitLine.Add(match.Groups[0].Value);
}
switch (splitLine[0])
{
@@ -167,7 +170,7 @@ namespace SabreTools.Serialization.Deserializers
// Read track information
case "TRACK":
if (splitLine.Length < 3)
if (splitLine.Count < 3)
throw new FormatException($"TRACK line malformed: {line}");
var track = CreateCueTrack(splitLine[1], splitLine[2], data, out lastLine);
@@ -237,12 +240,13 @@ namespace SabreTools.Serialization.Deserializers
continue;
// http://stackoverflow.com/questions/554013/regular-expression-to-split-on-spaces-unless-in-quotes
string[] splitLine = Regex
.Matches(line, @"[^\s""]+|""[^""]*""")
.Cast<Match>()
.Select(m => m.Groups[0].Value)
.ToArray();
var matchCol = Regex.Matches(line, @"[^\s""]+|""[^""]*""");
var splitLine = new List<string>();
foreach (Match? match in matchCol)
{
if (match != null)
splitLine.Add(match.Groups[0].Value);
}
switch (splitLine[0])
{
// Read comments
@@ -252,15 +256,15 @@ namespace SabreTools.Serialization.Deserializers
// Read flag information
case "FLAGS":
if (splitLine.Length < 2)
if (splitLine.Count < 2)
throw new FormatException($"FLAGS line malformed: {line}");
cueTrack.Flags = GetFlags(splitLine);
cueTrack.Flags = GetFlags([.. splitLine]);
break;
// Read International Standard Recording Code
case "ISRC":
if (splitLine.Length < 2)
if (splitLine.Count < 2)
throw new FormatException($"ISRC line malformed: {line}");
cueTrack.ISRC = splitLine[1].Trim('"');
@@ -268,7 +272,7 @@ namespace SabreTools.Serialization.Deserializers
// Read CD-Text enhanced performer
case "PERFORMER":
if (splitLine.Length < 2)
if (splitLine.Count < 2)
throw new FormatException($"PERFORMER line malformed: {line}");
cueTrack.Performer = splitLine[1].Trim('"');
@@ -276,7 +280,7 @@ namespace SabreTools.Serialization.Deserializers
// Read CD-Text enhanced songwriter
case "SONGWRITER":
if (splitLine.Length < 2)
if (splitLine.Count < 2)
throw new FormatException($"SONGWRITER line malformed: {line}");
cueTrack.Songwriter = splitLine[1].Trim('"');
@@ -284,7 +288,7 @@ namespace SabreTools.Serialization.Deserializers
// Read CD-Text enhanced title
case "TITLE":
if (splitLine.Length < 2)
if (splitLine.Count < 2)
throw new FormatException($"TITLE line malformed: {line}");
cueTrack.Title = splitLine[1].Trim('"');
@@ -292,7 +296,7 @@ namespace SabreTools.Serialization.Deserializers
// Read pregap information
case "PREGAP":
if (splitLine.Length < 2)
if (splitLine.Count < 2)
throw new FormatException($"PREGAP line malformed: {line}");
var pregap = CreatePreGap(splitLine[1]);
@@ -304,7 +308,7 @@ namespace SabreTools.Serialization.Deserializers
// Read index information
case "INDEX":
if (splitLine.Length < 3)
if (splitLine.Count < 3)
throw new FormatException($"INDEX line malformed: {line}");
var index = CreateCueIndex(splitLine[1], splitLine[2]);
@@ -316,7 +320,7 @@ namespace SabreTools.Serialization.Deserializers
// Read postgap information
case "POSTGAP":
if (splitLine.Length < 2)
if (splitLine.Count < 2)
throw new FormatException($"POSTGAP line malformed: {line}");
var postgap = CreatePostGap(splitLine[1]);
@@ -356,7 +360,7 @@ namespace SabreTools.Serialization.Deserializers
throw new ArgumentException("Length was null or whitespace");
// Ignore lines that don't contain the correct information
if (length!.Length != 8 || length.Count(c => c == ':') != 2)
if (length!.Length != 8)
throw new FormatException($"Length was not in a recognized format: {length}");
// Split the line
@@ -413,7 +417,7 @@ namespace SabreTools.Serialization.Deserializers
throw new ArgumentException("Start time was null or whitespace");
// Ignore lines that don't contain the correct information
if (startTime!.Length != 8 || startTime.Count(c => c == ':') != 2)
if (startTime!.Length != 8)
throw new FormatException($"Start time was not in a recognized format: {startTime}");
// Split the line
@@ -464,7 +468,7 @@ namespace SabreTools.Serialization.Deserializers
throw new ArgumentException("Length was null or whitespace");
// Ignore lines that don't contain the correct information
if (length!.Length != 8 || length.Count(c => c == ':') != 2)
if (length!.Length != 8)
throw new FormatException($"Length was not in a recognized format: {length}");
// Split the line

View File

@@ -26,9 +26,6 @@ namespace SabreTools.Serialization.Deserializers
var games = new List<Game>();
var files = new List<Models.DosCenter.File>();
var additional = new List<string>();
var headerAdditional = new List<string>();
var gameAdditional = new List<string>();
while (!reader.EndOfStream)
{
// If we have no next line
@@ -44,26 +41,15 @@ namespace SabreTools.Serialization.Deserializers
case CmpRowType.EndTopLevel:
switch (lastTopLevel)
{
case "doscenter":
if (dat.DosCenter != null)
dat.DosCenter.ADDITIONAL_ELEMENTS = headerAdditional.ToArray();
headerAdditional.Clear();
break;
case "game":
if (game != null)
{
game.File = files.ToArray();
game.ADDITIONAL_ELEMENTS = gameAdditional.ToArray();
game.File = [.. files];
games.Add(game);
}
game = null;
files.Clear();
gameAdditional.Clear();
break;
default:
// No-op
break;
}
continue;
@@ -81,10 +67,6 @@ namespace SabreTools.Serialization.Deserializers
case "game":
game = new Game();
break;
default:
if (reader.CurrentLine != null)
additional.Add(reader.CurrentLine);
break;
}
}
@@ -117,10 +99,6 @@ namespace SabreTools.Serialization.Deserializers
case "comment:":
dat.DosCenter.Comment = reader.Standalone?.Value;
break;
default:
if (reader.CurrentLine != null)
headerAdditional.Add(item: reader.CurrentLine);
break;
}
}
@@ -135,10 +113,6 @@ namespace SabreTools.Serialization.Deserializers
case "name":
game.Name = reader.Standalone?.Value;
break;
default:
if (reader.CurrentLine != null)
gameAdditional.Add(item: reader.CurrentLine);
break;
}
}
@@ -147,28 +121,17 @@ namespace SabreTools.Serialization.Deserializers
{
// If we have an unknown type, log it
if (reader.InternalName != "file")
{
if (reader.CurrentLine != null)
gameAdditional.Add(reader.CurrentLine);
continue;
}
// Create the file and add to the list
var file = CreateFile(reader);
if (file != null)
files.Add(file);
}
else
{
if (reader.CurrentLine != null)
additional.Add(item: reader.CurrentLine);
}
}
// Add extra pieces and return
dat.Game = games.ToArray();
dat.ADDITIONAL_ELEMENTS = additional.ToArray();
dat.Game = [.. games];
return dat;
}
@@ -182,7 +145,6 @@ namespace SabreTools.Serialization.Deserializers
if (reader.Internal == null)
return null;
var itemAdditional = new List<string>();
var file = new Models.DosCenter.File();
foreach (var kvp in reader.Internal)
{
@@ -200,14 +162,9 @@ namespace SabreTools.Serialization.Deserializers
case "date":
file.Date = kvp.Value;
break;
default:
if (reader.CurrentLine != null)
itemAdditional.Add(item: reader.CurrentLine);
break;
}
}
file.ADDITIONAL_ELEMENTS = itemAdditional.ToArray();
return file;
}
}

View File

@@ -1,6 +1,5 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using SabreTools.IO.Readers;
using SabreTools.Models.EverdriveSMDB;
@@ -47,15 +46,11 @@ namespace SabreTools.Serialization.Deserializers
if (reader.Line.Count > 5)
row.Size = reader.Line[5];
// If we have additional fields
if (reader.Line.Count > 6)
row.ADDITIONAL_ELEMENTS = reader.Line.Skip(5).ToArray();
rows.Add(row);
}
// Assign the rows to the Dat and return
dat.Row = rows.ToArray();
dat.Row = [.. rows];
return dat;
}
}

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SabreTools.Hashing;
using SabreTools.Models.Hashfile;
@@ -60,7 +59,7 @@ namespace SabreTools.Serialization.Deserializers
using var stream = PathProcessor.OpenStream(path);
return DeserializeStream(stream, hash);
}
#endregion
#region IStreamDeserializer
@@ -71,7 +70,7 @@ namespace SabreTools.Serialization.Deserializers
var deserializer = new Hashfile();
return deserializer.Deserialize(data, hash);
}
/// <inheritdoc/>
public override Models.Hashfile.Hashfile? Deserialize(Stream? data)
=> Deserialize(data, HashType.CRC32);
@@ -86,19 +85,22 @@ namespace SabreTools.Serialization.Deserializers
// Setup the reader and output
var reader = new StreamReader(data);
var dat = new Models.Hashfile.Hashfile();
var additional = new List<string>();
// Create lists for each hash type
var sfvList = new List<SFV>();
var md5List = new List<MD5>();
var sha1List = new List<SHA1>();
var sha256List = new List<SHA256>();
var sha384List = new List<SHA384>();
var sha512List = new List<SHA512>();
var spamsumList = new List<SpamSum>();
// Loop through the rows and parse out values
var hashes = new List<object>();
while (!reader.EndOfStream)
{
// Read and split the line
string? line = reader.ReadLine();
#if NETFRAMEWORK || NETCOREAPP3_1
string[]? lineParts = line?.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
#else
string[]? lineParts = line?.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
#endif
string[]? lineParts = line?.Split([' '], StringSplitOptions.RemoveEmptyEntries);
if (lineParts == null)
continue;
@@ -106,93 +108,60 @@ namespace SabreTools.Serialization.Deserializers
switch (hash)
{
case HashType.CRC32:
case HashType.CRC32_ISO:
case HashType.CRC32_Naive:
case HashType.CRC32_Optimized:
case HashType.CRC32_Parallel:
var sfv = new SFV
{
#if NETFRAMEWORK
File = string.Join(" ", lineParts.Take(lineParts.Length - 1).ToArray()),
File = string.Join(" ", lineParts, 0, lineParts.Length - 1),
Hash = lineParts[lineParts.Length - 1],
#else
File = string.Join(" ", lineParts[..^1]),
Hash = lineParts[^1],
#endif
};
hashes.Add(sfv);
sfvList.Add(sfv);
break;
case HashType.MD5:
var md5 = new MD5
{
Hash = lineParts[0],
#if NETFRAMEWORK
File = string.Join(" ", lineParts.Skip(1).ToArray()),
#else
File = string.Join(" ", lineParts[1..]),
#endif
File = string.Join(" ", lineParts, 1, lineParts.Length - 1),
};
hashes.Add(md5);
md5List.Add(md5);
break;
case HashType.SHA1:
var sha1 = new SHA1
{
Hash = lineParts[0],
#if NETFRAMEWORK
File = string.Join(" ", lineParts.Skip(1).ToArray()),
#else
File = string.Join(" ", lineParts[1..]),
#endif
File = string.Join(" ", lineParts, 1, lineParts.Length - 1),
};
hashes.Add(sha1);
sha1List.Add(sha1);
break;
case HashType.SHA256:
var sha256 = new SHA256
{
Hash = lineParts[0],
#if NETFRAMEWORK
File = string.Join(" ", lineParts.Skip(1).ToArray()),
#else
File = string.Join(" ", lineParts[1..]),
#endif
File = string.Join(" ", lineParts, 1, lineParts.Length - 1),
};
hashes.Add(sha256);
sha256List.Add(sha256);
break;
case HashType.SHA384:
var sha384 = new SHA384
{
Hash = lineParts[0],
#if NETFRAMEWORK
File = string.Join(" ", lineParts.Skip(1).ToArray()),
#else
File = string.Join(" ", lineParts[1..]),
#endif
File = string.Join(" ", lineParts, 1, lineParts.Length - 1),
};
hashes.Add(sha384);
sha384List.Add(sha384);
break;
case HashType.SHA512:
var sha512 = new SHA512
{
Hash = lineParts[0],
#if NETFRAMEWORK
File = string.Join(" ", lineParts.Skip(1).ToArray()),
#else
File = string.Join(" ", lineParts[1..]),
#endif
File = string.Join(" ", lineParts, 1, lineParts.Length - 1),
};
hashes.Add(sha512);
sha512List.Add(sha512);
break;
case HashType.SpamSum:
var spamSum = new SpamSum
{
Hash = lineParts[0],
#if NETFRAMEWORK
File = string.Join(" ", lineParts.Skip(1).ToArray()),
#else
File = string.Join(" ", lineParts[1..]),
#endif
File = string.Join(" ", lineParts, 1, lineParts.Length - 1),
};
hashes.Add(spamSum);
spamsumList.Add(spamSum);
break;
}
}
@@ -201,32 +170,28 @@ namespace SabreTools.Serialization.Deserializers
switch (hash)
{
case HashType.CRC32:
case HashType.CRC32_ISO:
case HashType.CRC32_Naive:
case HashType.CRC32_Optimized:
case HashType.CRC32_Parallel:
dat.SFV = hashes.Cast<SFV>().ToArray();
dat.SFV = [.. sfvList];
break;
case HashType.MD5:
dat.MD5 = hashes.Cast<MD5>().ToArray();
dat.MD5 = [.. md5List];
break;
case HashType.SHA1:
dat.SHA1 = hashes.Cast<SHA1>().ToArray();
dat.SHA1 = [.. sha1List];
break;
case HashType.SHA256:
dat.SHA256 = hashes.Cast<SHA256>().ToArray();
dat.SHA256 = [.. sha256List];
break;
case HashType.SHA384:
dat.SHA384 = hashes.Cast<SHA384>().ToArray();
dat.SHA384 = [.. sha384List];
break;
case HashType.SHA512:
dat.SHA512 = hashes.Cast<SHA512>().ToArray();
dat.SHA512 = [.. sha512List];
break;
case HashType.SpamSum:
dat.SpamSum = hashes.Cast<SpamSum>().ToArray();
dat.SpamSum = [.. spamsumList];
break;
}
dat.ADDITIONAL_ELEMENTS = [.. additional];
return dat;
}

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
using SabreTools.Models.InstallShieldArchiveV3;
@@ -114,7 +115,17 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled directory on success, null on error</returns>
public static Models.InstallShieldArchiveV3.Directory? ParseDirectory(Stream data)
{
return data.ReadType<Models.InstallShieldArchiveV3.Directory>();
var directory = new Models.InstallShieldArchiveV3.Directory();
directory.FileCount = data.ReadUInt16();
directory.ChunkSize = data.ReadUInt16();
// TODO: Is there any equivilent automatic type for UInt16-prefixed ANSI?
ushort nameLength = data.ReadUInt16();
byte[] nameBytes = data.ReadBytes(nameLength);
directory.Name = Encoding.ASCII.GetString(nameBytes);
return directory;
}
/// <summary>

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using SabreTools.IO.Extensions;
@@ -447,14 +448,9 @@ namespace SabreTools.Serialization.Deserializers
var fileGroup = new FileGroup();
fileGroup.NameOffset = data.ReadUInt32();
fileGroup.ExpandedSize = data.ReadUInt32();
fileGroup.Reserved0 = data.ReadBytes(4);
fileGroup.CompressedSize = data.ReadUInt32();
fileGroup.Reserved1 = data.ReadBytes(4);
fileGroup.Reserved2 = data.ReadBytes(2);
fileGroup.Attribute1 = data.ReadUInt16();
fileGroup.Attribute2 = data.ReadUInt16();
fileGroup.Attributes = (FileGroupAttributes)data.ReadUInt16();
// TODO: Figure out what data lives in this area for V5 and below
if (majorVersion <= 5)
@@ -462,19 +458,19 @@ namespace SabreTools.Serialization.Deserializers
fileGroup.FirstFile = data.ReadUInt32();
fileGroup.LastFile = data.ReadUInt32();
fileGroup.UnknownOffset = data.ReadUInt32();
fileGroup.Var4Offset = data.ReadUInt32();
fileGroup.Var1Offset = data.ReadUInt32();
fileGroup.UnknownStringOffset = data.ReadUInt32();
fileGroup.OperatingSystemOffset = data.ReadUInt32();
fileGroup.LanguageOffset = data.ReadUInt32();
fileGroup.HTTPLocationOffset = data.ReadUInt32();
fileGroup.FTPLocationOffset = data.ReadUInt32();
fileGroup.MiscOffset = data.ReadUInt32();
fileGroup.Var2Offset = data.ReadUInt32();
fileGroup.TargetDirectoryOffset = data.ReadUInt32();
fileGroup.Reserved3 = data.ReadBytes(2);
fileGroup.Reserved4 = data.ReadBytes(2);
fileGroup.Reserved5 = data.ReadBytes(2);
fileGroup.Reserved6 = data.ReadBytes(2);
fileGroup.Reserved7 = data.ReadBytes(2);
fileGroup.OverwriteFlags = (FileGroupFlags)data.ReadUInt32();
fileGroup.Reserved = new uint[4];
for (int i = 0; i < fileGroup.Reserved.Length; i++)
{
fileGroup.Reserved[i] = data.ReadUInt32();
}
// Cache the current position
long currentPosition = data.Position;
@@ -489,7 +485,7 @@ namespace SabreTools.Serialization.Deserializers
if (majorVersion >= 17)
fileGroup.Name = data.ReadNullTerminatedUnicodeString();
else
fileGroup.Name = data.ReadNullTerminatedUnicodeString();
fileGroup.Name = data.ReadNullTerminatedAnsiString();
}
// Seek back to the correct offset
@@ -512,15 +508,19 @@ namespace SabreTools.Serialization.Deserializers
component.IdentifierOffset = data.ReadUInt32();
component.DescriptorOffset = data.ReadUInt32();
component.DisplayNameOffset = data.ReadUInt32();
component.Reserved0 = data.ReadUInt16();
component.ReservedOffset0 = data.ReadUInt32();
component.ReservedOffset1 = data.ReadUInt32();
component.Status = (ComponentStatus)data.ReadUInt16();
component.PasswordOffset = data.ReadUInt32();
component.MiscOffset = data.ReadUInt32();
component.ComponentIndex = data.ReadUInt16();
component.NameOffset = data.ReadUInt32();
component.ReservedOffset2 = data.ReadUInt32();
component.ReservedOffset3 = data.ReadUInt32();
component.ReservedOffset4 = data.ReadUInt32();
component.Reserved1 = data.ReadBytes(32);
component.CDRomFolderOffset = data.ReadUInt32();
component.HTTPLocationOffset = data.ReadUInt32();
component.FTPLocationOffset = data.ReadUInt32();
component.Guid = new Guid[2];
for (int i = 0; i < component.Guid.Length; i++)
{
component.Guid[i] = data.ReadGuid();
}
component.CLSIDOffset = data.ReadUInt32();
component.Reserved2 = data.ReadBytes(28);
component.Reserved3 = data.ReadBytes(majorVersion <= 5 ? 2 : 1);
@@ -533,10 +533,10 @@ namespace SabreTools.Serialization.Deserializers
component.SubComponentsCount = data.ReadUInt16();
component.SubComponentsOffset = data.ReadUInt32();
component.NextComponentOffset = data.ReadUInt32();
component.ReservedOffset5 = data.ReadUInt32();
component.ReservedOffset6 = data.ReadUInt32();
component.ReservedOffset7 = data.ReadUInt32();
component.ReservedOffset8 = data.ReadUInt32();
component.OnInstallingOffset = data.ReadUInt32();
component.OnInstalledOffset = data.ReadUInt32();
component.OnUninstallingOffset = data.ReadUInt32();
component.OnUninstalledOffset = data.ReadUInt32();
// Cache the current position
long currentPosition = data.Position;

View File

@@ -476,7 +476,7 @@ namespace SabreTools.Serialization.Deserializers
var entry = new ResidentNamesTableEntry();
entry.Length = data.ReadByteValue();
if (entry.Length > 0)
if (entry.Length > 0 && data.Position + entry.Length <= data.Length)
{
byte[]? name = data.ReadBytes(entry.Length);
if (name != null)
@@ -810,7 +810,7 @@ namespace SabreTools.Serialization.Deserializers
var entry = new ImportModuleNameTableEntry();
entry.Length = data.ReadByteValue();
if (entry.Length > 0)
if (entry.Length > 0 && data.Position + entry.Length <= data.Length)
{
byte[]? name = data.ReadBytes(entry.Length);
if (name != null)
@@ -831,7 +831,7 @@ namespace SabreTools.Serialization.Deserializers
var entry = new ImportModuleProcedureNameTableEntry();
entry.Length = data.ReadByteValue();
if (entry.Length > 0)
if (entry.Length > 0 && data.Position + entry.Length <= data.Length)
{
byte[]? name = data.ReadBytes(entry.Length);
if (name != null)
@@ -862,7 +862,7 @@ namespace SabreTools.Serialization.Deserializers
var entry = new NonResidentNamesTableEntry();
entry.Length = data.ReadByteValue();
if (entry.Length > 0)
if (entry.Length > 0 && data.Position + entry.Length <= data.Length)
{
byte[]? name = data.ReadBytes(entry.Length);
if (name != null)

View File

@@ -23,7 +23,6 @@ namespace SabreTools.Serialization.Deserializers
var sets = new List<Set>();
var rows = new List<Row>();
var additional = new List<string>();
while (!reader.EndOfStream)
{
// Read the line and don't split yet
@@ -33,7 +32,7 @@ namespace SabreTools.Serialization.Deserializers
// If we have a set to process
if (set != null)
{
set.Row = rows.ToArray();
set.Row = [.. rows];
sets.Add(set);
set = null;
rows.Clear();
@@ -215,7 +214,6 @@ namespace SabreTools.Serialization.Deserializers
default:
row = null;
additional.Add(line);
break;
}
@@ -226,15 +224,14 @@ namespace SabreTools.Serialization.Deserializers
// If we have a set to process
if (set != null)
{
set.Row = rows.ToArray();
set.Row = [.. rows];
sets.Add(set);
set = null;
rows.Clear();
}
// Add extra pieces and return
dat.Set = sets.ToArray();
dat.ADDITIONAL_ELEMENTS = additional.ToArray();
dat.Set = [.. sets];
return dat;
}
}

View File

@@ -102,7 +102,7 @@ namespace SabreTools.Serialization.Deserializers
hashTable.Add(hashEntry);
}
archive.HashTable = hashTable.ToArray();
archive.HashTable = [.. hashTable];
}
}
@@ -131,7 +131,7 @@ namespace SabreTools.Serialization.Deserializers
hashTable.Add(hashEntry);
}
archive.HashTable = hashTable.ToArray();
archive.HashTable = [.. hashTable];
}
}
@@ -160,7 +160,7 @@ namespace SabreTools.Serialization.Deserializers
hashTable.Add(hashEntry);
}
archive.HashTable = hashTable.ToArray();
archive.HashTable = [.. hashTable];
}
}
@@ -193,7 +193,7 @@ namespace SabreTools.Serialization.Deserializers
blockTable.Add(blockEntry);
}
archive.BlockTable = blockTable.ToArray();
archive.BlockTable = [.. blockTable];
}
}
@@ -222,7 +222,7 @@ namespace SabreTools.Serialization.Deserializers
blockTable.Add(blockEntry);
}
archive.BlockTable = blockTable.ToArray();
archive.BlockTable = [.. blockTable];
}
}
@@ -251,7 +251,7 @@ namespace SabreTools.Serialization.Deserializers
blockTable.Add(blockEntry);
}
archive.BlockTable = blockTable.ToArray();
archive.BlockTable = [.. blockTable];
}
}
@@ -278,7 +278,7 @@ namespace SabreTools.Serialization.Deserializers
hiBlockTable.Add(hiBlockEntry);
}
archive.HiBlockTable = hiBlockTable.ToArray();
archive.HiBlockTable = [.. hiBlockTable];
}
}

View File

@@ -21,7 +21,7 @@ namespace SabreTools.Serialization.Deserializers
return null;
// Cache the current offset
int initialOffset = (int)data.Position;
long initialOffset = data.Position;
// Create a new cart image to fill
var cart = new Cart();
@@ -62,118 +62,72 @@ namespace SabreTools.Serialization.Deserializers
#endregion
#region Partitions
// Create the partition table
cart.Partitions = new NCCHHeader[8];
// Iterate and build the partitions
for (int i = 0; i < 8; i++)
{
cart.Partitions[i] = ParseNCCHHeader(data);
}
#endregion
// Cache the media unit size for further use
long mediaUnitSize = 0;
if (header.PartitionFlags != null)
mediaUnitSize = (uint)(0x200 * Math.Pow(2, header.PartitionFlags[(int)NCSDFlags.MediaUnitSize]));
#region Extended Headers
#region Partitions
// Create the extended header table
cart.ExtendedHeaders = new NCCHExtendedHeader[8];
// Create the tables
cart.Partitions = new NCCHHeader[8];
cart.ExtendedHeaders = new NCCHExtendedHeader?[8];
cart.ExeFSHeaders = new ExeFSHeader?[8];
cart.RomFSHeaders = new RomFSHeader?[8];
// Iterate and build the extended headers
// Iterate and build the partitions
for (int i = 0; i < 8; i++)
{
// If we have an encrypted or invalid partition
if (cart.Partitions[i]!.MagicID != NCCHMagicNumber)
// Cache the offset of the partition
initialOffset = data.Position;
// Handle the normal header
var partition = ParseNCCHHeader(data);
if (partition == null || partition.MagicID != NCCHMagicNumber)
continue;
// If we have no partitions table
if (cart.Header!.PartitionsTable == null)
continue;
// Set the normal header
cart.Partitions[i] = partition;
// Get the extended header offset
long offset = (cart.Header.PartitionsTable[i]!.Offset * mediaUnitSize) + 0x200;
if (offset < 0 || offset >= data.Length)
continue;
// Handle the extended header, if it exists
if (partition.ExtendedHeaderSizeInBytes > 0)
{
var extendedHeader = ParseNCCHExtendedHeader(data);
if (extendedHeader != null)
cart.ExtendedHeaders[i] = extendedHeader;
}
// Seek to the extended header
data.Seek(offset, SeekOrigin.Begin);
// Handle the ExeFS, if it exists
if (partition.ExeFSSizeInMediaUnits > 0)
{
long offset = partition.ExeFSOffsetInMediaUnits * mediaUnitSize;
data.Seek(initialOffset + offset, SeekOrigin.Begin);
// Parse the extended header
var extendedHeader = ParseNCCHExtendedHeader(data);
if (extendedHeader != null)
cart.ExtendedHeaders[i] = extendedHeader;
}
var exeFsHeader = ParseExeFSHeader(data);
if (exeFsHeader == null)
return null;
#endregion
cart.ExeFSHeaders[i] = exeFsHeader;
}
#region ExeFS Headers
// Handle the RomFS, if it exists
if (partition.RomFSSizeInMediaUnits > 0)
{
long offset = partition.RomFSOffsetInMediaUnits * mediaUnitSize;
data.Seek(initialOffset + offset, SeekOrigin.Begin);
// Create the ExeFS header table
cart.ExeFSHeaders = new ExeFSHeader[8];
var romFsHeader = ParseRomFSHeader(data);
if (romFsHeader == null)
continue;
else if (romFsHeader.MagicString != RomFSMagicNumber || romFsHeader.MagicNumber != RomFSSecondMagicNumber)
continue;
// Iterate and build the ExeFS headers
for (int i = 0; i < 8; i++)
{
// If we have an encrypted or invalid partition
if (cart.Partitions[i]!.MagicID != NCCHMagicNumber)
continue;
// If we have no partitions table
if (cart.Header!.PartitionsTable == null)
continue;
// Get the ExeFS header offset
long offset = (cart.Header.PartitionsTable[i]!.Offset + cart.Partitions[i]!.ExeFSOffsetInMediaUnits) * mediaUnitSize;
if (offset < 0 || offset >= data.Length)
continue;
// Seek to the ExeFS header
data.Seek(offset, SeekOrigin.Begin);
// Parse the ExeFS header
var exeFsHeader = ParseExeFSHeader(data);
if (exeFsHeader == null)
return null;
cart.ExeFSHeaders[i] = exeFsHeader;
}
#endregion
#region RomFS Headers
// Create the RomFS header table
cart.RomFSHeaders = new RomFSHeader[8];
// Iterate and build the RomFS headers
for (int i = 0; i < 8; i++)
{
// If we have an encrypted or invalid partition
if (cart.Partitions[i]!.MagicID != NCCHMagicNumber)
continue;
// If we have no partitions table
if (cart.Header!.PartitionsTable == null)
continue;
// Get the RomFS header offset
long offset = (cart.Header.PartitionsTable[i]!.Offset + cart.Partitions[i]!.RomFSOffsetInMediaUnits) * mediaUnitSize;
if (offset < 0 || offset >= data.Length)
continue;
// Seek to the RomFS header
data.Seek(offset, SeekOrigin.Begin);
// Parse the RomFS header
var romFsHeader = ParseRomFSHeader(data);
if (romFsHeader != null)
cart.RomFSHeaders[i] = romFsHeader;
}
// Skip past other data
long partitionSize = partition.ContentSizeInMediaUnits * mediaUnitSize;
data.Seek(initialOffset + partitionSize, SeekOrigin.Begin);
}
#endregion
@@ -259,7 +213,43 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled card info header on success, null on error</returns>
public static CardInfoHeader? ParseCardInfoHeader(Stream data)
{
return data.ReadType<CardInfoHeader>();
// TODO: Use marshalling here instead of building
var header = new CardInfoHeader();
header.WritableAddressMediaUnits = data.ReadUInt32();
header.CardInfoBitmask = data.ReadUInt32();
header.Reserved1 = data.ReadBytes(0xF8);
header.FilledSize = data.ReadUInt32();
header.Reserved2 = data.ReadBytes(0x0C);
header.TitleVersion = data.ReadUInt16();
header.CardRevision = data.ReadUInt16();
header.Reserved3 = data.ReadBytes(0x0C);
header.CVerTitleID = data.ReadBytes(0x08);
header.CVerVersionNumber = data.ReadUInt16();
header.Reserved4 = data.ReadBytes(0xCD6);
header.InitialData = ParseInitialData(data);
return header;
}
/// <summary>
/// Parse a Stream into initial data
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled initial data on success, null on error</returns>
public static InitialData? ParseInitialData(Stream data)
{
// TODO: Use marshalling here instead of building
var id = new InitialData();
id.CardSeedKeyY = data.ReadBytes(0x10);
id.EncryptedCardSeed = data.ReadBytes(0x10);
id.CardSeedAESMAC = data.ReadBytes(0x10);
id.CardSeedNonce = data.ReadBytes(0x0C);
id.Reserved = data.ReadBytes(0xC4);
id.BackupHeader = ParseNCCHHeader(data, skipSignature: true);
return id;
}
/// <summary>
@@ -339,7 +329,51 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled NCCH extended header on success, null on error</returns>
public static NCCHExtendedHeader? ParseNCCHExtendedHeader(Stream data)
{
return data.ReadType<NCCHExtendedHeader>();
// TODO: Replace with `data.ReadType<NCCHExtendedHeader>();` when enum serialization fixed
var header = new NCCHExtendedHeader();
header.SCI = data.ReadType<SystemControlInfo>();
header.ACI = ParseAccessControlInfo(data);
header.AccessDescSignature = data.ReadBytes(0x100);
header.NCCHHDRPublicKey = data.ReadBytes(0x100);
header.ACIForLimitations = ParseAccessControlInfo(data);
return header;
}
/// <summary>
/// Parse a Stream into an access control info
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled access control info on success, null on error</returns>
public static AccessControlInfo? ParseAccessControlInfo(Stream data)
{
var aci = new AccessControlInfo();
aci.ARM11LocalSystemCapabilities = data.ReadType<ARM11LocalSystemCapabilities>();
aci.ARM11KernelCapabilities = data.ReadType<ARM11KernelCapabilities>();
aci.ARM9AccessControl = ParseARM9AccessControl(data);
return aci;
}
/// <summary>
/// Parse a Stream into an ARM9 access control
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled ARM9 access control on success, null on error</returns>
public static ARM9AccessControl? ParseARM9AccessControl(Stream data)
{
var a9ac = new ARM9AccessControl();
a9ac.Descriptors = new ARM9AccessControlDescriptors[15];
for (int i = 0; i < a9ac.Descriptors.Length; i++)
{
a9ac.Descriptors[i] = (ARM9AccessControlDescriptors)data.ReadByteValue();
}
a9ac.DescriptorVersion = data.ReadByteValue();
return a9ac;
}
/// <summary>

View File

@@ -1,6 +1,5 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SabreTools.IO.Extensions;
using SabreTools.Models.NewExecutable;
using static SabreTools.Models.NewExecutable.Constants;
@@ -76,7 +75,7 @@ namespace SabreTools.Serialization.Deserializers
// If the offset for the segment table doesn't exist
tableAddress = initialOffset
+ (int)stub.Header.NewExeHeaderAddr
+ executableHeader.SegmentTableOffset;
+ executableHeader.ResourceTableOffset;
if (tableAddress >= data.Length)
return executable;
@@ -262,7 +261,7 @@ namespace SabreTools.Serialization.Deserializers
/// <param name="data">Stream to parse</param>
/// <param name="count">Number of resource table entries to read</param>
/// <returns>Filled resource table on success, null on error</returns>
public static ResourceTable? ParseResourceTable(Stream data, int count)
public static ResourceTable? ParseResourceTable(Stream data, ushort count)
{
long initialOffset = data.Position;
@@ -270,13 +269,23 @@ namespace SabreTools.Serialization.Deserializers
var resourceTable = new ResourceTable();
resourceTable.AlignmentShiftCount = data.ReadUInt16();
resourceTable.ResourceTypes = new ResourceTypeInformationEntry[count];
for (int i = 0; i < resourceTable.ResourceTypes.Length; i++)
var resourceTypes = new List<ResourceTypeInformationEntry>();
for (int i = 0; i < count; i++)
{
var entry = new ResourceTypeInformationEntry();
entry.TypeID = data.ReadUInt16();
entry.ResourceCount = data.ReadUInt16();
entry.Reserved = data.ReadUInt32();
// A zero type ID marks the end of the resource type information blocks.
if (entry.TypeID == 0)
{
resourceTypes.Add(entry);
break;
}
entry.Resources = new ResourceTypeResourceEntry[entry.ResourceCount];
for (int j = 0; j < entry.ResourceCount; j++)
{
@@ -287,22 +296,40 @@ namespace SabreTools.Serialization.Deserializers
entry.Resources[j] = resource;
}
resourceTable.ResourceTypes[i] = entry;
resourceTypes.Add(entry);
}
resourceTable.ResourceTypes = [.. resourceTypes];
// Get the full list of unique string offsets
var stringOffsets = resourceTable.ResourceTypes
.Where(rt => rt != null)
.Where(rt => rt!.IsIntegerType() == false)
.Select(rt => rt!.TypeID)
.Union(resourceTable.ResourceTypes
.Where(rt => rt != null)
.SelectMany(rt => rt!.Resources ?? [])
.Where(r => r!.IsIntegerType() == false)
.Select(r => r!.ResourceID))
.Distinct()
.OrderBy(o => o)
.ToList();
var stringOffsets = new List<ushort>();
foreach (var rtie in resourceTable.ResourceTypes)
{
// Skip invalid entries
if (rtie == null || rtie.TypeID == 0)
continue;
// Handle offset types
if (!rtie.IsIntegerType() && !stringOffsets.Contains(rtie.TypeID))
stringOffsets.Add(rtie.TypeID);
// Handle types with resources
foreach (var rtre in rtie.Resources ?? [])
{
// Skip invalid entries
if (rtre == null || rtre.IsIntegerType() || rtre.ResourceID == 0)
continue;
// Skip already added entries
if (stringOffsets.Contains(rtre.ResourceID))
continue;
stringOffsets.Add(rtre.ResourceID);
}
}
// Order the offsets list
stringOffsets.Sort();
// Populate the type and name string dictionary
resourceTable.TypeAndNameStrings = [];
@@ -359,7 +386,7 @@ namespace SabreTools.Serialization.Deserializers
// TODO: Use marshalling here instead of building
var residentNameTable = new List<ResidentNameTableEntry>();
while (data.Position < endOffset)
while (data.Position < endOffset && data.Position < data.Length)
{
var entry = ParseResidentNameTableEntry(data);
if (entry == null)
@@ -432,7 +459,7 @@ namespace SabreTools.Serialization.Deserializers
// TODO: Use marshalling here instead of building
var importedNameTable = new Dictionary<ushort, ImportedNameTableEntry>();
while (data.Position < endOffset)
while (data.Position < endOffset && data.Position < data.Length)
{
ushort currentOffset = (ushort)data.Position;
var entry = ParseImportedNameTableEntry(data);
@@ -472,7 +499,7 @@ namespace SabreTools.Serialization.Deserializers
// TODO: Use marshalling here instead of building
var entryTable = new List<EntryTableBundle>();
while (data.Position < endOffset)
while (data.Position < endOffset && data.Position < data.Length)
{
var entry = new EntryTableBundle();
entry.EntryCount = data.ReadByteValue();
@@ -511,7 +538,7 @@ namespace SabreTools.Serialization.Deserializers
// TODO: Use marshalling here instead of building
var residentNameTable = new List<NonResidentNameTableEntry>();
while (data.Position < endOffset)
while (data.Position < endOffset && data.Position < data.Length)
{
var entry = ParseNonResidentNameTableEntry(data);
if (entry == null)

View File

@@ -110,7 +110,7 @@ namespace SabreTools.Serialization.Deserializers
}
// Set the file allocation table
cart.FileAllocationTable = fileAllocationTable.ToArray();
cart.FileAllocationTable = [.. fileAllocationTable];
#endregion
@@ -170,7 +170,7 @@ namespace SabreTools.Serialization.Deserializers
}
// Assign the folder allocation table
nameTable.FolderAllocationTable = folderAllocationTable.ToArray();
nameTable.FolderAllocationTable = [.. folderAllocationTable];
// Create a variable-length table
var nameList = new List<NameListEntry>();
@@ -184,7 +184,7 @@ namespace SabreTools.Serialization.Deserializers
}
// Assign the name list
nameTable.NameList = nameList.ToArray();
nameTable.NameList = [.. nameList];
return nameTable;
}

View File

@@ -43,7 +43,7 @@ namespace SabreTools.Serialization.Deserializers
}
// Assign the units and return
di.Units = diUnits.ToArray();
di.Units = [.. diUnits];
return di;
}

View File

@@ -0,0 +1,697 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
using SabreTools.Models.PKZIP;
using static SabreTools.Models.PKZIP.Constants;
namespace SabreTools.Serialization.Deserializers
{
public class PKZIP : BaseBinaryDeserializer<Archive>
{
/// <inheritdoc/>
protected override bool SkipCompression => true;
/// <inheritdoc/>
public override Archive? Deserialize(Stream? data)
{
// If the data is invalid
if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead)
return null;
// If the offset is out of bounds
if (data.Position < 0 || data.Position >= data.Length)
return null;
var archive = new Archive();
#region End of Central Directory Record
// Find the end of central directory record
long eocdrOffset = SearchForEndOfCentralDirectoryRecord(data);
if (eocdrOffset < 0 || eocdrOffset >= data.Length)
return null;
// Seek to the end of central directory record
data.Seek(eocdrOffset, SeekOrigin.Begin);
// Read the end of central directory record
var eocdr = ParseEndOfCentralDirectoryRecord(data);
if (eocdr == null)
return null;
// Assign the end of central directory record
archive.EndOfCentralDirectoryRecord = eocdr;
#endregion
#region ZIP64 End of Central Directory Locator and Record
// Set a flag for ZIP64 not found by default
bool zip64 = false;
// Process ZIP64 if any fields are set to max value
if (eocdr.DiskNumber == 0xFFFF
|| eocdr.StartDiskNumber == 0xFFFF
|| eocdr.TotalEntriesOnDisk == 0xFFFF
|| eocdr.TotalEntries == 0xFFFF
|| eocdr.CentralDirectorySize == 0xFFFFFFFF
|| eocdr.CentralDirectoryOffset == 0xFFFFFFFF)
{
// Set the ZIP64 flag
zip64 = true;
// Find the ZIP64 end of central directory locator
long eocdlOffset = SearchForZIP64EndOfCentralDirectoryLocator(data);
if (eocdlOffset < 0 || eocdlOffset >= data.Length)
return null;
// Seek to the ZIP64 end of central directory locator
data.Seek(eocdlOffset, SeekOrigin.Begin);
// Read the ZIP64 end of central directory locator
var eocdl64 = ParseEndOfCentralDirectoryLocator64(data);
if (eocdl64 == null)
return null;
// Assign the ZIP64 end of central directory record
archive.ZIP64EndOfCentralDirectoryLocator = eocdl64;
// Try to get the ZIP64 end of central directory record offset
if ((long)eocdl64.CentralDirectoryOffset < 0 || (long)eocdl64.CentralDirectoryOffset >= data.Length)
return null;
// Seek to the ZIP64 end of central directory record
data.Seek((long)eocdl64.CentralDirectoryOffset, SeekOrigin.Begin);
// Read the ZIP64 end of central directory record
var eocdr64 = ParseEndOfCentralDirectoryRecord64(data);
if (eocdr64 == null)
return null;
// Assign the ZIP64 end of central directory record
archive.ZIP64EndOfCentralDirectoryRecord = eocdr64;
}
#endregion
#region Central Directory Records
// Try to get the central directory record offset
long cdrOffset, cdrSize;
if (zip64 && archive.ZIP64EndOfCentralDirectoryRecord != null)
{
cdrOffset = (long)archive.ZIP64EndOfCentralDirectoryRecord.CentralDirectoryOffset;
cdrSize = (long)archive.ZIP64EndOfCentralDirectoryRecord.CentralDirectorySize;
}
else if (archive.EndOfCentralDirectoryRecord != null)
{
cdrOffset = archive.EndOfCentralDirectoryRecord.CentralDirectoryOffset;
cdrSize = archive.EndOfCentralDirectoryRecord.CentralDirectorySize;
}
else
{
return null;
}
// Try to get the central directory record offset
if (cdrOffset < 0 || cdrOffset >= data.Length)
return null;
// Seek to the first central directory record
data.Seek(cdrOffset, SeekOrigin.Begin);
// Cache the current offset
long currentOffset = data.Position;
// Read the central directory records
var cdrs = new List<CentralDirectoryFileHeader>();
while (data.Position < currentOffset + cdrSize)
{
// Read the central directory record
var cdr = ParseCentralDirectoryFileHeader(data);
if (cdr == null)
return null;
// Add the central directory record
cdrs.Add(cdr);
}
// Assign the central directory records
archive.CentralDirectoryHeaders = [.. cdrs];
#endregion
// TODO: Handle digital signature -- immediately following central directory records
#region Archive Extra Data Record
// Find the archive extra data record
long aedrOffset = SearchForArchiveExtraDataRecord(data, cdrOffset);
if (aedrOffset >= 0 && aedrOffset < data.Length)
{
// Seek to the archive extra data record
data.Seek(aedrOffset, SeekOrigin.Begin);
// Read the archive extra data record
var aedr = ParseArchiveExtraDataRecord(data);
if (aedr == null)
return null;
// Assign the archive extra data record
archive.ArchiveExtraDataRecord = aedr;
}
#endregion
#region Local File
// Setup all of the collections
var localFileHeaders = new List<LocalFileHeader?>();
var encryptionHeaders = new List<byte[]?>();
var fileData = new List<byte[]>(); // TODO: Should this data be read here?
var dataDescriptors = new List<DataDescriptor?>();
var zip64DataDescriptors = new List<DataDescriptor64?>();
// Read the local file headers
for (int i = 0; i < archive.CentralDirectoryHeaders.Length; i++)
{
var header = archive.CentralDirectoryHeaders[i];
// Get the local file header offset
long headerOffset = header.RelativeOffsetOfLocalHeader;
if (headerOffset == 0xFFFFFFFF && header.ExtraField != null)
{
// TODO: Parse into a proper structure instead of this
byte[] extraData = header.ExtraField;
if (BitConverter.ToUInt16(extraData, 0) == 0x0001)
headerOffset = BitConverter.ToInt64(extraData, 4);
}
if (headerOffset < 0 || headerOffset >= data.Length)
return null;
// Seek to the local file header
data.Seek(headerOffset, SeekOrigin.Begin);
// Try to parse the local header
var localFileHeader = ParseLocalFileHeader(data);
if (localFileHeader == null)
{
// Add a placeholder null item
localFileHeaders.Add(null);
encryptionHeaders.Add(null);
fileData.Add([]);
dataDescriptors.Add(null);
zip64DataDescriptors.Add(null);
continue;
}
// Add the local file header
localFileHeaders.Add(localFileHeader);
// Only read the encryption header if necessary
#if NET20 || NET35
if ((header.Flags & GeneralPurposeBitFlags.FileEncrypted) != 0)
#else
if (header.Flags.HasFlag(GeneralPurposeBitFlags.FileEncrypted))
#endif
{
// Try to read the encryption header data -- TODO: Verify amount to read
byte[] encryptionHeader = data.ReadBytes(12);
if (encryptionHeader.Length != 12)
return null;
// Add the encryption header
encryptionHeaders.Add(encryptionHeader);
}
else
{
// Add the null encryption header
encryptionHeaders.Add(null);
}
// Try to read the file data
byte[] fileDatum = data.ReadBytes((int)header.CompressedSize);
if (fileDatum.Length < header.CompressedSize)
return null;
// Add the file data
fileData.Add(fileDatum);
// Only read the data descriptor if necessary
#if NET20 || NET35
if ((header.Flags & GeneralPurposeBitFlags.NoCRC) != 0)
#else
if (header.Flags.HasFlag(GeneralPurposeBitFlags.NoCRC))
#endif
{
// Select the data descriptor that is being used
if (zip64)
{
// Try to parse the data descriptor
var dataDescriptor64 = ParseDataDescriptor64(data);
if (dataDescriptor64 == null)
return null;
// Add the data descriptor
dataDescriptors.Add(null);
zip64DataDescriptors.Add(dataDescriptor64);
}
else
{
// Try to parse the data descriptor
var dataDescriptor = ParseDataDescriptor(data);
if (dataDescriptor == null)
return null;
// Add the data descriptor
dataDescriptors.Add(dataDescriptor);
zip64DataDescriptors.Add(null);
}
}
else
{
// Add the null data descriptor
dataDescriptors.Add(null);
zip64DataDescriptors.Add(null);
}
}
// Assign the local file headers
archive.LocalFileHeaders = [.. localFileHeaders];
// Assign the encryption headers
archive.EncryptionHeaders = [.. encryptionHeaders];
// Assign the file data
archive.FileData = [.. fileData];
// Assign the data descriptors
archive.DataDescriptors = [.. dataDescriptors];
archive.ZIP64DataDescriptors = [.. zip64DataDescriptors];
#endregion
// TODO: Handle archive decryption header
return archive;
}
/// <summary>
/// Search for the end of central directory record
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Position of the end of central directory record, -1 on error</returns>
public static long SearchForEndOfCentralDirectoryRecord(Stream data)
{
// Cache the current offset
long current = data.Position;
// Seek to the minimum size of the record from the end
data.Seek(-22, SeekOrigin.End);
// Attempt to find the end of central directory signature
while (data.Position > 0)
{
// Read the potential signature
uint possibleSignature = data.ReadUInt32();
if (possibleSignature == EndOfCentralDirectoryRecordSignature)
{
long signaturePosition = data.Position - 4;
data.Seek(current, SeekOrigin.Begin);
return signaturePosition;
}
// If we find any other signature
switch (possibleSignature)
{
case ArchiveExtraDataRecordSignature:
case CentralDirectoryFileHeaderSignature:
case DataDescriptorSignature:
case DigitalSignatureSignature:
case EndOfCentralDirectoryLocator64Signature:
case EndOfCentralDirectoryRecord64Signature:
case LocalFileHeaderSignature:
data.Seek(current, SeekOrigin.Begin);
return -1;
}
// Seek backward 5 bytes, if possible
data.Seek(-5, SeekOrigin.Current);
}
// No signature was found
data.Seek(current, SeekOrigin.Begin);
return -1;
}
/// <summary>
/// Parse a Stream into an end of central directory record
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled end of central directory record on success, null on error</returns>
public static EndOfCentralDirectoryRecord? ParseEndOfCentralDirectoryRecord(Stream data)
{
// TODO: Use marshalling here instead of building
var record = new EndOfCentralDirectoryRecord();
record.Signature = data.ReadUInt32();
if (record.Signature != EndOfCentralDirectoryRecordSignature)
return null;
record.DiskNumber = data.ReadUInt16();
record.StartDiskNumber = data.ReadUInt16();
record.TotalEntriesOnDisk = data.ReadUInt16();
record.TotalEntries = data.ReadUInt16();
record.CentralDirectorySize = data.ReadUInt32();
record.CentralDirectoryOffset = data.ReadUInt32();
record.FileCommentLength = data.ReadUInt16();
if (record.FileCommentLength > 0 && data.Position + record.FileCommentLength <= data.Length)
{
byte[] commentBytes = data.ReadBytes(record.FileCommentLength);
if (commentBytes.Length != record.FileCommentLength)
return null;
record.FileComment = Encoding.ASCII.GetString(commentBytes);
}
return record;
}
/// <summary>
/// Search for the ZIP64 end of central directory locator
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Position of the ZIP64 end of central directory locator, -1 on error</returns>
public static long SearchForZIP64EndOfCentralDirectoryLocator(Stream data)
{
// Cache the current offset
long current = data.Position;
// Seek to the minimum size of the record from the minimum start
// of theend of central directory record
data.Seek(-22 + -20, SeekOrigin.Current);
// Attempt to find the ZIP64 end of central directory locator signature
while (data.Position > 0)
{
// Read the potential signature
uint possibleSignature = data.ReadUInt32();
if (possibleSignature == EndOfCentralDirectoryLocator64Signature)
{
long signaturePosition = data.Position - 4;
data.Seek(current, SeekOrigin.Begin);
return signaturePosition;
}
// If we find any other signature
switch (possibleSignature)
{
case ArchiveExtraDataRecordSignature:
case CentralDirectoryFileHeaderSignature:
case DataDescriptorSignature:
case DigitalSignatureSignature:
case EndOfCentralDirectoryRecordSignature:
case EndOfCentralDirectoryRecord64Signature:
case LocalFileHeaderSignature:
data.Seek(current, SeekOrigin.Begin);
return -1;
}
// Seek backward 5 bytes, if possible
data.Seek(-5, SeekOrigin.Current);
}
// No signature was found
data.Seek(current, SeekOrigin.Begin);
return -1;
}
/// <summary>
/// Parse a Stream into a ZIP64 end of central directory locator
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled ZIP64 end of central directory locator on success, null on error</returns>
public static EndOfCentralDirectoryLocator64? ParseEndOfCentralDirectoryLocator64(Stream data)
{
return data.ReadType<EndOfCentralDirectoryLocator64>();
}
/// <summary>
/// Parse a Stream into a ZIP64 end of central directory record
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled ZIP64 end of central directory record on success, null on error</returns>
public static EndOfCentralDirectoryRecord64? ParseEndOfCentralDirectoryRecord64(Stream data)
{
// TODO: Use marshalling here instead of building
var record = new EndOfCentralDirectoryRecord64();
record.Signature = data.ReadUInt32();
if (record.Signature != EndOfCentralDirectoryRecord64Signature)
return null;
record.DirectoryRecordSize = data.ReadUInt64();
record.HostSystem = (HostSystem)data.ReadByteValue();
record.VersionMadeBy = data.ReadByteValue();
record.VersionNeededToExtract = data.ReadUInt16();
record.DiskNumber = data.ReadUInt32();
record.StartDiskNumber = data.ReadUInt32();
record.TotalEntriesOnDisk = data.ReadUInt64();
record.TotalEntries = data.ReadUInt64();
record.CentralDirectorySize = data.ReadUInt64();
record.CentralDirectoryOffset = data.ReadUInt64();
// TODO: Handle the ExtensibleDataSector -- How to detect if exists?
return record;
}
/// <summary>
/// Parse a Stream into a central directory file header
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled central directory file header on success, null on error</returns>
public static CentralDirectoryFileHeader? ParseCentralDirectoryFileHeader(Stream data)
{
// TODO: Use marshalling here instead of building
var header = new CentralDirectoryFileHeader();
header.Signature = data.ReadUInt32();
if (header.Signature != CentralDirectoryFileHeaderSignature)
return null;
header.HostSystem = (HostSystem)data.ReadByteValue();
header.VersionMadeBy = data.ReadByteValue();
header.VersionNeededToExtract = data.ReadUInt16();
header.Flags = (GeneralPurposeBitFlags)data.ReadUInt16();
header.CompressionMethod = (CompressionMethod)data.ReadUInt16();
header.LastModifedFileTime = data.ReadUInt16();
header.LastModifiedFileDate = data.ReadUInt16();
header.CRC32 = data.ReadUInt32();
header.CompressedSize = data.ReadUInt32();
header.UncompressedSize = data.ReadUInt32();
header.FileNameLength = data.ReadUInt16();
header.ExtraFieldLength = data.ReadUInt16();
header.FileCommentLength = data.ReadUInt16();
header.DiskNumberStart = data.ReadUInt16();
header.InternalFileAttributes = (InternalFileAttributes)data.ReadUInt16();
header.ExternalFileAttributes = data.ReadUInt32();
header.RelativeOffsetOfLocalHeader = data.ReadUInt32();
if (header.FileNameLength > 0 && data.Position + header.FileNameLength <= data.Length)
{
byte[] filenameBytes = data.ReadBytes(header.FileNameLength);
if (filenameBytes.Length != header.FileNameLength)
return null;
header.FileName = Encoding.ASCII.GetString(filenameBytes);
}
if (header.ExtraFieldLength > 0 && data.Position + header.ExtraFieldLength <= data.Length)
{
byte[] extraBytes = data.ReadBytes(header.ExtraFieldLength);
if (extraBytes.Length != header.ExtraFieldLength)
return null;
header.ExtraField = extraBytes;
}
if (header.FileCommentLength > 0 && data.Position + header.FileCommentLength <= data.Length)
{
byte[] commentBytes = data.ReadBytes(header.FileCommentLength);
if (commentBytes.Length != header.FileCommentLength)
return null;
header.FileComment = Encoding.ASCII.GetString(commentBytes);
}
return header;
}
/// <summary>
/// Search for the archive extra data record
/// </summary>
/// <param name="data">Stream to parse</param>
/// <param name="centralDirectoryoffset">Offset to the first central directory record</param>
/// <returns>Position of the archive extra data record, -1 on error</returns>
public static long SearchForArchiveExtraDataRecord(Stream data, long centralDirectoryoffset)
{
// Cache the current offset
long current = data.Position;
// Seek to the minimum size of the record from the central directory
data.Seek(centralDirectoryoffset - 8, SeekOrigin.Begin);
// Attempt to find the end of central directory signature
while (data.Position > 0)
{
// Read the potential signature
uint possibleSignature = data.ReadUInt32();
if (possibleSignature == ArchiveExtraDataRecordSignature)
{
long signaturePosition = data.Position - 4;
data.Seek(current, SeekOrigin.Begin);
return signaturePosition;
}
// If we find any other signature
switch (possibleSignature)
{
case CentralDirectoryFileHeaderSignature:
case DataDescriptorSignature:
case DigitalSignatureSignature:
case EndOfCentralDirectoryLocator64Signature:
case EndOfCentralDirectoryRecordSignature:
case EndOfCentralDirectoryRecord64Signature:
case LocalFileHeaderSignature:
data.Seek(current, SeekOrigin.Begin);
return -1;
}
// Seek backward 5 bytes, if possible
data.Seek(-5, SeekOrigin.Current);
}
// No signature was found
data.Seek(current, SeekOrigin.Begin);
return -1;
}
/// <summary>
/// Parse a Stream into an archive extra data record
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled archive extra data record on success, null on error</returns>
public static ArchiveExtraDataRecord? ParseArchiveExtraDataRecord(Stream data)
{
// TODO: Use marshalling here instead of building
var record = new ArchiveExtraDataRecord();
record.Signature = data.ReadUInt32();
if (record.Signature != ArchiveExtraDataRecordSignature)
return null;
record.ExtraFieldLength = data.ReadUInt32();
if (record.ExtraFieldLength > 0 && data.Position + record.ExtraFieldLength <= data.Length)
{
byte[] extraBytes = data.ReadBytes((int)record.ExtraFieldLength);
if (extraBytes.Length != record.ExtraFieldLength)
return null;
record.ExtraFieldData = extraBytes;
}
return record;
}
/// <summary>
/// Parse a Stream into a local file header
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled local file header on success, null on error</returns>
public static LocalFileHeader? ParseLocalFileHeader(Stream data)
{
// TODO: Use marshalling here instead of building
var header = new LocalFileHeader();
header.Signature = data.ReadUInt32();
if (header.Signature != LocalFileHeaderSignature)
return null;
header.Version = data.ReadUInt16();
header.Flags = (GeneralPurposeBitFlags)data.ReadUInt16();
header.CompressionMethod = (CompressionMethod)data.ReadUInt16();
header.LastModifedFileTime = data.ReadUInt16();
header.LastModifiedFileDate = data.ReadUInt16();
header.CRC32 = data.ReadUInt32();
header.CompressedSize = data.ReadUInt32();
header.UncompressedSize = data.ReadUInt32();
header.FileNameLength = data.ReadUInt16();
header.ExtraFieldLength = data.ReadUInt16();
if (header.FileNameLength > 0 && data.Position + header.FileNameLength <= data.Length)
{
byte[] filenameBytes = data.ReadBytes(header.FileNameLength);
if (filenameBytes.Length != header.FileNameLength)
return null;
header.FileName = Encoding.ASCII.GetString(filenameBytes);
}
if (header.ExtraFieldLength > 0 && data.Position + header.ExtraFieldLength <= data.Length)
{
byte[] extraBytes = data.ReadBytes(header.ExtraFieldLength);
if (extraBytes.Length != header.ExtraFieldLength)
return null;
header.ExtraField = extraBytes;
}
return header;
}
/// <summary>
/// Parse a Stream into a data descriptor
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled data descriptor on success, null on error</returns>
public static DataDescriptor? ParseDataDescriptor(Stream data)
{
// TODO: Use marshalling here instead of building
var dataDescriptor = new DataDescriptor();
// Signatures are expected but not required
dataDescriptor.Signature = data.ReadUInt32();
if (dataDescriptor.Signature != DataDescriptorSignature)
data.Seek(-4, SeekOrigin.Current);
dataDescriptor.CRC32 = data.ReadUInt32();
dataDescriptor.CompressedSize = data.ReadUInt32();
dataDescriptor.UncompressedSize = data.ReadUInt32();
return dataDescriptor;
}
/// <summary>
/// Parse a Stream into a ZIP64 data descriptor
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled ZIP64 data descriptor on success, null on error</returns>
public static DataDescriptor64? ParseDataDescriptor64(Stream data)
{
// TODO: Use marshalling here instead of building
var zip64DataDescriptor = new DataDescriptor64();
// Signatures are expected but not required
zip64DataDescriptor.Signature = data.ReadUInt32();
if (zip64DataDescriptor.Signature != DataDescriptorSignature)
data.Seek(-4, SeekOrigin.Current);
zip64DataDescriptor.CRC32 = data.ReadUInt32();
zip64DataDescriptor.CompressedSize = data.ReadUInt64();
zip64DataDescriptor.UncompressedSize = data.ReadUInt64();
return zip64DataDescriptor;
}
}
}

View File

@@ -495,7 +495,7 @@ namespace SabreTools.Serialization.Deserializers
entry.Value = data.ReadUInt32();
entry.SectionNumber = data.ReadUInt16();
entry.SymbolType = (SymbolType)data.ReadUInt16();
entry.StorageClass = (StorageClass)data.ReadByte();
entry.StorageClass = (StorageClass)data.ReadByteValue();
entry.NumberOfAuxSymbols = data.ReadByteValue();
coffSymbolTable[i] = entry;
@@ -668,7 +668,7 @@ namespace SabreTools.Serialization.Deserializers
entry.CertificateType = (WindowsCertificateType)data.ReadUInt16();
int certificateDataLength = (int)(entry.Length - 8);
if (certificateDataLength > 0)
if (certificateDataLength > 0 && data.Position + certificateDataLength <= data.Length)
entry.Certificate = data.ReadBytes(certificateDataLength);
attributeCertificateTable.Add(entry);
@@ -678,7 +678,7 @@ namespace SabreTools.Serialization.Deserializers
_ = data.ReadByteValue();
}
return attributeCertificateTable.ToArray();
return [.. attributeCertificateTable];
}
/// <summary>
@@ -703,7 +703,7 @@ namespace SabreTools.Serialization.Deserializers
// TODO: Use marshalling here instead of building
var baseRelocationTable = new List<BaseRelocationBlock>();
while (data.Position < endOffset)
while (data.Position < endOffset && data.Position < data.Length)
{
var baseRelocationBlock = new BaseRelocationBlock();
@@ -724,12 +724,12 @@ namespace SabreTools.Serialization.Deserializers
totalSize += 2;
}
baseRelocationBlock.TypeOffsetFieldEntries = typeOffsetFieldEntries.ToArray();
baseRelocationBlock.TypeOffsetFieldEntries = [.. typeOffsetFieldEntries];
baseRelocationTable.Add(baseRelocationBlock);
}
return baseRelocationTable.ToArray();
return [.. baseRelocationTable];
}
/// <summary>
@@ -745,7 +745,7 @@ namespace SabreTools.Serialization.Deserializers
var debugDirectoryTable = new List<DebugDirectoryEntry>();
while (data.Position < endOffset)
while (data.Position < endOffset && data.Position < data.Length)
{
var debugDirectoryEntry = data.ReadType<DebugDirectoryEntry>();
if (debugDirectoryEntry == null)
@@ -913,7 +913,7 @@ namespace SabreTools.Serialization.Deserializers
break;
}
importTable.ImportDirectoryTable = importDirectoryTable.ToArray();
importTable.ImportDirectoryTable = [.. importDirectoryTable];
// Names
for (int i = 0; i < importTable.ImportDirectoryTable.Length; i++)
@@ -981,7 +981,7 @@ namespace SabreTools.Serialization.Deserializers
break;
}
importLookupTables[i] = entryLookupTable.ToArray();
importLookupTables[i] = [.. entryLookupTable];
}
importTable.ImportLookupTables = importLookupTables;
@@ -1035,7 +1035,7 @@ namespace SabreTools.Serialization.Deserializers
break;
}
importAddressTables[i] = addressLookupTable.ToArray();
importAddressTables[i] = [.. addressLookupTable];
}
importTable.ImportAddressTables = importAddressTables;
@@ -1047,14 +1047,13 @@ namespace SabreTools.Serialization.Deserializers
|| importTable.ImportAddressTables != null && importTable.ImportAddressTables.Count > 0)
{
// Get the addresses of the hint/name table entries
List<int> hintNameTableEntryAddresses = new List<int>();
var hintNameTableEntryAddresses = new List<int>();
// If we have import lookup tables
if (importTable.ImportLookupTables != null && importLookupTables.Count > 0)
{
var addresses = importTable.ImportLookupTables
.Where(kvp => kvp.Value != null)
.SelectMany(kvp => kvp.Value!)
.SelectMany(kvp => kvp.Value ?? [])
.Where(ilte => ilte != null)
.Select(ilte => (int)ilte!.HintNameTableRVA.ConvertVirtualAddress(sections));
hintNameTableEntryAddresses.AddRange(addresses);
@@ -1064,8 +1063,7 @@ namespace SabreTools.Serialization.Deserializers
if (importTable.ImportAddressTables != null && importTable.ImportAddressTables.Count > 0)
{
var addresses = importTable.ImportAddressTables
.Where(kvp => kvp.Value != null)
.SelectMany(kvp => kvp.Value!)
.SelectMany(kvp => kvp.Value ?? [])
.Where(iate => iate != null)
.Select(iate => (int)iate!.HintNameTableRVA.ConvertVirtualAddress(sections));
hintNameTableEntryAddresses.AddRange(addresses);
@@ -1078,7 +1076,7 @@ namespace SabreTools.Serialization.Deserializers
.ToList();
// If we have any addresses, add them to the table
if (hintNameTableEntryAddresses.Any())
if (hintNameTableEntryAddresses.Count > 0)
{
for (int i = 0; i < hintNameTableEntryAddresses.Count; i++)
{
@@ -1164,7 +1162,7 @@ namespace SabreTools.Serialization.Deserializers
var resourceDirectoryString = new ResourceDirectoryString();
resourceDirectoryString.Length = data.ReadUInt16();
if (resourceDirectoryString.Length > 0)
if (resourceDirectoryString.Length > 0 && data.Position + resourceDirectoryString.Length <= data.Length)
resourceDirectoryString.UnicodeString = data.ReadBytes(resourceDirectoryString.Length * 2);
entry.Name = resourceDirectoryString;
@@ -1194,7 +1192,7 @@ namespace SabreTools.Serialization.Deserializers
// Read the data from the offset
offset = resourceDataEntry.DataRVA.ConvertVirtualAddress(sections);
if (offset > 0 && resourceDataEntry.Size > 0)
if (offset > 0 && resourceDataEntry.Size > 0 && offset + (int)resourceDataEntry.Size < data.Length)
{
data.Seek(offset, SeekOrigin.Begin);
resourceDataEntry.Data = data.ReadBytes((int)resourceDataEntry.Size);
@@ -1246,7 +1244,7 @@ namespace SabreTools.Serialization.Deserializers
resourceDirectoryTable.Entries[totalEntryCount] = new ResourceDirectoryEntry
{
Name = new ResourceDirectoryString { UnicodeString = Encoding.ASCII.GetBytes("HIDDEN RESOURCE") },
Name = new ResourceDirectoryString { UnicodeString = Encoding.Unicode.GetBytes("HIDDEN RESOURCE") },
IntegerID = uint.MaxValue,
DataEntryOffset = (uint)data.Position,
DataEntry = new ResourceDataEntry

View File

@@ -1,6 +1,5 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using SabreTools.IO.Readers;
using SabreTools.Models.RomCenter;
@@ -25,11 +24,6 @@ namespace SabreTools.Serialization.Deserializers
// Loop through and parse out the values
var roms = new List<Rom>();
var additional = new List<string>();
var creditsAdditional = new List<string>();
var datAdditional = new List<string>();
var emulatorAdditional = new List<string>();
var gamesAdditional = new List<string>();
while (!reader.EndOfStream)
{
// If we have no next line
@@ -57,10 +51,6 @@ namespace SabreTools.Serialization.Deserializers
case "games":
dat.Games ??= new Games();
break;
default:
if (reader.CurrentLine != null)
additional.Add(reader.CurrentLine);
break;
}
continue;
}
@@ -94,10 +84,6 @@ namespace SabreTools.Serialization.Deserializers
case "comment":
dat.Credits.Comment = reader.KeyValuePair?.Value;
break;
default:
if (reader.CurrentLine != null)
creditsAdditional.Add(reader.CurrentLine);
break;
}
}
@@ -121,10 +107,6 @@ namespace SabreTools.Serialization.Deserializers
case "merge":
dat.Dat.Merge = reader.KeyValuePair?.Value;
break;
default:
if (reader.CurrentLine != null)
datAdditional.Add(reader.CurrentLine);
break;
}
}
@@ -142,10 +124,6 @@ namespace SabreTools.Serialization.Deserializers
case "version":
dat.Emulator.Version = reader.KeyValuePair?.Value;
break;
default:
if (reader.CurrentLine != null)
emulatorAdditional.Add(reader.CurrentLine);
break;
}
}
@@ -156,13 +134,12 @@ namespace SabreTools.Serialization.Deserializers
dat.Games ??= new Games();
// If the line doesn't contain the delimiter
#if NETFRAMEWORK
if (!(reader.CurrentLine?.Contains("¬") ?? false))
#else
if (!(reader.CurrentLine?.Contains('¬') ?? false))
{
if (reader.CurrentLine != null)
gamesAdditional.Add(reader.CurrentLine);
#endif
continue;
}
// Otherwise, separate out the line
string[] splitLine = reader.CurrentLine.Split('¬');
@@ -181,32 +158,14 @@ namespace SabreTools.Serialization.Deserializers
// EMPTY = splitLine[10]
};
if (splitLine.Length > 11)
rom.ADDITIONAL_ELEMENTS = splitLine.Skip(11).ToArray();
roms.Add(rom);
}
else
{
if (reader.CurrentLine != null)
additional.Add(reader.CurrentLine);
}
}
// Add extra pieces and return
dat.ADDITIONAL_ELEMENTS = additional.Where(s => s != null).ToArray();
if (dat.Credits != null)
dat.Credits.ADDITIONAL_ELEMENTS = creditsAdditional.Where(s => s != null).ToArray();
if (dat.Dat != null)
dat.Dat.ADDITIONAL_ELEMENTS = datAdditional.Where(s => s != null).ToArray();
if (dat.Emulator != null)
dat.Emulator.ADDITIONAL_ELEMENTS = emulatorAdditional.Where(s => s != null).ToArray();
if (dat.Games != null)
{
dat.Games.Rom = roms.ToArray();
dat.Games.ADDITIONAL_ELEMENTS = gamesAdditional.Where(s => s != null).Select(s => s).ToArray();
}
dat.Games.Rom = [.. roms];
return dat;
}
}

View File

@@ -1,6 +1,5 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using SabreTools.IO.Readers;
using SabreTools.Models.SeparatedValue;
@@ -104,7 +103,7 @@ namespace SabreTools.Serialization.Deserializers
if (!reader.ReadHeader() || reader.HeaderValues == null)
return null;
dat.Header = reader.HeaderValues.ToArray();
dat.Header = [.. reader.HeaderValues];
// Loop through the rows and parse out values
var rows = new List<Row>();
@@ -135,10 +134,6 @@ namespace SabreTools.Serialization.Deserializers
SHA256 = reader.Line[12],
Status = reader.Line[13],
};
// If we have additional fields
if (reader.Line.Count > HeaderWithoutExtendedHashesCount)
row.ADDITIONAL_ELEMENTS = reader.Line.Skip(HeaderWithoutExtendedHashesCount).ToArray();
}
else
{
@@ -162,16 +157,12 @@ namespace SabreTools.Serialization.Deserializers
SpamSum = reader.Line[15],
Status = reader.Line[16],
};
// If we have additional fields
if (reader.Line.Count > HeaderWithExtendedHashesCount)
row.ADDITIONAL_ELEMENTS = reader.Line.Skip(HeaderWithExtendedHashesCount).ToArray();
}
rows.Add(row);
}
// Assign the rows to the Dat and return
dat.Row = rows.ToArray();
dat.Row = [.. rows];
return dat;
}

View File

@@ -67,7 +67,10 @@ namespace SabreTools.Serialization.Deserializers
#region Archive Hashes
if (header?.Version == 2 && file.ExtendedHeader != null && file.ExtendedHeader.ArchiveHashLength > 0)
if (header?.Version == 2
&& file.ExtendedHeader != null
&& file.ExtendedHeader.ArchiveHashLength > 0
&& data.Position + file.ExtendedHeader.ArchiveHashLength <= data.Length)
{
// Create the archive hashes list
var archiveHashes = new List<ArchiveHash>();
@@ -192,7 +195,7 @@ namespace SabreTools.Serialization.Deserializers
}
}
return directoryItems.ToArray();
return [.. directoryItems];
}
/// <summary>
@@ -218,7 +221,9 @@ namespace SabreTools.Serialization.Deserializers
// Get the preload data pointer
long preloadDataPointer = -1; int preloadDataLength = -1;
if (directoryEntry.ArchiveIndex == HL_VPK_NO_ARCHIVE && directoryEntry.EntryLength > 0)
if (directoryEntry.ArchiveIndex == HL_VPK_NO_ARCHIVE
&& directoryEntry.EntryLength > 0
&& data.Position + directoryEntry.EntryLength <= data.Length)
{
preloadDataPointer = directoryEntry.EntryOffset;
preloadDataLength = (int)directoryEntry.EntryLength;
@@ -231,7 +236,9 @@ namespace SabreTools.Serialization.Deserializers
// If we had a valid preload data pointer
byte[]? preloadData = null;
if (preloadDataPointer >= 0 && preloadDataLength > 0)
if (preloadDataPointer >= 0
&& preloadDataLength > 0
&& data.Position + preloadDataLength <= data.Length)
{
// Cache the current offset
long initialOffset = data.Position;

View File

@@ -184,7 +184,7 @@ namespace SabreTools.Serialization.Deserializers
private static DirectoryItem ParseDirectoryItem(Stream data)
{
// TODO: Use marshalling here instead of building
DirectoryItem directoryItem = new DirectoryItem();
var directoryItem = new DirectoryItem();
directoryItem.FileNameCRC = data.ReadUInt32();
directoryItem.NameOffset = data.ReadUInt32();

View File

@@ -9,13 +9,8 @@ namespace SabreTools.Serialization
/// </summary>
/// <param name="entry">Resource type information entry to check</param>
/// <returns>True if the entry is an integer type, false if an offset, null on error</returns>
public static bool? IsIntegerType(this ResourceTypeInformationEntry entry)
public static bool IsIntegerType(this ResourceTypeInformationEntry entry)
{
// We can't do anything with an invalid entry
if (entry == null)
return null;
// If the highest order bit is set, it's an integer type
return (entry.TypeID & 0x8000) != 0;
}
@@ -24,13 +19,8 @@ namespace SabreTools.Serialization
/// </summary>
/// <param name="entry">Resource type resource entry to check</param>
/// <returns>True if the entry is an integer type, false if an offset, null on error</returns>
public static bool? IsIntegerType(this ResourceTypeResourceEntry entry)
public static bool IsIntegerType(this ResourceTypeResourceEntry entry)
{
// We can't do anything with an invalid entry
if (entry == null)
return null;
// If the highest order bit is set, it's an integer type
return (entry.ResourceID & 0x8000) != 0;
}
@@ -41,10 +31,6 @@ namespace SabreTools.Serialization
/// <returns>SegmentEntryType corresponding to the type</returns>
public static SegmentEntryType GetEntryType(this EntryTableBundle entry)
{
// We can't do anything with an invalid entry
if (entry == null)
return SegmentEntryType.Unused;
// Determine the entry type based on segment indicator
if (entry.SegmentIndicator == 0x00)
return SegmentEntryType.Unused;

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using SabreTools.IO.Extensions;
@@ -28,7 +27,7 @@ namespace SabreTools.Serialization
return 0;
// If the RVA matches a section start exactly, use that
var matchingSection = sections.FirstOrDefault(s => s != null && s.VirtualAddress == rva);
var matchingSection = Array.Find(sections, s => s != null && s.VirtualAddress == rva);
if (matchingSection != null)
return rva - matchingSection.VirtualAddress + matchingSection.PointerToRawData;
@@ -127,6 +126,15 @@ namespace SabreTools.Serialization
if (rsdsProgramDatabase.Signature != 0x53445352)
return null;
#if NET20 || NET35 || NET40 || NET452 || NET462
// Convert ASCII string to UTF-8
if (rsdsProgramDatabase.PathAndFileName != null)
{
byte[] bytes = Encoding.ASCII.GetBytes(rsdsProgramDatabase.PathAndFileName);
rsdsProgramDatabase.PathAndFileName = Encoding.UTF8.GetString(bytes);
}
#endif
return rsdsProgramDatabase;
}
@@ -156,7 +164,9 @@ namespace SabreTools.Serialization
if (string.IsNullOrEmpty(addD.Version))
offset = originalOffset + 0x10;
addD.Build = data.ReadBytes(ref offset, 4)?.Select(b => (char)b)?.ToArray();
var buildBytes = data.ReadBytes(ref offset, 4);
var buildChars = Array.ConvertAll(buildBytes, b => (char)b);
addD.Build = buildChars;
// Distinguish between v1 and v2
int bytesToRead = 112; // v2
@@ -595,7 +605,11 @@ namespace SabreTools.Serialization
#region Class resource
currentOffset = offset;
ushort classResourceIdentifier = entry.Data.ReadUInt16(ref offset);
ushort classResourceIdentifier;
if (offset >= entry.Data.Length)
classResourceIdentifier = 0x0000;
else
classResourceIdentifier = entry.Data.ReadUInt16(ref offset);
offset = currentOffset;
// 0x0000 means no elements
@@ -631,7 +645,11 @@ namespace SabreTools.Serialization
#region Title resource
currentOffset = offset;
ushort titleResourceIdentifier = entry.Data.ReadUInt16(ref offset);
ushort titleResourceIdentifier;
if (offset >= entry.Data.Length)
titleResourceIdentifier = 0x0000;
else
titleResourceIdentifier = entry.Data.ReadUInt16(ref offset);
offset = currentOffset;
// 0x0000 means no elements
@@ -891,7 +909,7 @@ namespace SabreTools.Serialization
if (menuHeaderExtended == null)
return null;
menuResource.ExtendedMenuHeader = menuHeaderExtended;
menuResource.MenuHeader = menuHeaderExtended;
#endregion
@@ -920,7 +938,7 @@ namespace SabreTools.Serialization
}
}
menuResource.ExtendedMenuItems = [.. extendedMenuItems];
menuResource.MenuItems = [.. extendedMenuItems];
#endregion
}
@@ -928,7 +946,7 @@ namespace SabreTools.Serialization
{
#region Menu header
var menuHeader = entry.Data.ReadType<MenuHeader>(ref offset);
var menuHeader = entry.Data.ReadType<NormalMenuHeader>(ref offset);
if (menuHeader == null)
return null;
@@ -1067,21 +1085,9 @@ namespace SabreTools.Serialization
// Loop through and add
while (offset < entry.Data.Length)
{
ushort stringLength = entry.Data.ReadUInt16(ref offset);
if (stringLength == 0)
string? stringValue = entry.Data.ReadPrefixedUnicodeString(ref offset);
if (stringValue != null)
{
stringTable[stringIndex++] = "[EMPTY]";
}
else
{
if (stringLength * 2 > entry.Data.Length - offset)
{
Console.WriteLine($"{stringLength * 2} requested but {entry.Data.Length - offset} remains");
stringLength = (ushort)((entry.Data.Length - offset) / 2);
}
string stringValue = Encoding.Unicode.GetString(entry.Data, offset, stringLength * 2);
offset += stringLength * 2;
stringValue = stringValue.Replace("\n", "\\n").Replace("\r", newValue: "\\r");
stringTable[stringIndex++] = stringValue;
}
@@ -1118,7 +1124,7 @@ namespace SabreTools.Serialization
versionInfo.Padding1 = entry.Data.ReadUInt16(ref offset);
// Read fixed file info
if (versionInfo.ValueLength > 0)
if (versionInfo.ValueLength > 0 && offset + versionInfo.ValueLength <= entry.Data.Length)
{
var fixedFileInfo = entry.Data.ReadType<FixedFileInfo>(ref offset);

View File

@@ -0,0 +1,18 @@
using System.Text;
namespace SabreTools.Serialization.Interfaces
{
/// <summary>
/// Marks a class as a printer associated with a model
/// </summary>
/// <typeparam name="TModel">Type of the top-level model</typeparam>
public interface IPrinter<TModel>
{
/// <summary>
/// Print information associated with a model
/// </summary>
/// <param name="builder">StringBuilder to append information to</param>
/// <param name="model">Model to print</param>
void PrintInformation(StringBuilder builder, TModel model);
}
}

View File

@@ -11,7 +11,7 @@ namespace SabreTools.Serialization
/// </summary>
/// <param name="path">Path to open as a stream</param>
/// <returns>Stream representing the file, null on error</returns>
public static Stream? OpenStream(string? path)
public static Stream? OpenStream(string? path, bool skipCompression = false)
{
try
{
@@ -26,11 +26,11 @@ namespace SabreTools.Serialization
string ext = Path.GetExtension(path).TrimStart('.');
// Determine what we do based on the extension
if (string.Equals(ext, "gz", StringComparison.OrdinalIgnoreCase))
if (!skipCompression && string.Equals(ext, "gz", StringComparison.OrdinalIgnoreCase))
{
return new GZipStream(stream, CompressionMode.Decompress);
}
else if (string.Equals(ext, "zip", StringComparison.OrdinalIgnoreCase))
else if (!skipCompression && string.Equals(ext, "zip", StringComparison.OrdinalIgnoreCase))
{
// TODO: Support zip-compressed files
return null;

View File

@@ -0,0 +1,454 @@
using System;
using System.Text;
using SabreTools.Serialization.Interfaces;
using SabreTools.Serialization.Printers;
using Wrapper = SabreTools.Serialization.Wrappers;
namespace SabreTools.Serialization
{
/// <summary>
/// Generic wrapper around printing methods
/// </summary>
public static class Printer
{
/// <summary>
/// Print the item information from a wrapper to console as
/// pretty-printed text
/// </summary>
public static void PrintToConsole(this IWrapper wrapper)
{
var sb = wrapper.ExportStringBuilder();
if (sb == null)
{
Console.WriteLine("No item information could be generated");
return;
}
Console.WriteLine(sb.ToString());
}
/// <summary>
/// Export the item information as a StringBuilder
/// </summary>
public static StringBuilder? ExportStringBuilder(this IWrapper wrapper)
{
return wrapper switch
{
Wrapper.AACSMediaKeyBlock item => item.PrettyPrint(),
Wrapper.BDPlusSVM item => item.PrettyPrint(),
Wrapper.BFPK item => item.PrettyPrint(),
Wrapper.BSP item => item.PrettyPrint(),
Wrapper.CFB item => item.PrettyPrint(),
Wrapper.CHD item => item.PrettyPrint(),
Wrapper.CIA item => item.PrettyPrint(),
Wrapper.GCF item => item.PrettyPrint(),
Wrapper.InstallShieldCabinet item => item.PrettyPrint(),
Wrapper.IRD item => item.PrettyPrint(),
Wrapper.LinearExecutable item => item.PrettyPrint(),
Wrapper.MicrosoftCabinet item => item.PrettyPrint(),
Wrapper.MoPaQ item => item.PrettyPrint(),
Wrapper.MSDOS item => item.PrettyPrint(),
Wrapper.N3DS item => item.PrettyPrint(),
Wrapper.NCF item => item.PrettyPrint(),
Wrapper.NewExecutable item => item.PrettyPrint(),
Wrapper.Nitro item => item.PrettyPrint(),
Wrapper.PAK item => item.PrettyPrint(),
Wrapper.PFF item => item.PrettyPrint(),
Wrapper.PIC item => item.PrettyPrint(),
Wrapper.PKZIP item => item.PrettyPrint(),
Wrapper.PlayJAudioFile item => item.PrettyPrint(),
Wrapper.PlayJPlaylist item => item.PrettyPrint(),
Wrapper.PortableExecutable item => item.PrettyPrint(),
Wrapper.Quantum item => item.PrettyPrint(),
Wrapper.SGA item => item.PrettyPrint(),
Wrapper.VBSP item => item.PrettyPrint(),
Wrapper.VPK item => item.PrettyPrint(),
Wrapper.WAD item => item.PrettyPrint(),
Wrapper.XeMID item => item.PrettyPrint(),
Wrapper.XMID item => item.PrettyPrint(),
Wrapper.XZP item => item.PrettyPrint(),
_ => null,
};
}
#if NET6_0_OR_GREATER
/// <summary>
/// Export the item information as JSON
/// </summary>
public static string ExportJSON(this IWrapper wrapper)
{
return wrapper switch
{
Wrapper.AACSMediaKeyBlock item => item.ExportJSON(),
Wrapper.BDPlusSVM item => item.ExportJSON(),
Wrapper.BFPK item => item.ExportJSON(),
Wrapper.BSP item => item.ExportJSON(),
Wrapper.CFB item => item.ExportJSON(),
Wrapper.CHD item => item.ExportJSON(),
Wrapper.CIA item => item.ExportJSON(),
Wrapper.GCF item => item.ExportJSON(),
Wrapper.InstallShieldCabinet item => item.ExportJSON(),
Wrapper.IRD item => item.ExportJSON(),
Wrapper.LinearExecutable item => item.ExportJSON(),
Wrapper.MicrosoftCabinet item => item.ExportJSON(),
Wrapper.MoPaQ item => item.ExportJSON(),
Wrapper.MSDOS item => item.ExportJSON(),
Wrapper.N3DS item => item.ExportJSON(),
Wrapper.NCF item => item.ExportJSON(),
Wrapper.NewExecutable item => item.ExportJSON(),
Wrapper.Nitro item => item.ExportJSON(),
Wrapper.PAK item => item.ExportJSON(),
Wrapper.PFF item => item.ExportJSON(),
Wrapper.PIC item => item.ExportJSON(),
Wrapper.PKZIP item => item.ExportJSON(),
Wrapper.PlayJAudioFile item => item.ExportJSON(),
Wrapper.PlayJPlaylist item => item.ExportJSON(),
Wrapper.PortableExecutable item => item.ExportJSON(),
Wrapper.Quantum item => item.ExportJSON(),
Wrapper.SGA item => item.ExportJSON(),
Wrapper.VBSP item => item.ExportJSON(),
Wrapper.VPK item => item.ExportJSON(),
Wrapper.WAD item => item.ExportJSON(),
Wrapper.XeMID item => item.ExportJSON(),
Wrapper.XMID item => item.ExportJSON(),
Wrapper.XZP item => item.ExportJSON(),
_ => string.Empty,
};
}
#endif
#region Static Printing Implementations
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.AACSMediaKeyBlock item)
{
var builder = new StringBuilder();
AACSMediaKeyBlock.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.BDPlusSVM item)
{
var builder = new StringBuilder();
BDPlusSVM.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.BFPK item)
{
var builder = new StringBuilder();
BFPK.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.BSP item)
{
var builder = new StringBuilder();
BSP.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.CFB item)
{
var builder = new StringBuilder();
CFB.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.CHD item)
{
var builder = new StringBuilder();
CHD.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.CIA item)
{
var builder = new StringBuilder();
CIA.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.GCF item)
{
var builder = new StringBuilder();
GCF.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.InstallShieldCabinet item)
{
var builder = new StringBuilder();
InstallShieldCabinet.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.IRD item)
{
var builder = new StringBuilder();
IRD.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.LinearExecutable item)
{
var builder = new StringBuilder();
LinearExecutable.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.MicrosoftCabinet item)
{
var builder = new StringBuilder();
MicrosoftCabinet.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.MoPaQ item)
{
var builder = new StringBuilder();
MoPaQ.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.MSDOS item)
{
var builder = new StringBuilder();
MSDOS.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.N3DS item)
{
var builder = new StringBuilder();
N3DS.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.NCF item)
{
var builder = new StringBuilder();
NCF.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.NewExecutable item)
{
var builder = new StringBuilder();
NewExecutable.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.Nitro item)
{
var builder = new StringBuilder();
Nitro.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.PAK item)
{
var builder = new StringBuilder();
PAK.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.PFF item)
{
var builder = new StringBuilder();
PFF.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.PIC item)
{
var builder = new StringBuilder();
PIC.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.PKZIP item)
{
var builder = new StringBuilder();
PKZIP.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.PlayJAudioFile item)
{
var builder = new StringBuilder();
PlayJAudioFile.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.PlayJPlaylist item)
{
var builder = new StringBuilder();
PlayJPlaylist.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.PortableExecutable item)
{
var builder = new StringBuilder();
PortableExecutable.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.Quantum item)
{
var builder = new StringBuilder();
Quantum.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.SGA item)
{
var builder = new StringBuilder();
SGA.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.VBSP item)
{
var builder = new StringBuilder();
VBSP.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.VPK item)
{
var builder = new StringBuilder();
VPK.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.WAD item)
{
var builder = new StringBuilder();
WAD.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.XeMID item)
{
var builder = new StringBuilder();
XeMID.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.XMID item)
{
var builder = new StringBuilder();
XMID.Print(builder, item.Model);
return builder;
}
/// <summary>
/// Export the item information as pretty-printed text
/// </summary>
private static StringBuilder PrettyPrint(this Wrapper.XZP item)
{
var builder = new StringBuilder();
XZP.Print(builder, item.Model);
return builder;
}
#endregion
}
}

View File

@@ -0,0 +1,290 @@
using System.Text;
using SabreTools.Models.AACS;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class AACSMediaKeyBlock : IPrinter<MediaKeyBlock>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, MediaKeyBlock model)
=> Print(builder, model);
public static void Print(StringBuilder builder, MediaKeyBlock mediaKeyBlock)
{
builder.AppendLine("AACS Media Key Block Information:");
builder.AppendLine("-------------------------");
builder.AppendLine();
Print(builder, mediaKeyBlock.Records);
}
private static void Print(StringBuilder builder, Record?[]? records)
{
builder.AppendLine(" Records Information:");
builder.AppendLine(" -------------------------");
if (records == null || records.Length == 0)
{
builder.AppendLine(" No records");
builder.AppendLine();
return;
}
for (int i = 0; i < records.Length; i++)
{
var record = records[i];
Print(builder, record, i);
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, Record? record, int index)
{
builder.AppendLine($" Record Entry {index}");
if (record == null)
{
builder.AppendLine(" [NULL]");
return;
}
builder.AppendLine($" Record type: {record.RecordType} (0x{record.RecordType:X})");
builder.AppendLine(record.RecordLength, " Record length");
switch (record)
{
case EndOfMediaKeyBlockRecord eomkb:
Print(builder, eomkb);
break;
case ExplicitSubsetDifferenceRecord esd:
Print(builder, esd);
break;
case MediaKeyDataRecord mkd:
Print(builder, mkd);
break;
case SubsetDifferenceIndexRecord sdi:
Print(builder, sdi);
break;
case TypeAndVersionRecord tav:
Print(builder, tav);
break;
case DriveRevocationListRecord drl:
Print(builder, drl);
break;
case HostRevocationListRecord hrl:
Print(builder, hrl);
break;
case VerifyMediaKeyRecord vmk:
Print(builder, vmk);
break;
case CopyrightRecord c:
Print(builder, c);
break;
}
}
private static void Print(StringBuilder builder, EndOfMediaKeyBlockRecord record)
{
if (record == null)
return;
builder.AppendLine(record.SignatureData, " Signature data");
}
private static void Print(StringBuilder builder, ExplicitSubsetDifferenceRecord? record)
{
if (record == null)
return;
builder.AppendLine(" Subset Differences:");
builder.AppendLine(" -------------------------");
if (record?.SubsetDifferences == null || record.SubsetDifferences.Length == 0)
{
builder.AppendLine(" No subset differences");
return;
}
for (int j = 0; j < record.SubsetDifferences.Length; j++)
{
var sd = record.SubsetDifferences[j];
builder.AppendLine($" Subset Difference {j}");
if (sd == null)
{
builder.AppendLine(" [NULL]");
}
else
{
builder.AppendLine(sd.Mask, " Mask");
builder.AppendLine(sd.Number, " Number");
}
}
}
private static void Print(StringBuilder builder, MediaKeyDataRecord? record)
{
if (record == null)
return;
builder.AppendLine(" Media Keys:");
builder.AppendLine(" -------------------------");
if (record?.MediaKeyData == null || record.MediaKeyData.Length == 0)
{
builder.AppendLine(" No media keys");
return;
}
for (int j = 0; j < record.MediaKeyData.Length; j++)
{
var mk = record.MediaKeyData[j];
builder.AppendLine(mk, $" Media key {j}");
}
}
private static void Print(StringBuilder builder, SubsetDifferenceIndexRecord? record)
{
if (record == null)
return;
builder.AppendLine($" Span: {record.Span} (0x{record.Span:X})");
builder.AppendLine(" Offsets:");
builder.AppendLine(" -------------------------");
if (record.Offsets == null || record.Offsets.Length == 0)
{
builder.AppendLine(" No offsets");
return;
}
for (int j = 0; j < record.Offsets.Length; j++)
{
var offset = record.Offsets[j];
builder.AppendLine(offset, $" Offset {j}");
}
}
private static void Print(StringBuilder builder, TypeAndVersionRecord? record)
{
if (record == null)
return;
builder.AppendLine($" Media key block type: {record.MediaKeyBlockType} (0x{record.MediaKeyBlockType:X})");
builder.AppendLine(record.VersionNumber, " Version number");
}
private static void Print(StringBuilder builder, DriveRevocationListRecord? record)
{
if (record == null)
return;
builder.AppendLine(record.TotalNumberOfEntries, " Total number of entries");
builder.AppendLine(" Signature Blocks:");
builder.AppendLine(" -------------------------");
if (record.SignatureBlocks == null || record.SignatureBlocks.Length == 0)
{
builder.AppendLine(" No signature blocks");
return;
}
for (int j = 0; j < record.SignatureBlocks.Length; j++)
{
var block = record.SignatureBlocks[j];
builder.AppendLine($" Signature Block {j}");
if (block == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(block.NumberOfEntries, " Number of entries");
builder.AppendLine(" Entry Fields:");
builder.AppendLine(" -------------------------");
if (block.EntryFields == null || block.EntryFields.Length == 0)
{
builder.AppendLine(" No entry fields");
}
else
{
for (int k = 0; k < block.EntryFields.Length; k++)
{
var ef = block.EntryFields[k];
builder.AppendLine($" Entry {k}");
if (ef == null)
{
builder.AppendLine(" [NULL]");
}
else
{
builder.AppendLine(ef.Range, " Range");
builder.AppendLine(ef.DriveID, " Drive ID");
}
}
}
}
}
private static void Print(StringBuilder builder, HostRevocationListRecord? record)
{
if (record == null)
return;
builder.AppendLine($" Total number of entries: {record.TotalNumberOfEntries} (0x{record.TotalNumberOfEntries:X})");
builder.AppendLine(" Signature Blocks:");
builder.AppendLine(" -------------------------");
if (record.SignatureBlocks == null || record.SignatureBlocks.Length == 0)
{
builder.AppendLine(" No signature blocks");
return;
}
for (int j = 0; j < record.SignatureBlocks.Length; j++)
{
builder.AppendLine($" Signature Block {j}");
var block = record.SignatureBlocks[j];
if (block == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(block.NumberOfEntries, " Number of entries");
builder.AppendLine(" Entry Fields:");
builder.AppendLine(" -------------------------");
if (block.EntryFields == null || block.EntryFields.Length == 0)
{
builder.AppendLine(" No entry fields");
continue;
}
for (int k = 0; k < block.EntryFields.Length; k++)
{
var ef = block.EntryFields[k];
builder.AppendLine($" Entry {k}");
if (ef == null)
{
builder.AppendLine(" [NULL]");
}
else
{
builder.AppendLine(ef.Range, " Range");
builder.AppendLine(ef.HostID, " Host ID");
}
}
}
}
private static void Print(StringBuilder builder, VerifyMediaKeyRecord? record)
{
if (record == null)
return;
builder.AppendLine(record.CiphertextValue, " Ciphertext value");
}
private static void Print(StringBuilder builder, CopyrightRecord? record)
{
if (record == null)
return;
builder.AppendLine(record.Copyright, " Copyright");
}
}
}

View File

@@ -0,0 +1,28 @@
using System.Text;
using SabreTools.Models.BDPlus;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class BDPlusSVM : IPrinter<SVM>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, SVM model)
=> Print(builder, model);
public static void Print(StringBuilder builder, SVM svm)
{
builder.AppendLine("BD+ SVM Information:");
builder.AppendLine("-------------------------");
builder.AppendLine(svm.Signature, "Signature");
builder.AppendLine(svm.Unknown1, "Unknown 1");
builder.AppendLine(svm.Year, "Year");
builder.AppendLine(svm.Month, "Month");
builder.AppendLine(svm.Day, "Day");
builder.AppendLine(svm.Unknown2, "Unknown 2");
builder.AppendLine(svm.Length, "Length");
//builder.AppendLine(svm.Data, "Data");
builder.AppendLine();
}
}
}

View File

@@ -0,0 +1,68 @@
using System.Text;
using SabreTools.Models.BFPK;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class BFPK : IPrinter<Archive>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, Archive model)
=> Print(builder, model);
public static void Print(StringBuilder builder, Archive archive)
{
builder.AppendLine("BFPK Information:");
builder.AppendLine("-------------------------");
builder.AppendLine();
Print(builder, archive.Header);
Print(builder, archive.Files);
}
private static void Print(StringBuilder builder, Header? header)
{
builder.AppendLine(" Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Magic, " Magic");
builder.AppendLine(header.Version, " Version");
builder.AppendLine(header.Files, " Files");
builder.AppendLine();
}
private static void Print(StringBuilder builder, FileEntry?[]? files)
{
builder.AppendLine(" File Table Information:");
builder.AppendLine(" -------------------------");
if (files == null || files.Length == 0)
{
builder.AppendLine(" No file table items");
return;
}
for (int i = 0; i < files.Length; i++)
{
var entry = files[i];
builder.AppendLine($" File Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.NameSize, " Name size");
builder.AppendLine(entry.Name, " Name");
builder.AppendLine(entry.UncompressedSize, " Uncompressed size");
builder.AppendLine(entry.Offset, " Offset");
builder.AppendLine(entry.CompressedSize, " Compressed size");
}
}
}
}

View File

@@ -0,0 +1,150 @@
using System.Text;
using SabreTools.Models.BSP;
using SabreTools.Serialization.Interfaces;
using static SabreTools.Models.BSP.Constants;
namespace SabreTools.Serialization.Printers
{
public class BSP : IPrinter<File>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, File model)
=> Print(builder, model);
public static void Print(StringBuilder builder, File file)
{
builder.AppendLine("BSP Information:");
builder.AppendLine("-------------------------");
builder.AppendLine();
Print(builder, file.Header);
Print(builder, file.Lumps);
Print(builder, file.TextureHeader);
Print(builder, file.Textures);
}
private static void Print(StringBuilder builder, Header? header)
{
builder.AppendLine(" Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Version, " Version");
builder.AppendLine();
}
private static void Print(StringBuilder builder, Lump?[]? lumps)
{
builder.AppendLine(" Lumps Information:");
builder.AppendLine(" -------------------------");
if (lumps == null || lumps.Length == 0)
{
builder.AppendLine(" No lumps");
builder.AppendLine();
return;
}
for (int i = 0; i < lumps.Length; i++)
{
var lump = lumps[i];
string specialLumpName = string.Empty;
switch (i)
{
case HL_BSP_LUMP_ENTITIES:
specialLumpName = " (entities)";
break;
case HL_BSP_LUMP_TEXTUREDATA:
specialLumpName = " (texture data)";
break;
}
builder.AppendLine($" Lump {i}{specialLumpName}");
if (lump == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(lump.Offset, " Offset");
builder.AppendLine(lump.Length, " Length");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, TextureHeader? header)
{
builder.AppendLine(" Texture Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No texture header");
builder.AppendLine();
return;
}
builder.AppendLine(header.TextureCount, " Texture count");
builder.AppendLine(" Offsets:");
if (header.Offsets == null || header.Offsets.Length == 0)
{
builder.AppendLine(" No offsets");
builder.AppendLine();
return;
}
for (int i = 0; i < header.Offsets.Length; i++)
{
builder.AppendLine(header.Offsets[i], $" Offset {i}");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, Texture?[]? textures)
{
builder.AppendLine(" Textures Information:");
builder.AppendLine(" -------------------------");
if (textures == null || textures.Length == 0)
{
builder.AppendLine(" No textures");
builder.AppendLine();
return;
}
for (int i = 0; i < textures.Length; i++)
{
var texture = textures[i];
builder.AppendLine($" Texture {i}");
if (texture == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(texture.Name, " Name");
builder.AppendLine(texture.Width, " Width");
builder.AppendLine(texture.Height, " Height");
builder.AppendLine(" Offsets:");
if (texture.Offsets == null || texture.Offsets.Length == 0)
{
builder.AppendLine(" No offsets");
continue;
}
else
{
for (int j = 0; j < texture.Offsets.Length; j++)
{
builder.AppendLine(texture.Offsets[i], $" Offset {j}");
}
}
// Skip texture data
builder.AppendLine(texture.PaletteSize, " Palette size");
// Skip palette data
}
builder.AppendLine();
}
}
}

View File

@@ -0,0 +1,125 @@
using System;
using System.Text;
using SabreTools.Models.CFB;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class CFB : IPrinter<Binary>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, Binary model)
=> Print(builder, model);
public static void Print(StringBuilder builder, Binary binary)
{
builder.AppendLine("Compound File Binary Information:");
builder.AppendLine("-------------------------");
builder.AppendLine();
Print(builder, binary.Header);
Print(builder, binary.FATSectorNumbers, "FAT");
Print(builder, binary.MiniFATSectorNumbers, "Mini FAT");
Print(builder, binary.DIFATSectorNumbers, "DIFAT");
Print(builder, binary.DirectoryEntries);
}
private static void Print(StringBuilder builder, FileHeader? header)
{
builder.AppendLine(" File Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No file header");
return;
}
builder.AppendLine(header.Signature, " Signature");
builder.AppendLine(header.CLSID, " CLSID");
builder.AppendLine(header.MinorVersion, " Minor version");
builder.AppendLine(header.MajorVersion, " Major version");
builder.AppendLine(header.ByteOrder, " Byte order");
builder.AppendLine($" Sector shift: {header.SectorShift} (0x{header.SectorShift:X}) => {Math.Pow(2, header.SectorShift)}");
builder.AppendLine($" Mini sector shift: {header.MiniSectorShift} (0x{header.MiniSectorShift:X}) => {Math.Pow(2, header.MiniSectorShift)}");
builder.AppendLine(header.Reserved, " Reserved");
builder.AppendLine(header.NumberOfDirectorySectors, " Number of directory sectors");
builder.AppendLine(header.NumberOfFATSectors, " Number of FAT sectors");
builder.AppendLine(header.FirstDirectorySectorLocation, " First directory sector location");
builder.AppendLine(header.TransactionSignatureNumber, " Transaction signature number");
builder.AppendLine(header.MiniStreamCutoffSize, " Mini stream cutoff size");
builder.AppendLine(header.FirstMiniFATSectorLocation, " First mini FAT sector location");
builder.AppendLine(header.NumberOfMiniFATSectors, " Number of mini FAT sectors");
builder.AppendLine(header.FirstDIFATSectorLocation, " First DIFAT sector location");
builder.AppendLine(header.NumberOfDIFATSectors, " Number of DIFAT sectors");
builder.AppendLine(" DIFAT:");
if (header.DIFAT == null || header.DIFAT.Length == 0)
{
builder.AppendLine(" No DIFAT entries");
builder.AppendLine();
return;
}
for (int i = 0; i < header.DIFAT.Length; i++)
{
builder.AppendLine($" DIFAT Entry {i}: {header.DIFAT[i]} (0x{header.DIFAT[i]:X})");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, SectorNumber[]? sectorNumbers, string name)
{
builder.AppendLine($" {name} Sectors Information:");
builder.AppendLine(" -------------------------");
if (sectorNumbers == null || sectorNumbers.Length == 0)
{
builder.AppendLine($" No {name} sectors");
builder.AppendLine();
return;
}
for (int i = 0; i < sectorNumbers.Length; i++)
{
builder.AppendLine($" {name} Sector Entry {i}: {sectorNumbers[i]} (0x{sectorNumbers[i]:X})");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, DirectoryEntry?[]? directoryEntries)
{
builder.AppendLine(" Directory Entries Information:");
builder.AppendLine(" -------------------------");
if (directoryEntries == null || directoryEntries.Length == 0)
{
builder.AppendLine(" No directory entries");
builder.AppendLine();
return;
}
for (int i = 0; i < directoryEntries.Length; i++)
{
var directoryEntry = directoryEntries[i];
builder.AppendLine($" Directory Entry {i}");
if (directoryEntry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(directoryEntry.Name, " Name");
builder.AppendLine(directoryEntry.NameLength, " Name length");
builder.AppendLine($" Object type: {directoryEntry.ObjectType} (0x{directoryEntry.ObjectType:X})");
builder.AppendLine($" Color flag: {directoryEntry.ColorFlag} (0x{directoryEntry.ColorFlag:X})");
builder.AppendLine($" Left sibling ID: {directoryEntry.LeftSiblingID} (0x{directoryEntry.LeftSiblingID:X})");
builder.AppendLine($" Right sibling ID: {directoryEntry.RightSiblingID} (0x{directoryEntry.RightSiblingID:X})");
builder.AppendLine($" Child ID: {directoryEntry.ChildID} (0x{directoryEntry.ChildID:X})");
builder.AppendLine(directoryEntry.CLSID, " CLSID");
builder.AppendLine(directoryEntry.StateBits, " State bits");
builder.AppendLine(directoryEntry.CreationTime, " Creation time");
builder.AppendLine(directoryEntry.ModifiedTime, " Modification time");
builder.AppendLine(directoryEntry.StartingSectorLocation, " Staring sector location");
builder.AppendLine(directoryEntry.StreamSize, " Stream size");
}
builder.AppendLine();
}
}
}

View File

@@ -0,0 +1,159 @@
using System;
using System.Collections.Generic;
using System.Text;
using SabreTools.Models.CHD;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class CHD : IPrinter<Header>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, Header model)
=> Print(builder, model);
public static void Print(StringBuilder builder, Header header)
{
builder.AppendLine("CHD Header Information:");
builder.AppendLine("-------------------------");
if (header == null)
{
builder.AppendLine("No header");
builder.AppendLine();
return;
}
switch (header)
{
case HeaderV1 v1:
Print(builder, v1);
break;
case HeaderV2 v2:
Print(builder, v2);
break;
case HeaderV3 v3:
Print(builder, v3);
break;
case HeaderV4 v4:
Print(builder, v4);
break;
case HeaderV5 v5:
Print(builder, v5);
break;
default:
builder.AppendLine("Unrecognized header type");
builder.AppendLine();
break;
}
}
private static void Print(StringBuilder builder, HeaderV1 header)
{
builder.AppendLine(header.Tag, $"Tag");
builder.AppendLine(header.Length, $"Length");
builder.AppendLine(header.Version, $"Version");
builder.AppendLine($" Flags: {header.Flags} (0x{header.Flags:X})");
builder.AppendLine($" Compression: {header.Compression} (0x{header.Compression:X})");
builder.AppendLine(header.HunkSize, $"Hunk size");
builder.AppendLine(header.TotalHunks, $"Total hunks");
builder.AppendLine(header.Cylinders, $"Cylinders");
builder.AppendLine(header.Heads, $"Heads");
builder.AppendLine(header.Sectors, $"Sectors");
builder.AppendLine(header.MD5, $"MD5");
builder.AppendLine(header.ParentMD5, $"Parent MD5");
builder.AppendLine();
}
private static void Print(StringBuilder builder, HeaderV2 header)
{
builder.AppendLine(header.Tag, $"Tag");
builder.AppendLine(header.Length, $"Length");
builder.AppendLine(header.Version, $"Version");
builder.AppendLine($" Flags: {header.Flags} (0x{header.Flags:X})");
builder.AppendLine($" Compression: {header.Compression} (0x{header.Compression:X})");
builder.AppendLine(header.HunkSize, $"Hunk size");
builder.AppendLine(header.TotalHunks, $"Total hunks");
builder.AppendLine(header.Cylinders, $"Cylinders");
builder.AppendLine(header.Heads, $"Heads");
builder.AppendLine(header.Sectors, $"Sectors");
builder.AppendLine(header.MD5, $"MD5");
builder.AppendLine(header.ParentMD5, $"Parent MD5");
builder.AppendLine(header.BytesPerSector, $"Bytes per sector");
builder.AppendLine();
}
private static void Print(StringBuilder builder, HeaderV3 header)
{
builder.AppendLine(header.Tag, $"Tag");
builder.AppendLine(header.Length, $"Length");
builder.AppendLine(header.Version, $"Version");
builder.AppendLine($" Flags: {header.Flags} (0x{header.Flags:X})");
builder.AppendLine($" Compression: {header.Compression} (0x{header.Compression:X})");
builder.AppendLine(header.TotalHunks, $"Total hunks");
builder.AppendLine(header.LogicalBytes, $"Logical bytes");
builder.AppendLine(header.MetaOffset, $"Meta offset");
builder.AppendLine(header.MD5, $"MD5");
builder.AppendLine(header.ParentMD5, $"Parent MD5");
builder.AppendLine(header.HunkBytes, $"Hunk bytes");
builder.AppendLine(header.SHA1, $"SHA-1");
builder.AppendLine(header.ParentSHA1, $"Parent SHA-1");
builder.AppendLine();
}
private static void Print(StringBuilder builder, HeaderV4 header)
{
builder.AppendLine(header.Tag, $"Tag");
builder.AppendLine(header.Length, $"Length");
builder.AppendLine(header.Version, $"Version");
builder.AppendLine($" Flags: {header.Flags} (0x{header.Flags:X})");
builder.AppendLine($" Compression: {header.Compression} (0x{header.Compression:X})");
builder.AppendLine(header.TotalHunks, $"Total hunks");
builder.AppendLine(header.LogicalBytes, $"Logical bytes");
builder.AppendLine(header.MetaOffset, $"Meta offset");
builder.AppendLine(header.HunkBytes, $"Hunk bytes");
builder.AppendLine(header.SHA1, $"SHA-1");
builder.AppendLine(header.ParentSHA1, $"Parent SHA-1");
builder.AppendLine(header.RawSHA1, $"Raw SHA-1");
builder.AppendLine();
}
private static void Print(StringBuilder builder, HeaderV5 header)
{
builder.AppendLine(header.Tag, $"Tag");
builder.AppendLine(header.Length, $"Length");
builder.AppendLine(header.Version, $"Version");
string compressorsLine = "Compressors: ";
if (header.Compressors == null)
{
compressorsLine += "[NULL]";
}
else
{
var compressors = new List<string>();
for (int i = 0; i < header.Compressors.Length; i++)
{
uint compressor = (uint)header.Compressors[i];
byte[] compressorBytes = BitConverter.GetBytes(compressor);
Array.Reverse(compressorBytes);
string compressorString = Encoding.ASCII.GetString(compressorBytes);
compressors.Add(compressorString);
}
compressorsLine += string.Join(", ", [.. compressors]);
}
builder.AppendLine(compressorsLine);
builder.AppendLine(header.LogicalBytes, $"Logical bytes");
builder.AppendLine(header.MapOffset, $"Map offset");
builder.AppendLine(header.MetaOffset, $"Meta offset");
builder.AppendLine(header.HunkBytes, $"Hunk bytes");
builder.AppendLine(header.UnitBytes, $"Unit bytes");
builder.AppendLine(header.RawSHA1, $"Raw SHA-1");
builder.AppendLine(header.SHA1, $"SHA-1");
builder.AppendLine(header.ParentSHA1, $"Parent SHA-1");
builder.AppendLine();
}
}
}

View File

@@ -0,0 +1,454 @@
using System.Text;
using SabreTools.Models.N3DS;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class CIA : IPrinter<Models.N3DS.CIA>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, Models.N3DS.CIA model)
=> Print(builder, model);
public static void Print(StringBuilder builder, Models.N3DS.CIA cia)
{
builder.AppendLine("CIA Archive Information:");
builder.AppendLine("-------------------------");
builder.AppendLine();
Print(builder, cia.Header);
Print(builder, cia.CertificateChain);
Print(builder, cia.Ticket);
Print(builder, cia.TMDFileData);
Print(builder, cia.Partitions);
Print(builder, cia.MetaData);
}
private static void Print(StringBuilder builder, CIAHeader? header)
{
builder.AppendLine(" CIA Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No CIA header");
builder.AppendLine();
return;
}
builder.AppendLine(header.HeaderSize, " Header size");
builder.AppendLine(header.Type, " Type");
builder.AppendLine(header.Version, " Version");
builder.AppendLine(header.CertificateChainSize, " Certificate chain size");
builder.AppendLine(header.TicketSize, " Ticket size");
builder.AppendLine(header.TMDFileSize, " TMD file size");
builder.AppendLine(header.MetaSize, " Meta size");
builder.AppendLine(header.ContentSize, " Content size");
builder.AppendLine(header.ContentIndex, " Content index");
builder.AppendLine();
}
private static void Print(StringBuilder builder, Certificate?[]? certificateChain)
{
builder.AppendLine(" Certificate Chain Information:");
builder.AppendLine(" -------------------------");
if (certificateChain == null || certificateChain.Length == 0)
{
builder.AppendLine(" No certificates, expected 3");
builder.AppendLine();
return;
}
for (int i = 0; i < certificateChain.Length; i++)
{
var certificate = certificateChain[i];
string certificateName = string.Empty;
switch (i)
{
case 0: certificateName = " (CA)"; break;
case 1: certificateName = " (Ticket)"; break;
case 2: certificateName = " (TMD)"; break;
}
builder.AppendLine($" Certificate {i}{certificateName}");
if (certificate == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine($" Signature type: {certificate.SignatureType} (0x{certificate.SignatureType:X})");
builder.AppendLine(certificate.SignatureSize, " Signature size");
builder.AppendLine(certificate.PaddingSize, " Padding size");
builder.AppendLine(certificate.Signature, " Signature");
builder.AppendLine(certificate.Padding, " Padding");
builder.AppendLine(certificate.Issuer, " Issuer");
builder.AppendLine($" Key type: {certificate.KeyType} (0x{certificate.KeyType:X})");
builder.AppendLine(certificate.Name, " Name");
builder.AppendLine(certificate.ExpirationTime, " Expiration time");
switch (certificate.KeyType)
{
case PublicKeyType.RSA_4096:
case PublicKeyType.RSA_2048:
builder.AppendLine(certificate.RSAModulus, " Modulus");
builder.AppendLine(certificate.RSAPublicExponent, " Public exponent");
builder.AppendLine(certificate.RSAPadding, " Padding");
break;
case PublicKeyType.EllipticCurve:
builder.AppendLine(certificate.ECCPublicKey, " Public key");
builder.AppendLine(certificate.ECCPadding, " Padding");
break;
}
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, Ticket? ticket)
{
builder.AppendLine(" Ticket Information:");
builder.AppendLine(" -------------------------");
if (ticket == null)
{
builder.AppendLine(" No ticket");
builder.AppendLine();
return;
}
builder.AppendLine($" Signature type: {ticket.SignatureType} (0x{ticket.SignatureType:X})");
builder.AppendLine(ticket.SignatureSize, " Signature size");
builder.AppendLine(ticket.PaddingSize, " Padding size");
builder.AppendLine(ticket.Signature, " Signature");
builder.AppendLine(ticket.Padding, " Padding");
builder.AppendLine(ticket.Issuer, " Issuer");
builder.AppendLine(ticket.ECCPublicKey, " ECC public key");
builder.AppendLine(ticket.Version, " Version");
builder.AppendLine(ticket.CaCrlVersion, " CaCrlVersion");
builder.AppendLine(ticket.SignerCrlVersion, " SignerCrlVersion");
builder.AppendLine(ticket.TitleKey, " Title key");
builder.AppendLine(ticket.Reserved1, " Reserved 1");
builder.AppendLine(ticket.TicketID, " Ticket ID");
builder.AppendLine(ticket.ConsoleID, " Console ID");
builder.AppendLine(ticket.TitleID, " Title ID");
builder.AppendLine(ticket.Reserved2, " Reserved 2");
builder.AppendLine(ticket.TicketTitleVersion, " Ticket title version");
builder.AppendLine(ticket.Reserved3, " Reserved 3");
builder.AppendLine(ticket.LicenseType, " License type");
builder.AppendLine(ticket.CommonKeyYIndex, " Common key Y index");
builder.AppendLine(ticket.Reserved4, " Reserved 4");
builder.AppendLine(ticket.eShopAccountID, " eShop Account ID");
builder.AppendLine(ticket.Reserved5, " Reserved 5");
builder.AppendLine(ticket.Audit, " Audit");
builder.AppendLine(ticket.Reserved6, " Reserved 6");
builder.AppendLine(" Limits:");
if (ticket.Limits == null || ticket.Limits.Length == 0)
{
builder.AppendLine(" No limits");
}
else
{
for (int i = 0; i < ticket.Limits.Length; i++)
{
builder.AppendLine(ticket.Limits[i], $" Limit {i}");
}
}
builder.AppendLine(ticket.ContentIndexSize, " Content index size");
builder.AppendLine(ticket.ContentIndex, " Content index");
builder.AppendLine();
builder.AppendLine(" Ticket Certificate Chain Information:");
builder.AppendLine(" -------------------------");
if (ticket.CertificateChain == null || ticket.CertificateChain.Length == 0)
{
builder.AppendLine(" No certificates, expected 2");
}
else
{
for (int i = 0; i < ticket.CertificateChain.Length; i++)
{
var certificate = ticket.CertificateChain[i];
string certificateName = string.Empty;
switch (i)
{
case 0: certificateName = " (Ticket)"; break;
case 1: certificateName = " (CA)"; break;
}
builder.AppendLine($" Certificate {i}{certificateName}");
if (certificate == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine($" Signature type: {certificate.SignatureType} (0x{certificate.SignatureType:X})");
builder.AppendLine(certificate.SignatureSize, " Signature size");
builder.AppendLine(certificate.PaddingSize, " Padding size");
builder.AppendLine(certificate.Signature, " Signature");
builder.AppendLine(certificate.Padding, " Padding");
builder.AppendLine(certificate.Issuer, " Issuer");
builder.AppendLine($" Key type: {certificate.KeyType} (0x{certificate.KeyType:X})");
builder.AppendLine(certificate.Name, " Name");
builder.AppendLine(certificate.ExpirationTime, " Expiration time");
switch (certificate.KeyType)
{
case PublicKeyType.RSA_4096:
case PublicKeyType.RSA_2048:
builder.AppendLine(certificate.RSAModulus, " Modulus");
builder.AppendLine(certificate.RSAPublicExponent, " Public exponent");
builder.AppendLine(certificate.RSAPadding, " Padding");
break;
case PublicKeyType.EllipticCurve:
builder.AppendLine(certificate.ECCPublicKey, " Public key");
builder.AppendLine(certificate.ECCPadding, " Padding");
break;
}
}
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, TitleMetadata? tmd)
{
builder.AppendLine(" Title Metadata Information:");
builder.AppendLine(" -------------------------");
if (tmd == null)
{
builder.AppendLine(" No title metadata");
builder.AppendLine();
return;
}
builder.AppendLine($" Signature type: {tmd.SignatureType} (0x{tmd.SignatureType:X})");
builder.AppendLine(tmd.SignatureSize, " Signature size");
builder.AppendLine(tmd.PaddingSize, " Padding size");
builder.AppendLine(tmd.Signature, " Signature");
builder.AppendLine(tmd.Padding1, " Padding 1");
builder.AppendLine(tmd.Issuer, " Issuer");
builder.AppendLine(tmd.Version, " Version");
builder.AppendLine(tmd.CaCrlVersion, " CaCrlVersion");
builder.AppendLine(tmd.SignerCrlVersion, " SignerCrlVersion");
builder.AppendLine(tmd.Reserved1, " Reserved 1");
builder.AppendLine(tmd.SystemVersion, " System version");
builder.AppendLine(tmd.TitleID, " Title ID");
builder.AppendLine(tmd.TitleType, " Title type");
builder.AppendLine(tmd.GroupID, " Group ID");
builder.AppendLine(tmd.SaveDataSize, " Save data size");
builder.AppendLine(tmd.SRLPrivateSaveDataSize, " SRL private save data size");
builder.AppendLine(tmd.Reserved2, " Reserved 2");
builder.AppendLine(tmd.SRLFlag, " SRL flag");
builder.AppendLine(tmd.Reserved3, " Reserved 3");
builder.AppendLine(tmd.AccessRights, " Access rights");
builder.AppendLine(tmd.TitleVersion, " Title version");
builder.AppendLine(tmd.ContentCount, " Content count");
builder.AppendLine(tmd.BootContent, " Boot content");
builder.AppendLine(tmd.Padding2, " Padding 2");
builder.AppendLine(tmd.SHA256HashContentInfoRecords, " SHA-256 hash of the content info records");
builder.AppendLine();
builder.AppendLine(" Ticket Content Info Records Information:");
builder.AppendLine(" -------------------------");
if (tmd.ContentInfoRecords == null || tmd.ContentInfoRecords.Length == 0)
{
builder.AppendLine(" No content info records, expected 64");
}
else
{
for (int i = 0; i < tmd.ContentInfoRecords.Length; i++)
{
var contentInfoRecord = tmd.ContentInfoRecords[i];
builder.AppendLine($" Content Info Record {i}");
if (contentInfoRecord == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(contentInfoRecord.ContentIndexOffset, " Content index offset");
builder.AppendLine(contentInfoRecord.ContentCommandCount, " Content command count");
builder.AppendLine(contentInfoRecord.UnhashedContentRecordsSHA256Hash, $" SHA-256 hash of the next {contentInfoRecord.ContentCommandCount} records not hashed");
}
}
builder.AppendLine();
builder.AppendLine(" Ticket Content Chunk Records Information:");
builder.AppendLine(" -------------------------");
if (tmd.ContentChunkRecords == null || tmd.ContentChunkRecords.Length == 0)
{
builder.AppendLine($" No content chunk records, expected {tmd.ContentCount}");
}
else
{
for (int i = 0; i < tmd.ContentChunkRecords.Length; i++)
{
var contentChunkRecord = tmd.ContentChunkRecords[i];
builder.AppendLine($" Content Chunk Record {i}");
if (contentChunkRecord == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(contentChunkRecord.ContentId, " Content ID");
builder.AppendLine($" Content index: {contentChunkRecord.ContentIndex} (0x{contentChunkRecord.ContentIndex:X})");
builder.AppendLine($" Content type: {contentChunkRecord.ContentType} (0x{contentChunkRecord.ContentType:X})");
builder.AppendLine(contentChunkRecord.ContentSize, " Content size");
builder.AppendLine(contentChunkRecord.SHA256Hash, " SHA-256 hash");
}
}
builder.AppendLine();
builder.AppendLine(" Ticket Certificate Chain Information:");
builder.AppendLine(" -------------------------");
if (tmd.CertificateChain == null || tmd.CertificateChain.Length == 0)
{
builder.AppendLine(" No certificates, expected 2");
}
else
{
for (int i = 0; i < tmd.CertificateChain.Length; i++)
{
var certificate = tmd.CertificateChain[i];
string certificateName = string.Empty;
switch (i)
{
case 0: certificateName = " (TMD)"; break;
case 1: certificateName = " (CA)"; break;
}
builder.AppendLine($" Certificate {i}{certificateName}");
if (certificate == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine($" Signature type: {certificate.SignatureType} (0x{certificate.SignatureType:X})");
builder.AppendLine(certificate.SignatureSize, " Signature size");
builder.AppendLine(certificate.PaddingSize, " Padding size");
builder.AppendLine(certificate.Signature, " Signature");
builder.AppendLine(certificate.Padding, " Padding");
builder.AppendLine(certificate.Issuer, " Issuer");
builder.AppendLine($" Key type: {certificate.KeyType} (0x{certificate.KeyType:X})");
builder.AppendLine(certificate.Name, " Name");
builder.AppendLine(certificate.ExpirationTime, " Expiration time");
switch (certificate.KeyType)
{
case PublicKeyType.RSA_4096:
case PublicKeyType.RSA_2048:
builder.AppendLine(certificate.RSAModulus, " Modulus");
builder.AppendLine(certificate.RSAPublicExponent, " Public exponent");
builder.AppendLine(certificate.RSAPadding, " Padding");
break;
case PublicKeyType.EllipticCurve:
builder.AppendLine(certificate.ECCPublicKey, " Public key");
builder.AppendLine(certificate.ECCPadding, " Padding");
break;
}
}
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, NCCHHeader?[]? partitions)
{
builder.AppendLine(" NCCH Partition Header Information:");
builder.AppendLine(" -------------------------");
if (partitions == null || partitions.Length == 0)
{
builder.AppendLine(" No NCCH partition headers");
builder.AppendLine();
return;
}
for (int i = 0; i < partitions.Length; i++)
{
var partitionHeader = partitions[i];
builder.AppendLine($" NCCH Partition Header {i}");
if (partitionHeader == null)
{
builder.AppendLine(" [NULL]");
continue;
}
if (partitionHeader.MagicID == string.Empty)
{
builder.AppendLine(" Empty partition, no data can be parsed");
continue;
}
else if (partitionHeader.MagicID != Constants.NCCHMagicNumber)
{
builder.AppendLine(" Unrecognized partition data, no data can be parsed");
continue;
}
builder.AppendLine(partitionHeader.RSA2048Signature, " RSA-2048 SHA-256 signature");
builder.AppendLine(partitionHeader.MagicID, " Magic ID");
builder.AppendLine(partitionHeader.ContentSizeInMediaUnits, " Content size in media units");
builder.AppendLine(partitionHeader.PartitionId, " Partition ID");
builder.AppendLine(partitionHeader.MakerCode, " Maker code");
builder.AppendLine(partitionHeader.Version, " Version");
builder.AppendLine(partitionHeader.VerificationHash, " Verification hash");
builder.AppendLine(partitionHeader.ProgramId, " Program ID");
builder.AppendLine(partitionHeader.Reserved1, " Reserved 1");
builder.AppendLine(partitionHeader.LogoRegionHash, " Logo region SHA-256 hash");
builder.AppendLine(partitionHeader.ProductCode, " Product code");
builder.AppendLine(partitionHeader.ExtendedHeaderHash, " Extended header SHA-256 hash");
builder.AppendLine(partitionHeader.ExtendedHeaderSizeInBytes, " Extended header size in bytes");
builder.AppendLine(partitionHeader.Reserved2, " Reserved 2");
builder.AppendLine(" Flags:");
if (partitionHeader.Flags == null)
{
builder.AppendLine(" [NULL]");
}
else
{
builder.AppendLine(partitionHeader.Flags.Reserved0, " Reserved 0");
builder.AppendLine(partitionHeader.Flags.Reserved1, " Reserved 1");
builder.AppendLine(partitionHeader.Flags.Reserved2, " Reserved 2");
builder.AppendLine($" Crypto method: {partitionHeader.Flags.CryptoMethod} (0x{partitionHeader.Flags.CryptoMethod:X})");
builder.AppendLine($" Content platform: {partitionHeader.Flags.ContentPlatform} (0x{partitionHeader.Flags.ContentPlatform:X})");
builder.AppendLine($" Content type: {partitionHeader.Flags.MediaPlatformIndex} (0x{partitionHeader.Flags.MediaPlatformIndex:X})");
builder.AppendLine(partitionHeader.Flags.ContentUnitSize, " Content unit size");
builder.AppendLine($" Bitmasks: {partitionHeader.Flags.BitMasks} (0x{partitionHeader.Flags.BitMasks:X})");
}
builder.AppendLine(partitionHeader.PlainRegionOffsetInMediaUnits, " Plain region offset, in media units");
builder.AppendLine(partitionHeader.PlainRegionSizeInMediaUnits, " Plain region size, in media units");
builder.AppendLine(partitionHeader.LogoRegionOffsetInMediaUnits, " Logo region offset, in media units");
builder.AppendLine(partitionHeader.LogoRegionSizeInMediaUnits, " Logo region size, in media units");
builder.AppendLine(partitionHeader.ExeFSOffsetInMediaUnits, " ExeFS offset, in media units");
builder.AppendLine(partitionHeader.ExeFSSizeInMediaUnits, " ExeFS size, in media units");
builder.AppendLine(partitionHeader.ExeFSHashRegionSizeInMediaUnits, " ExeFS hash region offset, in media units");
builder.AppendLine(partitionHeader.Reserved3, " Reserved 3");
builder.AppendLine(partitionHeader.RomFSOffsetInMediaUnits, " RomFS offset, in media units");
builder.AppendLine(partitionHeader.RomFSSizeInMediaUnits, " RomFS size, in media units");
builder.AppendLine(partitionHeader.RomFSHashRegionSizeInMediaUnits, " RomFS hash region offset, in media units");
builder.AppendLine(partitionHeader.Reserved4, " Reserved 4");
builder.AppendLine(partitionHeader.ExeFSSuperblockHash, " ExeFS superblock SHA-256 hash");
builder.AppendLine(partitionHeader.RomFSSuperblockHash, " RomFS superblock SHA-256 hash");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, MetaData? metaData)
{
builder.AppendLine(" Meta Data Information:");
builder.AppendLine(" -------------------------");
if (metaData == null)
{
builder.AppendLine(" No meta file data");
builder.AppendLine();
return;
}
builder.AppendLine(metaData.TitleIDDependencyList, " Title ID dependency list");
builder.AppendLine(metaData.Reserved1, " Reserved 1");
builder.AppendLine(metaData.CoreVersion, " Core version");
builder.AppendLine(metaData.Reserved2, " Reserved 2");
builder.AppendLine(metaData.IconData, " Icon data");
builder.AppendLine();
}
}
}

View File

@@ -0,0 +1,539 @@
using System.Collections.Generic;
using System.Text;
using SabreTools.Models.GCF;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class GCF : IPrinter<File>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, File model)
=> Print(builder, model);
public static void Print(StringBuilder builder, File file)
{
builder.AppendLine("GCF Information:");
builder.AppendLine("-------------------------");
builder.AppendLine();
// Header
Print(builder, file.Header);
// Block Entries
Print(builder, file.BlockEntryHeader);
Print(builder, file.BlockEntries);
// Fragmentation Maps
Print(builder, file.FragmentationMapHeader);
Print(builder, file.FragmentationMaps);
// Block Entry Maps
Print(builder, file.BlockEntryMapHeader);
Print(builder, file.BlockEntryMaps);
// Directory and Directory Maps
Print(builder, file.DirectoryHeader);
Print(builder, file.DirectoryEntries, file.DirectoryNames);
// TODO: Should we print out the entire string table?
Print(builder, file.DirectoryInfo1Entries);
Print(builder, file.DirectoryInfo2Entries);
Print(builder, file.DirectoryCopyEntries);
Print(builder, file.DirectoryLocalEntries);
Print(builder, file.DirectoryMapHeader);
Print(builder, file.DirectoryMapEntries);
// Checksums and Checksum Maps
Print(builder, file.ChecksumHeader);
Print(builder, file.ChecksumMapHeader);
Print(builder, file.ChecksumMapEntries);
Print(builder, file.ChecksumEntries);
// Data Blocks
Print(builder, file.DataBlockHeader);
}
private static void Print(StringBuilder builder, Header? header)
{
builder.AppendLine(" Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Dummy0, " Dummy 0");
builder.AppendLine(header.MajorVersion, " Major version");
builder.AppendLine(header.MinorVersion, " Minor version");
builder.AppendLine(header.CacheID, " Cache ID");
builder.AppendLine(header.LastVersionPlayed, " Last version played");
builder.AppendLine(header.Dummy1, " Dummy 1");
builder.AppendLine(header.Dummy2, " Dummy 2");
builder.AppendLine(header.FileSize, " File size");
builder.AppendLine(header.BlockSize, " Block size");
builder.AppendLine(header.BlockCount, " Block count");
builder.AppendLine(header.Dummy3, " Dummy 3");
builder.AppendLine();
}
private static void Print(StringBuilder builder, BlockEntryHeader? header)
{
builder.AppendLine(" Block Entry Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No block entry header");
builder.AppendLine();
return;
}
builder.AppendLine(header.BlockCount, " Block count");
builder.AppendLine(header.BlocksUsed, " Blocks used");
builder.AppendLine(header.Dummy0, " Dummy 0");
builder.AppendLine(header.Dummy1, " Dummy 1");
builder.AppendLine(header.Dummy2, " Dummy 2");
builder.AppendLine(header.Dummy3, " Dummy 3");
builder.AppendLine(header.Dummy4, " Dummy 4");
builder.AppendLine(header.Checksum, " Checksum");
builder.AppendLine();
}
private static void Print(StringBuilder builder, BlockEntry?[]? entries)
{
builder.AppendLine(" Block Entries Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No block entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Block Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.EntryFlags, " Entry flags");
builder.AppendLine(entry.FileDataOffset, " File data offset");
builder.AppendLine(entry.FileDataSize, " File data size");
builder.AppendLine(entry.FirstDataBlockIndex, " First data block index");
builder.AppendLine(entry.NextBlockEntryIndex, " Next block entry index");
builder.AppendLine(entry.PreviousBlockEntryIndex, " Previous block entry index");
builder.AppendLine(entry.DirectoryIndex, " Directory index");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, FragmentationMapHeader? header)
{
builder.AppendLine(" Fragmentation Map Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No fragmentation map header");
builder.AppendLine();
return;
}
builder.AppendLine(header.BlockCount, " Block count");
builder.AppendLine(header.FirstUnusedEntry, " First unused entry");
builder.AppendLine(header.Terminator, " Terminator");
builder.AppendLine(header.Checksum, " Checksum");
builder.AppendLine();
}
private static void Print(StringBuilder builder, FragmentationMap?[]? entries)
{
builder.AppendLine(" Fragmentation Maps Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No fragmentation maps");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Fragmentation Map {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.NextDataBlockIndex, " Next data block index");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, BlockEntryMapHeader? header)
{
builder.AppendLine(" Block Entry Map Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No block entry map header");
builder.AppendLine();
return;
}
builder.AppendLine(header.BlockCount, " Block count");
builder.AppendLine(header.FirstBlockEntryIndex, " First block entry index");
builder.AppendLine(header.LastBlockEntryIndex, " Last block entry index");
builder.AppendLine(header.Dummy0, " Dummy 0");
builder.AppendLine(header.Checksum, " Checksum");
builder.AppendLine();
}
private static void Print(StringBuilder builder, BlockEntryMap?[]? entries)
{
builder.AppendLine(" Block Entry Maps Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No block entry maps");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Block Entry Map {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.PreviousBlockEntryIndex, " Previous data block index");
builder.AppendLine(entry.NextBlockEntryIndex, " Next data block index");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, DirectoryHeader? header)
{
builder.AppendLine(" Directory Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No directory header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Dummy0, " Dummy 0");
builder.AppendLine(header.CacheID, " Cache ID");
builder.AppendLine(header.LastVersionPlayed, " Last version played");
builder.AppendLine(header.ItemCount, " Item count");
builder.AppendLine(header.FileCount, " File count");
builder.AppendLine(header.Dummy1, " Dummy 1");
builder.AppendLine(header.DirectorySize, " Directory size");
builder.AppendLine(header.NameSize, " Name size");
builder.AppendLine(header.Info1Count, " Info 1 count");
builder.AppendLine(header.CopyCount, " Copy count");
builder.AppendLine(header.LocalCount, " Local count");
builder.AppendLine(header.Dummy2, " Dummy 2");
builder.AppendLine(header.Dummy3, " Dummy 3");
builder.AppendLine(header.Checksum, " Checksum");
builder.AppendLine();
}
private static void Print(StringBuilder builder, DirectoryEntry?[]? entries, Dictionary<long, string?>? entryNames)
{
builder.AppendLine(" Directory Entries Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No directory entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Directory Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.NameOffset, " Name offset");
builder.AppendLine(entryNames![entry.NameOffset], " Name");
builder.AppendLine(entry.ItemSize, " Item size");
builder.AppendLine(entry.ChecksumIndex, " Checksum index");
builder.AppendLine($" Directory flags: {entry.DirectoryFlags} (0x{entry.DirectoryFlags:X})");
builder.AppendLine(entry.ParentIndex, " Parent index");
builder.AppendLine(entry.NextIndex, " Next index");
builder.AppendLine(entry.FirstIndex, " First index");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, DirectoryInfo1Entry?[]? entries)
{
builder.AppendLine(" Directory Info 1 Entries Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No directory info 1 entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Directory Info 1 Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.Dummy0, " Dummy 0");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, DirectoryInfo2Entry?[]? entries)
{
builder.AppendLine(" Directory Info 2 Entries Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No directory info 2 entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Directory Info 2 Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.Dummy0, " Dummy 0");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, DirectoryCopyEntry?[]? entries)
{
builder.AppendLine(" Directory Copy Entries Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No directory copy entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Directory Copy Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.DirectoryIndex, " Directory index");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, DirectoryLocalEntry?[]? entries)
{
builder.AppendLine(" Directory Local Entries Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No directory local entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Directory Local Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.DirectoryIndex, " Directory index");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, DirectoryMapHeader? header)
{
builder.AppendLine(" Directory Map Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No directory map header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Dummy0, " Dummy 0");
builder.AppendLine(header.Dummy1, " Dummy 1");
builder.AppendLine();
}
private static void Print(StringBuilder builder, DirectoryMapEntry?[]? entries)
{
builder.AppendLine(" Directory Map Entries Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No directory map entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Directory Map Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.FirstBlockIndex, " First block index");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, ChecksumHeader? header)
{
builder.AppendLine(" Checksum Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No checksum header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Dummy0, " Dummy 0");
builder.AppendLine(header.ChecksumSize, " Checksum size");
builder.AppendLine();
}
private static void Print(StringBuilder builder, ChecksumMapHeader? header)
{
builder.AppendLine(" Checksum Map Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No checksum map header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Dummy0, " Dummy 0");
builder.AppendLine(header.Dummy1, " Dummy 1");
builder.AppendLine(header.ItemCount, " Item count");
builder.AppendLine(header.ChecksumCount, " Checksum count");
builder.AppendLine();
}
private static void Print(StringBuilder builder, ChecksumMapEntry?[]? entries)
{
builder.AppendLine(" Checksum Map Entries Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No checksum map entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Checksum Map Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.ChecksumCount, " Checksum count");
builder.AppendLine(entry.FirstChecksumIndex, " First checksum index");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, ChecksumEntry?[]? entries)
{
builder.AppendLine(" Checksum Entries Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No checksum entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Checksum Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.Checksum, " Checksum");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, DataBlockHeader? header)
{
builder.AppendLine(" Data Block Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No data block header");
builder.AppendLine();
return;
}
builder.AppendLine(header.LastVersionPlayed, " Last version played");
builder.AppendLine(header.BlockCount, " Block count");
builder.AppendLine(header.BlockSize, " Block size");
builder.AppendLine(header.FirstBlockOffset, " First block offset");
builder.AppendLine(header.BlocksUsed, " Blocks used");
builder.AppendLine(header.Checksum, " Checksum");
builder.AppendLine();
}
}
}

View File

@@ -0,0 +1,55 @@
using System.Text;
using SabreTools.Models.IRD;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class IRD : IPrinter<File>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, File model)
=> Print(builder, model);
public static void Print(StringBuilder builder, File ird)
{
builder.AppendLine("IRD Information:");
builder.AppendLine("-------------------------");
builder.AppendLine(ird.Magic, "Magic", Encoding.ASCII);
builder.AppendLine(ird.Version, "Version");
builder.AppendLine(ird.TitleID, "Title ID");
builder.AppendLine(ird.TitleLength, "Title length");
builder.AppendLine(ird.Title, "Title");
builder.AppendLine(ird.SystemVersion, "System version");
builder.AppendLine(ird.GameVersion, "Game version");
builder.AppendLine(ird.AppVersion, "App version");
builder.AppendLine(ird.HeaderLength, "Header length");
builder.AppendLine(ird.Header, "Header");
builder.AppendLine(ird.FooterLength, "Footer length");
builder.AppendLine(ird.Footer, "Footer");
builder.AppendLine(ird.RegionCount, "Region count");
if (ird.RegionCount != 0 && ird.RegionHashes != null && ird.RegionHashes.Length != 0)
{
for (int i = 0; i < ird.RegionCount; i++)
{
builder.AppendLine(ird.RegionHashes[i], $"Region {i} hash");
}
}
builder.AppendLine(ird.FileCount, "File count");
for (int i = 0; i < ird.FileCount; i++)
{
if (ird.FileKeys != null)
builder.AppendLine(ird.FileKeys[i], $"File {i} key");
if (ird.FileHashes != null)
builder.AppendLine(ird.FileHashes[i], $"File {i} hash");
}
builder.AppendLine(ird.ExtraConfig, "Extra config");
builder.AppendLine(ird.Attachments, "Attachments");
builder.AppendLine(ird.Data1Key, "Data 1 key");
builder.AppendLine(ird.Data2Key, "Data 2 key");
builder.AppendLine(ird.PIC, "PIC");
builder.AppendLine(ird.UID, "UID");
builder.AppendLine(ird.CRC, "CRC");
builder.AppendLine();
}
}
}

View File

@@ -0,0 +1,409 @@
using System.Collections.Generic;
using System.Text;
using SabreTools.Models.InstallShieldCabinet;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class InstallShieldCabinet : IPrinter<Cabinet>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, Cabinet model)
=> Print(builder, model);
public static void Print(StringBuilder builder, Cabinet cabinet)
{
builder.AppendLine("InstallShield Cabinet Information:");
builder.AppendLine("-------------------------");
builder.AppendLine();
// Major Version
int majorVersion = GetMajorVersion(cabinet.CommonHeader);
// Headers
Print(builder, cabinet.CommonHeader, majorVersion);
Print(builder, cabinet.VolumeHeader, majorVersion);
Print(builder, cabinet.Descriptor);
// File Descriptors
Print(builder, cabinet.FileDescriptorOffsets);
Print(builder, cabinet.DirectoryNames);
Print(builder, cabinet.FileDescriptors);
// File Groups
Print(builder, cabinet.FileGroupOffsets, "File Group");
Print(builder, cabinet.FileGroups);
// Components
Print(builder, cabinet.ComponentOffsets, "Component");
Print(builder, cabinet.Components);
}
private static int GetMajorVersion(CommonHeader? header)
{
uint majorVersion = header?.Version ?? 0;
if (majorVersion >> 24 == 1)
{
majorVersion = (majorVersion >> 12) & 0x0F;
}
else if (majorVersion >> 24 == 2 || majorVersion >> 24 == 4)
{
majorVersion = majorVersion & 0xFFFF;
if (majorVersion != 0)
majorVersion /= 100;
}
return (int)majorVersion;
}
private static void Print(StringBuilder builder, CommonHeader? header, int majorVersion)
{
builder.AppendLine(" Common Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(value: " No common header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Signature, " Signature");
builder.AppendLine($" Version: {header.Version} (0x{header.Version:X}) [{majorVersion}]");
builder.AppendLine(header.VolumeInfo, " Volume info");
builder.AppendLine(header.DescriptorOffset, " Descriptor offset");
builder.AppendLine(header.DescriptorSize, " Descriptor size");
builder.AppendLine();
}
private static void Print(StringBuilder builder, VolumeHeader? header, int majorVersion)
{
builder.AppendLine(" Volume Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(value: " No volume header");
builder.AppendLine();
return;
}
if (majorVersion <= 5)
{
builder.AppendLine(header.DataOffset, " Data offset");
builder.AppendLine(header.FirstFileIndex, " First file index");
builder.AppendLine(header.LastFileIndex, " Last file index");
builder.AppendLine(header.FirstFileOffset, " First file offset");
builder.AppendLine(header.FirstFileSizeExpanded, " First file size expanded");
builder.AppendLine(header.FirstFileSizeCompressed, " First file size compressed");
builder.AppendLine(header.LastFileOffset, " Last file offset");
builder.AppendLine(header.LastFileSizeExpanded, " Last file size expanded");
builder.AppendLine(header.LastFileSizeCompressed, " Last file size compressed");
}
else
{
builder.AppendLine(header.DataOffset, " Data offset");
builder.AppendLine(header.DataOffsetHigh, " Data offset high");
builder.AppendLine(header.FirstFileIndex, " First file index");
builder.AppendLine(header.LastFileIndex, " Last file index");
builder.AppendLine(header.FirstFileOffset, " First file offset");
builder.AppendLine(header.FirstFileOffsetHigh, " First file offset high");
builder.AppendLine(header.FirstFileSizeExpanded, " First file size expanded");
builder.AppendLine(header.FirstFileSizeExpandedHigh, " First file size expanded high");
builder.AppendLine(header.FirstFileSizeCompressed, " First file size compressed");
builder.AppendLine(header.FirstFileSizeCompressedHigh, " First file size compressed high");
builder.AppendLine(header.LastFileOffset, " Last file offset");
builder.AppendLine(header.LastFileOffsetHigh, " Last file offset high");
builder.AppendLine(header.LastFileSizeExpanded, " Last file size expanded");
builder.AppendLine(header.LastFileSizeExpandedHigh, " Last file size expanded high");
builder.AppendLine(header.LastFileSizeCompressed, " Last file size compressed");
builder.AppendLine(header.LastFileSizeCompressedHigh, " Last file size compressed high");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, Descriptor? descriptor)
{
builder.AppendLine(" Descriptor Information:");
builder.AppendLine(" -------------------------");
if (descriptor == null)
{
builder.AppendLine(" No descriptor");
builder.AppendLine();
return;
}
builder.AppendLine(descriptor.StringsOffset, " Strings offset");
builder.AppendLine(descriptor.Reserved0, " Reserved 0");
builder.AppendLine(descriptor.ComponentListOffset, " Component list offset");
builder.AppendLine(descriptor.FileTableOffset, " File table offset");
builder.AppendLine(descriptor.Reserved1, " Reserved 1");
builder.AppendLine(descriptor.FileTableSize, " File table size");
builder.AppendLine(descriptor.FileTableSize2, " File table size 2");
builder.AppendLine(descriptor.DirectoryCount, " Directory count");
builder.AppendLine(descriptor.Reserved2, " Reserved 2");
builder.AppendLine(descriptor.Reserved3, " Reserved 3");
builder.AppendLine(descriptor.Reserved4, " Reserved 4");
builder.AppendLine(descriptor.FileCount, " File count");
builder.AppendLine(descriptor.FileTableOffset2, " File table offset 2");
builder.AppendLine(descriptor.ComponentTableInfoCount, " Component table info count");
builder.AppendLine(descriptor.ComponentTableOffset, " Component table offset");
builder.AppendLine(descriptor.Reserved5, " Reserved 5");
builder.AppendLine(descriptor.Reserved6, " Reserved 6");
builder.AppendLine();
builder.AppendLine(" File group offsets:");
builder.AppendLine(" -------------------------");
if (descriptor.FileGroupOffsets == null || descriptor.FileGroupOffsets.Length == 0)
{
builder.AppendLine(" No file group offsets");
}
else
{
for (int i = 0; i < descriptor.FileGroupOffsets.Length; i++)
{
builder.AppendLine(descriptor.FileGroupOffsets[i], $" File Group Offset {i}");
}
}
builder.AppendLine();
builder.AppendLine(" Component offsets:");
builder.AppendLine(" -------------------------");
if (descriptor.ComponentOffsets == null || descriptor.ComponentOffsets.Length == 0)
{
builder.AppendLine(" No component offsets");
}
else
{
for (int i = 0; i < descriptor.ComponentOffsets.Length; i++)
{
builder.AppendLine(descriptor.ComponentOffsets[i], $" Component Offset {i}");
}
}
builder.AppendLine();
builder.AppendLine(descriptor.SetupTypesOffset, " Setup types offset");
builder.AppendLine(descriptor.SetupTableOffset, " Setup table offset");
builder.AppendLine(descriptor.Reserved7, " Reserved 7");
builder.AppendLine(descriptor.Reserved8, " Reserved 8");
builder.AppendLine();
}
private static void Print(StringBuilder builder, uint[]? entries)
{
builder.AppendLine(" File Descriptor Offsets:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No file descriptor offsets");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
builder.AppendLine(entries[i], $" File Descriptor Offset {i}");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, string?[]? entries)
{
builder.AppendLine(" Directory Names:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No directory names");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
builder.AppendLine(entries[i], $" Directory Name {i}");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, FileDescriptor?[]? entries)
{
builder.AppendLine(" File Descriptors:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No file descriptors");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" File Descriptor {i}:");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.NameOffset, " Name offset");
builder.AppendLine(entry.Name, " Name");
builder.AppendLine(entry.DirectoryIndex, " Directory index");
builder.AppendLine($" Flags: {entry.Flags} (0x{entry.Flags:X})");
builder.AppendLine(entry.ExpandedSize, " Expanded size");
builder.AppendLine(entry.CompressedSize, " Compressed size");
builder.AppendLine(entry.DataOffset, " Data offset");
builder.AppendLine(entry.MD5, " MD5");
builder.AppendLine(entry.Volume, " Volume");
builder.AppendLine(entry.LinkPrevious, " Link previous");
builder.AppendLine(entry.LinkNext, " Link next");
builder.AppendLine($" Link flags: {entry.LinkFlags} (0x{entry.LinkFlags:X})");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, Dictionary<long, OffsetList?>? entries, string name)
{
builder.AppendLine($" {name} Offsets:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Count == 0)
{
builder.AppendLine($" No {name.ToLowerInvariant()} offsets");
builder.AppendLine();
return;
}
foreach (var kvp in entries)
{
long offset = kvp.Key;
var value = kvp.Value;
builder.AppendLine($" {name} Offset {offset}:");
if (value == null)
{
builder.AppendLine($" Unassigned {name.ToLowerInvariant()}");
continue;
}
builder.AppendLine(value.NameOffset, " Name offset");
builder.AppendLine(value.Name, " Name");
builder.AppendLine(value.DescriptorOffset, " Descriptor offset");
builder.AppendLine(value.NextOffset, " Next offset");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, FileGroup?[]? entries)
{
builder.AppendLine(" File Groups:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No file groups");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var fileGroup = entries[i];
builder.AppendLine($" File Group {i}:");
if (fileGroup == null)
{
builder.AppendLine(" Unassigned file group");
continue;
}
builder.AppendLine(fileGroup.NameOffset, " Name offset");
builder.AppendLine(fileGroup.Name, " Name");
builder.AppendLine(fileGroup.ExpandedSize, " Expanded size");
builder.AppendLine(fileGroup.CompressedSize, " Compressed size");
builder.AppendLine($" Attributes: {fileGroup.Attributes} (0x{fileGroup.Attributes:X})");
builder.AppendLine(fileGroup.FirstFile, " First file");
builder.AppendLine(fileGroup.LastFile, " Last file");
builder.AppendLine(fileGroup.UnknownStringOffset, " Unknown string offset");
builder.AppendLine(fileGroup.OperatingSystemOffset, " Operating system offset");
builder.AppendLine(fileGroup.LanguageOffset, " Language offset");
builder.AppendLine(fileGroup.HTTPLocationOffset, " HTTP location offset");
builder.AppendLine(fileGroup.FTPLocationOffset, " FTP location offset");
builder.AppendLine(fileGroup.MiscOffset, " Misc. offset");
builder.AppendLine(fileGroup.TargetDirectoryOffset, " Target directory offset");
builder.AppendLine($" Overwrite flags: {fileGroup.OverwriteFlags} (0x{fileGroup.OverwriteFlags:X})");
builder.AppendLine(fileGroup.Reserved, " Reserved");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, Component?[]? entries)
{
builder.AppendLine(" Components:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No components");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var component = entries[i];
builder.AppendLine($" Component {i}:");
if (component == null)
{
builder.AppendLine(" Unassigned component");
continue;
}
builder.AppendLine(component.IdentifierOffset, " Identifier offset");
builder.AppendLine(component.Identifier, " Identifier");
builder.AppendLine(component.DescriptorOffset, " Descriptor offset");
builder.AppendLine(component.DisplayNameOffset, " Display name offset");
builder.AppendLine(component.DisplayName, " Display name");
builder.AppendLine($" Status: {component.Status} (0x{component.Status:X})");
builder.AppendLine(component.PasswordOffset, " Password offset");
builder.AppendLine(component.MiscOffset, " Misc. offset");
builder.AppendLine(component.ComponentIndex, " Component index");
builder.AppendLine(component.NameOffset, " Name offset");
builder.AppendLine(component.Name, " Name");
builder.AppendLine(component.CDRomFolderOffset, " CD-ROM folder offset");
builder.AppendLine(component.HTTPLocationOffset, " HTTP location offset");
builder.AppendLine(component.FTPLocationOffset, " FTP location offset");
builder.AppendLine(component.Guid, " GUIDs");
builder.AppendLine(component.CLSIDOffset, " CLSID offset");
builder.AppendLine(component.CLSID, " CLSID");
builder.AppendLine(component.Reserved2, " Reserved 2");
builder.AppendLine(component.Reserved3, " Reserved 3");
builder.AppendLine(component.DependsCount, " Depends count");
builder.AppendLine(component.DependsOffset, " Depends offset");
builder.AppendLine(component.FileGroupCount, " File group count");
builder.AppendLine(component.FileGroupNamesOffset, " File group names offset");
builder.AppendLine();
builder.AppendLine(" File group names:");
builder.AppendLine(" -------------------------");
if (component.FileGroupNames == null || component.FileGroupNames.Length == 0)
{
builder.AppendLine(" No file group names");
}
else
{
for (int j = 0; j < component.FileGroupNames.Length; j++)
{
builder.AppendLine(component.FileGroupNames[j], $" File Group Name {j}");
}
}
builder.AppendLine();
builder.AppendLine(component.X3Count, " X3 count");
builder.AppendLine(component.X3Offset, " X3 offset");
builder.AppendLine(component.SubComponentsCount, " Sub-components count");
builder.AppendLine(component.SubComponentsOffset, " Sub-components offset");
builder.AppendLine(component.NextComponentOffset, " Next component offset");
builder.AppendLine(component.OnInstallingOffset, " On installing offset");
builder.AppendLine(component.OnInstalledOffset, " On installed offset");
builder.AppendLine(component.OnUninstallingOffset, " On uninstalling offset");
builder.AppendLine(component.OnUninstalledOffset, " On uninstalled offset");
}
builder.AppendLine();
}
}
}

View File

@@ -0,0 +1,783 @@
using System.Text;
using SabreTools.Models.LinearExecutable;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class LinearExecutable : IPrinter<Executable>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, Executable model)
=> Print(builder, model);
public static void Print(StringBuilder builder, Executable executable)
{
builder.AppendLine("New Executable Information:");
builder.AppendLine("-------------------------");
builder.AppendLine();
// Stub
Print(builder, executable.Stub?.Header);
// Information Block
Print(builder, executable.InformationBlock);
// Tables
Print(builder, executable.ObjectTable);
Print(builder, executable.ObjectPageMap);
Print(builder, executable.ResourceTable);
Print(builder, executable.ResidentNamesTable);
Print(builder, executable.EntryTable);
Print(builder, executable.ModuleFormatDirectivesTable);
Print(builder, executable.VerifyRecordDirectiveTable);
Print(builder, executable.FixupPageTable);
Print(builder, executable.FixupRecordTable);
Print(builder, executable.ImportModuleNameTable);
Print(builder, executable.ImportModuleProcedureNameTable);
Print(builder, executable.PerPageChecksumTable);
Print(builder, executable.NonResidentNamesTable);
// Debug
Print(builder, executable.DebugInformation);
}
private static void Print(StringBuilder builder, Models.MSDOS.ExecutableHeader? header)
{
builder.AppendLine(" MS-DOS Stub Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No MS-DOS stub header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Magic, " Magic number");
builder.AppendLine(header.LastPageBytes, " Last page bytes");
builder.AppendLine(header.Pages, " Pages");
builder.AppendLine(header.RelocationItems, " Relocation items");
builder.AppendLine(header.HeaderParagraphSize, " Header paragraph size");
builder.AppendLine(header.MinimumExtraParagraphs, " Minimum extra paragraphs");
builder.AppendLine(header.MaximumExtraParagraphs, " Maximum extra paragraphs");
builder.AppendLine(header.InitialSSValue, " Initial SS value");
builder.AppendLine(header.InitialSPValue, " Initial SP value");
builder.AppendLine(header.Checksum, " Checksum");
builder.AppendLine(header.InitialIPValue, " Initial IP value");
builder.AppendLine(header.InitialCSValue, " Initial CS value");
builder.AppendLine(header.RelocationTableAddr, " Relocation table address");
builder.AppendLine(header.OverlayNumber, " Overlay number");
builder.AppendLine();
builder.AppendLine(" MS-DOS Stub Extended Header Information:");
builder.AppendLine(" -------------------------");
builder.AppendLine(header.Reserved1, " Reserved words");
builder.AppendLine(header.OEMIdentifier, " OEM identifier");
builder.AppendLine(header.OEMInformation, " OEM information");
builder.AppendLine(header.Reserved2, " Reserved words");
builder.AppendLine(header.NewExeHeaderAddr, " New EXE header address");
builder.AppendLine();
}
private static void Print(StringBuilder builder, InformationBlock? block)
{
builder.AppendLine(" Information Block Information:");
builder.AppendLine(" -------------------------");
if (block == null)
{
builder.AppendLine(" No information block");
builder.AppendLine();
return;
}
builder.AppendLine(block.Signature, " Signature");
builder.AppendLine($" Byte order: {block.ByteOrder} (0x{block.ByteOrder:X})");
builder.AppendLine($" Word order: {block.WordOrder} (0x{block.WordOrder:X})");
builder.AppendLine(block.ExecutableFormatLevel, " Executable format level");
builder.AppendLine($" CPU type: {block.CPUType} (0x{block.CPUType:X})");
builder.AppendLine($" Module OS: {block.ModuleOS} (0x{block.ModuleOS:X})");
builder.AppendLine(block.ModuleVersion, " Module version");
builder.AppendLine($" Module type flags: {block.ModuleTypeFlags} (0x{block.ModuleTypeFlags:X})");
builder.AppendLine(block.ModuleNumberPages, " Module number pages");
builder.AppendLine(block.InitialObjectCS, " Initial object CS");
builder.AppendLine(block.InitialEIP, " Initial EIP");
builder.AppendLine(block.InitialObjectSS, " Initial object SS");
builder.AppendLine(block.InitialESP, " Initial ESP");
builder.AppendLine(block.MemoryPageSize, " Memory page size");
builder.AppendLine(block.BytesOnLastPage, " Bytes on last page");
builder.AppendLine(block.FixupSectionSize, " Fix-up section size");
builder.AppendLine(block.FixupSectionChecksum, " Fix-up section checksum");
builder.AppendLine(block.LoaderSectionSize, " Loader section size");
builder.AppendLine(block.LoaderSectionChecksum, " Loader section checksum");
builder.AppendLine(block.ObjectTableOffset, " Object table offset");
builder.AppendLine(block.ObjectTableCount, " Object table count");
builder.AppendLine(block.ObjectPageMapOffset, " Object page map offset");
builder.AppendLine(block.ObjectIterateDataMapOffset, " Object iterate data map offset");
builder.AppendLine(block.ResourceTableOffset, " Resource table offset");
builder.AppendLine(block.ResourceTableCount, " Resource table count");
builder.AppendLine(block.ResidentNamesTableOffset, " Resident names table offset");
builder.AppendLine(block.EntryTableOffset, " Entry table offset");
builder.AppendLine(block.ModuleDirectivesTableOffset, " Module directives table offset");
builder.AppendLine(block.ModuleDirectivesCount, " Module directives table count");
builder.AppendLine(block.FixupPageTableOffset, " Fix-up page table offset");
builder.AppendLine(block.FixupRecordTableOffset, " Fix-up record table offset");
builder.AppendLine(block.ImportedModulesNameTableOffset, " Imported modules name table offset");
builder.AppendLine(block.ImportedModulesCount, " Imported modules count");
builder.AppendLine(block.ImportProcedureNameTableOffset, " Imported procedure name table count");
builder.AppendLine(block.PerPageChecksumTableOffset, " Per-page checksum table offset");
builder.AppendLine(block.DataPagesOffset, " Data pages offset");
builder.AppendLine(block.PreloadPageCount, " Preload page count");
builder.AppendLine(block.NonResidentNamesTableOffset, " Non-resident names table offset");
builder.AppendLine(block.NonResidentNamesTableLength, " Non-resident names table length");
builder.AppendLine(block.NonResidentNamesTableChecksum, " Non-resident names table checksum");
builder.AppendLine(block.AutomaticDataObject, " Automatic data object");
builder.AppendLine(block.DebugInformationOffset, " Debug information offset");
builder.AppendLine(block.DebugInformationLength, " Debug information length");
builder.AppendLine(block.PreloadInstancePagesNumber, " Preload instance pages number");
builder.AppendLine(block.DemandInstancePagesNumber, " Demand instance pages number");
builder.AppendLine(block.ExtraHeapAllocation, " Extra heap allocation");
builder.AppendLine();
}
private static void Print(StringBuilder builder, ObjectTableEntry?[]? entries)
{
builder.AppendLine(" Object Table Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No object table entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Object Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.VirtualSegmentSize, " Virtual segment size");
builder.AppendLine(entry.RelocationBaseAddress, " Relocation base address");
builder.AppendLine($" Object flags: {entry.ObjectFlags} (0x{entry.ObjectFlags:X})");
builder.AppendLine(entry.PageTableIndex, " Page table index");
builder.AppendLine(entry.PageTableEntries, " Page table entries");
builder.AppendLine(entry.Reserved, " Reserved");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, ObjectPageMapEntry?[]? entries)
{
builder.AppendLine(" Object Page Map Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No object page map entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Object Page Map Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.PageDataOffset, " Page data offset");
builder.AppendLine(entry.DataSize, " Data size");
builder.AppendLine($" Flags: {entry.Flags} (0x{entry.Flags:X})");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, ResourceTableEntry?[]? entries)
{
builder.AppendLine(" Resource Table Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No resource table entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Resource Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine($" Type ID: {entry.TypeID} (0x{entry.TypeID:X})");
builder.AppendLine(entry.NameID, " Name ID");
builder.AppendLine(entry.ResourceSize, " Resource size");
builder.AppendLine(entry.ObjectNumber, " Object number");
builder.AppendLine(entry.Offset, " Offset");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, ResidentNamesTableEntry?[]? entries)
{
builder.AppendLine(" Resident Names Table Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No resident names table entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Resident Names Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.Length, " Length");
builder.AppendLine(entry.Name, " Name");
builder.AppendLine(entry.OrdinalNumber, " Ordinal number");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, EntryTableBundle?[]? bundles)
{
builder.AppendLine(" Entry Table Information:");
builder.AppendLine(" -------------------------");
if (bundles == null || bundles.Length == 0)
{
builder.AppendLine(" No entry table bundles");
builder.AppendLine();
return;
}
for (int i = 0; i < bundles.Length; i++)
{
var bundle = bundles[i];
builder.AppendLine($" Entry Table Bundle {i}");
if (bundle == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(bundle.Entries, " Entries");
builder.AppendLine($" Bundle type: {bundle.BundleType} (0x{bundle.BundleType:X})");
builder.AppendLine();
builder.AppendLine(" Entry Table Entries:");
builder.AppendLine(" -------------------------");
if (bundle.TableEntries == null || bundle.TableEntries.Length == 0)
{
builder.AppendLine(" No entry table entries");
builder.AppendLine();
continue;
}
for (int j = 0; j < bundle.TableEntries.Length; j++)
{
var entry = bundle.TableEntries[j];
builder.AppendLine($" Entry Table Entry {j}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
switch (bundle.BundleType & ~BundleType.ParameterTypingInformationPresent)
{
case BundleType.UnusedEntry:
builder.AppendLine(" Unused, empty entry");
break;
case BundleType.SixteenBitEntry:
builder.AppendLine(entry.SixteenBitObjectNumber, " Object number");
builder.AppendLine($" Entry flags: {entry.SixteenBitEntryFlags} (0x{entry.SixteenBitEntryFlags:X})");
builder.AppendLine(entry.SixteenBitOffset, " Offset");
break;
case BundleType.TwoEightySixCallGateEntry:
builder.AppendLine(entry.TwoEightySixObjectNumber, " Object number");
builder.AppendLine($" Entry flags: {entry.TwoEightySixEntryFlags} (0x{entry.TwoEightySixEntryFlags:X})");
builder.AppendLine(entry.TwoEightySixOffset, " Offset");
builder.AppendLine(entry.TwoEightySixCallgate, " Callgate");
break;
case BundleType.ThirtyTwoBitEntry:
builder.AppendLine(entry.ThirtyTwoBitObjectNumber, " Object number");
builder.AppendLine($" Entry flags: {entry.ThirtyTwoBitEntryFlags} (0x{entry.ThirtyTwoBitEntryFlags:X})");
builder.AppendLine(entry.ThirtyTwoBitOffset, " Offset");
break;
case BundleType.ForwarderEntry:
builder.AppendLine(entry.ForwarderReserved, " Reserved");
builder.AppendLine($" Forwarder flags: {entry.ForwarderFlags} (0x{entry.ForwarderFlags:X})");
builder.AppendLine(entry.ForwarderModuleOrdinalNumber, " Module ordinal number");
builder.AppendLine(entry.ProcedureNameOffset, " Procedure name offset");
builder.AppendLine(entry.ImportOrdinalNumber, " Import ordinal number");
break;
default:
builder.AppendLine($" Unknown entry type {bundle.BundleType}");
break;
}
}
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, ModuleFormatDirectivesTableEntry?[]? entries)
{
builder.AppendLine(" Module Format Directives Table Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No module format directives table entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Moduile Format Directives Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine($" Directive number: {entry.DirectiveNumber} (0x{entry.DirectiveNumber:X})");
builder.AppendLine(entry.DirectiveDataLength, " Directive data length");
builder.AppendLine(entry.DirectiveDataOffset, " Directive data offset");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, VerifyRecordDirectiveTableEntry?[]? entries)
{
builder.AppendLine(" Verify Record Directive Table Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No verify record directive table entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Verify Record Directive Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.EntryCount, " Entry count");
builder.AppendLine(entry.OrdinalIndex, " Ordinal index");
builder.AppendLine(entry.Version, " Version");
builder.AppendLine(entry.ObjectEntriesCount, " Object entries count");
builder.AppendLine(entry.ObjectNumberInModule, " Object number in module");
builder.AppendLine(entry.ObjectLoadBaseAddress, " Object load base address");
builder.AppendLine(entry.ObjectVirtualAddressSize, " Object virtual address size");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, FixupPageTableEntry?[]? entries)
{
builder.AppendLine(" Fix-up Page Table Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No fix-up page table entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Fix-up Page Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.Offset, " Offset");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, FixupRecordTableEntry?[]? entries)
{
builder.AppendLine(" Fix-up Record Table Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No fix-up record table entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Fix-up Record Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine($" Source type: {entry.SourceType} (0x{entry.SourceType:X})");
builder.AppendLine($" Target flags: {entry.TargetFlags} (0x{entry.TargetFlags:X})");
// Source list flag
#if NET20 || NET35
if ((entry.SourceType & FixupRecordSourceType.SourceListFlag) != 0)
#else
if (entry.SourceType.HasFlag(FixupRecordSourceType.SourceListFlag))
#endif
builder.AppendLine(entry.SourceOffsetListCount, " Source offset list count");
else
builder.AppendLine(entry.SourceOffset, " Source offset");
// OBJECT / TRGOFF
#if NET20 || NET35
if ((entry.TargetFlags & FixupRecordTargetFlags.InternalReference) != 0)
#else
if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.InternalReference))
#endif
{
// 16-bit Object Number/Module Ordinal Flag
#if NET20 || NET35
if ((entry.TargetFlags & FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag) != 0)
#else
if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag))
#endif
builder.AppendLine(entry.TargetObjectNumberWORD, " Target object number");
else
builder.AppendLine(entry.TargetObjectNumberByte, " Target object number");
// 16-bit Selector fixup
#if NET20 || NET35
if ((entry.SourceType & FixupRecordSourceType.SixteenBitSelectorFixup) != 0)
#else
if (!entry.SourceType.HasFlag(FixupRecordSourceType.SixteenBitSelectorFixup))
#endif
{
// 32-bit Target Offset Flag
#if NET20 || NET35
if ((entry.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag) != 0)
#else
if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag))
#endif
builder.AppendLine(entry.TargetOffsetDWORD, " Target offset");
else
builder.AppendLine(entry.TargetOffsetWORD, " Target offset");
}
}
// MOD ORD# / IMPORT ORD / ADDITIVE
#if NET20 || NET35
else if ((entry.TargetFlags & FixupRecordTargetFlags.ImportedReferenceByOrdinal) != 0)
#else
else if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.ImportedReferenceByOrdinal))
#endif
{
// 16-bit Object Number/Module Ordinal Flag
#if NET20 || NET35
if ((entry.TargetFlags & FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag) != 0)
#else
if (!entry.TargetFlags.HasFlag(FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag))
#endif
builder.AppendLine(entry.OrdinalIndexImportModuleNameTableWORD, " Ordinal index import module name table");
else
builder.AppendLine(entry.OrdinalIndexImportModuleNameTableByte, " Ordinal index import module name table");
// 8-bit Ordinal Flag & 32-bit Target Offset Flag
#if NET20 || NET35
if ((entry.TargetFlags & FixupRecordTargetFlags.EightBitOrdinalFlag) != 0)
#else
if (!entry.TargetFlags.HasFlag(FixupRecordTargetFlags.EightBitOrdinalFlag))
#endif
builder.AppendLine(entry.ImportedOrdinalNumberByte, " Imported ordinal number");
#if NET20 || NET35
else if ((entry.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag) != 0)
#else
else if (!entry.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag))
#endif
builder.AppendLine(entry.ImportedOrdinalNumberDWORD, " Imported ordinal number");
else
builder.AppendLine(entry.ImportedOrdinalNumberWORD, " Imported ordinal number");
// Additive Fixup Flag
#if NET20 || NET35
if ((entry.TargetFlags & FixupRecordTargetFlags.AdditiveFixupFlag) != 0)
#else
if (!entry.TargetFlags.HasFlag(FixupRecordTargetFlags.AdditiveFixupFlag))
#endif
{
// 32-bit Additive Flag
#if NET20 || NET35
if ((entry.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag) != 0)
#else
if (!entry.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag))
#endif
builder.AppendLine(entry.AdditiveFixupValueDWORD, " Additive fixup value");
else
builder.AppendLine(entry.AdditiveFixupValueWORD, " Additive fixup value");
}
}
// MOD ORD# / PROCEDURE NAME OFFSET / ADDITIVE
#if NET20 || NET35
else if ((entry.TargetFlags & FixupRecordTargetFlags.ImportedReferenceByName) != 0)
#else
else if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.ImportedReferenceByName))
#endif
{
// 16-bit Object Number/Module Ordinal Flag
#if NET20 || NET35
if ((entry.TargetFlags & FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag) != 0)
#else
if (!entry.TargetFlags.HasFlag(FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag))
#endif
builder.AppendLine(entry.OrdinalIndexImportModuleNameTableWORD, " Ordinal index import module name table");
else
builder.AppendLine(entry.OrdinalIndexImportModuleNameTableByte, " Ordinal index import module name table");
// 32-bit Target Offset Flag
#if NET20 || NET35
if ((entry.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag) != 0)
#else
if (!entry.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag))
#endif
builder.AppendLine(entry.OffsetImportProcedureNameTableDWORD, " Offset import procedure name table");
else
builder.AppendLine(entry.OffsetImportProcedureNameTableWORD, " Offset import procedure name table");
// Additive Fixup Flag
#if NET20 || NET35
if ((entry.TargetFlags & FixupRecordTargetFlags.AdditiveFixupFlag) != 0)
#else
if (!entry.TargetFlags.HasFlag(FixupRecordTargetFlags.AdditiveFixupFlag))
#endif
{
// 32-bit Additive Flag
#if NET20 || NET35
if ((entry.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag) != 0)
#else
if (!entry.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag))
#endif
builder.AppendLine(entry.AdditiveFixupValueDWORD, " Additive fixup value");
else
builder.AppendLine(entry.AdditiveFixupValueWORD, " Additive fixup value");
}
}
// ORD # / ADDITIVE
#if NET20 || NET35
else if ((entry.TargetFlags & FixupRecordTargetFlags.InternalReferenceViaEntryTable) != 0)
#else
else if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.InternalReferenceViaEntryTable))
#endif
{
// 16-bit Object Number/Module Ordinal Flag
#if NET20 || NET35
if ((entry.TargetFlags & FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag) != 0)
#else
if (!entry.TargetFlags.HasFlag(FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag))
#endif
builder.AppendLine(entry.TargetObjectNumberWORD, " Target object number");
else
builder.AppendLine(entry.TargetObjectNumberByte, " Target object number");
// Additive Fixup Flag
#if NET20 || NET35
if ((entry.TargetFlags & FixupRecordTargetFlags.AdditiveFixupFlag) != 0)
#else
if (!entry.TargetFlags.HasFlag(FixupRecordTargetFlags.AdditiveFixupFlag))
#endif
{
// 32-bit Additive Flag
#if NET20 || NET35
if ((entry.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag) != 0)
#else
if (!entry.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag))
#endif
builder.AppendLine(entry.AdditiveFixupValueDWORD, " Additive fixup value");
else
builder.AppendLine(entry.AdditiveFixupValueWORD, " Additive fixup value");
}
}
// No other top-level flags recognized
else
{
builder.AppendLine(" Unknown entry format");
}
builder.AppendLine();
builder.AppendLine(" Source Offset List:");
builder.AppendLine(" -------------------------");
if (entry.SourceOffsetList == null || entry.SourceOffsetList.Length == 0)
{
builder.AppendLine(" No source offset list entries");
}
else
{
for (int j = 0; j < entry.SourceOffsetList.Length; j++)
{
builder.AppendLine(entry.SourceOffsetList[j], $" Source Offset List Entry {j}");
}
}
builder.AppendLine();
}
}
private static void Print(StringBuilder builder, ImportModuleNameTableEntry?[]? entries)
{
builder.AppendLine(" Import Module Name Table Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No import module name table entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Import Module Name Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.Length, " Length");
builder.AppendLine(entry.Name, " Name");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, ImportModuleProcedureNameTableEntry?[]? entries)
{
builder.AppendLine(" Import Module Procedure Name Table Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No import module procedure name table entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Import Module Procedure Name Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.Length, " Length");
builder.AppendLine(entry.Name, " Name");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, PerPageChecksumTableEntry?[]? entries)
{
builder.AppendLine(" Per-Page Checksum Table Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No per-page checksum table entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Per-Page Checksum Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.Checksum, " Checksum");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, NonResidentNamesTableEntry?[]? entries)
{
builder.AppendLine(" Non-Resident Names Table Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No non-resident names table entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Non-Resident Names Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.Length, " Length");
builder.AppendLine(entry.Name, " Name");
builder.AppendLine(entry.OrdinalNumber, " Ordinal number");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, DebugInformation? di)
{
builder.AppendLine(" Debug Information:");
builder.AppendLine(" -------------------------");
if (di == null)
{
builder.AppendLine(" No debug information");
builder.AppendLine();
return;
}
builder.AppendLine(di.Signature, " Signature");
builder.AppendLine($" Format type: {di.FormatType} (0x{di.FormatType:X})");
// Debugger data
builder.AppendLine();
}
}
}

View File

@@ -0,0 +1,78 @@
using System.Text;
using SabreTools.Models.MSDOS;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class MSDOS : IPrinter<Executable>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, Executable model)
=> Print(builder, model);
public static void Print(StringBuilder builder, Executable executable)
{
builder.AppendLine("MS-DOS Executable Information:");
builder.AppendLine("-------------------------");
builder.AppendLine();
Print(builder, executable.Header);
Print(builder, executable.RelocationTable);
}
private static void Print(StringBuilder builder, ExecutableHeader? header)
{
builder.AppendLine(" Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Magic, " Magic number");
builder.AppendLine(header.LastPageBytes, " Last page bytes");
builder.AppendLine(header.Pages, " Pages");
builder.AppendLine(header.RelocationItems, " Relocation items");
builder.AppendLine(header.HeaderParagraphSize, " Header paragraph size");
builder.AppendLine(header.MinimumExtraParagraphs, " Minimum extra paragraphs");
builder.AppendLine(header.MaximumExtraParagraphs, " Maximum extra paragraphs");
builder.AppendLine(header.InitialSSValue, " Initial SS value");
builder.AppendLine(header.InitialSPValue, " Initial SP value");
builder.AppendLine(header.Checksum, " Checksum");
builder.AppendLine(header.InitialIPValue, " Initial IP value");
builder.AppendLine(header.InitialCSValue, " Initial CS value");
builder.AppendLine(header.RelocationTableAddr, " Relocation table address");
builder.AppendLine(header.OverlayNumber, " Overlay number");
builder.AppendLine();
}
private static void Print(StringBuilder builder, RelocationEntry?[]? entries)
{
builder.AppendLine(" Relocation Table Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No relocation table items");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Relocation Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.Offset, " Offset");
builder.AppendLine(entry.Segment, " Segment");
}
builder.AppendLine();
}
}
}

View File

@@ -0,0 +1,172 @@
using System.Text;
using SabreTools.Models.MicrosoftCabinet;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class MicrosoftCabinet : IPrinter<Cabinet>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, Cabinet model)
=> Print(builder, model);
public static void Print(StringBuilder builder, Cabinet cabinet)
{
builder.AppendLine("Microsoft Cabinet Information:");
builder.AppendLine("-------------------------");
builder.AppendLine();
Print(builder, cabinet.Header);
Print(builder, cabinet.Folders);
Print(builder, cabinet.Files);
}
private static void Print(StringBuilder builder, CFHEADER? header)
{
builder.AppendLine(" Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Signature, " Signature");
builder.AppendLine(header.Reserved1, " Reserved 1");
builder.AppendLine(header.CabinetSize, " Cabinet size");
builder.AppendLine(header.Reserved2, " Reserved 2");
builder.AppendLine(header.FilesOffset, " Files offset");
builder.AppendLine(header.Reserved3, " Reserved 3");
builder.AppendLine(header.VersionMinor, " Minor version");
builder.AppendLine(header.VersionMajor, " Major version");
builder.AppendLine(header.FolderCount, " Folder count");
builder.AppendLine(header.FileCount, " File count");
builder.AppendLine($" Flags: {header.Flags} (0x{header.Flags:X})");
builder.AppendLine(header.SetID, " Set ID");
builder.AppendLine(header.CabinetIndex, " Cabinet index");
#if NET20 || NET35
if ((header.Flags & HeaderFlags.RESERVE_PRESENT) != 0)
#else
if (header.Flags.HasFlag(HeaderFlags.RESERVE_PRESENT))
#endif
{
builder.AppendLine(header.HeaderReservedSize, " Header reserved size");
builder.AppendLine(header.FolderReservedSize, " Folder reserved size");
builder.AppendLine(header.DataReservedSize, " Data reserved size");
builder.AppendLine(header.ReservedData, " Reserved data");
}
#if NET20 || NET35
if ((header.Flags & HeaderFlags.PREV_CABINET) != 0)
#else
if (header.Flags.HasFlag(HeaderFlags.PREV_CABINET))
#endif
{
builder.AppendLine(header.CabinetPrev, " Previous cabinet");
builder.AppendLine(header.DiskPrev, " Previous disk");
}
#if NET20 || NET35
if ((header.Flags & HeaderFlags.NEXT_CABINET) != 0)
#else
if (header.Flags.HasFlag(HeaderFlags.NEXT_CABINET))
#endif
{
builder.AppendLine(header.CabinetNext, " Next cabinet");
builder.AppendLine(header.DiskNext, " Next disk");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, CFFOLDER?[]? entries)
{
builder.AppendLine(" Folders:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No folders");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Folder {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.CabStartOffset, " Cab start offset");
builder.AppendLine(entry.DataCount, " Data count");
builder.AppendLine($" Compression type: {entry.CompressionType} (0x{entry.CompressionType:X})");
builder.AppendLine($" Masked compression type: {entry.CompressionType & CompressionType.MASK_TYPE}");
builder.AppendLine(entry.ReservedData, " Reserved data");
builder.AppendLine();
builder.AppendLine(" Data Blocks");
builder.AppendLine(" -------------------------");
if (entry.DataBlocks == null || entry.DataBlocks.Length == 0)
{
builder.AppendLine(" No data blocks");
continue;
}
for (int j = 0; j < entry.DataBlocks.Length; j++)
{
var dataBlock = entry.DataBlocks[j];
builder.AppendLine($" Data Block {j}");
if (dataBlock == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(dataBlock.Checksum, " Checksum");
builder.AppendLine(dataBlock.CompressedSize, " Compressed size");
builder.AppendLine(dataBlock.UncompressedSize, " Uncompressed size");
builder.AppendLine(dataBlock.ReservedData, " Reserved data");
//builder.AppendLine(dataBlock.CompressedData, " Compressed data");
}
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, CFFILE?[]? entries)
{
builder.AppendLine(" Files:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No files");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" File {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.FileSize, " File size");
builder.AppendLine(entry.FolderStartOffset, " Folder start offset");
builder.AppendLine($" Folder index: {entry.FolderIndex} (0x{entry.FolderIndex:X})");
builder.AppendLine(entry.Date, " Date");
builder.AppendLine(entry.Time, " Time");
builder.AppendLine($" Attributes: {entry.Attributes} (0x{entry.Attributes:X})");
builder.AppendLine(entry.Name, " Name");
}
builder.AppendLine();
}
}
}

View File

@@ -0,0 +1,243 @@
using System.Text;
using SabreTools.Models.MoPaQ;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class MoPaQ : IPrinter<Archive>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, Archive model)
=> Print(builder, model);
public static void Print(StringBuilder builder, Archive archive)
{
builder.AppendLine("MoPaQ Archive Information:");
builder.AppendLine("-------------------------");
builder.AppendLine();
Print(builder, archive.UserData);
Print(builder, archive.ArchiveHeader);
Print(builder, archive.HetTable);
Print(builder, archive.BetTable);
Print(builder, archive.HashTable);
Print(builder, archive.BlockTable);
Print(builder, archive.HiBlockTable);
}
private static void Print(StringBuilder builder, UserData? userData)
{
builder.AppendLine(" User Data Information:");
builder.AppendLine(" -------------------------");
if (userData == null)
{
builder.AppendLine(" No user data");
builder.AppendLine();
return;
}
builder.AppendLine(userData.Signature, " Signature");
builder.AppendLine(userData.UserDataSize, " User data size");
builder.AppendLine(userData.HeaderOffset, " Header offset");
builder.AppendLine(userData.UserDataHeaderSize, " User data header size");
builder.AppendLine();
}
private static void Print(StringBuilder builder, ArchiveHeader? header)
{
builder.AppendLine(" Archive Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No archive header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Signature, " Signature");
builder.AppendLine(header.HeaderSize, " Header size");
builder.AppendLine(header.ArchiveSize, " Archive size");
builder.AppendLine($" Format version: {header.FormatVersion} (0x{header.FormatVersion:X})");
builder.AppendLine(header.BlockSize, " Block size");
builder.AppendLine(header.HashTablePosition, " Hash table position");
builder.AppendLine(header.BlockTablePosition, " Block table position");
builder.AppendLine(header.HashTableSize, " Hash table size");
builder.AppendLine(header.BlockTableSize, " Block table size");
builder.AppendLine(header.HiBlockTablePosition, " Hi-block table position");
builder.AppendLine(header.HashTablePositionHi, " Hash table position hi");
builder.AppendLine(header.BlockTablePositionHi, " Block table position hi");
builder.AppendLine(header.ArchiveSizeLong, " Archive size long");
builder.AppendLine(header.BetTablePosition, " BET table position");
builder.AppendLine(header.HetTablePosition, " HET table position");
builder.AppendLine(header.HashTableSizeLong, " Hash table size long");
builder.AppendLine(header.BlockTableSizeLong, " Block table size long");
builder.AppendLine(header.HiBlockTableSize, " Hi-block table size");
builder.AppendLine(header.HetTableSize, " HET table size");
builder.AppendLine(header.BetTablesize, " BET table size"); // TODO: Fix casing
builder.AppendLine(header.RawChunkSize, " Raw chunk size");
builder.AppendLine(header.BlockTableMD5, " Block table MD5");
builder.AppendLine(header.HashTableMD5, " Hash table MD5");
builder.AppendLine(header.HiBlockTableMD5, " Hi-block table MD5");
builder.AppendLine(header.BetTableMD5, " BET table MD5");
builder.AppendLine(header.HetTableMD5, " HET table MD5");
builder.AppendLine(header.MpqHeaderMD5, " MPQ header MD5");
builder.AppendLine();
}
private static void Print(StringBuilder builder, HetTable? table)
{
builder.AppendLine(" HET Table Information:");
builder.AppendLine(" -------------------------");
if (table == null)
{
builder.AppendLine(" No HET table");
builder.AppendLine();
return;
}
builder.AppendLine(table.Signature, " Signature");
builder.AppendLine(table.Version, " Version");
builder.AppendLine(table.DataSize, " Data size");
builder.AppendLine(table.TableSize, " Table size");
builder.AppendLine(table.MaxFileCount, " Max file count");
builder.AppendLine(table.HashTableSize, " Hash table size");
builder.AppendLine(table.HashEntrySize, " Hash entry size");
builder.AppendLine(table.TotalIndexSize, " Total index size");
builder.AppendLine(table.IndexSizeExtra, " Index size extra");
builder.AppendLine(table.IndexSize, " Index size");
builder.AppendLine(table.BlockTableSize, " Block table size");
builder.AppendLine(table.HashTable, " Hash table");
builder.AppendLine(" File indexes:");
builder.AppendLine(" -------------------------");
if (table.FileIndexes == null)
{
builder.AppendLine(" No file indexes ");
}
else
{
for (int i = 0; i < table.FileIndexes.Length; i++)
{
builder.AppendLine(table.FileIndexes[i], $" File index {i}");
}
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, BetTable? table)
{
builder.AppendLine(" BET Table Information:");
builder.AppendLine(" -------------------------");
if (table == null)
{
builder.AppendLine(" No BET table");
builder.AppendLine();
return;
}
builder.AppendLine(table.Signature, " Signature");
builder.AppendLine(table.Version, " Version");
builder.AppendLine(table.DataSize, " Data size");
builder.AppendLine(table.TableSize, " Table size");
builder.AppendLine(table.FileCount, " File count");
builder.AppendLine(table.Unknown, " Unknown");
builder.AppendLine(table.TableEntrySize, " Table entry size");
builder.AppendLine(table.FilePositionBitIndex, " File position bit index");
builder.AppendLine(table.FileSizeBitIndex, " File size bit index");
builder.AppendLine(table.CompressedSizeBitIndex, " Compressed size bit index");
builder.AppendLine(table.FlagIndexBitIndex, " Flag index bit index");
builder.AppendLine(table.UnknownBitIndex, " Unknown bit index");
builder.AppendLine(table.FilePositionBitCount, " File position bit count");
builder.AppendLine(table.FileSizeBitCount, " File size bit count");
builder.AppendLine(table.CompressedSizeBitCount, " Compressed size bit count");
builder.AppendLine(table.FlagIndexBitCount, " Flag index bit count");
builder.AppendLine(table.UnknownBitCount, " Unknown bit count");
builder.AppendLine(table.TotalBetHashSize, " Total BET hash size");
builder.AppendLine(table.BetHashSizeExtra, " BET hash size extra");
builder.AppendLine(table.BetHashSize, " BET hash size");
builder.AppendLine(table.BetHashArraySize, " BET hash array size");
builder.AppendLine(table.FlagCount, " Flag count");
builder.AppendLine(table.FlagsArray, " Flags array");
builder.AppendLine();
}
private static void Print(StringBuilder builder, HashEntry?[]? entries)
{
builder.AppendLine(" Hash Table Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No hash table items");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Hash Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.NameHashPartA, " Name hash, part A");
builder.AppendLine(entry.NameHashPartB, " Name hash, part B");
builder.AppendLine($" Locale: {entry.Locale} (0x{entry.Locale:X})");
builder.AppendLine(entry.Platform, " Platform");
builder.AppendLine(entry.BlockIndex, " BlockIndex");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, BlockEntry?[]? entries)
{
builder.AppendLine(" Block Table Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No block table items");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Block Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.FilePosition, " File position");
builder.AppendLine(entry.CompressedSize, " Compressed size");
builder.AppendLine(entry.UncompressedSize, " Uncompressed size");
builder.AppendLine($" Flags: {entry.Flags} (0x{entry.Flags:X})");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, short[]? entries)
{
builder.AppendLine(" Hi-block Table Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No hi-block table items");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Hi-block Table Entry {i}: {entry}");
}
builder.AppendLine();
}
}
}

View File

@@ -0,0 +1,695 @@
using System;
using System.Text;
using SabreTools.Models.N3DS;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class N3DS : IPrinter<Cart>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, Cart model)
=> Print(builder, model);
public static void Print(StringBuilder builder, Cart cart)
{
builder.AppendLine("3DS Cart Information:");
builder.AppendLine("-------------------------");
builder.AppendLine();
Print(builder, cart.Header);
Print(builder, cart.CardInfoHeader);
Print(builder, cart.DevelopmentCardInfoHeader);
Print(builder, cart.Partitions);
Print(builder, cart.ExtendedHeaders);
Print(builder, cart.ExeFSHeaders);
Print(builder, cart.RomFSHeaders);
}
private static void Print(StringBuilder builder, NCSDHeader? header)
{
builder.AppendLine(" NCSD Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No NCSD header");
builder.AppendLine();
return;
}
builder.AppendLine(header.RSA2048Signature, " RSA-2048 SHA-256 signature");
builder.AppendLine(header.MagicNumber, " Magic number");
builder.AppendLine(header.ImageSizeInMediaUnits, " Image size in media units");
builder.AppendLine(header.MediaId, " Media ID");
builder.AppendLine($" Partitions filesystem type: {header.PartitionsFSType} (0x{header.PartitionsFSType:X})");
builder.AppendLine(header.PartitionsCryptType, " Partitions crypt type");
builder.AppendLine();
builder.AppendLine(" Partition table:");
builder.AppendLine(" -------------------------");
if (header.PartitionsTable == null || header.PartitionsTable.Length == 0)
{
builder.AppendLine(" No partition table entries");
}
else
{
for (int i = 0; i < header.PartitionsTable.Length; i++)
{
var partitionTableEntry = header.PartitionsTable[i];
builder.AppendLine($" Partition table entry {i}");
if (partitionTableEntry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(partitionTableEntry.Offset, " Offset");
builder.AppendLine(partitionTableEntry.Length, " Length");
}
}
builder.AppendLine();
// If we have a cart image
if (header.PartitionsFSType == FilesystemType.Normal || header.PartitionsFSType == FilesystemType.None)
{
builder.AppendLine(header.ExheaderHash, " Exheader SHA-256 hash");
builder.AppendLine(header.AdditionalHeaderSize, " Additional header size");
builder.AppendLine(header.SectorZeroOffset, " Sector zero offset");
builder.AppendLine(header.PartitionFlags, " Partition flags");
builder.AppendLine();
builder.AppendLine(" Partition ID table:");
builder.AppendLine(" -------------------------");
if (header.PartitionIdTable == null || header.PartitionIdTable.Length == 0)
{
builder.AppendLine(" No partition ID table entries");
}
else
{
for (int i = 0; i < header.PartitionIdTable.Length; i++)
{
builder.AppendLine(header.PartitionIdTable[i], $" Partition {i} ID");
}
}
builder.AppendLine();
builder.AppendLine(header.Reserved1, " Reserved 1");
builder.AppendLine(header.Reserved2, " Reserved 2");
builder.AppendLine(header.FirmUpdateByte1, " Firmware update byte 1");
builder.AppendLine(header.FirmUpdateByte2, " Firmware update byte 2");
}
// If we have a firmware image
else if (header.PartitionsFSType == FilesystemType.FIRM)
{
builder.AppendLine(header.Unknown, " Unknown");
builder.AppendLine(header.EncryptedMBR, " Encrypted MBR");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, CardInfoHeader? header)
{
builder.AppendLine(" Card Info Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No card info header");
builder.AppendLine();
return;
}
builder.AppendLine(header.WritableAddressMediaUnits, " Writable address in media units");
builder.AppendLine(header.CardInfoBitmask, " Card info bitmask");
builder.AppendLine(header.Reserved1, " Reserved 1");
builder.AppendLine(header.FilledSize, " Filled size of cartridge");
builder.AppendLine(header.Reserved2, " Reserved 2");
builder.AppendLine(header.TitleVersion, " Title version");
builder.AppendLine(header.CardRevision, " Card revision");
builder.AppendLine(header.Reserved3, " Reserved 3");
builder.AppendLine(header.CVerTitleID, " Title ID of CVer in included update partition");
builder.AppendLine(header.CVerVersionNumber, " Version number of CVer in included update partition");
builder.AppendLine(header.Reserved4, " Reserved 4");
builder.AppendLine();
Print(builder, header.InitialData);
}
private static void Print(StringBuilder builder, DevelopmentCardInfoHeader? header)
{
builder.AppendLine(" Development Card Info Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No development card info header");
builder.AppendLine();
return;
}
builder.AppendLine(header.CardDeviceReserved1, " Card device reserved 1");
builder.AppendLine(header.TitleKey, " Title key");
builder.AppendLine(header.CardDeviceReserved2, " Card device reserved 2");
builder.AppendLine();
builder.AppendLine(" Test Data:");
builder.AppendLine(" -------------------------");
if (header.TestData == null)
{
builder.AppendLine(" No test data");
}
else
{
builder.AppendLine(header.TestData.Signature, " Signature");
builder.AppendLine(header.TestData.AscendingByteSequence, " Ascending byte sequence");
builder.AppendLine(header.TestData.DescendingByteSequence, " Descending byte sequence");
builder.AppendLine(header.TestData.Filled00, " Filled with 00");
builder.AppendLine(header.TestData.FilledFF, " Filled with FF");
builder.AppendLine(header.TestData.Filled0F, " Filled with 0F");
builder.AppendLine(header.TestData.FilledF0, " Filled with F0");
builder.AppendLine(header.TestData.Filled55, " Filled with 55");
builder.AppendLine(header.TestData.FilledAA, " Filled with AA");
builder.AppendLine(header.TestData.FinalByte, " Final byte");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, InitialData? id)
{
builder.AppendLine(" Initial Data Information:");
builder.AppendLine(" -------------------------");
if (id == null)
{
builder.AppendLine(" No initial data");
builder.AppendLine();
return;
}
builder.AppendLine(id.CardSeedKeyY, " Card seed KeyY");
builder.AppendLine(id.EncryptedCardSeed, " Encrypted card seed");
builder.AppendLine(id.CardSeedAESMAC, " Card seed AES-MAC");
builder.AppendLine(id.CardSeedNonce, " Card seed nonce");
builder.AppendLine(id.Reserved, " Reserved");
builder.AppendLine();
PrintBackup(builder, id.BackupHeader);
}
private static void PrintBackup(StringBuilder builder, NCCHHeader? header)
{
builder.AppendLine(" Backup NCCH Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No backup NCCH header");
builder.AppendLine();
return;
}
if (header.MagicID == string.Empty)
{
builder.AppendLine(" Empty backup header, no data can be parsed");
}
else if (header.MagicID != Constants.NCCHMagicNumber)
{
builder.AppendLine(" Unrecognized backup header, no data can be parsed");
}
else
{
// Backup header omits RSA signature
builder.AppendLine(header.MagicID, " Magic ID");
builder.AppendLine(header.ContentSizeInMediaUnits, " Content size in media units");
builder.AppendLine(header.PartitionId, " Partition ID");
builder.AppendLine(header.MakerCode, " Maker code");
builder.AppendLine(header.Version, " Version");
builder.AppendLine(header.VerificationHash, " Verification hash");
builder.AppendLine(header.ProgramId, " Program ID");
builder.AppendLine(header.Reserved1, " Reserved 1");
builder.AppendLine(header.LogoRegionHash, " Logo region SHA-256 hash");
builder.AppendLine(header.ProductCode, " Product code");
builder.AppendLine(header.ExtendedHeaderHash, " Extended header SHA-256 hash");
builder.AppendLine(header.ExtendedHeaderSizeInBytes, " Extended header size in bytes");
builder.AppendLine(header.Reserved2, " Reserved 2");
builder.AppendLine(" Flags:");
if (header.Flags == null)
{
builder.AppendLine(" [NULL]");
}
else
{
builder.AppendLine(header.Flags.Reserved0, " Reserved 0");
builder.AppendLine(header.Flags.Reserved1, " Reserved 1");
builder.AppendLine(header.Flags.Reserved2, " Reserved 2");
builder.AppendLine($" Crypto method: {header.Flags.CryptoMethod} (0x{header.Flags.CryptoMethod:X})");
builder.AppendLine($" Content platform: {header.Flags.ContentPlatform} (0x{header.Flags.ContentPlatform:X})");
builder.AppendLine($" Content type: {header.Flags.MediaPlatformIndex} (0x{header.Flags.MediaPlatformIndex:X})");
builder.AppendLine(header.Flags.ContentUnitSize, " Content unit size");
builder.AppendLine($" Bitmasks: {header.Flags.BitMasks} (0x{header.Flags.BitMasks:X})");
}
builder.AppendLine(header.PlainRegionOffsetInMediaUnits, " Plain region offset, in media units");
builder.AppendLine(header.PlainRegionSizeInMediaUnits, " Plain region size, in media units");
builder.AppendLine(header.LogoRegionOffsetInMediaUnits, " Logo region offset, in media units");
builder.AppendLine(header.LogoRegionSizeInMediaUnits, " Logo region size, in media units");
builder.AppendLine(header.ExeFSOffsetInMediaUnits, " ExeFS offset, in media units");
builder.AppendLine(header.ExeFSSizeInMediaUnits, " ExeFS size, in media units");
builder.AppendLine(header.ExeFSHashRegionSizeInMediaUnits, " ExeFS hash region size, in media units");
builder.AppendLine(header.Reserved3, " Reserved 3");
builder.AppendLine(header.RomFSOffsetInMediaUnits, " RomFS offset, in media units");
builder.AppendLine(header.RomFSSizeInMediaUnits, " RomFS size, in media units");
builder.AppendLine(header.RomFSHashRegionSizeInMediaUnits, " RomFS hash region size, in media units");
builder.AppendLine(header.Reserved4, " Reserved 4");
builder.AppendLine(header.ExeFSSuperblockHash, " ExeFS superblock SHA-256 hash");
builder.AppendLine(header.RomFSSuperblockHash, " RomFS superblock SHA-256 hash");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, NCCHHeader?[]? entries)
{
builder.AppendLine(" NCCH Partition Header Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No NCCH partition headers");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" NCCH Partition Header {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
if (entry.MagicID == string.Empty)
{
builder.AppendLine(" Empty partition, no data can be parsed");
}
else if (entry.MagicID != Constants.NCCHMagicNumber)
{
builder.AppendLine(" Unrecognized partition data, no data can be parsed");
}
else
{
builder.AppendLine(entry.RSA2048Signature, " RSA-2048 SHA-256 signature");
builder.AppendLine(entry.MagicID, " Magic ID");
builder.AppendLine(entry.ContentSizeInMediaUnits, " Content size in media units");
builder.AppendLine(entry.PartitionId, " Partition ID");
builder.AppendLine(entry.MakerCode, " Maker code");
builder.AppendLine(entry.Version, " Version");
builder.AppendLine(entry.VerificationHash, " Verification hash");
builder.AppendLine(entry.ProgramId, " Program ID");
builder.AppendLine(entry.Reserved1, " Reserved 1");
builder.AppendLine(entry.LogoRegionHash, " Logo region SHA-256 hash");
builder.AppendLine(entry.ProductCode, " Product code");
builder.AppendLine(entry.ExtendedHeaderHash, " Extended header SHA-256 hash");
builder.AppendLine(entry.ExtendedHeaderSizeInBytes, " Extended header size in bytes");
builder.AppendLine(entry.Reserved2, " Reserved 2");
builder.AppendLine(" Flags:");
if (entry.Flags == null)
{
builder.AppendLine(" [NULL]");
}
else
{
builder.AppendLine(entry.Flags.Reserved0, " Reserved 0");
builder.AppendLine(entry.Flags.Reserved1, " Reserved 1");
builder.AppendLine(entry.Flags.Reserved2, " Reserved 2");
builder.AppendLine($" Crypto method: {entry.Flags.CryptoMethod} (0x{entry.Flags.CryptoMethod:X})");
builder.AppendLine($" Content platform: {entry.Flags.ContentPlatform} (0x{entry.Flags.ContentPlatform:X})");
builder.AppendLine($" Content type: {entry.Flags.MediaPlatformIndex} (0x{entry.Flags.MediaPlatformIndex:X})");
builder.AppendLine(entry.Flags.ContentUnitSize, " Content unit size");
builder.AppendLine($" Bitmasks: {entry.Flags.BitMasks} (0x{entry.Flags.BitMasks:X})");
}
builder.AppendLine(entry.PlainRegionOffsetInMediaUnits, " Plain region offset, in media units");
builder.AppendLine(entry.PlainRegionSizeInMediaUnits, " Plain region size, in media units");
builder.AppendLine(entry.LogoRegionOffsetInMediaUnits, " Logo region offset, in media units");
builder.AppendLine(entry.LogoRegionSizeInMediaUnits, " Logo region size, in media units");
builder.AppendLine(entry.ExeFSOffsetInMediaUnits, " ExeFS offset, in media units");
builder.AppendLine(entry.ExeFSSizeInMediaUnits, " ExeFS size, in media units");
builder.AppendLine(entry.ExeFSHashRegionSizeInMediaUnits, " ExeFS hash region size, in media units");
builder.AppendLine(entry.Reserved3, " Reserved 3");
builder.AppendLine(entry.RomFSOffsetInMediaUnits, " RomFS offset, in media units");
builder.AppendLine(entry.RomFSSizeInMediaUnits, " RomFS size, in media units");
builder.AppendLine(entry.RomFSHashRegionSizeInMediaUnits, " RomFS hash region size, in media units");
builder.AppendLine(entry.Reserved4, " Reserved 4");
builder.AppendLine(entry.ExeFSSuperblockHash, " ExeFS superblock SHA-256 hash");
builder.AppendLine(entry.RomFSSuperblockHash, " RomFS superblock SHA-256 hash");
}
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, NCCHExtendedHeader?[]? entries)
{
builder.AppendLine(" NCCH Extended Header Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No NCCH extended headers");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" NCCH Extended Header {i}");
if (entry == null)
{
builder.AppendLine(" Unrecognized partition data, no data can be parsed");
continue;
}
builder.AppendLine(" System control info:");
if (entry.SCI == null)
{
builder.AppendLine(" [NULL]");
}
else
{
builder.AppendLine(entry.SCI.ApplicationTitle, " Application title");
builder.AppendLine(entry.SCI.Reserved1, " Reserved 1");
builder.AppendLine(entry.SCI.Flag, " Flag");
builder.AppendLine(entry.SCI.RemasterVersion, " Remaster version");
builder.AppendLine(" Text code set info:");
if (entry.SCI.TextCodeSetInfo == null)
{
builder.AppendLine(" [NULL]");
}
else
{
builder.AppendLine(entry.SCI.TextCodeSetInfo.Address, " Address");
builder.AppendLine(entry.SCI.TextCodeSetInfo.PhysicalRegionSizeInPages, " Physical region size (in page-multiples)");
builder.AppendLine(entry.SCI.TextCodeSetInfo.SizeInBytes, " Size (in bytes)");
}
builder.AppendLine(entry.SCI.StackSize, " Stack size");
builder.AppendLine(" Read-only code set info:");
if (entry.SCI.ReadOnlyCodeSetInfo == null)
{
builder.AppendLine(" [NULL]");
}
else
{
builder.AppendLine(entry.SCI.ReadOnlyCodeSetInfo.Address, " Address");
builder.AppendLine(entry.SCI.ReadOnlyCodeSetInfo.PhysicalRegionSizeInPages, " Physical region size (in page-multiples)");
builder.AppendLine(entry.SCI.ReadOnlyCodeSetInfo.SizeInBytes, " Size (in bytes)");
}
builder.AppendLine(entry.SCI.Reserved2, " Reserved 2");
builder.AppendLine(" Data code set info:");
if (entry.SCI.DataCodeSetInfo == null)
{
builder.AppendLine(" [NULL]");
}
else
{
builder.AppendLine(entry.SCI.DataCodeSetInfo.Address, " Address");
builder.AppendLine(entry.SCI.DataCodeSetInfo.PhysicalRegionSizeInPages, " Physical region size (in page-multiples)");
builder.AppendLine(entry.SCI.DataCodeSetInfo.SizeInBytes, " Size (in bytes)");
}
builder.AppendLine(entry.SCI.BSSSize, " BSS size");
builder.AppendLine(entry.SCI.DependencyModuleList, " Dependency module list");
builder.AppendLine(" System info:");
if (entry.SCI.SystemInfo == null)
{
builder.AppendLine(" [NULL]");
}
else
{
builder.AppendLine(entry.SCI.SystemInfo.SaveDataSize, " SaveData size");
builder.AppendLine(entry.SCI.SystemInfo.JumpID, " Jump ID");
builder.AppendLine(entry.SCI.SystemInfo.Reserved, " Reserved");
}
}
builder.AppendLine(" Access control info:");
if (entry.ACI == null)
{
builder.AppendLine(" [NULL]");
}
else
{
builder.AppendLine(" ARM11 local system capabilities:");
if (entry.ACI.ARM11LocalSystemCapabilities == null)
{
builder.AppendLine(" [NULL]");
}
else
{
builder.AppendLine(entry.ACI.ARM11LocalSystemCapabilities.ProgramID, " Program ID");
builder.AppendLine(entry.ACI.ARM11LocalSystemCapabilities.CoreVersion, " Core version");
builder.AppendLine($" Flag 1: {entry.ACI.ARM11LocalSystemCapabilities.Flag1} (0x{entry.ACI.ARM11LocalSystemCapabilities.Flag1:X})");
builder.AppendLine($" Flag 2: {entry.ACI.ARM11LocalSystemCapabilities.Flag2} (0x{entry.ACI.ARM11LocalSystemCapabilities.Flag2:X})");
builder.AppendLine($" Flag 0: {entry.ACI.ARM11LocalSystemCapabilities.Flag0} (0x{entry.ACI.ARM11LocalSystemCapabilities.Flag0:X})");
builder.AppendLine(entry.ACI.ARM11LocalSystemCapabilities.Priority, " Priority");
builder.AppendLine(entry.ACI.ARM11LocalSystemCapabilities.ResourceLimitDescriptors, " Resource limit descriptors");
builder.AppendLine(" Storage info:");
if (entry.ACI.ARM11LocalSystemCapabilities.StorageInfo == null)
{
builder.AppendLine(" [NULL]");
}
else
{
builder.AppendLine(entry.ACI.ARM11LocalSystemCapabilities.StorageInfo.ExtdataID, " Extdata ID");
builder.AppendLine(entry.ACI.ARM11LocalSystemCapabilities.StorageInfo.SystemSavedataIDs, " System savedata IDs");
builder.AppendLine(entry.ACI.ARM11LocalSystemCapabilities.StorageInfo.StorageAccessibleUniqueIDs, " Storage accessible unique IDs");
builder.AppendLine(entry.ACI.ARM11LocalSystemCapabilities.StorageInfo.FileSystemAccessInfo, " File system access info");
builder.AppendLine($" Other attributes: {entry.ACI.ARM11LocalSystemCapabilities.StorageInfo.OtherAttributes} (0x{entry.ACI.ARM11LocalSystemCapabilities.StorageInfo.OtherAttributes:X})");
}
builder.AppendLine(entry.ACI.ARM11LocalSystemCapabilities.ServiceAccessControl, " Service access control");
builder.AppendLine(entry.ACI.ARM11LocalSystemCapabilities.ExtendedServiceAccessControl, " Extended service access control");
builder.AppendLine(entry.ACI.ARM11LocalSystemCapabilities.Reserved, " Reserved");
builder.AppendLine($" Resource limit cateogry: {entry.ACI.ARM11LocalSystemCapabilities.ResourceLimitCategory} (0x{entry.ACI.ARM11LocalSystemCapabilities.ResourceLimitCategory:X})");
}
builder.AppendLine(" ARM11 kernel capabilities:");
if (entry.ACI.ARM11KernelCapabilities == null)
{
builder.AppendLine(" [NULL]");
}
else
{
builder.AppendLine(entry.ACI.ARM11KernelCapabilities.Descriptors, " Descriptors");
builder.AppendLine(entry.ACI.ARM11KernelCapabilities.Reserved, " Reserved");
}
builder.AppendLine(" ARM9 access control:");
if (entry.ACI.ARM9AccessControl == null)
{
builder.AppendLine(" [NULL]");
}
else
{
string descriptorsStr = "[NULL]";
if (entry.ACI.ARM9AccessControl.Descriptors != null)
{
var descriptors = Array.ConvertAll(entry.ACI.ARM9AccessControl.Descriptors, d => d.ToString());
descriptorsStr = string.Join(", ", descriptors);
}
builder.AppendLine(descriptorsStr, " Descriptors");
builder.AppendLine(entry.ACI.ARM9AccessControl.DescriptorVersion, " Descriptor version");
}
}
builder.AppendLine(entry.AccessDescSignature, " AccessDec signature (RSA-2048-SHA256)");
builder.AppendLine(entry.NCCHHDRPublicKey, " NCCH HDR RSA-2048 public key");
builder.AppendLine(" Access control info (for limitations of first ACI):");
if (entry.ACIForLimitations == null)
{
builder.AppendLine(" [NULL]");
}
else
{
builder.AppendLine(" ARM11 local system capabilities:");
if (entry.ACIForLimitations.ARM11LocalSystemCapabilities == null)
{
builder.AppendLine(" [NULL]");
}
else
{
builder.AppendLine(entry.ACIForLimitations.ARM11LocalSystemCapabilities.ProgramID, " Program ID");
builder.AppendLine(entry.ACIForLimitations.ARM11LocalSystemCapabilities.CoreVersion, " Core version");
builder.AppendLine($" Flag 1: {entry.ACIForLimitations.ARM11LocalSystemCapabilities.Flag1} (0x{entry.ACIForLimitations.ARM11LocalSystemCapabilities.Flag1:X})");
builder.AppendLine($" Flag 2: {entry.ACIForLimitations.ARM11LocalSystemCapabilities.Flag2} (0x{entry.ACIForLimitations.ARM11LocalSystemCapabilities.Flag2:X})");
builder.AppendLine($" Flag 0: {entry.ACIForLimitations.ARM11LocalSystemCapabilities.Flag0} (0x{entry.ACIForLimitations.ARM11LocalSystemCapabilities.Flag0:X})");
builder.AppendLine(entry.ACIForLimitations.ARM11LocalSystemCapabilities.Priority, " Priority");
builder.AppendLine(entry.ACIForLimitations.ARM11LocalSystemCapabilities.ResourceLimitDescriptors, " Resource limit descriptors");
builder.AppendLine(" Storage info:");
if (entry.ACIForLimitations.ARM11LocalSystemCapabilities.StorageInfo == null)
{
builder.AppendLine(" [NULL]");
}
else
{
builder.AppendLine(entry.ACIForLimitations.ARM11LocalSystemCapabilities.StorageInfo.ExtdataID, " Extdata ID");
builder.AppendLine(entry.ACIForLimitations.ARM11LocalSystemCapabilities.StorageInfo.SystemSavedataIDs, " System savedata IDs");
builder.AppendLine(entry.ACIForLimitations.ARM11LocalSystemCapabilities.StorageInfo.StorageAccessibleUniqueIDs, " Storage accessible unique IDs");
builder.AppendLine(entry.ACIForLimitations.ARM11LocalSystemCapabilities.StorageInfo.FileSystemAccessInfo, " File system access info");
builder.AppendLine($" Other attributes: {entry.ACIForLimitations.ARM11LocalSystemCapabilities.StorageInfo.OtherAttributes} (0x{entry.ACIForLimitations.ARM11LocalSystemCapabilities.StorageInfo.OtherAttributes:X})");
}
builder.AppendLine(entry.ACIForLimitations.ARM11LocalSystemCapabilities.ServiceAccessControl, " Service access control");
builder.AppendLine(entry.ACIForLimitations.ARM11LocalSystemCapabilities.ExtendedServiceAccessControl, " Extended service access control");
builder.AppendLine(entry.ACIForLimitations.ARM11LocalSystemCapabilities.Reserved, " Reserved");
builder.AppendLine($" Resource limit cateogry: {entry.ACIForLimitations.ARM11LocalSystemCapabilities.ResourceLimitCategory} (0x{entry.ACIForLimitations.ARM11LocalSystemCapabilities.ResourceLimitCategory:X})");
}
builder.AppendLine(" ARM11 kernel capabilities:");
if (entry.ACIForLimitations.ARM11KernelCapabilities == null)
{
builder.AppendLine(" [NULL]");
}
else
{
builder.AppendLine(entry.ACIForLimitations.ARM11KernelCapabilities.Descriptors, " Descriptors");
builder.AppendLine(entry.ACIForLimitations.ARM11KernelCapabilities.Reserved, " Reserved");
}
builder.AppendLine(" ARM9 access control:");
if (entry.ACIForLimitations.ARM9AccessControl == null)
{
builder.AppendLine(" [NULL]");
}
else
{
string descriptorsStr = "[NULL]";
if (entry.ACIForLimitations.ARM9AccessControl.Descriptors != null)
{
var descriptors = Array.ConvertAll(entry.ACIForLimitations.ARM9AccessControl.Descriptors, d => d.ToString());
descriptorsStr = string.Join(", ", descriptors);
}
builder.AppendLine(descriptorsStr, " Descriptors");
builder.AppendLine(entry.ACIForLimitations.ARM9AccessControl.DescriptorVersion, " Descriptor version");
}
}
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, ExeFSHeader?[]? entries)
{
builder.AppendLine(" ExeFS Header Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No ExeFS headers");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" ExeFS Header {i}");
if (entry == null)
{
builder.AppendLine(" Unrecognized partition data, no data can be parsed");
continue;
}
builder.AppendLine(" File headers:");
if (entry.FileHeaders == null || entry.FileHeaders.Length == 0)
{
builder.AppendLine(" No file headers");
}
else
{
for (int j = 0; j < entry.FileHeaders.Length; j++)
{
var fileHeader = entry.FileHeaders[j];
builder.AppendLine($" File Header {j}");
if (fileHeader == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(fileHeader.FileName, " File name");
builder.AppendLine(fileHeader.FileOffset, " File offset");
builder.AppendLine(fileHeader.FileSize, " File size");
}
}
builder.AppendLine(entry.Reserved, " Reserved");
builder.AppendLine(" File hashes:");
if (entry.FileHashes == null || entry.FileHashes.Length == 0)
{
builder.AppendLine(" No file hashes");
}
else
{
for (int j = 0; j < entry.FileHashes.Length; j++)
{
var fileHash = entry.FileHashes[j];
builder.AppendLine($" File Hash {j}");
if (fileHash == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(fileHash, " SHA-256");
}
}
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, RomFSHeader?[]? entries)
{
builder.AppendLine(" RomFS Header Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No RomFS headers");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var romFSHeader = entries[i];
builder.AppendLine($" RomFS Header {i}");
if (romFSHeader == null)
{
builder.AppendLine(" Unrecognized RomFS data, no data can be parsed");
continue;
}
builder.AppendLine(romFSHeader.MagicString, " Magic string");
builder.AppendLine(romFSHeader.MagicNumber, " Magic number");
builder.AppendLine(romFSHeader.MasterHashSize, " Master hash size");
builder.AppendLine(romFSHeader.Level1LogicalOffset, " Level 1 logical offset");
builder.AppendLine(romFSHeader.Level1HashdataSize, " Level 1 hashdata size");
builder.AppendLine(romFSHeader.Level1BlockSizeLog2, " Level 1 block size");
builder.AppendLine(romFSHeader.Reserved1, " Reserved 1");
builder.AppendLine(romFSHeader.Level2LogicalOffset, " Level 2 logical offset");
builder.AppendLine(romFSHeader.Level2HashdataSize, " Level 2 hashdata size");
builder.AppendLine(romFSHeader.Level2BlockSizeLog2, " Level 2 block size");
builder.AppendLine(romFSHeader.Reserved2, " Reserved 2");
builder.AppendLine(romFSHeader.Level3LogicalOffset, " Level 3 logical offset");
builder.AppendLine(romFSHeader.Level3HashdataSize, " Level 3 hashdata size");
builder.AppendLine(romFSHeader.Level3BlockSizeLog2, " Level 3 block size");
builder.AppendLine(romFSHeader.Reserved3, " Reserved 3");
builder.AppendLine(romFSHeader.Reserved4, " Reserved 4");
builder.AppendLine(romFSHeader.OptionalInfoSize, " Optional info size");
}
builder.AppendLine();
}
}
}

View File

@@ -0,0 +1,360 @@
using System.Collections.Generic;
using System.Text;
using SabreTools.Models.NCF;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class NCF : IPrinter<File>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, File model)
=> Print(builder, model);
public static void Print(StringBuilder builder, File file)
{
builder.AppendLine("NCF Information:");
builder.AppendLine("-------------------------");
builder.AppendLine();
// Header
Print(builder, file.Header);
// Directory and Directory Maps
Print(builder, file.DirectoryHeader);
Print(builder, file.DirectoryEntries, file.DirectoryNames);
// TODO: Should we print out the entire string table?
Print(builder, file.DirectoryInfo1Entries);
Print(builder, file.DirectoryInfo2Entries);
Print(builder, file.DirectoryCopyEntries);
Print(builder, file.DirectoryLocalEntries);
Print(builder, file.UnknownHeader);
Print(builder, file.UnknownEntries);
// Checksums and Checksum Maps
Print(builder, file.ChecksumHeader);
Print(builder, file.ChecksumMapHeader);
Print(builder, file.ChecksumMapEntries);
Print(builder, file.ChecksumEntries);
}
private static void Print(StringBuilder builder, Header? header)
{
builder.AppendLine(" Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Dummy0, " Dummy 0");
builder.AppendLine(header.MajorVersion, " Major version");
builder.AppendLine(header.MinorVersion, " Minor version");
builder.AppendLine(header.CacheID, " Cache ID");
builder.AppendLine(header.LastVersionPlayed, " Last version played");
builder.AppendLine(header.Dummy1, " Dummy 1");
builder.AppendLine(header.Dummy2, " Dummy 2");
builder.AppendLine(header.FileSize, " File size");
builder.AppendLine(header.BlockSize, " Block size");
builder.AppendLine(header.BlockCount, " Block count");
builder.AppendLine(header.Dummy3, " Dummy 3");
builder.AppendLine();
}
private static void Print(StringBuilder builder, DirectoryHeader? header)
{
builder.AppendLine(" Directory Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No directory header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Dummy0, " Dummy 0");
builder.AppendLine(header.CacheID, " Cache ID");
builder.AppendLine(header.LastVersionPlayed, " Last version played");
builder.AppendLine(header.ItemCount, " Item count");
builder.AppendLine(header.FileCount, " File count");
builder.AppendLine(header.ChecksumDataLength, " Checksum data length");
builder.AppendLine(header.DirectorySize, " Directory size");
builder.AppendLine(header.NameSize, " Name size");
builder.AppendLine(header.Info1Count, " Info 1 count");
builder.AppendLine(header.CopyCount, " Copy count");
builder.AppendLine(header.LocalCount, " Local count");
builder.AppendLine(header.Dummy1, " Dummy 1");
builder.AppendLine(header.Dummy2, " Dummy 2");
builder.AppendLine(header.Checksum, " Checksum");
builder.AppendLine();
}
private static void Print(StringBuilder builder, DirectoryEntry?[]? entries, Dictionary<long, string?>? entryNames)
{
builder.AppendLine(" Directory Entries Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No directory entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Directory Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.NameOffset, " Name offset");
builder.AppendLine(entryNames![entry.NameOffset], " Name");
builder.AppendLine(entry.ItemSize, " Item size");
builder.AppendLine(entry.ChecksumIndex, " Checksum index");
builder.AppendLine($" Directory flags: {entry.DirectoryFlags} (0x{entry.DirectoryFlags:X})");
builder.AppendLine(entry.ParentIndex, " Parent index");
builder.AppendLine(entry.NextIndex, " Next index");
builder.AppendLine(entry.FirstIndex, " First index");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, DirectoryInfo1Entry?[]? entries)
{
builder.AppendLine(" Directory Info 1 Entries Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No directory info 1 entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Directory Info 1 Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.Dummy0, " Dummy 0");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, DirectoryInfo2Entry?[]? entries)
{
builder.AppendLine(" Directory Info 2 Entries Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No directory info 2 entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Directory Info 2 Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.Dummy0, " Dummy 0");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, DirectoryCopyEntry?[]? entries)
{
builder.AppendLine(" Directory Copy Entries Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No directory copy entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Directory Copy Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.DirectoryIndex, " Directory index");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, DirectoryLocalEntry?[]? entries)
{
builder.AppendLine(" Directory Local Entries Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No directory local entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Directory Local Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.DirectoryIndex, " Directory index");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, UnknownHeader? header)
{
builder.AppendLine(" Unknown Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No unknown header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Dummy0, " Dummy 0");
builder.AppendLine(header.Dummy1, " Dummy 1");
builder.AppendLine();
}
private static void Print(StringBuilder builder, UnknownEntry?[]? entries)
{
builder.AppendLine(" Unknown Entries Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No unknown entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Unknown Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.Dummy0, " Dummy 0");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, ChecksumHeader? header)
{
builder.AppendLine(" Checksum Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No checksum header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Dummy0, " Dummy 0");
builder.AppendLine(header.ChecksumSize, " Checksum size");
builder.AppendLine();
}
private static void Print(StringBuilder builder, ChecksumMapHeader? header)
{
builder.AppendLine(" Checksum Map Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No checksum map header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Dummy0, " Dummy 0");
builder.AppendLine(header.Dummy1, " Dummy 1");
builder.AppendLine(header.ItemCount, " Item count");
builder.AppendLine(header.ChecksumCount, " Checksum count");
builder.AppendLine();
}
private static void Print(StringBuilder builder, ChecksumMapEntry?[]? entries)
{
builder.AppendLine(" Checksum Map Entries Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No checksum map entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Checksum Map Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.ChecksumCount, " Checksum count");
builder.AppendLine(entry.FirstChecksumIndex, " First checksum index");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, ChecksumEntry?[]? entries)
{
builder.AppendLine(" Checksum Entries Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No checksum entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Checksum Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.Checksum, " Checksum");
}
builder.AppendLine();
}
}
}

View File

@@ -0,0 +1,379 @@
using System.Collections.Generic;
using System.Text;
using SabreTools.Models.NewExecutable;
using SabreTools.Serialization.Interfaces;
using static SabreTools.Serialization.Extensions;
namespace SabreTools.Serialization.Printers
{
public class NewExecutable : IPrinter<Executable>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, Executable model)
=> Print(builder, model);
public static void Print(StringBuilder builder, Executable executable)
{
builder.AppendLine("New Executable Information:");
builder.AppendLine("-------------------------");
builder.AppendLine();
// Stub
Print(builder, executable.Stub?.Header);
// Header
Print(builder, executable.Header);
// Tables
Print(builder, executable.SegmentTable);
Print(builder, executable.ResourceTable);
Print(builder, executable.ResidentNameTable);
Print(builder, executable.ModuleReferenceTable, executable.Stub?.Header, executable.Header);
Print(builder, executable.ImportedNameTable);
Print(builder, executable.EntryTable);
Print(builder, executable.NonResidentNameTable);
}
private static void Print(StringBuilder builder, Models.MSDOS.ExecutableHeader? header)
{
builder.AppendLine(" MS-DOS Stub Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No MS-DOS stub header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Magic, " Magic number");
builder.AppendLine(header.LastPageBytes, " Last page bytes");
builder.AppendLine(header.Pages, " Pages");
builder.AppendLine(header.RelocationItems, " Relocation items");
builder.AppendLine(header.HeaderParagraphSize, " Header paragraph size");
builder.AppendLine(header.MinimumExtraParagraphs, " Minimum extra paragraphs");
builder.AppendLine(header.MaximumExtraParagraphs, " Maximum extra paragraphs");
builder.AppendLine(header.InitialSSValue, " Initial SS value");
builder.AppendLine(header.InitialSPValue, " Initial SP value");
builder.AppendLine(header.Checksum, " Checksum");
builder.AppendLine(header.InitialIPValue, " Initial IP value");
builder.AppendLine(header.InitialCSValue, " Initial CS value");
builder.AppendLine(header.RelocationTableAddr, " Relocation table address");
builder.AppendLine(header.OverlayNumber, " Overlay number");
builder.AppendLine();
builder.AppendLine(" MS-DOS Stub Extended Header Information:");
builder.AppendLine(" -------------------------");
builder.AppendLine(header.Reserved1, " Reserved words");
builder.AppendLine(header.OEMIdentifier, " OEM identifier");
builder.AppendLine(header.OEMInformation, " OEM information");
builder.AppendLine(header.Reserved2, " Reserved words");
builder.AppendLine(header.NewExeHeaderAddr, " New EXE header address");
builder.AppendLine();
}
private static void Print(StringBuilder builder, ExecutableHeader? header)
{
builder.AppendLine(" Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Magic, " Magic number");
builder.AppendLine(header.LinkerVersion, " Linker version");
builder.AppendLine(header.LinkerRevision, " Linker revision");
builder.AppendLine(header.EntryTableOffset, " Entry table offset");
builder.AppendLine(header.EntryTableSize, " Entry table size");
builder.AppendLine(header.CrcChecksum, " CRC checksum");
builder.AppendLine($" Flag word: {header.FlagWord} (0x{header.FlagWord:X})");
builder.AppendLine(header.AutomaticDataSegmentNumber, " Automatic data segment number");
builder.AppendLine(header.InitialHeapAlloc, " Initial heap allocation");
builder.AppendLine(header.InitialStackAlloc, " Initial stack allocation");
builder.AppendLine(header.InitialCSIPSetting, " Initial CS:IP setting");
builder.AppendLine(header.InitialSSSPSetting, " Initial SS:SP setting");
builder.AppendLine(header.FileSegmentCount, " File segment count");
builder.AppendLine(header.ModuleReferenceTableSize, " Module reference table size");
builder.AppendLine(header.NonResidentNameTableSize, " Non-resident name table size");
builder.AppendLine(header.SegmentTableOffset, " Segment table offset");
builder.AppendLine(header.ResourceTableOffset, " Resource table offset");
builder.AppendLine(header.ResidentNameTableOffset, " Resident name table offset");
builder.AppendLine(header.ModuleReferenceTableOffset, " Module reference table offset");
builder.AppendLine(header.ImportedNamesTableOffset, " Imported names table offset");
builder.AppendLine(header.NonResidentNamesTableOffset, " Non-resident name table offset");
builder.AppendLine(header.MovableEntriesCount, " Moveable entries count");
builder.AppendLine(header.SegmentAlignmentShiftCount, " Segment alignment shift count");
builder.AppendLine(header.ResourceEntriesCount, " Resource entries count");
builder.AppendLine($" Target operating system: {header.TargetOperatingSystem} (0x{header.TargetOperatingSystem:X})");
builder.AppendLine($" Additional flags: {header.AdditionalFlags} (0x{header.AdditionalFlags:X})");
builder.AppendLine(header.ReturnThunkOffset, " Return thunk offset");
builder.AppendLine(header.SegmentReferenceThunkOffset, " Segment reference thunk offset");
builder.AppendLine(header.MinCodeSwapAreaSize, " Minimum code swap area size");
builder.AppendLine(header.WindowsSDKRevision, " Windows SDK revision");
builder.AppendLine(header.WindowsSDKVersion, " Windows SDK version");
builder.AppendLine();
}
private static void Print(StringBuilder builder, SegmentTableEntry?[]? entries)
{
builder.AppendLine(" Segment Table Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No segment table items");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Segment Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.Offset, " Offset");
builder.AppendLine(entry.Length, " Length");
builder.AppendLine($" Flag word: {entry.FlagWord} (0x{entry.FlagWord:X})");
builder.AppendLine(entry.MinimumAllocationSize, " Minimum allocation size");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, ResourceTable? table)
{
builder.AppendLine(" Resource Table Information:");
builder.AppendLine(" -------------------------");
if (table == null)
{
builder.AppendLine(" No resource table");
builder.AppendLine();
return;
}
builder.AppendLine(table.AlignmentShiftCount, " Alignment shift count");
if (table.ResourceTypes == null || table.ResourceTypes.Length == 0)
{
builder.AppendLine(" No resource table items");
}
else
{
for (int i = 0; i < table.ResourceTypes.Length; i++)
{
// TODO: If not integer type, print out name
var entry = table.ResourceTypes[i];
builder.AppendLine($" Resource Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.TypeID, " Type ID");
builder.AppendLine(entry.ResourceCount, " Resource count");
builder.AppendLine(entry.Reserved, " Reserved");
builder.AppendLine(" Resources = ");
if (entry.ResourceCount == 0 || entry.Resources == null || entry.Resources.Length == 0)
{
builder.AppendLine(" No resource items");
}
else
{
for (int j = 0; j < entry.Resources.Length; j++)
{
// TODO: If not integer type, print out name
var resource = entry.Resources[j];
builder.AppendLine($" Resource Entry {j}");
if (resource == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(resource.Offset, " Offset");
builder.AppendLine(resource.Length, " Length");
builder.AppendLine($" Flag word: {resource.FlagWord} (0x{resource.FlagWord:X})");
builder.AppendLine(resource.ResourceID, " Resource ID");
builder.AppendLine(resource.Reserved, " Reserved");
}
}
}
}
if (table.TypeAndNameStrings == null || table.TypeAndNameStrings.Count == 0)
{
builder.AppendLine(" No resource table type/name strings");
}
else
{
foreach (var typeAndNameString in table.TypeAndNameStrings)
{
builder.AppendLine($" Resource Type/Name Offset {typeAndNameString.Key}");
if (typeAndNameString.Value == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(typeAndNameString.Value.Length, " Length");
builder.AppendLine(typeAndNameString.Value.Text, " Text", Encoding.ASCII);
}
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, ResidentNameTableEntry?[]? entries)
{
builder.AppendLine(" Resident-Name Table Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No resident-name table items");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Resident-Name Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.Length, " Length");
builder.AppendLine(entry.NameString, " Name string", Encoding.ASCII);
builder.AppendLine(entry.OrdinalNumber, " Ordinal number");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, ModuleReferenceTableEntry?[]? entries, Models.MSDOS.ExecutableHeader? stub, ExecutableHeader? header)
{
builder.AppendLine(" Module-Reference Table Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No module-reference table items");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
// TODO: Read the imported names table and print value here
var entry = entries[i];
builder.AppendLine($" Module-Reference Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine($" Offset: {entry.Offset} (adjusted to be {entry.Offset + (stub?.NewExeHeaderAddr ?? 0) + (header?.ImportedNamesTableOffset ?? 0)})");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, Dictionary<ushort, ImportedNameTableEntry>? entries)
{
builder.AppendLine(" Imported-Name Table Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Count == 0)
{
builder.AppendLine(" No imported-name table items");
builder.AppendLine();
return;
}
foreach (var entry in entries)
{
builder.AppendLine($" Imported-Name Table at Offset {entry.Key}");
if (entry.Value == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.Value.Length, " Length");
builder.AppendLine(entry.Value.NameString, " Name string", Encoding.ASCII);
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, EntryTableBundle?[]? entries)
{
builder.AppendLine(" Entry Table Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No entry table items");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Entry Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.EntryCount, " Entry count");
builder.AppendLine(entry.SegmentIndicator, " Segment indicator");
switch (entry.GetEntryType())
{
case SegmentEntryType.FixedSegment:
builder.AppendLine($" Flag word: {entry.FixedFlagWord} (0x{entry.FixedFlagWord:X})");
builder.AppendLine(entry.FixedOffset, " Offset");
break;
case SegmentEntryType.MoveableSegment:
builder.AppendLine($" Flag word: {entry.MoveableFlagWord} (0x{entry.MoveableFlagWord:X})");
builder.AppendLine(entry.MoveableReserved, " Reserved");
builder.AppendLine(entry.MoveableSegmentNumber, " Segment number");
builder.AppendLine(entry.MoveableOffset, " Offset");
break;
}
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, NonResidentNameTableEntry?[]? entries)
{
builder.AppendLine(" Nonresident-Name Table Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No nonresident-name table items");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Nonresident-Name Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.Length, " Length");
builder.AppendLine(entry.NameString, " Name string", Encoding.ASCII);
builder.AppendLine(entry.OrdinalNumber, " Ordinal number");
}
builder.AppendLine();
}
}
}

View File

@@ -0,0 +1,259 @@
using System.Text;
using SabreTools.Models.Nitro;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class Nitro : IPrinter<Cart>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, Cart model)
=> Print(builder, model);
public static void Print(StringBuilder builder, Cart cart)
{
builder.AppendLine("NDS Cart Information:");
builder.AppendLine("-------------------------");
builder.AppendLine();
Print(builder, cart.CommonHeader);
Print(builder, cart.ExtendedDSiHeader);
Print(builder, cart.SecureArea);
Print(builder, cart.NameTable);
Print(builder, cart.FileAllocationTable);
}
private static void Print(StringBuilder builder, CommonHeader? header)
{
builder.AppendLine(" Common Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No common header");
builder.AppendLine();
return;
}
builder.AppendLine(header.GameTitle, " Game title");
builder.AppendLine(header.GameCode, " Game code");
builder.AppendLine(header.MakerCode, " Maker code");
builder.AppendLine($" Unit code: {header.UnitCode} (0x{header.UnitCode:X})");
builder.AppendLine(header.EncryptionSeedSelect, " Encryption seed select");
builder.AppendLine(header.DeviceCapacity, " Device capacity");
builder.AppendLine(header.Reserved1, " Reserved 1");
builder.AppendLine(header.GameRevision, " Game revision");
builder.AppendLine(header.RomVersion, " Rom version");
builder.AppendLine(header.ARM9RomOffset, " ARM9 rom offset");
builder.AppendLine(header.ARM9EntryAddress, " ARM9 entry address");
builder.AppendLine(header.ARM9LoadAddress, " ARM9 load address");
builder.AppendLine(header.ARM9Size, " ARM9 size");
builder.AppendLine(header.ARM7RomOffset, " ARM7 rom offset");
builder.AppendLine(header.ARM7EntryAddress, " ARM7 entry address");
builder.AppendLine(header.ARM7LoadAddress, " ARM7 load address");
builder.AppendLine(header.ARM7Size, " ARM7 size");
builder.AppendLine(header.FileNameTableOffset, " File name table offset");
builder.AppendLine(header.FileNameTableLength, " File name table length");
builder.AppendLine(header.FileAllocationTableOffset, " File allocation table offset");
builder.AppendLine(header.FileAllocationTableLength, " File allocation table length");
builder.AppendLine(header.ARM9OverlayOffset, " ARM9 overlay offset");
builder.AppendLine(header.ARM9OverlayLength, " ARM9 overlay length");
builder.AppendLine(header.ARM7OverlayOffset, " ARM7 overlay offset");
builder.AppendLine(header.ARM7OverlayLength, " ARM7 overlay length");
builder.AppendLine(header.NormalCardControlRegisterSettings, " Normal card control register settings");
builder.AppendLine(header.SecureCardControlRegisterSettings, " Secure card control register settings");
builder.AppendLine(header.IconBannerOffset, " Icon banner offset");
builder.AppendLine(header.SecureAreaCRC, " Secure area CRC");
builder.AppendLine(header.SecureTransferTimeout, " Secure transfer timeout");
builder.AppendLine(header.ARM9Autoload, " ARM9 autoload");
builder.AppendLine(header.ARM7Autoload, " ARM7 autoload");
builder.AppendLine(header.SecureDisable, " Secure disable");
builder.AppendLine(header.NTRRegionRomSize, " NTR region rom size");
builder.AppendLine(header.HeaderSize, " Header size");
builder.AppendLine(header.Reserved2, " Reserved 2");
builder.AppendLine(header.NintendoLogo, " Nintendo logo");
builder.AppendLine(header.NintendoLogoCRC, " Nintendo logo CRC");
builder.AppendLine(header.HeaderCRC, " Header CRC");
builder.AppendLine(header.DebuggerReserved, " Debugger reserved");
builder.AppendLine();
}
private static void Print(StringBuilder builder, ExtendedDSiHeader? header)
{
builder.AppendLine(" Extended DSi Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No extended DSi header");
builder.AppendLine();
return;
}
builder.AppendLine(header.GlobalMBK15Settings, " Global MBK1..MBK5 settings");
builder.AppendLine(header.LocalMBK68SettingsARM9, " Local MBK6..MBK8 settings for ARM9");
builder.AppendLine(header.LocalMBK68SettingsARM7, " Local MBK6..MBK8 settings for ARM7");
builder.AppendLine(header.GlobalMBK9Setting, " Global MBK9 setting");
builder.AppendLine(header.RegionFlags, " Region flags");
builder.AppendLine(header.AccessControl, " Access control");
builder.AppendLine(header.ARM7SCFGEXTMask, " ARM7 SCFG EXT mask");
builder.AppendLine(header.ReservedFlags, " Reserved/flags?");
builder.AppendLine(header.ARM9iRomOffset, " ARM9i rom offset");
builder.AppendLine(header.Reserved3, " Reserved 3");
builder.AppendLine(header.ARM9iLoadAddress, " ARM9i load address");
builder.AppendLine(header.ARM9iSize, " ARM9i size");
builder.AppendLine(header.ARM7iRomOffset, " ARM7i rom offset");
builder.AppendLine(header.Reserved4, " Reserved 4");
builder.AppendLine(header.ARM7iLoadAddress, " ARM7i load address");
builder.AppendLine(header.ARM7iSize, " ARM7i size");
builder.AppendLine(header.DigestNTRRegionOffset, " Digest NTR region offset");
builder.AppendLine(header.DigestNTRRegionLength, " Digest NTR region length");
builder.AppendLine(header.DigestTWLRegionOffset, " Digest TWL region offset");
builder.AppendLine(header.DigestTWLRegionLength, " Digest TWL region length");
builder.AppendLine(header.DigestSectorHashtableRegionOffset, " Digest sector hashtable region offset");
builder.AppendLine(header.DigestSectorHashtableRegionLength, " Digest sector hashtable region length");
builder.AppendLine(header.DigestBlockHashtableRegionOffset, " Digest block hashtable region offset");
builder.AppendLine(header.DigestBlockHashtableRegionLength, " Digest block hashtable region length");
builder.AppendLine(header.DigestSectorSize, " Digest sector size");
builder.AppendLine(header.DigestBlockSectorCount, " Digest block sector count");
builder.AppendLine(header.IconBannerSize, " Icon banner size");
builder.AppendLine(header.Unknown1, " Unknown 1");
builder.AppendLine(header.ModcryptArea1Offset, " Modcrypt area 1 offset");
builder.AppendLine(header.ModcryptArea1Size, " Modcrypt area 1 size");
builder.AppendLine(header.ModcryptArea2Offset, " Modcrypt area 2 offset");
builder.AppendLine(header.ModcryptArea2Size, " Modcrypt area 2 size");
builder.AppendLine(header.TitleID, " Title ID");
builder.AppendLine(header.DSiWarePublicSavSize, " DSiWare 'public.sav' size");
builder.AppendLine(header.DSiWarePrivateSavSize, " DSiWare 'private.sav' size");
builder.AppendLine(header.ReservedZero, " Reserved (zero)");
builder.AppendLine(header.Unknown2, " Unknown 2");
builder.AppendLine(header.ARM9WithSecureAreaSHA1HMACHash, " ARM9 (with encrypted secure area) SHA1 HMAC hash");
builder.AppendLine(header.ARM7SHA1HMACHash, " ARM7 SHA1 HMAC hash");
builder.AppendLine(header.DigestMasterSHA1HMACHash, " Digest master SHA1 HMAC hash");
builder.AppendLine(header.BannerSHA1HMACHash, " Banner SHA1 HMAC hash");
builder.AppendLine(header.ARM9iDecryptedSHA1HMACHash, " ARM9i (decrypted) SHA1 HMAC hash");
builder.AppendLine(header.ARM7iDecryptedSHA1HMACHash, " ARM7i (decrypted) SHA1 HMAC hash");
builder.AppendLine(header.Reserved5, " Reserved 5");
builder.AppendLine(header.ARM9NoSecureAreaSHA1HMACHash, " ARM9 (without secure area) SHA1 HMAC hash");
builder.AppendLine(header.Reserved6, " Reserved 6");
builder.AppendLine(header.ReservedAndUnchecked, " Reserved and unchecked region");
builder.AppendLine(header.RSASignature, " RSA signature");
builder.AppendLine();
}
private static void Print(StringBuilder builder, byte[]? secureArea)
{
builder.AppendLine(" Secure Area Information:");
builder.AppendLine(" -------------------------");
builder.AppendLine(secureArea, " Secure Area");
builder.AppendLine();
}
private static void Print(StringBuilder builder, NameTable? table)
{
builder.AppendLine(" Name Table Information:");
builder.AppendLine(" -------------------------");
if (table == null)
{
builder.AppendLine(" No name table");
builder.AppendLine();
return;
}
builder.AppendLine();
Print(builder, table.FolderAllocationTable);
Print(builder, table.NameList);
}
private static void Print(StringBuilder builder, FolderAllocationTableEntry?[]? entries)
{
builder.AppendLine(" Folder Allocation Table:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No folder allocation table entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Folder Allocation Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.StartOffset, " Start offset");
builder.AppendLine(entry.FirstFileIndex, " First file index");
if (entry.Unknown == 0xF0)
{
builder.AppendLine(entry.ParentFolderIndex, " Parent folder index");
builder.AppendLine(entry.Unknown, " Unknown");
}
else
{
ushort totalEntries = (ushort)((entry.Unknown << 8) | entry.ParentFolderIndex);
builder.AppendLine(totalEntries, " Total entries");
}
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, NameListEntry?[]? entries)
{
builder.AppendLine(" Name List:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No name list entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Name List Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.Folder, " Folder");
builder.AppendLine(entry.Name, " Name");
if (entry.Folder)
builder.AppendLine(entry.Index, " Index");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, FileAllocationTableEntry?[]? entries)
{
builder.AppendLine(" File Allocation Table:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No file allocation table entries");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" File Allocation Table Entry {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.StartOffset, " Start offset");
builder.AppendLine(entry.EndOffset, " End offset");
}
builder.AppendLine();
}
}
}

View File

@@ -0,0 +1,68 @@
using System.Text;
using SabreTools.Models.PAK;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class PAK : IPrinter<File>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, File model)
=> Print(builder, model);
public static void Print(StringBuilder builder, File file)
{
builder.AppendLine("PAK Information:");
builder.AppendLine("-------------------------");
builder.AppendLine();
Print(builder, file.Header);
Print(builder, file.DirectoryItems);
}
private static void Print(StringBuilder builder, Header? header)
{
builder.AppendLine(" Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Signature, " Signature");
builder.AppendLine(header.DirectoryOffset, " Directory offset");
builder.AppendLine(header.DirectoryLength, " Directory length");
builder.AppendLine();
}
private static void Print(StringBuilder builder, DirectoryItem?[]? entries)
{
builder.AppendLine(" Directory Items Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No directory items");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Directory Item {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.ItemName, " Item name");
builder.AppendLine(entry.ItemOffset, " Item offset");
builder.AppendLine(entry.ItemLength, " Item length");
}
builder.AppendLine();
}
}
}

View File

@@ -0,0 +1,92 @@
using System.Text;
using SabreTools.Models.PFF;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class PFF : IPrinter<Archive>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, Archive model)
=> Print(builder, model);
public static void Print(StringBuilder builder, Archive archive)
{
builder.AppendLine("PFF Information:");
builder.AppendLine("-------------------------");
builder.AppendLine();
Print(builder, archive.Header);
Print(builder, archive.Segments);
Print(builder, archive.Footer);
}
private static void Print(StringBuilder builder, Header? header)
{
builder.AppendLine(" Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No header");
builder.AppendLine();
return;
}
builder.AppendLine(header.HeaderSize, " Header size");
builder.AppendLine(header.Signature, " Signature");
builder.AppendLine(header.NumberOfFiles, " Number of files");
builder.AppendLine(header.FileSegmentSize, " File segment size");
builder.AppendLine(header.FileListOffset, " File list offset");
builder.AppendLine();
}
private static void Print(StringBuilder builder, Segment?[]? segments)
{
builder.AppendLine(" Segments Information:");
builder.AppendLine(" -------------------------");
if (segments == null || segments.Length == 0)
{
builder.AppendLine(" No segments");
builder.AppendLine();
return;
}
for (int i = 0; i < segments.Length; i++)
{
var segment = segments[i];
builder.AppendLine($" Segment {i}");
if (segment == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(segment.Deleted, " Deleted");
builder.AppendLine(segment.FileLocation, " File location");
builder.AppendLine(segment.FileSize, " File size");
builder.AppendLine(segment.PackedDate, " Packed date");
builder.AppendLine(segment.FileName, " File name");
builder.AppendLine(segment.ModifiedDate, " Modified date");
builder.AppendLine(segment.CompressionLevel, " Compression level");
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, Footer? footer)
{
builder.AppendLine(" Footer Information:");
builder.AppendLine(" -------------------------");
if (footer == null)
{
builder.AppendLine(" No footer");
builder.AppendLine();
return;
}
builder.AppendLine(footer.SystemIP, " System IP");
builder.AppendLine(footer.Reserved, " Reserved");
builder.AppendLine(footer.KingTag, " King tag");
builder.AppendLine();
}
}
}

View File

@@ -0,0 +1,87 @@
using System.Text;
using SabreTools.Models.PIC;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class PIC : IPrinter<DiscInformation>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, DiscInformation model)
=> Print(builder, model);
public static void Print(StringBuilder builder, DiscInformation di)
{
builder.AppendLine("PIC Information:");
builder.AppendLine("-------------------------");
builder.AppendLine(di.DataStructureLength, "Data structure length");
builder.AppendLine(di.Reserved0, "Reserved");
builder.AppendLine(di.Reserved1, "Reserved");
builder.AppendLine();
Print(builder, di.Units);
}
private static void Print(StringBuilder builder, DiscInformationUnit?[]? entries)
{
builder.AppendLine(" Disc Information Units:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No disc information units");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Disc Information Unit {i}");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
if (entry.Header == null)
{
builder.AppendLine(" No header");
}
else
{
var header = entry.Header;
builder.AppendLine(header.DiscInformationIdentifier, " Disc information identifier");
builder.AppendLine(header.DiscInformationFormat, " Disc information format");
builder.AppendLine(header.Reserved0, " Reserved");
builder.AppendLine(header.SequenceNumber, " Sequence number");
builder.AppendLine(header.BytesInUse, " Bytes in use");
builder.AppendLine(header.Reserved1, " Reserved");
}
if (entry.Body == null)
{
builder.AppendLine(" No body");
}
else
{
DiscInformationUnitBody body = entry.Body;
builder.AppendLine(body.DiscTypeIdentifier, " Disc type identifer");
builder.AppendLine(body.DiscSizeClassVersion, " Disc size class version");
builder.AppendLine(body.FormatDependentContents, " Format-dependent contents");
}
if (entry.Trailer == null)
{
builder.AppendLine(" No trailer");
}
else
{
DiscInformationUnitTrailer trailer = entry.Trailer;
builder.AppendLine(trailer.DiscManufacturerID, " Disc manufacturer ID");
builder.AppendLine(trailer.MediaTypeID, " Media type ID");
builder.AppendLine(trailer.TimeStamp, " Timestamp");
builder.AppendLine(trailer.ProductRevisionNumber, " Product revision number");
}
}
builder.AppendLine();
}
}
}

View File

@@ -0,0 +1,279 @@
using System.Text;
using SabreTools.Models.PKZIP;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class PKZIP : IPrinter<Archive>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, Archive model)
=> Print(builder, model);
public static void Print(StringBuilder builder, Archive archive)
{
builder.AppendLine("PKZIP Archive (or Derived Format) Information:");
builder.AppendLine("-------------------------");
builder.AppendLine();
Print(builder, archive.EndOfCentralDirectoryRecord);
Print(builder, archive.ZIP64EndOfCentralDirectoryLocator);
Print(builder, archive.ZIP64EndOfCentralDirectoryRecord);
Print(builder, archive.CentralDirectoryHeaders);
Print(builder, archive.ArchiveExtraDataRecord);
Print(builder,
archive.LocalFileHeaders,
archive.EncryptionHeaders,
archive.FileData,
archive.DataDescriptors,
archive.ZIP64DataDescriptors);
}
private static void Print(StringBuilder builder, EndOfCentralDirectoryRecord? record)
{
builder.AppendLine(" End of Central Directory Record Information:");
builder.AppendLine(" -------------------------");
if (record == null)
{
builder.AppendLine(" No end of central directory record");
builder.AppendLine();
return;
}
builder.AppendLine(record.Signature, " Signature");
builder.AppendLine(record.DiskNumber, " Disk number");
builder.AppendLine(record.StartDiskNumber, " Start disk number");
builder.AppendLine(record.TotalEntriesOnDisk, " Total entries on disk");
builder.AppendLine(record.TotalEntries, " Total entries");
builder.AppendLine(record.CentralDirectorySize, " Central directory size");
builder.AppendLine(record.CentralDirectoryOffset, " Central directory offset");
builder.AppendLine(record.FileCommentLength, " File comment length");
builder.AppendLine(record.FileComment, " File comment");
builder.AppendLine();
}
private static void Print(StringBuilder builder, EndOfCentralDirectoryLocator64? locator)
{
builder.AppendLine(" ZIP64 End of Central Directory Locator Information:");
builder.AppendLine(" -------------------------");
if (locator == null)
{
builder.AppendLine(" No ZIP64 end of central directory locator");
builder.AppendLine();
return;
}
builder.AppendLine(locator.Signature, " Signature");
builder.AppendLine(locator.StartDiskNumber, " Start disk number");
builder.AppendLine(locator.CentralDirectoryOffset, " Central directory offset");
builder.AppendLine(locator.TotalDisks, " Total disks");
builder.AppendLine();
}
private static void Print(StringBuilder builder, EndOfCentralDirectoryRecord64? record)
{
builder.AppendLine(" ZIP64 End of Central Directory Record Information:");
builder.AppendLine(" -------------------------");
if (record == null)
{
builder.AppendLine(" No ZIP64 end of central directory record");
builder.AppendLine();
return;
}
builder.AppendLine(record.Signature, " Signature");
builder.AppendLine(record.DirectoryRecordSize, " Directory record size");
builder.AppendLine($" Host system: {record.HostSystem} (0x{record.HostSystem:X})");
builder.AppendLine(record.VersionMadeBy, " Version made by");
builder.AppendLine(record.VersionNeededToExtract, " Version needed to extract");
builder.AppendLine(record.DiskNumber, " Disk number");
builder.AppendLine(record.StartDiskNumber, " Start disk number");
builder.AppendLine(record.TotalEntriesOnDisk, " Total entries on disk");
builder.AppendLine(record.TotalEntries, " Total entries");
builder.AppendLine(record.CentralDirectorySize, " Central directory size");
builder.AppendLine(record.CentralDirectoryOffset, " Central directory offset");
//builder.AppendLine(record.ExtensibleDataSector, " Extensible data sector");
builder.AppendLine();
}
private static void Print(StringBuilder builder, CentralDirectoryFileHeader?[]? headers)
{
builder.AppendLine(" Central Directory File Headers Information:");
builder.AppendLine(" -------------------------");
if (headers == null || headers.Length == 0)
{
builder.AppendLine(" No central directory file headers");
builder.AppendLine();
return;
}
for (int i = 0; i < headers.Length; i++)
{
var record = headers[i];
Print(builder, record, i);
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, CentralDirectoryFileHeader? header, int index)
{
builder.AppendLine($" Central Directory File Header Entry {index}");
if (header == null)
{
builder.AppendLine(" [NULL]");
return;
}
builder.AppendLine(header.Signature, " Signature");
builder.AppendLine($" Host system: {header.HostSystem} (0x{header.HostSystem:X})");
builder.AppendLine(header.VersionMadeBy, " Version made by");
builder.AppendLine(header.VersionNeededToExtract, " Version needed to extract");
builder.AppendLine($" Flags: {header.Flags} (0x{header.Flags:X})");
builder.AppendLine($" Compression method: {header.CompressionMethod} (0x{header.CompressionMethod:X})");
builder.AppendLine(header.LastModifedFileTime, " Last modified file time"); // TODO: Parse from MS-DOS
builder.AppendLine(header.LastModifiedFileDate, " Last modified file date"); // TODO: Parse from MS-DOS
builder.AppendLine(header.CRC32, " CRC-32");
builder.AppendLine(header.CompressedSize, " Compressed size");
builder.AppendLine(header.UncompressedSize, " Uncompressed size");
builder.AppendLine(header.FileNameLength, " File name length");
builder.AppendLine(header.ExtraFieldLength, " Extra field length");
builder.AppendLine(header.FileCommentLength, " File comment length");
builder.AppendLine(header.DiskNumberStart, " Disk number start");
builder.AppendLine($" Internal file attributes: {header.InternalFileAttributes} (0x{header.InternalFileAttributes:X})");
builder.AppendLine(header.ExternalFileAttributes, " External file attributes");
builder.AppendLine(header.RelativeOffsetOfLocalHeader, " Relative offset of local header");
builder.AppendLine(header.FileName, " File name");
builder.AppendLine(header.ExtraField, " Extra field");
builder.AppendLine(header.FileComment, " File comment");
}
private static void Print(StringBuilder builder, ArchiveExtraDataRecord? record)
{
builder.AppendLine(" Archive Extra Data Record Information:");
builder.AppendLine(" -------------------------");
if (record == null)
{
builder.AppendLine(" No archive extra data record");
builder.AppendLine();
return;
}
builder.AppendLine(record.Signature, " Signature");
builder.AppendLine(record.ExtraFieldLength, " Extra field length");
builder.AppendLine(record.ExtraFieldData, " Extra field data");
builder.AppendLine();
}
private static void Print(StringBuilder builder,
LocalFileHeader[]? localFileHeaders,
byte[]?[]? encryptionHeaders,
byte[][]? fileData,
DataDescriptor?[]? dataDescriptors,
DataDescriptor64?[]? zip64DataDescriptors)
{
builder.AppendLine(" Local File Information:");
builder.AppendLine(" -------------------------");
if (localFileHeaders == null || localFileHeaders.Length == 0)
{
builder.AppendLine(" No local files");
builder.AppendLine();
return;
}
if (encryptionHeaders == null || localFileHeaders.Length > encryptionHeaders.Length
|| fileData == null || localFileHeaders.Length > fileData.Length
|| dataDescriptors == null || localFileHeaders.Length > dataDescriptors.Length
|| zip64DataDescriptors == null || localFileHeaders.Length > zip64DataDescriptors.Length)
{
builder.AppendLine(" Mismatch in local file array values");
builder.AppendLine();
}
for (int i = 0; i < localFileHeaders.Length; i++)
{
var localFileHeader = localFileHeaders[i];
var encryptionHeader = encryptionHeaders != null && i < encryptionHeaders.Length ? encryptionHeaders[i] : null;
var fileDatum = fileData != null && i < fileData.Length ? fileData[i] : null;
var dataDescriptor = dataDescriptors != null && i < dataDescriptors.Length ? dataDescriptors[i] : null;
var zip64DataDescriptor = zip64DataDescriptors != null && i < zip64DataDescriptors.Length ? zip64DataDescriptors[i] : null;
Print(builder, localFileHeader, encryptionHeader, fileDatum, dataDescriptor, zip64DataDescriptor, i);
}
builder.AppendLine();
}
private static void Print(StringBuilder builder,
LocalFileHeader localFileHeader,
byte[]? encryptionHeader,
byte[]? fileData,
DataDescriptor? dataDescriptor,
DataDescriptor64? zip64DataDescriptor,
int index)
{
builder.AppendLine($" Local File Entry {index}");
if (localFileHeader == null)
{
builder.AppendLine(" [NULL]");
return;
}
builder.AppendLine(localFileHeader.Signature, " [Local File Header] Signature");
builder.AppendLine(localFileHeader.Version, " [Local File Header] Version");
builder.AppendLine($" [Local File Header] Flags: {localFileHeader.Flags} (0x{localFileHeader.Flags:X})");
builder.AppendLine($" [Local File Header] Compression method: {localFileHeader.CompressionMethod} (0x{localFileHeader.CompressionMethod:X})");
builder.AppendLine(localFileHeader.LastModifedFileTime, " [Local File Header] Last modified file time"); // TODO: Parse from MS-DOS
builder.AppendLine(localFileHeader.LastModifiedFileDate, " [Local File Header] Last modified file date"); // TODO: Parse from MS-DOS
builder.AppendLine(localFileHeader.CRC32, " [Local File Header] CRC-32");
builder.AppendLine(localFileHeader.CompressedSize, " [Local File Header] Compressed size");
builder.AppendLine(localFileHeader.UncompressedSize, " [Local File Header] Uncompressed size");
builder.AppendLine(localFileHeader.FileNameLength, " [Local File Header] File name length");
builder.AppendLine(localFileHeader.ExtraFieldLength, " [Local File Header] Extra field length");
builder.AppendLine(localFileHeader.FileName, " [Local File Header] File name");
builder.AppendLine(localFileHeader.ExtraField, " [Local File Header] Extra field");
if (encryptionHeader == null)
{
builder.AppendLine(" [Encryption Header]: [NULL]");
}
else
{
builder.AppendLine(encryptionHeader.Length, " [Encryption Header] Length");
builder.AppendLine(encryptionHeader, " [Encryption Header] Data");
}
if (fileData == null)
{
builder.AppendLine(" [File Data]: [NULL]");
}
else
{
builder.AppendLine(fileData.Length, " [File Data] Length");
//builder.AppendLine(fileData, " [File Data] Data");
}
if (dataDescriptor == null)
{
builder.AppendLine(" [Data Descriptor]: [NULL]");
}
else
{
builder.AppendLine(dataDescriptor.Signature, " [Data Descriptor] Signature");
builder.AppendLine(dataDescriptor.CRC32, " [Data Descriptor] CRC-32");
builder.AppendLine(dataDescriptor.CompressedSize, " [Data Descriptor] Compressed size");
builder.AppendLine(dataDescriptor.UncompressedSize, " [Data Descriptor] Uncompressed size");
}
if (zip64DataDescriptor == null)
{
builder.AppendLine(" [ZIP64 Data Descriptor]: [NULL]");
}
else
{
builder.AppendLine(zip64DataDescriptor.Signature, " [ZIP64 Data Descriptor] Signature");
builder.AppendLine(zip64DataDescriptor.CRC32, " [ZIP64 Data Descriptor] CRC-32");
builder.AppendLine(zip64DataDescriptor.CompressedSize, " [ZIP64 Data Descriptor] Compressed size");
builder.AppendLine(zip64DataDescriptor.UncompressedSize, " [ZIP64 Data Descriptor] Uncompressed size");
}
}
}
}

View File

@@ -0,0 +1,183 @@
using System.Text;
using SabreTools.Models.PlayJ;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class PlayJAudioFile : IPrinter<AudioFile>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, AudioFile model)
=> Print(builder, model);
public static void Print(StringBuilder builder, AudioFile audio)
{
builder.AppendLine("PlayJ Audio File Information:");
builder.AppendLine("-------------------------");
builder.AppendLine();
Print(builder, audio.Header);
Print(builder, audio.UnknownBlock1);
if (audio.Header?.Version == 0x00000000)
{
Print(builder, audio.UnknownValue2);
Print(builder, audio.UnknownBlock3);
}
else if (audio.Header?.Version == 0x0000000A)
{
Print(builder, audio.DataFilesCount, audio.DataFiles);
}
}
private static void Print(StringBuilder builder, AudioHeader? header)
{
builder.AppendLine(" Audio Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No audio header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Signature, " Signature");
builder.AppendLine(header.Version, " Version");
if (header.Version == 0x00000000 && header is AudioHeaderV1 headerV1)
{
builder.AppendLine(headerV1.TrackID, " Track ID");
builder.AppendLine(headerV1.UnknownOffset1, " Unknown offset 1");
builder.AppendLine(headerV1.UnknownOffset2, " Unknown offset 2");
builder.AppendLine(headerV1.UnknownOffset3, " Unknown offset 3");
builder.AppendLine(headerV1.Unknown1, " Unknown 1");
builder.AppendLine(headerV1.Unknown2, " Unknown 2");
builder.AppendLine(headerV1.Year, " Year");
builder.AppendLine(headerV1.TrackNumber, " Track number");
builder.AppendLine($" Subgenre: {headerV1.Subgenre} (0x{headerV1.Subgenre:X})");
builder.AppendLine(headerV1.Duration, " Duration in seconds");
}
else if (header.Version == 0x0000000A && header is AudioHeaderV2 headerV2)
{
builder.AppendLine(headerV2.Unknown1, " Unknown 1");
builder.AppendLine(headerV2.Unknown2, " Unknown 2");
builder.AppendLine(headerV2.Unknown3, " Unknown 3");
builder.AppendLine(headerV2.Unknown4, " Unknown 4");
builder.AppendLine(headerV2.Unknown5, " Unknown 5");
builder.AppendLine(headerV2.Unknown6, " Unknown 6");
builder.AppendLine(headerV2.UnknownOffset1, " Unknown Offset 1");
builder.AppendLine(headerV2.Unknown7, " Unknown 7");
builder.AppendLine(headerV2.Unknown8, " Unknown 8");
builder.AppendLine(headerV2.Unknown9, " Unknown 9");
builder.AppendLine(headerV2.UnknownOffset2, " Unknown Offset 2");
builder.AppendLine(headerV2.Unknown10, " Unknown 10");
builder.AppendLine(headerV2.Unknown11, " Unknown 11");
builder.AppendLine(headerV2.Unknown12, " Unknown 12");
builder.AppendLine(headerV2.Unknown13, " Unknown 13");
builder.AppendLine(headerV2.Unknown14, " Unknown 14");
builder.AppendLine(headerV2.Unknown15, " Unknown 15");
builder.AppendLine(headerV2.Unknown16, " Unknown 16");
builder.AppendLine(headerV2.Unknown17, " Unknown 17");
builder.AppendLine(headerV2.TrackID, " Track ID");
builder.AppendLine(headerV2.Year, " Year");
builder.AppendLine(headerV2.TrackNumber, " Track number");
builder.AppendLine(headerV2.Unknown18, " Unknown 18");
}
else
{
builder.AppendLine(" Unrecognized version, not parsed...");
}
builder.AppendLine(header.TrackLength, " Track length");
builder.AppendLine(header.Track, " Track");
builder.AppendLine(header.ArtistLength, " Artist length");
builder.AppendLine(header.Artist, " Artist");
builder.AppendLine(header.AlbumLength, " Album length");
builder.AppendLine(header.Album, " Album");
builder.AppendLine(header.WriterLength, " Writer length");
builder.AppendLine(header.Writer, " Writer");
builder.AppendLine(header.PublisherLength, " Publisher length");
builder.AppendLine(header.Publisher, " Publisher");
builder.AppendLine(header.LabelLength, " Label length");
builder.AppendLine(header.Label, " Label");
builder.AppendLine(header.CommentsLength, " Comments length");
builder.AppendLine(header.Comments, " Comments");
builder.AppendLine();
}
private static void Print(StringBuilder builder, UnknownBlock1? block)
{
builder.AppendLine(" Unknown Block 1 Information:");
builder.AppendLine(" -------------------------");
if (block == null)
{
builder.AppendLine(" No unknown block 1r");
builder.AppendLine();
return;
}
builder.AppendLine(block.Length, " Length");
builder.AppendLine(block.Data, " Data");
builder.AppendLine();
}
private static void Print(StringBuilder builder, uint? value)
{
builder.AppendLine(" Unknown Value 2 Information:");
builder.AppendLine(" -------------------------");
if (value == null)
{
builder.AppendLine(" No unknown block 1r");
builder.AppendLine();
return;
}
builder.AppendLine(value, " Value");
builder.AppendLine();
}
private static void Print(StringBuilder builder, UnknownBlock3? block)
{
builder.AppendLine(" Unknown Block 3 Information:");
builder.AppendLine(" -------------------------");
if (block == null)
{
builder.AppendLine(" No unknown block 1r");
builder.AppendLine();
return;
}
builder.AppendLine(block.Data, " Data");
builder.AppendLine();
}
private static void Print(StringBuilder builder, uint count, DataFile?[]? entries)
{
builder.AppendLine(" Data Files Information:");
builder.AppendLine(" -------------------------");
builder.AppendLine(count, " Data files count");
if (count == 0 || entries == null || entries.Length == 0)
{
builder.AppendLine(" No data files");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Data File {i}:");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.FileNameLength, " File name length");
builder.AppendLine(entry.FileName, " File name");
builder.AppendLine(entry.DataLength, " Data length");
builder.AppendLine(entry.Data, " Data");
}
builder.AppendLine();
}
}
}

View File

@@ -0,0 +1,226 @@
using System.Text;
using SabreTools.Models.PlayJ;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Printers
{
public class PlayJPlaylist : IPrinter<Playlist>
{
/// <inheritdoc/>
public void PrintInformation(StringBuilder builder, Playlist model)
=> Print(builder, model);
public static void Print(StringBuilder builder, Playlist playlist)
{
builder.AppendLine("PlayJ Playlist Information:");
builder.AppendLine("-------------------------");
builder.AppendLine();
Print(builder, playlist.Header);
Print(builder, playlist.AudioFiles);
}
private static void Print(StringBuilder builder, PlaylistHeader? header)
{
builder.AppendLine(" Playlist Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No playlist header");
builder.AppendLine();
return;
}
builder.AppendLine(header.TrackCount, " Track count");
builder.AppendLine(header.Data, " Data");
builder.AppendLine();
}
private static void Print(StringBuilder builder, AudioFile?[]? entries)
{
builder.AppendLine(" Audio Files Information:");
builder.AppendLine(" -------------------------");
if (entries == null || entries.Length == 0)
{
builder.AppendLine(" No audio files");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Audio File {i}:");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
Print(builder, entry.Header);
Print(builder, entry.UnknownBlock1);
if (entry.Header?.Version == 0x00000000)
{
Print(builder, entry.UnknownValue2);
Print(builder, entry.UnknownBlock3);
}
else if (entry.Header?.Version == 0x0000000A)
{
Print(builder, entry.DataFilesCount, entry.DataFiles);
}
}
builder.AppendLine();
}
private static void Print(StringBuilder builder, AudioHeader? header)
{
builder.AppendLine(" Audio Header Information:");
builder.AppendLine(" -------------------------");
if (header == null)
{
builder.AppendLine(" No audio header");
builder.AppendLine();
return;
}
builder.AppendLine(header.Signature, " Signature");
builder.AppendLine(header.Version, " Version");
if (header.Version == 0x00000000 && header is AudioHeaderV1 headerV1)
{
builder.AppendLine(headerV1.TrackID, " Track ID");
builder.AppendLine(headerV1.UnknownOffset1, " Unknown offset 1");
builder.AppendLine(headerV1.UnknownOffset2, " Unknown offset 2");
builder.AppendLine(headerV1.UnknownOffset3, " Unknown offset 3");
builder.AppendLine(headerV1.Unknown1, " Unknown 1");
builder.AppendLine(headerV1.Unknown2, " Unknown 2");
builder.AppendLine(headerV1.Year, " Year");
builder.AppendLine(headerV1.TrackNumber, " Track number");
builder.AppendLine($" Subgenre: {headerV1.Subgenre} (0x{headerV1.Subgenre:X})");
builder.AppendLine(headerV1.Duration, " Duration in seconds");
}
else if (header.Version == 0x0000000A && header is AudioHeaderV2 headerV2)
{
builder.AppendLine(headerV2.Unknown1, " Unknown 1");
builder.AppendLine(headerV2.Unknown2, " Unknown 2");
builder.AppendLine(headerV2.Unknown3, " Unknown 3");
builder.AppendLine(headerV2.Unknown4, " Unknown 4");
builder.AppendLine(headerV2.Unknown5, " Unknown 5");
builder.AppendLine(headerV2.Unknown6, " Unknown 6");
builder.AppendLine(headerV2.UnknownOffset1, " Unknown Offset 1");
builder.AppendLine(headerV2.Unknown7, " Unknown 7");
builder.AppendLine(headerV2.Unknown8, " Unknown 8");
builder.AppendLine(headerV2.Unknown9, " Unknown 9");
builder.AppendLine(headerV2.UnknownOffset2, " Unknown Offset 2");
builder.AppendLine(headerV2.Unknown10, " Unknown 10");
builder.AppendLine(headerV2.Unknown11, " Unknown 11");
builder.AppendLine(headerV2.Unknown12, " Unknown 12");
builder.AppendLine(headerV2.Unknown13, " Unknown 13");
builder.AppendLine(headerV2.Unknown14, " Unknown 14");
builder.AppendLine(headerV2.Unknown15, " Unknown 15");
builder.AppendLine(headerV2.Unknown16, " Unknown 16");
builder.AppendLine(headerV2.Unknown17, " Unknown 17");
builder.AppendLine(headerV2.TrackID, " Track ID");
builder.AppendLine(headerV2.Year, " Year");
builder.AppendLine(headerV2.TrackNumber, " Track number");
builder.AppendLine(headerV2.Unknown18, " Unknown 18");
}
else
{
builder.AppendLine(" Unrecognized version, not parsed...");
}
builder.AppendLine(header.TrackLength, " Track length");
builder.AppendLine(header.Track, " Track");
builder.AppendLine(header.ArtistLength, " Artist length");
builder.AppendLine(header.Artist, " Artist");
builder.AppendLine(header.AlbumLength, " Album length");
builder.AppendLine(header.Album, " Album");
builder.AppendLine(header.WriterLength, " Writer length");
builder.AppendLine(header.Writer, " Writer");
builder.AppendLine(header.PublisherLength, " Publisher length");
builder.AppendLine(header.Publisher, " Publisher");
builder.AppendLine(header.LabelLength, " Label length");
builder.AppendLine(header.Label, " Label");
builder.AppendLine(header.CommentsLength, " Comments length");
builder.AppendLine(header.Comments, " Comments");
builder.AppendLine();
}
private static void Print(StringBuilder builder, UnknownBlock1? block)
{
builder.AppendLine(" Unknown Block 1 Information:");
builder.AppendLine(" -------------------------");
if (block == null)
{
builder.AppendLine(" No unknown block 1r");
builder.AppendLine();
return;
}
builder.AppendLine(block.Length, " Length");
builder.AppendLine(block.Data, " Data");
builder.AppendLine();
}
private static void Print(StringBuilder builder, uint? value)
{
builder.AppendLine(" Unknown Value 2 Information:");
builder.AppendLine(" -------------------------");
if (value == null)
{
builder.AppendLine(" No unknown block 1r");
builder.AppendLine();
return;
}
builder.AppendLine(value, " Value");
builder.AppendLine();
}
private static void Print(StringBuilder builder, UnknownBlock3? block)
{
builder.AppendLine(" Unknown Block 3 Information:");
builder.AppendLine(" -------------------------");
if (block == null)
{
builder.AppendLine(" No unknown block 1r");
builder.AppendLine();
return;
}
builder.AppendLine(block.Data, " Data");
builder.AppendLine();
}
private static void Print(StringBuilder builder, uint count, DataFile?[]? entries)
{
builder.AppendLine(" Data Files Information:");
builder.AppendLine(" -------------------------");
builder.AppendLine(count, " Data files count");
if (count == 0 || entries == null || entries.Length == 0)
{
builder.AppendLine(" No data files");
builder.AppendLine();
return;
}
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
builder.AppendLine($" Data File {i}:");
if (entry == null)
{
builder.AppendLine(" [NULL]");
continue;
}
builder.AppendLine(entry.FileNameLength, " File name length");
builder.AppendLine(entry.FileName, " File name");
builder.AppendLine(entry.DataLength, " Data length");
builder.AppendLine(entry.Data, " Data");
}
builder.AppendLine();
}
}
}

File diff suppressed because it is too large Load Diff

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