/// <summary> /// Writes the archive header. /// </summary> public void WriteHeader(byte[] aesKey = null, byte[] ngKey = null) { // backup position var positionBackup = BaseStream.Position; var writer = new DataWriter(BaseStream); var entries = new List <IRageArchiveEntry7>(); var stack = new Stack <RageArchiveDirectory7>(); var nameOffset = 1; entries.Add(Root); stack.Push(Root); var nameDict = new Dictionary <string, uint>(); nameDict.Add("", 0); while (stack.Count > 0) { var directory = stack.Pop(); directory.EntriesIndex = (uint)entries.Count; directory.EntriesCount = (uint)directory.Directories.Count + (uint)directory.Files.Count; var theList = new List <IRageArchiveEntry7>(); foreach (var xd in directory.Directories) { if (!nameDict.ContainsKey(xd.Name)) { nameDict.Add(xd.Name, (uint)nameOffset); nameOffset += xd.Name.Length + 1; } xd.NameOffset = nameDict[xd.Name]; //xd.NameOffset = (ushort)nameOffset; //nameOffset += xd.Name.Length + 1; //entries.Add(xd); //stack.Push(xd); theList.Add(xd); } foreach (var xf in directory.Files) { if (!nameDict.ContainsKey(xf.Name)) { nameDict.Add(xf.Name, (uint)nameOffset); nameOffset += xf.Name.Length + 1; } xf.NameOffset = nameDict[xf.Name]; //xf.NameOffset = (ushort)nameOffset; //nameOffset += xf.Name.Length + 1; //entries.Add(xf); theList.Add(xf); } theList.Sort( delegate(IRageArchiveEntry7 a, IRageArchiveEntry7 b) { return(string.CompareOrdinal(a.Name, b.Name)); } ); foreach (var xx in theList) { entries.Add(xx); } theList.Reverse(); foreach (var xx in theList) { if (xx is RageArchiveDirectory7) { stack.Push((RageArchiveDirectory7)xx); } } } // there are sometimes resources with length>=0xffffff which actually // means length=0xffffff // -> we therefore just cut the file size foreach (var entry in entries) { if (entry is RageArchiveResourceFile7) { var resource = entry as RageArchiveResourceFile7; if (resource.FileSize > 0xFFFFFF) { var buf = new byte[16]; buf[7] = (byte)((resource.FileSize >> 0) & 0xFF); buf[14] = (byte)((resource.FileSize >> 8) & 0xFF); buf[5] = (byte)((resource.FileSize >> 16) & 0xFF); buf[2] = (byte)((resource.FileSize >> 24) & 0xFF); if (writer.Length > 512 * resource.FileOffset) { writer.Position = 512 * resource.FileOffset; writer.Write(buf); } resource.FileSize = 0xFFFFFF; } } } // entries... var ent_str = new MemoryStream(); var ent_wr = new DataWriter(ent_str); foreach (var entry in entries) { entry.Write(ent_wr); } ent_str.Flush(); var ent_buf = new byte[ent_str.Length]; ent_str.Position = 0; ent_str.Read(ent_buf, 0, ent_buf.Length); if (Encryption == RageArchiveEncryption7.AES) { ent_buf = AesEncryption.EncryptData(ent_buf, aesKey); } else if (Encryption == RageArchiveEncryption7.NG) { ent_buf = GTA5Crypto.Encrypt(ent_buf, ngKey); } // names... var n_str = new MemoryStream(); var n_wr = new DataWriter(n_str); //foreach (var entry in entries) // n_wr.Write(entry.Name); foreach (var entry in nameDict) { n_wr.Write(entry.Key); } var empty = new byte[16 - (n_wr.Length % 16)]; n_wr.Write(empty); n_str.Flush(); var n_buf = new byte[n_str.Length]; n_str.Position = 0; n_str.Read(n_buf, 0, n_buf.Length); if (Encryption == RageArchiveEncryption7.AES) { n_buf = AesEncryption.EncryptData(n_buf, aesKey); } else if (Encryption == RageArchiveEncryption7.NG) { n_buf = GTA5Crypto.Encrypt(n_buf, ngKey); } writer.Position = 0; writer.Write((uint)IDENT); writer.Write((uint)entries.Count); writer.Write((uint)n_buf.Length); switch (Encryption) { case RageArchiveEncryption7.None: writer.Write((uint)0x04E45504F); break; case RageArchiveEncryption7.AES: writer.Write((uint)0x0ffffff9); break; case RageArchiveEncryption7.NG: writer.Write((uint)0x0fefffff); break; } writer.Write(ent_buf); writer.Write(n_buf); // restore position BaseStream.Position = positionBackup; }
/// <summary> /// Writes the archive header. /// </summary> public void WriteHeader(byte[] aesKey = null, byte[] ngKey = null) { long position = this.BaseStream.Position; DataWriter dataWriter = new DataWriter(this.BaseStream, Endianess.LittleEndian); List <IRageArchiveEntry7> list = new List <IRageArchiveEntry7>(); Stack <RageArchiveDirectory7> stack = new Stack <RageArchiveDirectory7>(); int num = 1; list.Add(this.Root); stack.Push(this.Root); Dictionary <string, uint> dictionary = new Dictionary <string, uint>(); dictionary.Add("", 0); while (stack.Count > 0) { RageArchiveDirectory7 rageArchiveDirectory = stack.Pop(); rageArchiveDirectory.EntriesIndex = (uint)list.Count; rageArchiveDirectory.EntriesCount = (uint)(rageArchiveDirectory.Directories.Count + rageArchiveDirectory.Files.Count); List <IRageArchiveEntry7> list2 = new List <IRageArchiveEntry7>(); foreach (RageArchiveDirectory7 rageArchiveDirectory2 in rageArchiveDirectory.Directories) { if (!dictionary.ContainsKey(rageArchiveDirectory2.Name)) { dictionary.Add(rageArchiveDirectory2.Name, (uint)num); num += rageArchiveDirectory2.Name.Length + 1; } rageArchiveDirectory2.NameOffset = dictionary[rageArchiveDirectory2.Name]; list2.Add(rageArchiveDirectory2); } foreach (IRageArchiveEntry7 rageArchiveEntry in rageArchiveDirectory.Files) { if (!dictionary.ContainsKey(rageArchiveEntry.Name)) { dictionary.Add(rageArchiveEntry.Name, (uint)num); num += rageArchiveEntry.Name.Length + 1; } rageArchiveEntry.NameOffset = dictionary[rageArchiveEntry.Name]; list2.Add(rageArchiveEntry); } list2.Sort((IRageArchiveEntry7 a, IRageArchiveEntry7 b) => string.CompareOrdinal(a.Name, b.Name)); foreach (IRageArchiveEntry7 item in list2) { list.Add(item); } list2.Reverse(); foreach (IRageArchiveEntry7 rageArchiveEntry2 in list2) { if (rageArchiveEntry2 is RageArchiveDirectory7) { stack.Push((RageArchiveDirectory7)rageArchiveEntry2); } } } foreach (IRageArchiveEntry7 rageArchiveEntry3 in list) { if (rageArchiveEntry3 is RageArchiveResourceFile7) { RageArchiveResourceFile7 rageArchiveResourceFile = rageArchiveEntry3 as RageArchiveResourceFile7; if (rageArchiveResourceFile.FileSize > 0x00FFFFFF) { byte[] array = new byte[16]; array[7] = (byte)(rageArchiveResourceFile.FileSize & 255); array[14] = (byte)(rageArchiveResourceFile.FileSize >> 8 & 255); array[5] = (byte)(rageArchiveResourceFile.FileSize >> 16 & 255); array[2] = (byte)(rageArchiveResourceFile.FileSize >> 24 & 255); if (dataWriter.Length > (512 * rageArchiveResourceFile.FileOffset)) { dataWriter.Position = (512 * rageArchiveResourceFile.FileOffset); dataWriter.Write(array); } rageArchiveResourceFile.FileSize = 0x00FFFFFF; } } } MemoryStream memoryStream = new MemoryStream(); DataWriter writer = new DataWriter(memoryStream, Endianess.LittleEndian); foreach (IRageArchiveEntry7 rageArchiveEntry4 in list) { rageArchiveEntry4.Write(writer); } memoryStream.Flush(); byte[] array2 = new byte[memoryStream.Length]; memoryStream.Position = 0L; memoryStream.Read(array2, 0, array2.Length); if (this.Encryption == RageArchiveEncryption7.AES) { array2 = AesEncryption.EncryptData(array2, aesKey, 1); } if (this.Encryption == RageArchiveEncryption7.NG) { array2 = GTA5Crypto.Encrypt(array2, ngKey); } MemoryStream memoryStream2 = new MemoryStream(); DataWriter dataWriter2 = new DataWriter(memoryStream2, Endianess.LittleEndian); foreach (KeyValuePair <string, uint> keyValuePair in dictionary) { dataWriter2.Write(keyValuePair.Key); } byte[] value = new byte[16L - dataWriter2.Length % 16L]; dataWriter2.Write(value); memoryStream2.Flush(); byte[] array3 = new byte[memoryStream2.Length]; memoryStream2.Position = 0L; memoryStream2.Read(array3, 0, array3.Length); if (this.Encryption == RageArchiveEncryption7.AES) { array3 = AesEncryption.EncryptData(array3, aesKey, 1); } if (this.Encryption == RageArchiveEncryption7.NG) { array3 = GTA5Crypto.Encrypt(array3, ngKey); } dataWriter.Position = 0L; dataWriter.Write(0x52504637); dataWriter.Write((uint)list.Count); dataWriter.Write((uint)array3.Length); switch (this.Encryption) { case RageArchiveEncryption7.None: dataWriter.Write(0x4E45504F); break; case RageArchiveEncryption7.AES: dataWriter.Write(0x0FFFFFF9); break; case RageArchiveEncryption7.NG: dataWriter.Write(0x0FEFFFFF); break; } dataWriter.Write(array2); dataWriter.Write(array3); this.BaseStream.Position = position; }