public void Load(byte[] data, RpfFileEntry entry) { //adapted from libertyV code //MemoryStream ms = new MemoryStream(data); Name = entry.Name; FileEntry = entry; Data = data; if ((data == null) || (data.Length < 8)) { ErrorMessage = "Data null or too short!"; return; //nothing to do, not enough data... } Endianess endianess = Endianess.LittleEndian; Magic = BitConverter.ToUInt32(data, 0); if (Magic != 0x54414441 && Magic != 0x41444154) { if (data.Length % 4 == 0) { Decrypt_RSXXTEA(data, GTA5Keys.PC_AWC_KEY); Magic = BitConverter.ToUInt32(data, 0); } else { ErrorMessage = "Corrupted data!"; } } switch (Magic) { default: ErrorMessage = "Unexpected Magic 0x" + Magic.ToString("X"); return; case 0x54414441: endianess = Endianess.LittleEndian; break; case 0x41444154: endianess = Endianess.BigEndian; break; } using (MemoryStream ms = new MemoryStream(data)) { DataReader r = new DataReader(ms, endianess); Magic = r.ReadUInt32(); Version = r.ReadUInt16(); Flags = r.ReadUInt16(); StreamCount = r.ReadInt32(); InfoOffset = r.ReadInt32(); //notes from libertyV: // first bit - means that there are unknown word for each stream after this header // second bit - I think that it means that not all the tags are in the start of the file, but all the tags of a stream are near the data tag // third bit - Multi channel audio if ((Flags >> 8) != 0xFF) { ErrorMessage = "Flags 0 not supported!"; return; } if ((Flags & 0xF8) != 0) { //ErrorMessage = "Flags 1 not supported!"; //return; } MultiChannel = ((Flags & 4) == 4); var flag0 = ((Flags & 1) == 1); var infoStart = 16 + (flag0 ? (StreamCount * 2) : 0); ms.Position = infoStart; List <AwcStreamInfo> infos = new List <AwcStreamInfo>(); Dictionary <uint, AwcStreamInfo> infoDict = new Dictionary <uint, AwcStreamInfo>(); List <uint> audioIds = new List <uint>(); List <AwcAudio> audios = new List <AwcAudio>(); for (int i = 0; i < StreamCount; i++) { var info = new AwcStreamInfo(r); infos.Add(info); infoDict[info.Id] = info; } for (int i = 0; i < StreamCount; i++) { var info = infos[i]; for (int j = 0; j < info.TagCount; j++) { var chunk = new AwcChunkInfo(r); info.Chunks[chunk.Tag] = chunk; } } StreamInfos = infos.ToArray(); byte hformat = 0xFA; // 250 0x6061D4FA & 0xFF; //JenkHash.GenHash("format"); byte hdata = 0x55; // 85 0x5EB5E655 & 0xFF; //JenkHash.GenHash("data"); byte hycd = 0x5C; // 92 YCD resource chunk... lip sync anims? byte hunk = 0x36; // 54 unk chunk? small number of bytes (2+) if (MultiChannel) { AwcStreamInfo stream0 = null; if (!infoDict.TryGetValue(0, out stream0)) { ErrorMessage = "Couldn't find MultiChannel stream0"; return; } AwcChunkInfo chunk72 = null; if (!stream0.Chunks.TryGetValue(72, out chunk72)) { ErrorMessage = "Couldn't find MultiChannel chunk72"; return; } ms.Position = chunk72.Offset; AwcChannelChunkInfo chanInfo = new AwcChannelChunkInfo(r); if (chanInfo.ChannelCount != StreamCount - 1) { ErrorMessage = "Channel Count did not match Stream Count"; return; } List <AwcChannelChunkItemInfo> chunkItems = new List <AwcChannelChunkItemInfo>(); for (int i = 0; i < chanInfo.ChannelCount; i++) { var itemInfo = new AwcChannelChunkItemInfo(r); chunkItems.Add(itemInfo); audioIds.Add(infos[i + 1].Id); } //AudioStreams.Add(new MultiChannelAudio(new ChunkStream(this.Stream, streamsChunks[0][Tag("data")]), channelsInfoHeader, streamsInfo, header.BigEndian)); AwcChunkInfo cdata = null; if (!stream0.Chunks.TryGetValue(hdata, out cdata)) { ErrorMessage = "Couldn't find Stream 0 data chunk"; return; } ms.Position = cdata.Offset; var lastPos = cdata.Offset + cdata.Size; //int chunkSize = 0x800; uint bigChunkSize = chanInfo.ChunkSize; var chanCount = chanInfo.ChannelCount; MultiChannelData = r.ReadBytes(cdata.Size); ms.Position = cdata.Offset; //var d = data;//temporary ////this doesn't seem to work :( //while (ms.Position < lastPos) //{ // uint totalChunks = 0; // var startPos = ms.Position; // var curPos = startPos; // //byte[] chunkdata = r.ReadBytes(chunkSize); // //ms.Position = startPos; // AwcChannelChunkHeader[] chanHeaders = new AwcChannelChunkHeader[chanCount]; // for (int i = 0; i < chanCount; i++) // { // var chanHeader = new AwcChannelChunkHeader(r); // chanHeaders[i] = chanHeader; // totalChunks += chanHeader.ChunkCount; // } // int headerSize = (int)(totalChunks * 4 + chanInfo.ChannelCount * AwcChannelChunkHeader.Size); // headerSize += (((-headerSize) % chunkSize) + chunkSize) % chunkSize; //todo: simplify this! // curPos += headerSize; // AwcChannelChunk[] chanChunks = new AwcChannelChunk[chanCount]; // for (int i = 0; i < chanCount; i++) // { // var chanChunk = new AwcChannelChunk(r, chanHeaders[i], chunkItems[i]); // chanChunks[i] = chanChunk; // curPos += chanChunk.TotalDataSize; // } // if (curPos - startPos > chanInfo.ChunkSize) // { // ErrorMessage = "Chunk was bigger than the chunk size"; // break; // } // if ((totalChunks == 0) || ((startPos + chanInfo.ChunkSize) > lastPos)) // { // ErrorMessage = "Unable to read chunk"; // break; // } // var newPos = startPos + bigChunkSize; // if (newPos >= lastPos) break; // ms.Position = newPos; //} } else { for (int i = 0; i < StreamCount; i++) { var info = infos[i]; AwcChunkInfo cformat = null; if (!info.Chunks.TryGetValue(hformat, out cformat)) { ErrorMessage = "Couldn't find Stream " + i.ToString() + " format chunk"; continue; } AwcChunkInfo cdata = null; if (!info.Chunks.TryGetValue(hdata, out cdata)) { ErrorMessage = "Couldn't find Stream " + i.ToString() + " data chunk"; continue; } AwcChunkInfo cycd = null; AwcAudioAnimClipDict oycd = null; if (info.Chunks.TryGetValue(hycd, out cycd)) { ms.Position = cycd.Offset; oycd = new AwcAudioAnimClipDict(r, cycd); } AwcChunkInfo cunk = null; AwcAudioUnk ounk = null; if (info.Chunks.TryGetValue(hunk, out cunk)) { ms.Position = cunk.Offset; ounk = new AwcAudioUnk(r, cunk); } ms.Position = cformat.Offset; AwcFormatChunk formatChunk = new AwcFormatChunk(r); ms.Position = cdata.Offset; AwcAudio audio = new AwcAudio(r, info, formatChunk, cdata); audio.ClipDict = oycd; audio.UnkData = ounk; audios.Add(audio); audioIds.Add(info.Id); } } Audios = audios.ToArray(); AudioIds = audioIds.ToArray(); } }
public void Load(byte[] data, RpfFileEntry entry) { //adapted from libertyV code //MemoryStream ms = new MemoryStream(data); Name = entry.Name; FileEntry = entry; Data = data; if ((data == null) || (data.Length < 8)) { ErrorMessage = "Data null or too short!"; return; //nothing to do, not enough data... } Magic = BitConverter.ToUInt32(data, 0); Endianess endianess = Endianess.LittleEndian; switch (Magic) { default: ErrorMessage = "Unexpected Magic 0x" + Magic.ToString("X"); return; case 0x54414441: endianess = Endianess.LittleEndian; break; case 0x41444154: endianess = Endianess.BigEndian; break; } /* francium - Today at 6:11 PM * IDA decompiler code from a function that seems to be called around audio loading if not ADAT: * if ( a3 ) * { * v3 = *a1; * v4 = -a2; * v5 = (unsigned int)(-a2 - 1); * v6 = 0x9E3779B9 * (52 / -a2 + 6); * do * { * LODWORD(v7) = -a2 - 1; * v8 = (v6 >> 2) & 3; * if ( -a2 != 1 ) * { * v9 = (unsigned int)v5; * v10 = &a1[v5]; * do * { * v7 = (unsigned int)(v7 - 1); * v11 = v9--; * v10 -= ((v6 ^ v3) + (a1[v7] ^ *(_DWORD *)(a3 + 4 * (v8 ^ (unsigned __int64)(v11 & 3))) ^ 0x7B3A207F)) ^ ((4 * v3 ^ (a1[v7] >> 5)) + ((v3 >> 3) ^ 16 * a1[v7])); * v3 = *v10; * --v10; * } * while ( (_DWORD)v7 ); * } * result = (v6 ^ v3) + (a1[v4 - 1] ^ *(_DWORD *)(a3 + 4 * (v8 ^ (unsigned __int64)(v7 & 3))) ^ 0x7B3A207F); * a1 -= result ^ ((4 * v3 ^ (a1[v4 - 1] >> 5)) + ((v3 >> 3) ^ 16 * a1[v4 - 1])); * v3 = *a1; * v6 += 0x61C88647; * } * while ( v6 ); * } */ using (MemoryStream ms = new MemoryStream(data)) { DataReader r = new DataReader(ms, endianess); Magic = r.ReadUInt32(); Version = r.ReadUInt16(); Flags = r.ReadUInt16(); StreamCount = r.ReadInt32(); InfoOffset = r.ReadInt32(); //notes from libertyV: // first bit - means that there are unknown word for each stream after this header // second bit - I think that it means that not all the tags are in the start of the file, but all the tags of a stream are near the data tag // third bit - Multi channel audio if ((Flags >> 8) != 0xFF) { ErrorMessage = "Flags 0 not supported!"; return; } if ((Flags & 0xF8) != 0) { //ErrorMessage = "Flags 1 not supported!"; //return; } MultiChannel = ((Flags & 4) == 4); var flag0 = ((Flags & 1) == 1); var infoStart = 16 + (flag0 ? (StreamCount * 2) : 0); ms.Position = infoStart; List <AwcStreamInfo> infos = new List <AwcStreamInfo>(); Dictionary <uint, AwcStreamInfo> infoDict = new Dictionary <uint, AwcStreamInfo>(); List <uint> audioIds = new List <uint>(); List <AwcAudio> audios = new List <AwcAudio>(); for (int i = 0; i < StreamCount; i++) { var info = new AwcStreamInfo(r); infos.Add(info); infoDict[info.Id] = info; } for (int i = 0; i < StreamCount; i++) { var info = infos[i]; for (int j = 0; j < info.TagCount; j++) { var chunk = new AwcChunkInfo(r); info.Chunks[chunk.Tag] = chunk; } } StreamInfos = infos.ToArray(); byte hformat = 0xFA; // 250 0x6061D4FA & 0xFF; //JenkHash.GenHash("format"); byte hdata = 0x55; // 85 0x5EB5E655 & 0xFF; //JenkHash.GenHash("data"); byte hycd = 0x5C; // 92 YCD resource chunk... lip sync anims? byte hunk = 0x36; // 54 unk chunk? small number of bytes (2+) if (MultiChannel) { AwcStreamInfo stream0 = null; if (!infoDict.TryGetValue(0, out stream0)) { ErrorMessage = "Couldn't find MultiChannel stream0"; return; } AwcChunkInfo chunk72 = null; if (!stream0.Chunks.TryGetValue(72, out chunk72)) { ErrorMessage = "Couldn't find MultiChannel chunk72"; return; } ms.Position = chunk72.Offset; AwcChannelChunkInfo chanInfo = new AwcChannelChunkInfo(r); if (chanInfo.ChannelCount != StreamCount - 1) { ErrorMessage = "Channel Count did not match Stream Count"; return; } List <AwcChannelChunkItemInfo> chunkItems = new List <AwcChannelChunkItemInfo>(); for (int i = 0; i < chanInfo.ChannelCount; i++) { var itemInfo = new AwcChannelChunkItemInfo(r); chunkItems.Add(itemInfo); audioIds.Add(infos[i + 1].Id); } //AudioStreams.Add(new MultiChannelAudio(new ChunkStream(this.Stream, streamsChunks[0][Tag("data")]), channelsInfoHeader, streamsInfo, header.BigEndian)); AwcChunkInfo cdata = null; if (!stream0.Chunks.TryGetValue(hdata, out cdata)) { ErrorMessage = "Couldn't find Stream 0 data chunk"; return; } ms.Position = cdata.Offset; var lastPos = cdata.Offset + cdata.Size; //int chunkSize = 0x800; uint bigChunkSize = chanInfo.ChunkSize; var chanCount = chanInfo.ChannelCount; MultiChannelData = r.ReadBytes(cdata.Size); ms.Position = cdata.Offset; //var d = data;//temporary ////this doesn't seem to work :( //while (ms.Position < lastPos) //{ // uint totalChunks = 0; // var startPos = ms.Position; // var curPos = startPos; // //byte[] chunkdata = r.ReadBytes(chunkSize); // //ms.Position = startPos; // AwcChannelChunkHeader[] chanHeaders = new AwcChannelChunkHeader[chanCount]; // for (int i = 0; i < chanCount; i++) // { // var chanHeader = new AwcChannelChunkHeader(r); // chanHeaders[i] = chanHeader; // totalChunks += chanHeader.ChunkCount; // } // int headerSize = (int)(totalChunks * 4 + chanInfo.ChannelCount * AwcChannelChunkHeader.Size); // headerSize += (((-headerSize) % chunkSize) + chunkSize) % chunkSize; //todo: simplify this! // curPos += headerSize; // AwcChannelChunk[] chanChunks = new AwcChannelChunk[chanCount]; // for (int i = 0; i < chanCount; i++) // { // var chanChunk = new AwcChannelChunk(r, chanHeaders[i], chunkItems[i]); // chanChunks[i] = chanChunk; // curPos += chanChunk.TotalDataSize; // } // if (curPos - startPos > chanInfo.ChunkSize) // { // ErrorMessage = "Chunk was bigger than the chunk size"; // break; // } // if ((totalChunks == 0) || ((startPos + chanInfo.ChunkSize) > lastPos)) // { // ErrorMessage = "Unable to read chunk"; // break; // } // var newPos = startPos + bigChunkSize; // if (newPos >= lastPos) break; // ms.Position = newPos; //} } else { for (int i = 0; i < StreamCount; i++) { var info = infos[i]; AwcChunkInfo cformat = null; if (!info.Chunks.TryGetValue(hformat, out cformat)) { ErrorMessage = "Couldn't find Stream " + i.ToString() + " format chunk"; continue; } AwcChunkInfo cdata = null; if (!info.Chunks.TryGetValue(hdata, out cdata)) { ErrorMessage = "Couldn't find Stream " + i.ToString() + " data chunk"; continue; } AwcChunkInfo cycd = null; AwcAudioAnimClipDict oycd = null; if (info.Chunks.TryGetValue(hycd, out cycd)) { ms.Position = cycd.Offset; oycd = new AwcAudioAnimClipDict(r, cycd); } AwcChunkInfo cunk = null; AwcAudioUnk ounk = null; if (info.Chunks.TryGetValue(hunk, out cunk)) { ms.Position = cunk.Offset; ounk = new AwcAudioUnk(r, cunk); } ms.Position = cformat.Offset; AwcFormatChunk formatChunk = new AwcFormatChunk(r); ms.Position = cdata.Offset; AwcAudio audio = new AwcAudio(r, info, formatChunk, cdata); audio.ClipDict = oycd; audio.UnkData = ounk; audios.Add(audio); audioIds.Add(info.Id); } } Audios = audios.ToArray(); AudioIds = audioIds.ToArray(); } }