1
- /* RUP module for Rom Patcher JS v20240721 - Marc Robledo 2018-2024 - http://www.marcrobledo.com/license */
1
+ /* RUP module for Rom Patcher JS v20241102 - Marc Robledo 2018-2024 - http://www.marcrobledo.com/license */
2
2
/* File format specification: http://www.romhacking.net/documents/288/ */
3
3
4
4
const RUP_MAGIC = 'NINJA2' ;
@@ -40,7 +40,11 @@ RUP.prototype.toString=function(){
40
40
s += '\nTarget file size: ' + file . targetFileSize ;
41
41
s += '\nSource MD5: ' + file . sourceMD5 ;
42
42
s += '\nTarget MD5: ' + file . targetMD5 ;
43
- s += '\nOverflow text: ' + file . overflowText ;
43
+ if ( file . overflowMode === 'A' ) {
44
+ s += '\nOverflow mode: Append ' + file . overflowData . length + ' bytes' ;
45
+ } else if ( file . overflowMode === 'M' ) {
46
+ s += '\nOverflow mode: Minify ' + file . overflowData . length + ' bytes' ;
47
+ }
44
48
s += '\n#records: ' + file . records . length ;
45
49
}
46
50
return s
@@ -50,8 +54,11 @@ RUP.prototype.toString=function(){
50
54
RUP . prototype . validateSource = function ( romFile , headerSize ) {
51
55
var md5string = romFile . hashMD5 ( headerSize ) ;
52
56
for ( var i = 0 ; i < this . files . length ; i ++ ) {
53
- if ( this . files [ i ] . sourceMD5 === md5string ) {
54
- return this . files [ i ] ;
57
+ if ( this . files [ i ] . sourceMD5 === md5string || this . files [ i ] . targetMD5 === md5string ) {
58
+ return {
59
+ file :this . files [ i ] ,
60
+ undo :this . files [ i ] . targetMD5 === md5string
61
+ } ;
55
62
}
56
63
}
57
64
return false ;
@@ -77,32 +84,54 @@ RUP.prototype.apply=function(romFile, validate){
77
84
if ( ! validFile )
78
85
throw new Error ( 'Source ROM checksum mismatch' ) ;
79
86
} else {
80
- validFile = this . files [ 0 ] ;
87
+ validFile = {
88
+ file :this . files [ 0 ] ,
89
+ undo :this . files [ 0 ] . targetMD5 === romFile . hashMD5 ( )
90
+ } ;
81
91
}
82
92
93
+ var undo = validFile . undo ;
94
+ var patch = validFile . file ;
83
95
84
-
85
- tempFile = new BinFile ( validFile . targetFileSize ) ;
96
+ tempFile = new BinFile ( ! undo ? patch . targetFileSize : patch . sourceFileSize ) ;
86
97
/* copy original file */
87
98
romFile . copyTo ( tempFile , 0 ) ;
88
99
89
100
90
- for ( var i = 0 ; i < validFile . records . length ; i ++ ) {
91
- var offset = validFile . records [ i ] . offset ;
101
+ for ( var i = 0 ; i < patch . records . length ; i ++ ) {
102
+ var offset = patch . records [ i ] . offset ;
92
103
romFile . seek ( offset ) ;
93
104
tempFile . seek ( offset ) ;
94
- for ( var j = 0 ; j < validFile . records [ i ] . xor . length ; j ++ ) {
105
+ for ( var j = 0 ; j < patch . records [ i ] . xor . length ; j ++ ) {
95
106
tempFile . writeU8 (
96
- ( romFile . isEOF ( ) ?0x00 :romFile . readU8 ( ) ) ^ validFile . records [ i ] . xor [ j ]
107
+ ( romFile . isEOF ( ) ?0x00 :romFile . readU8 ( ) ) ^ patch . records [ i ] . xor [ j ]
97
108
) ;
98
109
}
99
110
}
100
111
112
+ /* add overflow data if needed */
113
+ if ( patch . overflowMode === 'A' && ! undo ) { /* append */
114
+ tempFile . seek ( patch . sourceFileSize ) ;
115
+ tempFile . writeBytes ( patch . overflowData . map ( ( byte ) => byte ^ 0xff ) ) ;
116
+ } else if ( patch . overflowMode === 'M' && undo ) { /* minify */
117
+ tempFile . seek ( patch . targetFileSize ) ;
118
+ tempFile . writeBytes ( patch . overflowData . map ( ( byte ) => byte ^ 0xff ) ) ;
119
+ }
101
120
102
- if ( validate && tempFile . hashMD5 ( ) !== validFile . targetMD5 ) {
121
+
122
+ if (
123
+ validate &&
124
+ (
125
+ ( ! undo && tempFile . hashMD5 ( ) !== patch . targetMD5 ) ||
126
+ ( undo && tempFile . hashMD5 ( ) !== patch . sourceMD5 )
127
+ )
128
+ ) {
103
129
throw new Error ( 'Target ROM checksum mismatch' ) ;
104
130
}
105
131
132
+ if ( undo )
133
+ tempFile . unpatched = true ;
134
+
106
135
return tempFile
107
136
}
108
137
@@ -161,8 +190,10 @@ RUP.fromFile=function(file){
161
190
162
191
163
192
if ( nextFile . sourceFileSize !== nextFile . targetFileSize ) {
164
- file . skip ( 1 ) ; //skip 'M' (source>target) or 'A' (source<target)
165
- nextFile . overflowText = file . readString ( file . readVLV ( ) ) ;
193
+ nextFile . overflowMode = file . readString ( 1 ) ; // 'M' (source>target) or 'A' (source<target)
194
+ if ( nextFile . overflowMode !== 'M' && nextFile . overflowMode !== 'A' )
195
+ throw new Error ( 'RUP: invalid overflow mode' ) ;
196
+ nextFile . overflowData = file . readBytes ( file . readVLV ( ) ) ;
166
197
}
167
198
168
199
} else if ( command === RUP_COMMAND_XOR_RECORD ) {
@@ -229,8 +260,8 @@ RUP.prototype.export=function(fileName){
229
260
230
261
if ( file . sourceFileSize !== file . targetFileSize ) {
231
262
patchFileSize ++ ; // M or A
232
- patchFileSize += RUP_getVLVLen ( file . overflowText ) ;
233
- patchFileSize += file . overflowText ;
263
+ patchFileSize += RUP_getVLVLen ( file . overflowData . length ) ;
264
+ patchFileSize += file . overflowData . length ;
234
265
}
235
266
for ( var j = 0 ; j < file . records . length ; j ++ ) {
236
267
patchFileSize ++ ; //command 0x01
@@ -279,8 +310,8 @@ RUP.prototype.export=function(fileName){
279
310
280
311
if ( file . sourceFileSize !== file . targetFileSize ) {
281
312
patchFile . writeString ( file . sourceFileSize > file . targetFileSize ?'M' :'A' ) ;
282
- patchFile . writeVLV ( file . overflowText . length ) ;
283
- patchFile . writeString ( file . overflowText ) ;
313
+ patchFile . writeVLV ( file . overflowData . length ) ;
314
+ patchFile . writeBytes ( file . overflowData ) ;
284
315
}
285
316
286
317
for ( var j = 0 ; j < file . records . length ; j ++ ) {
@@ -314,10 +345,23 @@ RUP.buildFromRoms=function(original, modified){
314
345
targetFileSize :modified . fileSize ,
315
346
sourceMD5 :original . hashMD5 ( ) ,
316
347
targetMD5 :modified . hashMD5 ( ) ,
317
- overflowText :'' ,
348
+ overflowMode :null ,
349
+ overflowData :[ ] ,
318
350
records :[ ]
319
351
} ;
320
352
353
+ if ( file . sourceFileSize < file . targetFileSize ) {
354
+ modified . seek ( file . sourceFileSize ) ;
355
+ file . overflowMode = 'A' ;
356
+ file . overflowData = modified . readBytes ( file . targetFileSize - file . sourceFileSize ) . map ( ( byte ) => byte ^ 0xff ) ;
357
+ modified = modified . slice ( 0 , file . sourceFileSize ) ;
358
+ } else if ( file . sourceFileSize > file . targetFileSize ) {
359
+ original . seek ( file . targetFileSize ) ;
360
+ file . overflowMode = 'M' ;
361
+ file . overflowData = original . readBytes ( file . sourceFileSize - file . targetFileSize ) . map ( ( byte ) => byte ^ 0xff ) ;
362
+ original = original . slice ( 0 , file . targetFileSize ) ;
363
+ }
364
+
321
365
322
366
original . seek ( 0 ) ;
323
367
modified . seek ( 0 ) ;
0 commit comments