@@ -73,7 +73,8 @@ public SARCHeader()
7373 Endianness = 0xFFFE ; //0xFEFF;
7474 FileSize = 0 ;
7575 FileDataOffset = 0 ;
76- Unknown = 0x0100 ;
76+ Version = 0x0100 ;
77+ Reserved = 0 ;
7778 }
7879 public SARCHeader ( EndianBinaryReaderEx er )
7980 {
@@ -88,7 +89,8 @@ public void Write(EndianBinaryWriter er)
8889 if ( Endianness == 0xFFFE ) er . Endianness = LibEveryFileExplorer . IO . Endianness . LittleEndian ;
8990 er . Write ( FileSize ) ;
9091 er . Write ( FileDataOffset ) ;
91- er . Write ( Unknown ) ;
92+ er . Write ( Version ) ;
93+ er . Write ( Reserved ) ;
9294 }
9395 [ BinaryStringSignature ( "SARC" ) ]
9496 [ BinaryFixedSize ( 4 ) ]
@@ -98,7 +100,8 @@ public void Write(EndianBinaryWriter er)
98100 public UInt16 Endianness ;
99101 public UInt32 FileSize ;
100102 public UInt32 FileDataOffset ;
101- public UInt32 Unknown ;
103+ public UInt16 Version ;
104+ public UInt16 Reserved ;
102105 }
103106
104107 public SFAT SFat ;
@@ -192,17 +195,29 @@ public void Write(EndianBinaryWriter er)
192195 public bool CompressDuplicateFiles {
193196 get
194197 {
195- return ( Unknown1 & 1 ) == 1 ;
198+ return ( Unknown1 & 1 ) != 0 ;
196199 }
197200 set
198201 {
199202 Unknown1 = ( ushort ) ( ( Unknown1 & ~ 1 ) | ( value ? 1 : 0 ) ) ;
200203 }
201204 }
205+ public bool HashEntireFile
206+ {
207+ get
208+ {
209+ return ( Unknown1 & 2 ) != 0 ;
210+ }
211+ set
212+ {
213+ Unknown1 = ( ushort ) ( ( Unknown1 & ~ 2 ) | ( value ? 2 : 0 ) ) ;
214+ }
215+ }
202216 }
203217
204218 private class SARCDataBuilder
205219 {
220+ private bool HashFile = false ;
206221 private class FileEntry
207222 {
208223 public long position ;
@@ -225,12 +240,21 @@ public int GetHashCode(byte[] obj)
225240 }
226241 }
227242
228- public SARCDataBuilder ( bool duplicateFileCompress )
243+ public SARCDataBuilder ( bool duplicateFileCompress , bool StoreFileHash )
229244 {
230245 DuplicateFileCompress = duplicateFileCompress ;
231246 FileDataHashes = new Dictionary < byte [ ] , FileEntry > ( new ByteArrayComparer ( ) ) ;
232247 MemoryStream = new MemoryStream ( ) ;
233248 MD5Provider = MD5 . Create ( ) ;
249+ HashFile = StoreFileHash ;
250+ if ( HashFile ) {
251+ // Make room for the hash
252+ for ( int i = 0 ; i < 8 ; i ++ )
253+ MemoryStream . WriteByte ( 0 ) ;
254+
255+ while ( ( MemoryStream . Position % 128 ) != 0 )
256+ MemoryStream . WriteByte ( 0 ) ;
257+ }
234258 }
235259
236260 public long Append ( SFSFile file )
@@ -260,6 +284,39 @@ public long Append(SFSFile file)
260284 }
261285 }
262286
287+ public void UpdateFullFileHash ( )
288+ {
289+ if ( ! HashFile )
290+ return ;
291+
292+ var position = MemoryStream . Position ;
293+
294+ MemoryStream . Position = 128 ;
295+ UInt32 hash1 = 0 , hash2 = 0 ;
296+ byte [ ] buffer = new byte [ 4 ] ;
297+ long size = MemoryStream . Length - 128 ;
298+ // Align size to the next multiple of 8,
299+ // 0 will be read for the padding bytes.
300+ size = ( size + 7 ) & ~ 7L ;
301+ for ( int i = 0 ; i < size / sizeof ( UInt32 ) ; i += 2 )
302+ {
303+ buffer [ 0 ] = buffer [ 1 ] = buffer [ 2 ] = buffer [ 3 ] = 0 ;
304+ MemoryStream . Read ( buffer , 0 , 4 ) ;
305+ var data1 = BitConverter . ToUInt32 ( buffer , 0 ) ;
306+ buffer [ 0 ] = buffer [ 1 ] = buffer [ 2 ] = buffer [ 3 ] = 0 ;
307+ MemoryStream . Read ( buffer , 0 , 4 ) ;
308+ var data2 = BitConverter . ToUInt32 ( buffer , 0 ) ;
309+
310+ hash1 += data1 * 47U ;
311+ hash2 += data2 * 47U ;
312+ }
313+
314+ var finalHash = BitConverter . GetBytes ( ( UInt64 ) hash1 | ( ( UInt64 ) hash2 << 32 ) ) ;
315+ MemoryStream . Position = 0 ;
316+ MemoryStream . Write ( finalHash , 0 , finalHash . Length ) ;
317+ MemoryStream . Position = position ;
318+ }
319+
263320 public byte [ ] Get ( )
264321 {
265322 return MemoryStream . ToArray ( ) ;
@@ -360,7 +417,8 @@ public void FromFileSystem(SFSDirectory Root)
360417 SFat = new SFAT ( ) ;
361418 SFat . NrEntries = ( ushort ) Root . Files . Count ;
362419 bool CompressDuplicateFiles = SFnt != null ? SFnt . CompressDuplicateFiles : false ;
363- SARCDataBuilder DataBuilder = new SARCDataBuilder ( CompressDuplicateFiles ) ;
420+ bool HashEntireFile = SFnt != null ? SFnt . HashEntireFile : false ;
421+ SARCDataBuilder DataBuilder = new SARCDataBuilder ( CompressDuplicateFiles , HashEntireFile ) ;
364422 Root . Files . Sort ( delegate ( SFSFile a , SFSFile b ) {
365423 uint hasha = ( uint ) a . FileID ;
366424 uint hashb = ( uint ) b . FileID ;
@@ -372,9 +430,12 @@ public void FromFileSystem(SFSDirectory Root)
372430 long DataStart = DataBuilder . Append ( v ) ;
373431 SFat . Entries . Add ( new SFAT . SFATEntry ( ) { FileDataStart = ( uint ) DataStart , FileDataEnd = ( uint ) ( DataStart + v . Data . Length ) , FileNameHash = hash , FileNameOffset = 0 } ) ;
374432 }
433+ if ( HashEntireFile )
434+ DataBuilder . UpdateFullFileHash ( ) ;
375435 Data = DataBuilder . Get ( ) ;
376436 SFnt = new SFNT ( ) ;
377437 SFnt . CompressDuplicateFiles = CompressDuplicateFiles ;
438+ SFnt . HashEntireFile = HashEntireFile ;
378439 Header . FileSize = ( uint ) ( 0x14 + 0xC + SFat . NrEntries * 0x10 + 0x8 ) ;
379440 while ( ( Header . FileSize % 128 ) != 0 ) Header . FileSize ++ ;
380441 Header . FileDataOffset = Header . FileSize ;
0 commit comments