/// <summary> /// Releases all resources used by the archive. /// </summary> public void Dispose() { if (BaseStream != null) { BaseStream.Dispose(); } BaseStream = null; Root = null; }
/// <summary> /// Reads the archive header. /// </summary> public void ReadHeader(byte[] aesKey = null, byte[] ngKey = null) { var reader = new DataReader(BaseStream); var posbak = reader.Position; reader.Position = 0; uint header_identifier = reader.ReadUInt32(); // 0x52504637 if (header_identifier != IDENT) throw new Exception("The identifier " + header_identifier.ToString("X8") + " did not match the expected value of 0x52504637"); uint header_entriesCount = reader.ReadUInt32(); uint header_namesLength = reader.ReadUInt32(); uint header_encryption = reader.ReadUInt32(); byte[] entries_data_dec = null; byte[] names_data_dec = null; if (header_encryption == 0x04E45504F) // for OpenIV compatibility { // no encryption... Encryption = RageArchiveEncryption7.None; entries_data_dec = reader.ReadBytes(16 * (int)header_entriesCount); names_data_dec = reader.ReadBytes((int)header_namesLength); } else if (header_encryption == 0x0ffffff9) { // AES enceyption... Encryption = RageArchiveEncryption7.AES; var entries_data = reader.ReadBytes(16 * (int)header_entriesCount); entries_data_dec = AesEncryption.DecryptData(entries_data, aesKey); var names_data = reader.ReadBytes((int)header_namesLength); names_data_dec = AesEncryption.DecryptData(names_data, aesKey); } else { // NG encryption... Encryption = RageArchiveEncryption7.NG; var entries_data = reader.ReadBytes(16 * (int)header_entriesCount); entries_data_dec = GTA5Crypto.Decrypt(entries_data, ngKey); var names_data = reader.ReadBytes((int)header_namesLength); names_data_dec = GTA5Crypto.Decrypt(names_data, ngKey); } var entries_reader = new DataReader(new MemoryStream(entries_data_dec)); var names_reader = new DataReader(new MemoryStream(names_data_dec)); var entries = new List<IRageArchiveEntry7>(); for (var index = 0; index < header_entriesCount; index++) { entries_reader.Position += 4; int x = entries_reader.ReadInt32(); entries_reader.Position -= 8; if (x == 0x7fffff00) { // directory var e = new RageArchiveDirectory7(); e.Read(entries_reader); names_reader.Position = e.NameOffset; e.Name = names_reader.ReadString(); entries.Add(e); } else { if ((x & 0x80000000) == 0) { // binary file var e = new RageArchiveBinaryFile7(); e.Read(entries_reader); names_reader.Position = e.NameOffset; e.Name = names_reader.ReadString(); entries.Add(e); } else { // resource file var e = new RageArchiveResourceFile7(); e.Read(entries_reader); // there are sometimes resources with length=0xffffff which actually // means length>=0xffffff if (e.FileSize == 0xFFFFFF) { reader.Position = 512 * e.FileOffset; var buf = reader.ReadBytes(16); e.FileSize = ((uint)buf[7] << 0) | ((uint)buf[14] << 8) | ((uint)buf[5] << 16) | ((uint)buf[2] << 24); } names_reader.Position = e.NameOffset; e.Name = names_reader.ReadString(); entries.Add(e); } } } var stack = new Stack<RageArchiveDirectory7>(); stack.Push((RageArchiveDirectory7)entries[0]); Root = (RageArchiveDirectory7)entries[0]; while (stack.Count > 0) { var item = stack.Pop(); for (int index = (int)item.EntriesIndex; index < (item.EntriesIndex + item.EntriesCount); index++) { if (entries[index] is RageArchiveDirectory7) { item.Directories.Add(entries[index] as RageArchiveDirectory7); stack.Push(entries[index] as RageArchiveDirectory7); } else { item.Files.Add(entries[index]); } } } reader.Position = posbak; }
/// <summary> /// Releases all resources used by the archive. /// </summary> public void Dispose() { if (BaseStream != null) BaseStream.Dispose(); BaseStream = null; Root = null; }
/// <summary> /// Reads the archive header. /// </summary> public void ReadHeader(byte[] aesKey = null, byte[] ngKey = null) { var reader = new DataReader(BaseStream); var posbak = reader.Position; reader.Position = 0; uint header_identifier = reader.ReadUInt32(); // 0x52504637 if (header_identifier != IDENT) { throw new Exception("The identifier " + header_identifier.ToString("X8") + " did not match the expected value of 0x52504637"); } uint header_entriesCount = reader.ReadUInt32(); uint header_namesLength = reader.ReadUInt32(); uint header_encryption = reader.ReadUInt32(); byte[] entries_data_dec = null; byte[] names_data_dec = null; if (header_encryption == 0x04E45504F) // for OpenIV compatibility { // no encryption... Encryption = RageArchiveEncryption7.None; entries_data_dec = reader.ReadBytes(16 * (int)header_entriesCount); names_data_dec = reader.ReadBytes((int)header_namesLength); } else if (header_encryption == 0x0ffffff9) { // AES enceyption... Encryption = RageArchiveEncryption7.AES; var entries_data = reader.ReadBytes(16 * (int)header_entriesCount); entries_data_dec = AesEncryption.DecryptData(entries_data, aesKey); var names_data = reader.ReadBytes((int)header_namesLength); names_data_dec = AesEncryption.DecryptData(names_data, aesKey); } else { // NG encryption... Encryption = RageArchiveEncryption7.NG; var entries_data = reader.ReadBytes(16 * (int)header_entriesCount); entries_data_dec = GTA5Crypto.Decrypt(entries_data, ngKey); var names_data = reader.ReadBytes((int)header_namesLength); names_data_dec = GTA5Crypto.Decrypt(names_data, ngKey); } var entries_reader = new DataReader(new MemoryStream(entries_data_dec)); var names_reader = new DataReader(new MemoryStream(names_data_dec)); var entries = new List <IRageArchiveEntry7>(); for (var index = 0; index < header_entriesCount; index++) { entries_reader.Position += 4; int x = entries_reader.ReadInt32(); entries_reader.Position -= 8; if (x == 0x7fffff00) { // directory var e = new RageArchiveDirectory7(); e.Read(entries_reader); names_reader.Position = e.NameOffset; e.Name = names_reader.ReadString(); entries.Add(e); } else { if ((x & 0x80000000) == 0) { // binary file var e = new RageArchiveBinaryFile7(); e.Read(entries_reader); names_reader.Position = e.NameOffset; e.Name = names_reader.ReadString(); entries.Add(e); } else { // resource file var e = new RageArchiveResourceFile7(); e.Read(entries_reader); // there are sometimes resources with length=0xffffff which actually // means length>=0xffffff if (e.FileSize == 0xFFFFFF) { reader.Position = 512 * e.FileOffset; var buf = reader.ReadBytes(16); e.FileSize = ((uint)buf[7] << 0) | ((uint)buf[14] << 8) | ((uint)buf[5] << 16) | ((uint)buf[2] << 24); } names_reader.Position = e.NameOffset; e.Name = names_reader.ReadString(); entries.Add(e); } } } var stack = new Stack <RageArchiveDirectory7>(); stack.Push((RageArchiveDirectory7)entries[0]); Root = (RageArchiveDirectory7)entries[0]; while (stack.Count > 0) { var item = stack.Pop(); for (int index = (int)item.EntriesIndex; index < (item.EntriesIndex + item.EntriesCount); index++) { if (entries[index] is RageArchiveDirectory7) { item.Directories.Add(entries[index] as RageArchiveDirectory7); stack.Push(entries[index] as RageArchiveDirectory7); } else { item.Files.Add(entries[index]); } } } reader.Position = posbak; }
/// <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; }
/// <summary> /// Reads the archive header. /// </summary> public void ReadHeader(byte[] aesKey = null, byte[] ngKey = null) { DataReader dataReader = new DataReader(this.BaseStream, Endianess.LittleEndian); long position = dataReader.Position; dataReader.Position = 0L; uint num = dataReader.ReadUInt32(); if (num != 0x52504637) { throw new Exception("The identifier " + num.ToString("X8") + " did not match the expected value of 0x52504637"); } uint num2 = dataReader.ReadUInt32(); uint count = dataReader.ReadUInt32(); uint num3 = dataReader.ReadUInt32(); byte[] buffer; byte[] buffer2; if (num3 == 0x4E45504F) { this.Encryption = RageArchiveEncryption7.None; buffer = dataReader.ReadBytes(16 * (int)num2); buffer2 = dataReader.ReadBytes((int)count); } else if (num3 == 0x0FFFFFF9) { this.Encryption = RageArchiveEncryption7.AES; byte[] data = dataReader.ReadBytes(16 * (int)num2); buffer = AesEncryption.DecryptData(data, aesKey, 1); byte[] data2 = dataReader.ReadBytes((int)count); buffer2 = AesEncryption.DecryptData(data2, aesKey, 1); } else { this.Encryption = RageArchiveEncryption7.NG; byte[] data3 = dataReader.ReadBytes(16 * (int)num2); buffer = GTA5Crypto.Decrypt(data3, ngKey); byte[] data4 = dataReader.ReadBytes((int)count); buffer2 = GTA5Crypto.Decrypt(data4, ngKey); } DataReader dataReader2 = new DataReader(new MemoryStream(buffer), Endianess.LittleEndian); DataReader dataReader3 = new DataReader(new MemoryStream(buffer2), Endianess.LittleEndian); List <IRageArchiveEntry7> list = new List <IRageArchiveEntry7>(); int num4 = 0; while (num4 < num2) { dataReader2.Position += 4L; int num5 = dataReader2.ReadInt32(); dataReader2.Position -= 8L; if (num5 == 0x7FFFFF00) { RageArchiveDirectory7 rageArchiveDirectory = new RageArchiveDirectory7(); rageArchiveDirectory.Read(dataReader2); dataReader3.Position = (long)((ulong)rageArchiveDirectory.NameOffset); rageArchiveDirectory.Name = dataReader3.ReadString(); list.Add(rageArchiveDirectory); } else if ((num5 & 0x80000000) == 0L) { RageArchiveBinaryFile7 rageArchiveBinaryFile = new RageArchiveBinaryFile7(); rageArchiveBinaryFile.Read(dataReader2); dataReader3.Position = rageArchiveBinaryFile.NameOffset; rageArchiveBinaryFile.Name = dataReader3.ReadString(); list.Add(rageArchiveBinaryFile); } else { RageArchiveResourceFile7 rageArchiveResourceFile = new RageArchiveResourceFile7(); rageArchiveResourceFile.Read(dataReader2); if (rageArchiveResourceFile.FileSize == 0x00FFFFFF) { dataReader.Position = 512 * rageArchiveResourceFile.FileOffset; byte[] array = dataReader.ReadBytes(16); rageArchiveResourceFile.FileSize = (uint)(array[7] | array[14] << 8 | array[5] << 16 | array[2] << 24); } dataReader3.Position = rageArchiveResourceFile.NameOffset; rageArchiveResourceFile.Name = dataReader3.ReadString(); list.Add(rageArchiveResourceFile); } num4++; } Stack <RageArchiveDirectory7> stack = new Stack <RageArchiveDirectory7>(); stack.Push((RageArchiveDirectory7)list[0]); this.Root = (RageArchiveDirectory7)list[0]; while (stack.Count > 0) { RageArchiveDirectory7 rageArchiveDirectory2 = stack.Pop(); int num6 = (int)rageArchiveDirectory2.EntriesIndex; while ((long)num6 < (long)((ulong)(rageArchiveDirectory2.EntriesIndex + rageArchiveDirectory2.EntriesCount))) { if (list[num6] is RageArchiveDirectory7) { rageArchiveDirectory2.Directories.Add(list[num6] as RageArchiveDirectory7); stack.Push(list[num6] as RageArchiveDirectory7); } else { rageArchiveDirectory2.Files.Add(list[num6]); } num6++; } } dataReader.Position = position; }
public void Dispose() { this.archiveWrapper = null; this.directory = null; }
/// <summary> /// Creates a new directory inside this directory. /// </summary> public IArchiveDirectory CreateDirectory() { var newDirectory = new RageArchiveDirectory7(); var newDirectoryWrapper = new RageArchiveDirectoryWrapper7(archiveWrapper, newDirectory); this.directory.Directories.Add(newDirectory); return newDirectoryWrapper; }
internal RageArchiveDirectoryWrapper7(RageArchiveWrapper7 archiveWrapper, RageArchiveDirectory7 directory) { this.archiveWrapper = archiveWrapper; this.directory = directory; }
public static RageArchiveWrapper7 Create(Stream stream, string fileName, bool leaveOpen = false) { var arch = new RageArchiveWrapper7(stream, fileName, leaveOpen); var rootD = new RageArchiveDirectory7(); rootD.Name = ""; arch.archive_.Root = rootD; // arch.archive_.WriteHeader(); // write... return arch; }
///////////////////////////////////////////////////////////////////////////// // static functions ///////////////////////////////////////////////////////////////////////////// public static RageArchiveWrapper7 Create(string fileName) { var finfo = new FileInfo(fileName); var fs = new FileStream(fileName, FileMode.Create); var arch = new RageArchiveWrapper7(fs, finfo.Name, false); var rootD = new RageArchiveDirectory7(); rootD.Name = ""; arch.archive_.Root = rootD; // arch.archive_.WriteHeader(); // write... return arch; }