nitro-patcher 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { createAesBlockCipher } from '#nitro-runtime';
1
+ import { createAesBlockCipher } from "#nitro-runtime";
2
2
 
3
3
  export interface ModcryptHeader {
4
4
  gameCode: string;
@@ -10,78 +10,77 @@ export interface ModcryptHeader {
10
10
 
11
11
  // KEY1 table carried forward from NitroHelper/Arm9Encryptor.cs (Dirbaio/ndstool).
12
12
  const KEY1 = Buffer.from(
13
- '99D5205F5744F5B96E19A4D99E6A5A94D8AEF1EB4175E23A9382D03233EE31D5CC57619A3706A21B793972F555AEF6BE5F1B69FBE59DF1E9CE2CD9A15E3205E6' +
14
- 'FED3FECFD462040D8BF5ECB72B6079BB1295310D6E3FDA2B8884F0F13D127E254522F1BB24061A0611ADDF288B6481342BEB332999AAF2BD9C14959D9FF7F58C' +
15
- '7297A1299DD15FCF664D071ADED34A4B85C9A7A31795053A3D490ABF0A898BA24A8249DD2790F10BE9EB1C6A83764505BA817061173F4BDEAECFAB3957F23A56' +
16
- '4811AD8A40E1453FFA9B0254CAA693FBEF4DFE6FA3D8879C08BAD5486A8D2DFD6E15F874BDBE528B18228A9EFB7437071B366C4A19BA4262B97991107B676596' +
17
- 'FE0223E8EE998C773E5C86644D6D7886A54F65E21EB2DF5A0AD07E0814B071ACBDDB831CB9D7A162CDC6637C5269C3E6BF75CE12445D2104FAFBD33C381163D4' +
18
- '958541494609F2084311DC1F76C0156D1F3C6370EA87806CC3BD638BC2372137DCEE09232E376A4D7390F75030AC1C92041023914FD207AA683E4F9AC964606A' +
19
- 'C81421F3D62241124424CFE68A56DD0D534DE1851E8C525A9C1984C20357F16FE300BE58F64CEDD521649C1FBE55033C4ADCFFAAC9DAE05D5EBFE6DEF5D8B1F8' +
20
- 'FF36B3B9626795DB315F37ED4C70679990B518316C3D9999E442DAD3254213A0AED7706CB155CFC7D746D54361173D4428E93385D5D0A293AA25121FFBC50B46' +
21
- 'F597765645A6BE87B1946BE8B1FE3399AE1F3E6C39711D09009037E4103E7574FF8C833BB0F1B0F90105474295F1D6AC7E38E69E9574263FB4685018D04330B4' +
22
- '4C4BE368BFE54DB6958B0AA074253277CFA1F72CD871135AABEAC951E80DEEEFE9937E19A71E433881162CA148E373CC29216CD35DCEA0D9617143A01513B564' +
23
- '92CF2A19DCADB7A59F8665F81A9FE7FBF7FDB8136C27DB6FDF351CF78D2C5B9B12AB386406CCDE31E84E751164E3FAEAEB3454C2AD3F34EB932C7D26369D56F3' +
24
- '5AE1F6B398634A9E3283E49A84607D902E130EEE934B36A285EC1638E8880602BFF0A03AEDD76A9A73E157CFF844B8DC2E2359D1DF9552719961A04BD57F6E78' +
25
- 'BAA9C530D34086329D320C9C37B7022FBA5498A9C41304C98DBEC8E75D97502E93D622590C27BC2292E0A7200F936F7F4C9FD3B5A62A0B7467497D1026CBD1C5' +
26
- '8671E78CA09CE95BB21AF601EE8C9E5E83F21ADBE6E5EA845976D27CF68DA5493648C21652BB83A374B9070C3BFF6128E161E9E4EF6E15AA4EBAE85D0596BB32' +
27
- '56B0FB72520F0EC84225657689AFF2DE1027F0014B74A79707D5265454091F820A867D30390EB3269B0B57BB360631AFFD79FCD930102B0CB3E19BD77BDC5FEF' +
28
- 'D2F813454D4775BD46963C7E75F33EB567C59A3BB05B296BDE805BC81505B131B6CE49DDAD84B5AE60DC67313430FE4EBD802FA6BF63392186D9357F16682205' +
29
- '54E990268C076C51A43155D70907A83E2E5366C1F8F27BC4F258CFF187C5A2E7278F308758A064622318B9887CFACEC498AEAD17CC4A5BF3E948D556D30DF2C8' +
30
- '92738CDBD72F56AC81F992694DC632F6E6C08D21E276806111BCDC6C93AF19699BD0BFB9319F0267A351EE8306227B0CAB494240B8D5017DCE5EF7555339C599' +
31
- '46D8879FBAF764B4E39AFAA16D90681030CA8A54A79F60C319F56B0D7A5198E6984351B4D635E94FC3DF0F7BD62F5CBD3A156119F14BCBAADC6D64C9D3C61E56' +
32
- 'EF384C50718675CC0D0D4EE928F6065D701BAAD345CFA839AC95A62EB4E422D474A8375F487A04CCA54C40D828B428080D1C725241F07D47193A534E5884626B' +
33
- '93B58A81214E0DDCB43FA2C6FCC92B40DA3804E95E5A866B0C22258568118D7C921D95554DAB8EBBDAA6E6B751B6325A0541DD052A0A5650911747CCC9E67EB5' +
34
- '614ADB736751C833F5DA6E742E54C3370D6DAF08E8158A5FE25921CDA8DE0C065A776B5FDB18653EC850DE78E0B882B35D4E7232074FC13423BA96B7674EA428' +
35
- '1E3462EB2D6A70E92F42C4704E5A319CF95B4728AADA716F381FB378C4926B1C9EF6359AB74D0EBFCC1829410348355D55D02BC629AF5C6074698E5E9B7CD4BD' +
36
- '7B44647D3F925D69B61F004BD48335CF7E644E17AE8DD52E9A28124E2E2B49085CAEC64685AE41611E6F82D25137161F0BF659A49ACA5AAF0DD4338B2063F184' +
37
- '805CCBCF08B4B9D31605BD6283319B5651989FBAB25BAAB2226B2CB5D448FA632B5F58FA61FA6409BB38E0B89D9260A80D676F0E37F50D019FC277D4FEECF173' +
38
- '3039E07DF56198E42C2855045655DB2F6BECE55806B664806A2A1A4E5B0FD8C40A2E5219D962F53048BE8C7B4F389BA2C3AFC9D3C7C1624186B96121576F994F' +
39
- 'C1BACE7BB53B4D5E8A8B44575F135F706D5B2947DC38E2EC045565122AE81743E18EDD2AB3E294F7096E5CE6EB8AF86D89495448F52FADBFEA944BCAFC398782' +
40
- '5F8A01F275F2E671D6D842DEF12D1D28A6887EA3A0471D30D9A371DF491CCB01F836B1F2F022585D456BBDA0BBB28842C78C28CE93E8906308907C893CF57DB7' +
41
- '042D4F555116FD7E79E8BEC1F212D4F8B4840523A0CCD22BFDE1ABAD0DD1556C2341944D77374F05280CBF17B312676C8CC35AF741842A6DD09412272CB4ED9C' +
42
- '4DEC478297D567B91B9DC055077EE58EE2A8E73E12E40E3A2A455534A2F92D5A1BAB527C83105F55D2F15A432BC6A7A4891595E8B44B9DF875E39F60785BD6E6' +
43
- '0D44E62106BD472253A400AD8D43138539F7AAFC38AF7BEDFCE42B5450984CFC8580F7DF3C8022E194DADE24C6B07A3938DC0FA1A7F4F96F6318578B84412A2E' +
44
- 'D453F2D9000FD0DD996E19A60AD0EC5B5824ABC0CB0665EC1A1338940A67032F3FF7E377447733C61439D0E3C0A20879BB409957410B0190CDE1CC4867DBB3AF' +
45
- '8874F34C828F72B1B52329C4126C19FC8E46A49CC4256587D36DBE8A93110338ED832BF346A493EA3B53851DCED4F1088327EDFC9B1A18BCF98BAEDC24AB5038' +
46
- 'E9724B1022177B465DAB5964F340AEF8BBE5C8F926034E557DEBEBFEF739E6E00A11BE2E28FF98EDC0C9425642C3FD00F6AF87A25B013F329247959A72A5323D' +
47
- 'AE6BD09B07D24992E3784AFAA1067DF241CF77740414B20C86846416D5BB51A1E56FF1D1F2E2F75F58204DB857C7CFDDC5D8BE763DF65F7EE72A8B88241B383F' +
48
- '0E412377F5F04BD40C1FFAA40B805FCF45F6E0DA2F345953FB203C52625E35B562FE8B6063E3865A151A6ED14745BC32B4EB6738ABE46E333AB5EDA3AD67E04E' +
49
- '4195EE626271261D31EF6230AFD782ACC2DC0504F59707BF11592307C06402E897E53EAF18AC59A68B4A33901C6E7C9C207E4C3C3E6164BBC56B7C7E3E9FC54C' +
50
- '9FEA73F5D789C04CF4FBF42DEC141B51D5C112C810DF0B4A8B9CBC93456A3E3E7DC1A9BACDC1B407E4E1688643B26D38F3FB0C5C663771DE56EF6EA0104065A7' +
51
- '98F7D0BE0EC83736EC10CA7C9CAB841E051776021C4F52AA5FC1C6A056B9D80484444DA759D8DE60E6380E058F03E13B6D8104336F300BCE69052133FB26BB89' +
52
- '7DB6AE877E5107E0ACF7960A6BF9C45C1DE44447B85EFAE3788455424B485EF77D4735861D2B430503EC8AB81E063C760C481A43A7B78AED1E13C643EE10EFDB' +
53
- 'ECFB3C83B29544EFD854514E2D11441DFB36591E7A34C1C3CA570061EA67A5169B55D055E17FD936D24076AEDC01CEB07A83D5CB2098EC6BC1729234F3825737' +
54
- '628A32360C9043AEAE5C9B788E136502FD6871C1FEB031A02482B0C3B17969A7F5D2EBD082C032DC9EC7263C6D8D98C1BB22D4D00F33EC3EB9CCE1DC6A4C7736' +
55
- '141CF9BF819F285F71853229907548C4B34ACED8448F142FFD4057EFAA0875D946D1D66E32551FC318FE841FFC84D5FF715E1B48C386950E280827D33883717B' +
56
- '4C8063549A56B0ACCF80CA3109EFFEF3BEAF247EA6FE533FC28D4A3368D122A666AD7BEADEB643B0A1259500A33F7546141144ECD795BC92F04FA91653629760' +
57
- '2A0F41F17124BEEE947F08CD6093B3855B07003FD80F28839AD1699FD1DA2EC39001A2B96B4E2A669DDAAEA6EA2AD3682F0C0C9CD28C4AEDE29E57659D0987A3' +
58
- 'B4C4325DC9D4322BB1E0711E644DE69071E31E40ED7DF3840EEDC87876AEC0712772BB05EA0264FBF3486BB542933FED9F1353D2F7FE2AEC1D4725DB3C9186C6' +
59
- '8EF011FD237436F7A4F59E7A7E535044D447CAD3EB386DE6D971947F4AC6694B11F452EA22FE8AB036678B59E8E6802AEB650413EEECDC9E5FB1EC056A59E69F' +
60
- '5E596B89BFF71ACA44F95B6A718503E42962E0706F41C4CFB2B1CCE37EA607A887E77F8493DB524B6CEC7EDDD4244810699F046074E64818F3E42CB94F2E507A' +
61
- 'DFD454692B8BA7F3CEFF1FF33E26013917958489B0F04C4B82919FC44BAC9DA574AF1725C9CA32D3BC898A8489CC0DAE7CA2DB9C6A7891EEEA765D4E8760F569' +
62
- '1567D402CFAF483607EABF6F662D068FC49AFEF9F6908775B8F7AD0F76105A3D59B02EB3C7352CCC70562BCBE33796C52F461B8A2246C788A726329861DF8622' +
63
- '8AF41C2F87A109AACCA9AED3BD00451C9A5487865287EFFF1E8FA18FC1895C351BDA2D3A2C16B2C2F156E278C16B6397C5568FC9327F2CAAAFA6A8AC20912288' +
64
- 'DEE4608BF94B42251AE37F9C2C19893A7E05D436CC6958C2C1328B2F9085EB7A3950A5A12792C566B0204F587E5583432B45E29CE4D812902C168356167903B3' +
65
- 'AD2D61181A131F37E2E19C737B80D5FD2D5187FC7BAAD71F2C7A8EAFF48DBBCD95117C720BEE6FE2B9AFDE3783DE8C8D620567B796C68D56B60DD762BAD64636' +
66
- 'BD8EC8E6EA2A6C1014FF6B5BFA823C46B1304346518A7D9B923E83795B555DB26C5ECE90628E5398C90D6DE52D57CDC58157BAE1E8B88F72E54F13DCEA9D7115' +
67
- '10B21188D509D47F5B657F2C3B384C1168508DFB9EB059BF9480894AC51A18128953D14A1029E88C1CECB6EA46C7178B251531A8A26B43B19DE2DB0B879BB011' +
68
- '040E71D2297789820A66417F1D0B48FF72BB24FDC248A19BFE7B7FCE88DB86D9853B1CB0DCA83307BF512EE30E9A00971E06C097439DD8B645C486675F00F888' +
69
- '9AA4529EC7AA8A8375ECC518AECEC32F1A2BF918FFAE1AF5530BB53351A7FDE8A8E1A264B622174380CC0AD8AE3BBA40D7D9924A89DF0410EE9B182B6A77698A' +
70
- '68F4F9B9A221156EE61E3B0362309B60417E259B9E8FC5521008F8C269A1211188375E793566FF1042186EED97B66B1C4E36E56D7DB4E4BF20B9E0053A69D5B8' +
71
- 'E3D5DCE0B9AC533E07A457AD77FF4818762AAC492A8E47756D9F676330358C390539D56F643A5BADCA0BBB82529945B193363699AF13204436D8024409399285' +
72
- 'FF4A4A9787A663D7C7B5B524ED0FB46F0C585214D9A67BD379BC3858A1BD3B8406D81A06FD6BA8EA4B69280437AD8299FB0E1B85BDA85D73CDDC58750ABE636C' +
73
- '48E74CE4302B0460B915D8DA8681758F96D48D1C5D70857C1C677BD50867A6CE4B0A6670B7E563D45B8A82EA1067CAE2F4EF17852F2A5F8A9782F86AD63410EA' +
74
- 'EBC95C3CE149F846EBDEBDF6A992F1AAA6A018B03AD30F1FF36FFF31454344D3509AF7880996C1CE76CCF22C2CBAAD82778F1884C0D2079C3690834E0BA54F43' +
75
- '3E04AB784FD6FB09012490DA6F3C3A610D7F694AEB2B3002B4DBE084A9ECD735BF377D8558CEA94EE480C7A8D3306748EB29AF2F746AB4A73F0F3F92AFF3CAAC' +
76
- 'AF4BD994C043CA810D2F48A1B027D5D2EF4B0585A3DE4D93303CF0BB4A8F30274CEBE33E64ED9A2F3BF182F0BAF4CF7F40CBB0E17FBCAA57D3C974F2FA430D22' +
77
- 'D0F4774E93D785701F99BFB6DE35F130A75E71F06B012D7B64F033530A3988F36B3AA66B35D22F43CD02FDB5E9BC5BAAD8A4197E0E5D94819E6F77ADD60E7493' +
78
- '96E7C4185FADF519',
79
- 'hex',
13
+ "99D5205F5744F5B96E19A4D99E6A5A94D8AEF1EB4175E23A9382D03233EE31D5CC57619A3706A21B793972F555AEF6BE5F1B69FBE59DF1E9CE2CD9A15E3205E6" +
14
+ "FED3FECFD462040D8BF5ECB72B6079BB1295310D6E3FDA2B8884F0F13D127E254522F1BB24061A0611ADDF288B6481342BEB332999AAF2BD9C14959D9FF7F58C" +
15
+ "7297A1299DD15FCF664D071ADED34A4B85C9A7A31795053A3D490ABF0A898BA24A8249DD2790F10BE9EB1C6A83764505BA817061173F4BDEAECFAB3957F23A56" +
16
+ "4811AD8A40E1453FFA9B0254CAA693FBEF4DFE6FA3D8879C08BAD5486A8D2DFD6E15F874BDBE528B18228A9EFB7437071B366C4A19BA4262B97991107B676596" +
17
+ "FE0223E8EE998C773E5C86644D6D7886A54F65E21EB2DF5A0AD07E0814B071ACBDDB831CB9D7A162CDC6637C5269C3E6BF75CE12445D2104FAFBD33C381163D4" +
18
+ "958541494609F2084311DC1F76C0156D1F3C6370EA87806CC3BD638BC2372137DCEE09232E376A4D7390F75030AC1C92041023914FD207AA683E4F9AC964606A" +
19
+ "C81421F3D62241124424CFE68A56DD0D534DE1851E8C525A9C1984C20357F16FE300BE58F64CEDD521649C1FBE55033C4ADCFFAAC9DAE05D5EBFE6DEF5D8B1F8" +
20
+ "FF36B3B9626795DB315F37ED4C70679990B518316C3D9999E442DAD3254213A0AED7706CB155CFC7D746D54361173D4428E93385D5D0A293AA25121FFBC50B46" +
21
+ "F597765645A6BE87B1946BE8B1FE3399AE1F3E6C39711D09009037E4103E7574FF8C833BB0F1B0F90105474295F1D6AC7E38E69E9574263FB4685018D04330B4" +
22
+ "4C4BE368BFE54DB6958B0AA074253277CFA1F72CD871135AABEAC951E80DEEEFE9937E19A71E433881162CA148E373CC29216CD35DCEA0D9617143A01513B564" +
23
+ "92CF2A19DCADB7A59F8665F81A9FE7FBF7FDB8136C27DB6FDF351CF78D2C5B9B12AB386406CCDE31E84E751164E3FAEAEB3454C2AD3F34EB932C7D26369D56F3" +
24
+ "5AE1F6B398634A9E3283E49A84607D902E130EEE934B36A285EC1638E8880602BFF0A03AEDD76A9A73E157CFF844B8DC2E2359D1DF9552719961A04BD57F6E78" +
25
+ "BAA9C530D34086329D320C9C37B7022FBA5498A9C41304C98DBEC8E75D97502E93D622590C27BC2292E0A7200F936F7F4C9FD3B5A62A0B7467497D1026CBD1C5" +
26
+ "8671E78CA09CE95BB21AF601EE8C9E5E83F21ADBE6E5EA845976D27CF68DA5493648C21652BB83A374B9070C3BFF6128E161E9E4EF6E15AA4EBAE85D0596BB32" +
27
+ "56B0FB72520F0EC84225657689AFF2DE1027F0014B74A79707D5265454091F820A867D30390EB3269B0B57BB360631AFFD79FCD930102B0CB3E19BD77BDC5FEF" +
28
+ "D2F813454D4775BD46963C7E75F33EB567C59A3BB05B296BDE805BC81505B131B6CE49DDAD84B5AE60DC67313430FE4EBD802FA6BF63392186D9357F16682205" +
29
+ "54E990268C076C51A43155D70907A83E2E5366C1F8F27BC4F258CFF187C5A2E7278F308758A064622318B9887CFACEC498AEAD17CC4A5BF3E948D556D30DF2C8" +
30
+ "92738CDBD72F56AC81F992694DC632F6E6C08D21E276806111BCDC6C93AF19699BD0BFB9319F0267A351EE8306227B0CAB494240B8D5017DCE5EF7555339C599" +
31
+ "46D8879FBAF764B4E39AFAA16D90681030CA8A54A79F60C319F56B0D7A5198E6984351B4D635E94FC3DF0F7BD62F5CBD3A156119F14BCBAADC6D64C9D3C61E56" +
32
+ "EF384C50718675CC0D0D4EE928F6065D701BAAD345CFA839AC95A62EB4E422D474A8375F487A04CCA54C40D828B428080D1C725241F07D47193A534E5884626B" +
33
+ "93B58A81214E0DDCB43FA2C6FCC92B40DA3804E95E5A866B0C22258568118D7C921D95554DAB8EBBDAA6E6B751B6325A0541DD052A0A5650911747CCC9E67EB5" +
34
+ "614ADB736751C833F5DA6E742E54C3370D6DAF08E8158A5FE25921CDA8DE0C065A776B5FDB18653EC850DE78E0B882B35D4E7232074FC13423BA96B7674EA428" +
35
+ "1E3462EB2D6A70E92F42C4704E5A319CF95B4728AADA716F381FB378C4926B1C9EF6359AB74D0EBFCC1829410348355D55D02BC629AF5C6074698E5E9B7CD4BD" +
36
+ "7B44647D3F925D69B61F004BD48335CF7E644E17AE8DD52E9A28124E2E2B49085CAEC64685AE41611E6F82D25137161F0BF659A49ACA5AAF0DD4338B2063F184" +
37
+ "805CCBCF08B4B9D31605BD6283319B5651989FBAB25BAAB2226B2CB5D448FA632B5F58FA61FA6409BB38E0B89D9260A80D676F0E37F50D019FC277D4FEECF173" +
38
+ "3039E07DF56198E42C2855045655DB2F6BECE55806B664806A2A1A4E5B0FD8C40A2E5219D962F53048BE8C7B4F389BA2C3AFC9D3C7C1624186B96121576F994F" +
39
+ "C1BACE7BB53B4D5E8A8B44575F135F706D5B2947DC38E2EC045565122AE81743E18EDD2AB3E294F7096E5CE6EB8AF86D89495448F52FADBFEA944BCAFC398782" +
40
+ "5F8A01F275F2E671D6D842DEF12D1D28A6887EA3A0471D30D9A371DF491CCB01F836B1F2F022585D456BBDA0BBB28842C78C28CE93E8906308907C893CF57DB7" +
41
+ "042D4F555116FD7E79E8BEC1F212D4F8B4840523A0CCD22BFDE1ABAD0DD1556C2341944D77374F05280CBF17B312676C8CC35AF741842A6DD09412272CB4ED9C" +
42
+ "4DEC478297D567B91B9DC055077EE58EE2A8E73E12E40E3A2A455534A2F92D5A1BAB527C83105F55D2F15A432BC6A7A4891595E8B44B9DF875E39F60785BD6E6" +
43
+ "0D44E62106BD472253A400AD8D43138539F7AAFC38AF7BEDFCE42B5450984CFC8580F7DF3C8022E194DADE24C6B07A3938DC0FA1A7F4F96F6318578B84412A2E" +
44
+ "D453F2D9000FD0DD996E19A60AD0EC5B5824ABC0CB0665EC1A1338940A67032F3FF7E377447733C61439D0E3C0A20879BB409957410B0190CDE1CC4867DBB3AF" +
45
+ "8874F34C828F72B1B52329C4126C19FC8E46A49CC4256587D36DBE8A93110338ED832BF346A493EA3B53851DCED4F1088327EDFC9B1A18BCF98BAEDC24AB5038" +
46
+ "E9724B1022177B465DAB5964F340AEF8BBE5C8F926034E557DEBEBFEF739E6E00A11BE2E28FF98EDC0C9425642C3FD00F6AF87A25B013F329247959A72A5323D" +
47
+ "AE6BD09B07D24992E3784AFAA1067DF241CF77740414B20C86846416D5BB51A1E56FF1D1F2E2F75F58204DB857C7CFDDC5D8BE763DF65F7EE72A8B88241B383F" +
48
+ "0E412377F5F04BD40C1FFAA40B805FCF45F6E0DA2F345953FB203C52625E35B562FE8B6063E3865A151A6ED14745BC32B4EB6738ABE46E333AB5EDA3AD67E04E" +
49
+ "4195EE626271261D31EF6230AFD782ACC2DC0504F59707BF11592307C06402E897E53EAF18AC59A68B4A33901C6E7C9C207E4C3C3E6164BBC56B7C7E3E9FC54C" +
50
+ "9FEA73F5D789C04CF4FBF42DEC141B51D5C112C810DF0B4A8B9CBC93456A3E3E7DC1A9BACDC1B407E4E1688643B26D38F3FB0C5C663771DE56EF6EA0104065A7" +
51
+ "98F7D0BE0EC83736EC10CA7C9CAB841E051776021C4F52AA5FC1C6A056B9D80484444DA759D8DE60E6380E058F03E13B6D8104336F300BCE69052133FB26BB89" +
52
+ "7DB6AE877E5107E0ACF7960A6BF9C45C1DE44447B85EFAE3788455424B485EF77D4735861D2B430503EC8AB81E063C760C481A43A7B78AED1E13C643EE10EFDB" +
53
+ "ECFB3C83B29544EFD854514E2D11441DFB36591E7A34C1C3CA570061EA67A5169B55D055E17FD936D24076AEDC01CEB07A83D5CB2098EC6BC1729234F3825737" +
54
+ "628A32360C9043AEAE5C9B788E136502FD6871C1FEB031A02482B0C3B17969A7F5D2EBD082C032DC9EC7263C6D8D98C1BB22D4D00F33EC3EB9CCE1DC6A4C7736" +
55
+ "141CF9BF819F285F71853229907548C4B34ACED8448F142FFD4057EFAA0875D946D1D66E32551FC318FE841FFC84D5FF715E1B48C386950E280827D33883717B" +
56
+ "4C8063549A56B0ACCF80CA3109EFFEF3BEAF247EA6FE533FC28D4A3368D122A666AD7BEADEB643B0A1259500A33F7546141144ECD795BC92F04FA91653629760" +
57
+ "2A0F41F17124BEEE947F08CD6093B3855B07003FD80F28839AD1699FD1DA2EC39001A2B96B4E2A669DDAAEA6EA2AD3682F0C0C9CD28C4AEDE29E57659D0987A3" +
58
+ "B4C4325DC9D4322BB1E0711E644DE69071E31E40ED7DF3840EEDC87876AEC0712772BB05EA0264FBF3486BB542933FED9F1353D2F7FE2AEC1D4725DB3C9186C6" +
59
+ "8EF011FD237436F7A4F59E7A7E535044D447CAD3EB386DE6D971947F4AC6694B11F452EA22FE8AB036678B59E8E6802AEB650413EEECDC9E5FB1EC056A59E69F" +
60
+ "5E596B89BFF71ACA44F95B6A718503E42962E0706F41C4CFB2B1CCE37EA607A887E77F8493DB524B6CEC7EDDD4244810699F046074E64818F3E42CB94F2E507A" +
61
+ "DFD454692B8BA7F3CEFF1FF33E26013917958489B0F04C4B82919FC44BAC9DA574AF1725C9CA32D3BC898A8489CC0DAE7CA2DB9C6A7891EEEA765D4E8760F569" +
62
+ "1567D402CFAF483607EABF6F662D068FC49AFEF9F6908775B8F7AD0F76105A3D59B02EB3C7352CCC70562BCBE33796C52F461B8A2246C788A726329861DF8622" +
63
+ "8AF41C2F87A109AACCA9AED3BD00451C9A5487865287EFFF1E8FA18FC1895C351BDA2D3A2C16B2C2F156E278C16B6397C5568FC9327F2CAAAFA6A8AC20912288" +
64
+ "DEE4608BF94B42251AE37F9C2C19893A7E05D436CC6958C2C1328B2F9085EB7A3950A5A12792C566B0204F587E5583432B45E29CE4D812902C168356167903B3" +
65
+ "AD2D61181A131F37E2E19C737B80D5FD2D5187FC7BAAD71F2C7A8EAFF48DBBCD95117C720BEE6FE2B9AFDE3783DE8C8D620567B796C68D56B60DD762BAD64636" +
66
+ "BD8EC8E6EA2A6C1014FF6B5BFA823C46B1304346518A7D9B923E83795B555DB26C5ECE90628E5398C90D6DE52D57CDC58157BAE1E8B88F72E54F13DCEA9D7115" +
67
+ "10B21188D509D47F5B657F2C3B384C1168508DFB9EB059BF9480894AC51A18128953D14A1029E88C1CECB6EA46C7178B251531A8A26B43B19DE2DB0B879BB011" +
68
+ "040E71D2297789820A66417F1D0B48FF72BB24FDC248A19BFE7B7FCE88DB86D9853B1CB0DCA83307BF512EE30E9A00971E06C097439DD8B645C486675F00F888" +
69
+ "9AA4529EC7AA8A8375ECC518AECEC32F1A2BF918FFAE1AF5530BB53351A7FDE8A8E1A264B622174380CC0AD8AE3BBA40D7D9924A89DF0410EE9B182B6A77698A" +
70
+ "68F4F9B9A221156EE61E3B0362309B60417E259B9E8FC5521008F8C269A1211188375E793566FF1042186EED97B66B1C4E36E56D7DB4E4BF20B9E0053A69D5B8" +
71
+ "E3D5DCE0B9AC533E07A457AD77FF4818762AAC492A8E47756D9F676330358C390539D56F643A5BADCA0BBB82529945B193363699AF13204436D8024409399285" +
72
+ "FF4A4A9787A663D7C7B5B524ED0FB46F0C585214D9A67BD379BC3858A1BD3B8406D81A06FD6BA8EA4B69280437AD8299FB0E1B85BDA85D73CDDC58750ABE636C" +
73
+ "48E74CE4302B0460B915D8DA8681758F96D48D1C5D70857C1C677BD50867A6CE4B0A6670B7E563D45B8A82EA1067CAE2F4EF17852F2A5F8A9782F86AD63410EA" +
74
+ "EBC95C3CE149F846EBDEBDF6A992F1AAA6A018B03AD30F1FF36FFF31454344D3509AF7880996C1CE76CCF22C2CBAAD82778F1884C0D2079C3690834E0BA54F43" +
75
+ "3E04AB784FD6FB09012490DA6F3C3A610D7F694AEB2B3002B4DBE084A9ECD735BF377D8558CEA94EE480C7A8D3306748EB29AF2F746AB4A73F0F3F92AFF3CAAC" +
76
+ "AF4BD994C043CA810D2F48A1B027D5D2EF4B0585A3DE4D93303CF0BB4A8F30274CEBE33E64ED9A2F3BF182F0BAF4CF7F40CBB0E17FBCAA57D3C974F2FA430D22" +
77
+ "D0F4774E93D785701F99BFB6DE35F130A75E71F06B012D7B64F033530A3988F36B3AA66B35D22F43CD02FDB5E9BC5BAAD8A4197E0E5D94819E6F77ADD60E7493" +
78
+ "96E7C4185FADF519",
79
+ "hex",
80
80
  );
81
81
 
82
82
  export const aes128CtrCrypt = (key: Buffer, counter: Buffer, data: Buffer): Buffer => {
83
- if (key.length !== 16 || counter.length !== 16)
84
- throw new RangeError('AES key and counter must have 16 bytes');
83
+ if (key.length !== 16 || counter.length !== 16) throw new RangeError("AES key and counter must have 16 bytes");
85
84
  const ctr = Buffer.from(counter).reverse();
86
85
  const aes = createAesBlockCipher(Buffer.from(key).reverse());
87
86
  const output = Buffer.alloc(data.length);
@@ -97,20 +96,16 @@ export const aes128CtrCrypt = (key: Buffer, counter: Buffer, data: Buffer): Buff
97
96
  };
98
97
 
99
98
  export const modcryptKey = (header: ModcryptHeader): Buffer => {
100
- if (typeof header.gameCode !== 'string' || header.gameCode.length !== 4)
101
- throw new Error('Expected four-character game code');
99
+ if (typeof header.gameCode !== "string" || header.gameCode.length !== 4)
100
+ throw new Error("Expected four-character game code");
102
101
  if (header.twlInternalFlags & 4 || (header.appflags?.[3] ?? 0) & 0x80) {
103
102
  const key = Buffer.alloc(16);
104
- key.write(header.gameTitle, 0, 12, 'ascii');
105
- key.write(header.gameCode, 12, 4, 'ascii');
103
+ key.write(header.gameTitle, 0, 12, "ascii");
104
+ key.write(header.gameCode, 12, 4, "ascii");
106
105
  return key;
107
106
  }
108
- if (!header.hmac_arm9i || header.hmac_arm9i.length < 16)
109
- throw new Error('Missing ARM9i HMAC for modcrypt key');
110
- const x = Buffer.from(
111
- 'Nintendo' + header.gameCode + [...header.gameCode].reverse().join(''),
112
- 'ascii',
113
- );
107
+ if (!header.hmac_arm9i || header.hmac_arm9i.length < 16) throw new Error("Missing ARM9i HMAC for modcrypt key");
108
+ const x = Buffer.from(`Nintendo${header.gameCode}${[...header.gameCode].reverse().join("")}`, "ascii");
114
109
  for (let i = 0; i < 16; i++) x[i] ^= header.hmac_arm9i[i];
115
110
  const mask = (1n << 128n) - 1n;
116
111
  let v = x.readBigUInt64LE(0) | (x.readBigUInt64LE(8) << 64n);
@@ -123,9 +118,8 @@ export const modcryptKey = (header: ModcryptHeader): Buffer => {
123
118
  };
124
119
 
125
120
  export const encryptSecureArea = (gameCode: string, input: Buffer): Buffer => {
126
- if (typeof gameCode !== 'string' || gameCode.length !== 4)
127
- throw new Error('Expected four-character game code');
128
- if (input.length < 0x800) throw new RangeError('Secure area must contain at least 0x800 bytes');
121
+ if (typeof gameCode !== "string" || gameCode.length !== 4) throw new Error("Expected four-character game code");
122
+ if (input.length < 0x800) throw new RangeError("Secure area must contain at least 0x800 bytes");
129
123
  const output = Buffer.from(input);
130
124
  let magic = new Uint32Array(0x412);
131
125
  let args: [number, number, number] = [0, 0, 0];
@@ -155,7 +149,7 @@ export const encryptSecureArea = (gameCode: string, input: Buffer): Buffer => {
155
149
  }
156
150
  function init1() {
157
151
  magic = Uint32Array.from({ length: 0x412 }, (_, i) => KEY1.readUInt32LE(i * 4));
158
- const code = Buffer.from(gameCode, 'ascii').readUInt32LE();
152
+ const code = Buffer.from(gameCode, "ascii").readUInt32LE();
159
153
  args = [code, code >>> 1, (code << 1) >>> 0];
160
154
  init2();
161
155
  init2();
@@ -1,5 +1,5 @@
1
1
  // Based on NitroHelper FNT/FAT/OverlayTable, GPL-3.0.
2
- import { bytes, range } from './binary';
2
+ import { bytes, range } from "./binary";
3
3
 
4
4
  /** A file in the original ROM, optionally replaced with new bytes. */
5
5
  export interface NitroFile {
@@ -29,8 +29,8 @@ export class FileAllocationTable {
29
29
 
30
30
  constructor(input: Uint8Array, offset: number, size: number) {
31
31
  const data = bytes(input);
32
- const table = range(data, offset, size, 'FAT');
33
- if (size % 8 || size / 8 > 65535) throw new Error('Invalid FAT entry count');
32
+ const table = range(data, offset, size, "FAT");
33
+ if (size % 8 || size / 8 > 65535) throw new Error("Invalid FAT entry count");
34
34
  this.entries = [];
35
35
  for (let p = 0; p < size; p += 8) {
36
36
  const start = table.readUInt32LE(p),
@@ -38,9 +38,7 @@ export class FileAllocationTable {
38
38
  range(data, start, end - start, `FAT entry ${p / 8}`);
39
39
  this.entries.push({ id: p / 8, offset: start, size: end - start });
40
40
  }
41
- this.sortedIDs = [...this.entries]
42
- .sort((a, b) => a.offset - b.offset || a.id - b.id)
43
- .map((entry) => entry.id);
41
+ this.sortedIDs = [...this.entries].sort((a, b) => a.offset - b.offset || a.id - b.id).map((entry) => entry.id);
44
42
  }
45
43
  }
46
44
 
@@ -48,21 +46,20 @@ export class FileNameTable {
48
46
  readonly root: NitroFolder;
49
47
 
50
48
  constructor(fat: FileAllocationTable, input: Uint8Array, offset: number, size: number) {
51
- const table = range(bytes(input), offset, size, 'FNT');
52
- range(table, 0, 8, 'FNT root directory');
49
+ const table = range(bytes(input), offset, size, "FNT");
50
+ range(table, 0, 8, "FNT root directory");
53
51
  const count = table.readUInt16LE(6);
54
- if (count < 1 || count > 4096) throw new Error('Invalid FNT directory count');
55
- range(table, 0, count * 8, 'FNT directory table');
56
- const decoder = new TextDecoder('shift_jis');
52
+ if (count < 1 || count > 4096) throw new Error("Invalid FNT directory count");
53
+ range(table, 0, count * 8, "FNT directory table");
54
+ const decoder = new TextDecoder("shift_jis");
57
55
  const visited = new Set<number>();
58
56
  const fileIds = new Set<number>();
59
57
  const parse = (index: number, name: string, depth: number): NitroFolder => {
60
- if (depth > 256 || index >= count || visited.has(index))
61
- throw new Error('Invalid FNT directory tree or cycle');
58
+ if (depth > 256 || index >= count || visited.has(index)) throw new Error("Invalid FNT directory tree or cycle");
62
59
  visited.add(index);
63
60
  let cursor = table.readUInt32LE(index * 8);
64
61
  let fileId = table.readUInt16LE(index * 8 + 4);
65
- if (cursor < count * 8) throw new Error('FNT directory names overlap directory table');
62
+ if (cursor < count * 8) throw new Error("FNT directory names overlap directory table");
66
63
  const folder: NitroFolder = {
67
64
  name,
68
65
  id: index === 0 ? 0xffff : 0xf000 + index,
@@ -71,31 +68,31 @@ export class FileNameTable {
71
68
  };
72
69
  const names = new Set<string>();
73
70
  while (true) {
74
- const tag = range(table, cursor++, 1, 'FNT name')[0];
71
+ const tag = range(table, cursor++, 1, "FNT name")[0];
75
72
  if (!tag) break;
76
73
  const length = tag & 0x7f;
77
- if (!length) throw new Error('Empty FNT directory name');
78
- const filename = decoder.decode(range(table, cursor, length, 'FNT filename'));
74
+ if (!length) throw new Error("Empty FNT directory name");
75
+ const filename = decoder.decode(range(table, cursor, length, "FNT filename"));
79
76
  cursor += length;
80
77
  if (
81
- filename.includes('/') ||
82
- filename.includes('\\') ||
83
- filename.includes('\0') ||
84
- filename === '.' ||
85
- filename === '..'
78
+ filename.includes("/") ||
79
+ filename.includes("\\") ||
80
+ filename.includes("\0") ||
81
+ filename === "." ||
82
+ filename === ".."
86
83
  )
87
- throw new Error('Invalid FNT path component');
84
+ throw new Error("Invalid FNT path component");
88
85
  const normalized = filename.toLowerCase();
89
86
  if (names.has(normalized)) throw new Error(`Duplicate FNT path: ${filename}`);
90
87
  names.add(normalized);
91
88
  if (tag & 0x80) {
92
- const id = range(table, cursor, 2, 'FNT directory id').readUInt16LE();
89
+ const id = range(table, cursor, 2, "FNT directory id").readUInt16LE();
93
90
  cursor += 2;
94
- if (id < 0xf000) throw new Error('Invalid FNT directory id');
91
+ if (id < 0xf000) throw new Error("Invalid FNT directory id");
95
92
  folder.folders.push(parse(id & 0xfff, filename, depth + 1));
96
93
  } else {
97
94
  const entry = fat.entries[fileId++];
98
- if (!entry) throw new Error('FNT file id is outside FAT');
95
+ if (!entry) throw new Error("FNT file id is outside FAT");
99
96
  if (fileIds.has(entry.id)) throw new Error(`Duplicate FNT file id: ${entry.id}`);
100
97
  fileIds.add(entry.id);
101
98
  folder.files.push({ name: filename, ...entry });
@@ -103,7 +100,7 @@ export class FileNameTable {
103
100
  }
104
101
  return folder;
105
102
  };
106
- this.root = { name: 'root', id: 0xffff, files: [], folders: [parse(0, 'data', 0)] };
103
+ this.root = { name: "root", id: 0xffff, files: [], folders: [parse(0, "data", 0)] };
107
104
  }
108
105
 
109
106
  static findFile(id: number, folder: NitroFolder): NitroFile | undefined {
@@ -128,14 +125,14 @@ export interface OverlayItem {
128
125
  }
129
126
 
130
127
  const overlayFields = [
131
- 'overlayId',
132
- 'ramAddress',
133
- 'ramSize',
134
- 'bssSize',
135
- 'staticInitialiserStartAddress',
136
- 'staticInitialiserEndAddress',
137
- 'fileId',
138
- 'reserved',
128
+ "overlayId",
129
+ "ramAddress",
130
+ "ramSize",
131
+ "bssSize",
132
+ "staticInitialiserStartAddress",
133
+ "staticInitialiserEndAddress",
134
+ "fileId",
135
+ "reserved",
139
136
  ] as const;
140
137
 
141
138
  export class OverlayTable {
@@ -147,8 +144,8 @@ export class OverlayTable {
147
144
  readonly isArm9: boolean,
148
145
  ) {
149
146
  if (!size) return;
150
- const table = range(bytes(input), offset, size, 'overlay table');
151
- if (size % 32) throw new Error('Invalid overlay table size');
147
+ const table = range(bytes(input), offset, size, "overlay table");
148
+ if (size % 32) throw new Error("Invalid overlay table size");
152
149
  for (let p = 0; p < size; p += 32) {
153
150
  if (table.readUInt32LE(p) === 0xffffffff) break;
154
151
  this.entries.push({
@@ -166,10 +163,10 @@ export class OverlayTable {
166
163
  readBasicOverlays(fat: FileAllocationTable): NitroFile[] {
167
164
  return this.entries.map((item) => {
168
165
  const file = fat.entries[item.fileId];
169
- if (!file) throw new Error('Overlay file id is outside FAT');
166
+ if (!file) throw new Error("Overlay file id is outside FAT");
170
167
  return {
171
168
  ...file,
172
- name: `overlay${this.isArm9 ? '' : '7'}_${String(item.overlayId).padStart(4, '0')}.bin`,
169
+ name: `overlay${this.isArm9 ? "" : "7"}_${String(item.overlayId).padStart(4, "0")}.bin`,
173
170
  };
174
171
  });
175
172
  }
@@ -1,7 +1,7 @@
1
1
  // Port of NitroHelper/Header.cs. Copyright Xzonn and upstream contributors, GPL-3.0.
2
- import { bytes, range } from './binary';
3
- import { crc16 } from './crc';
4
- import { encryptSecureArea } from './crypto';
2
+ import { bytes, range } from "./binary";
3
+ import { crc16 } from "./crc";
4
+ import { encryptSecureArea } from "./crypto";
5
5
 
6
6
  export const UnitCode = Object.freeze({ NDS: 0, NDS_DSi: 2, DSi: 3 });
7
7
 
@@ -106,43 +106,30 @@ export class Header {
106
106
  declare secureDisable: bigint;
107
107
 
108
108
  constructor(input: Uint8Array) {
109
- const data = bytes(input, 'header');
110
- range(data, 0, 0x170, 'header');
109
+ const data = bytes(input, "header");
110
+ range(data, 0, 0x170, "header");
111
111
  const size = data.readUInt32LE(0x84);
112
112
  if (size < 0x170 || size > data.length) throw new RangeError(`Invalid header size: ${size}`);
113
113
  this.raw = Buffer.from(data.subarray(0, size));
114
- if (this.unitCode & 2 && size > 0x200) range(this.raw, 0, 0x1000, 'DSi header');
115
- this.trimmedRom = this.total_rom_size
116
- ? this.total_rom_size >= data.length
117
- : data.length !== this.size;
114
+ if (this.unitCode & 2 && size > 0x200) range(this.raw, 0, 0x1000, "DSi header");
115
+ this.trimmedRom = this.total_rom_size ? this.total_rom_size >= data.length : data.length !== this.size;
118
116
  this.doublePadding =
119
- (this.ARM9size % 0x400 < 0x200 &&
120
- this.ARM7romOffset % 0x400 === 0 &&
121
- this.ARM9overlayOffset % 0x400 === 0) ||
122
- (this.ARM7size % 0x400 < 0x200 &&
123
- this.FNToffset % 0x400 === 0 &&
124
- this.ARM7overlayOffset % 0x400 === 0) ||
117
+ (this.ARM9size % 0x400 < 0x200 && this.ARM7romOffset % 0x400 === 0 && this.ARM9overlayOffset % 0x400 === 0) ||
118
+ (this.ARM7size % 0x400 < 0x200 && this.FNToffset % 0x400 === 0 && this.ARM7overlayOffset % 0x400 === 0) ||
125
119
  (this.FNTsize % 0x400 < 0x200 && this.FAToffset % 0x400 === 0) ||
126
120
  (this.FATsize % 0x400 < 0x200 && this.bannerOffset % 0x400 === 0);
127
121
  const nitroOffset = this.ARM9romOffset + this.ARM9size;
128
122
  this.nitrocode =
129
- nitroOffset >= size &&
130
- nitroOffset + 4 <= data.length &&
131
- data.readUInt32LE(nitroOffset) === 0xdec00621;
123
+ nitroOffset >= size && nitroOffset + 4 <= data.length && data.readUInt32LE(nitroOffset) === 0xdec00621;
132
124
  this.decrypted = data.length >= 0x4008 && data.readBigUInt64LE(0x4000) === 0xe7ffdeffe7ffdeffn;
133
125
  this.headerCRC = crc16(this.raw.subarray(0, 0x15e)) === this.headerCRC16;
134
126
  this.logoCRC = crc16(this.logo) === this.logoCRC16;
135
127
  const secure = data.subarray(0x4000, 0x8000);
136
128
  this.secureCRC =
137
129
  secure.length > 0 &&
138
- crc16(this.decrypted ? encryptSecureArea(this.gameCode, secure) : secure) ===
139
- this.secureCRC16;
130
+ crc16(this.decrypted ? encryptSecureArea(this.gameCode, secure) : secure) === this.secureCRC16;
140
131
  this.dlp_signature = Buffer.alloc(0);
141
- if (
142
- this.ROMsize >= size &&
143
- this.ROMsize + 0x88 <= data.length &&
144
- data.readUInt32LE(this.ROMsize) === 0x00016361
145
- ) {
132
+ if (this.ROMsize >= size && this.ROMsize + 0x88 <= data.length && data.readUInt32LE(this.ROMsize) === 0x00016361) {
146
133
  this.dlp_signature = Buffer.from(data.subarray(this.ROMsize, this.ROMsize + 0x88));
147
134
  }
148
135
  }
@@ -153,7 +140,7 @@ export class Header {
153
140
  set size(value: number) {
154
141
  const power = Math.log2(value);
155
142
  if (!Number.isInteger(power) || power < 17 || power > 32)
156
- throw new RangeError('ROM capacity must be a power of two from 128 KiB to 4 GiB');
143
+ throw new RangeError("ROM capacity must be a power of two from 128 KiB to 4 GiB");
157
144
  this.raw[0x14] = power - 17;
158
145
  }
159
146
  toBuffer() {
@@ -163,7 +150,7 @@ export class Header {
163
150
  return data;
164
151
  }
165
152
  toString() {
166
- return `NDS header: ${this.gameTitle.replace(/\0+$/, '')} (${this.gameCode})`;
153
+ return `NDS header: ${this.gameTitle.replace(/\0+$/, "")} (${this.gameCode})`;
167
154
  }
168
155
  }
169
156
 
@@ -171,44 +158,44 @@ function field(
171
158
  name: string,
172
159
  offset: number,
173
160
  length: number,
174
- type: 'buffer' | 'string' | 'number' = 'buffer',
161
+ type: "buffer" | "string" | "number" = "buffer",
175
162
  dsi = false,
176
163
  ) {
177
164
  Object.defineProperty(Header.prototype, name, {
178
165
  enumerable: true,
179
166
  get(this: Header) {
180
167
  if (dsi && (!(this.unitCode & 2) || this.raw.length <= 0x200))
181
- return type === 'buffer' ? Buffer.alloc(length) : 0;
168
+ return type === "buffer" ? Buffer.alloc(length) : 0;
182
169
  const data = range(this.raw, offset, length, `header ${name}`);
183
- if (type === 'string') return data.toString('latin1');
184
- if (type === 'buffer') return data;
170
+ if (type === "string") return data.toString("latin1");
171
+ if (type === "buffer") return data;
185
172
  return length === 8 ? data.readBigUInt64LE() : data.readUIntLE(0, length);
186
173
  },
187
174
  set(this: Header, value: string | number | bigint | Uint8Array) {
188
175
  const target = range(this.raw, offset, length, `header ${name}`);
189
- if (type === 'string') {
190
- if (typeof value !== 'string' || Buffer.byteLength(value, 'latin1') > length)
176
+ if (type === "string") {
177
+ if (typeof value !== "string" || Buffer.byteLength(value, "latin1") > length)
191
178
  throw new TypeError(`Invalid ${name}`);
192
179
  target.fill(0);
193
- target.write(value, 'latin1');
194
- } else if (type === 'buffer') {
180
+ target.write(value, "latin1");
181
+ } else if (type === "buffer") {
195
182
  if (!(value instanceof Uint8Array)) throw new TypeError(`Invalid ${name}`);
196
183
  const source = bytes(value, name);
197
184
  if (source.length !== length) throw new RangeError(`${name} must contain ${length} bytes`);
198
185
  source.copy(target);
199
186
  } else if (length === 8) {
200
- if (typeof value !== 'bigint') throw new TypeError(`Invalid ${name}`);
187
+ if (typeof value !== "bigint") throw new TypeError(`Invalid ${name}`);
201
188
  target.writeBigUInt64LE(value);
202
189
  } else {
203
- if (typeof value !== 'number') throw new TypeError(`Invalid ${name}`);
190
+ if (typeof value !== "number") throw new TypeError(`Invalid ${name}`);
204
191
  target.writeUIntLE(value, 0, length);
205
192
  }
206
193
  },
207
194
  });
208
195
  }
209
- field('gameTitle', 0, 12, 'string');
210
- field('gameCode', 12, 4, 'string');
211
- field('makerCode', 16, 2, 'string');
196
+ field("gameTitle", 0, 12, "string");
197
+ field("gameCode", 12, 4, "string");
198
+ field("makerCode", 16, 2, "string");
212
199
  for (const [name, offset] of Object.entries({
213
200
  unitCode: 0x12,
214
201
  encryptionSeed: 0x13,
@@ -217,38 +204,38 @@ for (const [name, offset] of Object.entries({
217
204
  ROMversion: 0x1e,
218
205
  internalFlags: 0x1f,
219
206
  }))
220
- field(name, offset, 1, 'number');
221
- field('reserved', 0x15, 7);
207
+ field(name, offset, 1, "number");
208
+ field("reserved", 0x15, 7);
222
209
  const ntr32 =
223
- 'ARM9romOffset ARM9entryAddress ARM9ramAddress ARM9size ARM7romOffset ARM7entryAddress ARM7ramAddress ARM7size FNToffset FNTsize FAToffset FATsize ARM9overlayOffset ARM9overlaySize ARM7overlayOffset ARM7overlaySize flagsRead flagsInit bannerOffset'.split(
224
- ' ',
210
+ "ARM9romOffset ARM9entryAddress ARM9ramAddress ARM9size ARM7romOffset ARM7entryAddress ARM7ramAddress ARM7size FNToffset FNTsize FAToffset FATsize ARM9overlayOffset ARM9overlaySize ARM7overlayOffset ARM7overlaySize flagsRead flagsInit bannerOffset".split(
211
+ " ",
225
212
  );
226
- ntr32.forEach((name, i) => field(name, 0x20 + i * 4, 4, 'number'));
227
- field('secureCRC16', 0x6c, 2, 'number');
228
- field('ROMtimeout', 0x6e, 2, 'number');
229
- field('ARM9autoload', 0x70, 4, 'number');
230
- field('ARM7autoload', 0x74, 4, 'number');
231
- field('secureDisable', 0x78, 8, 'number');
232
- field('ROMsize', 0x80, 4, 'number');
233
- field('headerSize', 0x84, 4, 'number');
234
- field('reserved2', 0x88, 56);
235
- field('logo', 0xc0, 156);
236
- field('logoCRC16', 0x15c, 2, 'number');
237
- field('headerCRC16', 0x15e, 2, 'number');
238
- 'debug_romOffset debug_size debug_ramAddress reserved3'
239
- .split(' ')
240
- .forEach((name, i) => field(name, 0x160 + i * 4, 4, 'number'));
241
- field('appflags', 0x1bc, 4, 'buffer', true);
242
- 'mbk9_wramcnt_setting region_flags access_control scfg_ext_mask'
243
- .split(' ')
244
- .forEach((name, i) => field(name, 0x1ac + i * 4, 4, 'number', true));
213
+ ntr32.forEach((name, i) => field(name, 0x20 + i * 4, 4, "number"));
214
+ field("secureCRC16", 0x6c, 2, "number");
215
+ field("ROMtimeout", 0x6e, 2, "number");
216
+ field("ARM9autoload", 0x70, 4, "number");
217
+ field("ARM7autoload", 0x74, 4, "number");
218
+ field("secureDisable", 0x78, 8, "number");
219
+ field("ROMsize", 0x80, 4, "number");
220
+ field("headerSize", 0x84, 4, "number");
221
+ field("reserved2", 0x88, 56);
222
+ field("logo", 0xc0, 156);
223
+ field("logoCRC16", 0x15c, 2, "number");
224
+ field("headerCRC16", 0x15e, 2, "number");
225
+ "debug_romOffset debug_size debug_ramAddress reserved3"
226
+ .split(" ")
227
+ .forEach((name, i) => field(name, 0x160 + i * 4, 4, "number"));
228
+ field("appflags", 0x1bc, 4, "buffer", true);
229
+ "mbk9_wramcnt_setting region_flags access_control scfg_ext_mask"
230
+ .split(" ")
231
+ .forEach((name, i) => field(name, 0x1ac + i * 4, 4, "number", true));
245
232
  const twl32 =
246
- 'dsi9_rom_offset offset_0x1C4 dsi9_ram_address dsi9_size dsi7_rom_offset offset_0x1D4 dsi7_ram_address dsi7_size digest_ntr_start digest_ntr_size digest_twl_start digest_twl_size sector_hashtable_start sector_hashtable_size block_hashtable_start block_hashtable_size digest_sector_size digest_block_sectorcount banner_size offset_0x20C total_rom_size offset_0x214 offset_0x218 offset_0x21C modcrypt1_start modcrypt1_size modcrypt2_start modcrypt2_size tid_low tid_high public_sav_size private_sav_size'.split(
247
- ' ',
233
+ "dsi9_rom_offset offset_0x1C4 dsi9_ram_address dsi9_size dsi7_rom_offset offset_0x1D4 dsi7_ram_address dsi7_size digest_ntr_start digest_ntr_size digest_twl_start digest_twl_size sector_hashtable_start sector_hashtable_size block_hashtable_start block_hashtable_size digest_sector_size digest_block_sectorcount banner_size offset_0x20C total_rom_size offset_0x214 offset_0x218 offset_0x21C modcrypt1_start modcrypt1_size modcrypt2_start modcrypt2_size tid_low tid_high public_sav_size private_sav_size".split(
234
+ " ",
248
235
  );
249
- twl32.forEach((name, i) => field(name, 0x1c0 + i * 4, 4, 'number', true));
250
- 'hmac_arm9 hmac_arm7 hmac_digest_master hmac_icon_title hmac_arm9i hmac_arm7i'
251
- .split(' ')
252
- .forEach((name, i) => field(name, 0x300 + i * 20, 20, 'buffer', true));
253
- field('hmac_arm9_no_secure', 0x3a0, 20, 'buffer', true);
254
- field('rsa_signature', 0xf80, 0x80, 'buffer', true);
236
+ twl32.forEach((name, i) => field(name, 0x1c0 + i * 4, 4, "number", true));
237
+ "hmac_arm9 hmac_arm7 hmac_digest_master hmac_icon_title hmac_arm9i hmac_arm7i"
238
+ .split(" ")
239
+ .forEach((name, i) => field(name, 0x300 + i * 20, 20, "buffer", true));
240
+ field("hmac_arm9_no_secure", 0x3a0, 20, "buffer", true);
241
+ field("rsa_signature", 0xf80, 0x80, "buffer", true);