private void SaveZoneSetTable(IZoneSet[] sets, StructureValueCollection tagValues, string countName, string addressName, TagBlockCache <int> cache, IStream stream) { if (!tagValues.HasInteger(countName) || !tagValues.HasInteger(addressName)) { return; } var count = (int)tagValues.GetInteger(countName); if (count != sets.Length) { throw new InvalidOperationException("Zone set count does not match"); } uint address = (uint)tagValues.GetInteger(addressName); long expand = _expander.Expand(address); StructureLayout layout = _buildInfo.Layouts.GetLayout("zone set definition"); List <StructureValueCollection> entries = sets.Select(set => ((ThirdGenZoneSet)set).Serialize(stream, _allocator, cache, _expander)).ToList(); TagBlockWriter.WriteTagBlock(entries, expand, layout, _metaArea, stream); }
private void Load(StructureValueCollection values, IReader reader, FileSegmentGroup metaArea, StringIDSource stringIDs, EngineDescription buildInfo) { Name = values.HasInteger("name index") ? stringIDs.GetString(new StringID(values.GetInteger("name index"))) : values.GetString("name"); ExecutionType = (short)values.GetInteger("execution type"); ReturnType = (short)values.GetInteger("return type"); RootExpressionIndex = new DatumIndex(values.GetInteger("first expression index")); if (Name == null) { Name = "script_" + RootExpressionIndex.Value.ToString("X8"); } Parameters = LoadParameters(reader, values, metaArea, buildInfo); }
private void SaveTags(StructureValueCollection headerValues, int offset, IStream stream) { StructureLayout layout = _buildInfo.Layouts.GetLayout("tag element"); IEnumerable <StructureValueCollection> entries = _tags.Select(t => ((SecondGenTag)t).Serialize()); var addr = _metaArea.OffsetToPointer(_metaArea.Offset + offset); TagBlockWriter.WriteTagBlock(entries, addr, layout, _metaArea, stream); uint adjustedOffset = (uint)offset; if (headerValues.HasInteger("meta header mask")) { adjustedOffset += (uint)headerValues.GetInteger("meta header mask"); } headerValues.SetInteger("number of tags", (uint)_tags.Count); headerValues.SetInteger("tag table offset", adjustedOffset); }
private SecondGenHeader LoadHeader(IReader reader, out uint primaryMask) { primaryMask = 0; reader.SeekTo(0); StructureValueCollection values = StructureReader.ReadStructure(reader, _buildInfo.Layouts.GetLayout("header")); //set up a mask for xbox if needed if (!values.HasInteger("meta offset mask")) { //oh boy StructureLayout indexHeaderLayout = _buildInfo.Layouts.GetLayout("meta header"); StructureLayout tagElementLayout = _buildInfo.Layouts.GetLayout("tag element"); uint indexHeaderOffset = (uint)values.GetInteger("meta offset"); reader.SeekTo(indexHeaderOffset + indexHeaderLayout.GetFieldOffset("tag table offset")); uint tagTableAddress = reader.ReadUInt32(); uint maskReference; if (indexHeaderLayout.HasField("tag group table offset")) { reader.SeekTo(indexHeaderOffset + indexHeaderLayout.GetFieldOffset("tag group table offset")); maskReference = reader.ReadUInt32(); } else { maskReference = tagTableAddress; } primaryMask = maskReference - (uint)indexHeaderLayout.Size; uint tagTableOffset = tagTableAddress - primaryMask + indexHeaderOffset; reader.SeekTo(tagTableOffset + tagElementLayout.GetFieldOffset("offset")); uint firstTagAddress = reader.ReadUInt32(); values.SetInteger("xbox meta offset mask", firstTagAddress - (uint)values.GetInteger("tag data offset")); } return(new SecondGenHeader(values, _buildInfo, _segmenter)); }
private FirstGenHeader LoadHeader(IReader reader, out uint mask) { mask = 0; reader.SeekTo(0); StructureValueCollection values = StructureReader.ReadStructure(reader, _buildInfo.Layouts.GetLayout("header")); // hack to pack meta header size for metaOffsetMask calculation var oldReadPos = reader.Position; if (values.HasInteger("tag data offset")) { //oh boy StructureLayout indexHeaderLayout = _buildInfo.Layouts.GetLayout("meta header"); StructureLayout tagElementLayout = _buildInfo.Layouts.GetLayout("tag element"); uint indexHeaderOffset = (uint)values.GetInteger("meta offset"); reader.SeekTo(indexHeaderOffset); uint firstVal = reader.ReadUInt32(); reader.SeekTo(indexHeaderOffset + indexHeaderLayout.GetFieldOffset("tag table offset")); uint tagTableAddress = reader.ReadUInt32(); mask = firstVal - (uint)indexHeaderLayout.Size; uint tagTableOffset = tagTableAddress - mask + indexHeaderOffset; reader.SeekTo(tagTableOffset + tagElementLayout.GetFieldOffset("offset")); uint firstTagAddress = reader.ReadUInt32(); values.SetInteger("xbox meta offset mask", firstTagAddress - (uint)values.GetInteger("tag data offset")); } else { reader.SeekTo((long)values.GetInteger("meta offset")); var tagTableOffset = reader.ReadUInt32(); values.SetInteger("meta header size", (ulong)_buildInfo.Layouts.GetLayout("meta header").Size); values.SetInteger("tag table offset", (ulong)tagTableOffset); } return(new FirstGenHeader(values, _buildInfo, _segmenter)); }
private void CalculateStringGroup(StructureValueCollection values, FileSegmenter segmenter) { if (DebugPointerConverter == null) { return; } StringArea = new FileSegmentGroup(DebugPointerConverter); // StringIDs StringIDCount = (int)values.GetInteger("string table count"); if (StringIDCount > 0) { int sidIndexTableOff = DebugPointerConverter.PointerToOffset((uint)values.GetInteger("string index table offset")); int sidDataOff = DebugPointerConverter.PointerToOffset((uint)values.GetInteger("string table offset")); var sidTableSize = (int)values.GetInteger("string table size"); StringIDIndexTable = segmenter.WrapSegment(sidIndexTableOff, StringIDCount * 4, 4, SegmentResizeOrigin.End); StringIDData = segmenter.WrapSegment(sidDataOff, sidTableSize, 1, SegmentResizeOrigin.End); StringIDIndexTableLocation = StringArea.AddSegment(StringIDIndexTable); StringIDDataLocation = StringArea.AddSegment(StringIDData); // idk what this is, but H3Beta has it if (values.HasInteger("string block offset")) { int sidBlockOff = DebugPointerConverter.PointerToOffset((uint)values.GetInteger("string block offset")); StringBlock = segmenter.WrapSegment(sidBlockOff, StringIDCount * 0x80, 0x80, SegmentResizeOrigin.End); StringBlockLocation = StringArea.AddSegment(StringBlock); } // newest reach mcc caches store namespace information, hopefully others follow because thats one less thing to worry about every update if (values.HasInteger("string namespace table count")) { StringIDNamespaceCount = (int)values.GetInteger("string namespace table count"); if (StringIDNamespaceCount > 0) { int namespaceTableOff = DebugPointerConverter.PointerToOffset((uint)values.GetInteger("string namespace table offset")); StringIDNamespaceTable = segmenter.WrapSegment(namespaceTableOff, StringIDNamespaceCount * 4, 4, SegmentResizeOrigin.End); StringIDNamespaceTableLocation = StringArea.AddSegment(StringIDNamespaceTable); } } } // Tag names FileNameCount = (int)values.GetInteger("file table count"); if (FileNameCount > 0) { int nameIndexTableOff = DebugPointerConverter.PointerToOffset((uint)values.GetInteger("file index table offset")); int nameDataOff = DebugPointerConverter.PointerToOffset((uint)values.GetInteger("file table offset")); var fileTableSize = (int)values.GetInteger("file table size"); FileNameIndexTable = segmenter.WrapSegment(nameIndexTableOff, FileNameCount * 4, 4, SegmentResizeOrigin.End); FileNameData = segmenter.WrapSegment(nameDataOff, fileTableSize, 1, SegmentResizeOrigin.End); FileNameIndexTableLocation = StringArea.AddSegment(FileNameIndexTable); FileNameDataLocation = StringArea.AddSegment(FileNameData); } // Some H4-only unknown table if (values.HasInteger("unknown table count") && values.HasInteger("unknown table offset")) { UnknownCount = (int)values.GetInteger("unknown table count"); if (UnknownCount > 0) { int unknownOff = DebugPointerConverter.PointerToOffset((uint)values.GetInteger("unknown table offset")); UnknownTable = segmenter.WrapSegment(unknownOff, UnknownCount * 0x10, 0x10, SegmentResizeOrigin.End); UnknownTableLocation = StringArea.AddSegment(UnknownTable); } } }
private Resource LoadResource(StructureValueCollection values, int index, TagTable tags, IList <ResourcePointer> pointers, byte[] infoBuffer, IReader reader) { var result = new Resource(); var parentTag = new DatumIndex(values.GetInteger("parent tag datum index")); result.ParentTag = parentTag.IsValid ? tags[parentTag] : null; var salt = (ushort)values.GetInteger("datum index salt"); result.Index = new DatumIndex(salt, (ushort)index); var typeIndex = (int)values.GetInteger("resource type index"); if (typeIndex >= 0 && typeIndex < _resourceTypes.Length) { result.Type = _resourceTypes[typeIndex].Name; } result.Flags = (uint)values.GetInteger("flags"); var infoSize = (int)values.GetInteger("resource info size"); if (infoSize > 0) { var infoOffset = 0; if (values.HasInteger("number of resource info offsets")) //for h4 { var infocount = (int)values.GetInteger("number of resource info offsets"); uint address = (uint)values.GetInteger("resource info offsets table address"); long expand = _expander.Expand(address); StructureLayout layout = _buildInfo.Layouts.GetLayout("resource info offset entry"); StructureValueCollection[] entries = ReflexiveReader.ReadReflexive(reader, infocount, expand, layout, _metaArea); if (infocount > 0) { infoOffset = (int)entries[0].GetInteger("offset"); } } else { infoOffset = (int)values.GetInteger("resource info offset"); } // Copy the section of the info buffer that the resource is pointing to result.Info = new byte[infoSize]; Buffer.BlockCopy(infoBuffer, infoOffset, result.Info, 0, infoSize); } result.ResourceBits = (ushort)values.GetInteger("resource bits"); var segmentIndex = (int)values.GetInteger("segment index"); result.Location = (segmentIndex >= 0) ? pointers[segmentIndex] : null; result.BaseDefinitionAddress = (int)values.GetInteger("base definition address"); result.ResourceFixups.AddRange(LoadResourceFixups(values, reader)); result.DefinitionFixups.AddRange(LoadDefinitionFixups(values, reader)); return(result); }
public IEnumerable <ResourcePredictionD> LoadPredictions(IReader reader, TagTable tags, List <Resource> resources) { StructureValueCollection values = LoadTag(reader); if (!values.HasInteger("number of prediction d2s") || !values.HasInteger("prediction d2 table address")) { return(null); } int subcount = 2; StructureLayout templayout = _buildInfo.Layouts.GetLayout("raw segment table entry"); if (templayout.HasField("tertiary page index")) { subcount = 3; } var result = new List <ResourcePredictionD>(); StructureValueCollection[] d2entries = ReadReflexive(values, reader, "number of prediction d2s", "prediction d2 table address", "prediction d2 entry"); StructureValueCollection[] dentries = ReadReflexive(values, reader, "number of prediction ds", "prediction d table address", "prediction d entry"); StructureValueCollection[] centries = ReadReflexive(values, reader, "number of prediction cs", "prediction c table address", "prediction c entry"); StructureValueCollection[] bentries = ReadReflexive(values, reader, "number of prediction bs", "prediction b table address", "prediction b entry"); StructureValueCollection[] aentries = ReadReflexive(values, reader, "number of prediction as", "prediction a table address", "prediction a entry"); for (int i = 0; i < d2entries.Length; i++) { ResourcePredictionD pd = new ResourcePredictionD(); pd.Index = i; var tag = new DatumIndex(d2entries[i].GetInteger("tag datum")); pd.Tag = tag.IsValid ? tags[tag] : null; pd.Unknown1 = (int)d2entries[i].GetInteger("unknown 1"); pd.Unknown2 = (int)d2entries[i].GetInteger("unknown 2"); var dccount = (int)dentries[i].GetInteger("c count"); var dcindex = (int)dentries[i].GetInteger("c index"); var dacount = (int)dentries[i].GetInteger("a count"); var daindex = (int)dentries[i].GetInteger("a index"); for (int c = dcindex; c < dcindex + dccount; c++) { ResourcePredictionC pc = new ResourcePredictionC(); pc.Index = c; var cbindex = (int)centries[c].GetInteger("b index"); pc.OverallIndex = (short)centries[c].GetInteger("overall index"); ResourcePredictionB pb = new ResourcePredictionB(); pb.Index = cbindex; var bacount = (int)bentries[cbindex].GetInteger("a count"); var baindex = (int)bentries[cbindex].GetInteger("a index"); pb.OverallIndex = (short)bentries[cbindex].GetInteger("overall index"); for (int a = baindex; a < baindex + bacount; a++) { ResourcePredictionA pa = new ResourcePredictionA(); pa.Index = a; pa.Value = new DatumIndex(aentries[a].GetInteger("value")); int resolvedresource = pa.Value.Index / subcount; int subresource = pa.Value.Index - resolvedresource * subcount; if (resolvedresource >= resources.Count) { continue; } var res = resources[resolvedresource]; pa.Resource = res.Index; pa.SubResource = subresource; pb.AEntries.Add(pa); } pc.BEntry = pb; pd.CEntries.Add(pc); } for (int a = daindex; a < daindex + dacount; a++) { ResourcePredictionA pa = new ResourcePredictionA(); pa.Index = a; pa.Value = new DatumIndex(aentries[a].GetInteger("value")); int resolvedresource = pa.Value.Index / subcount; int subresource = pa.Value.Index - resolvedresource * subcount; if (resolvedresource >= resources.Count) { continue; } var res = resources[resolvedresource]; pa.Resource = res.Index; pa.SubResource = subresource; pd.AEntries.Add(pa); } result.Add(pd); } return(result); }
private void Load(StructureValueCollection values, FileSegmenter segmenter) { _eofSegment = segmenter.WrapEOF((int)values.GetInteger("file size")); var metaOffset = (int)values.GetInteger("meta offset"); int tagTableSize = (int)values.GetInteger("tag data offset"); int tagDataSize = (int)values.GetInteger("tag data size"); var headSegment = new FileSegment( segmenter.DefineSegment(metaOffset, tagTableSize, 0x1000, SegmentResizeOrigin.Beginning), segmenter); //xbox haxx, we can assume thru the existance of the code-set xbox mask uint metaOffsetMask; FileSegment metaSegment = null; if (values.HasInteger("xbox meta offset mask")) { // store the stock meta size since xbox's size is virtual //todo: figure out how this is calculated instead of doing a hack _saved_meta_size_hack = (uint)values.GetInteger("meta size"); metaOffsetMask = (uint)values.GetInteger("xbox meta offset mask"); metaSegment = new FileSegment( segmenter.DefineSegment(metaOffset + tagTableSize, tagDataSize, 0x4, SegmentResizeOrigin.End), segmenter); } else { metaOffsetMask = (uint)values.GetInteger("meta offset mask"); metaSegment = new FileSegment( segmenter.DefineSegment(metaOffset + tagTableSize, tagDataSize, 0x1000, SegmentResizeOrigin.End), segmenter); } MetaArea = new FileSegmentGroup(new MetaOffsetConverter(headSegment, metaOffsetMask)); IndexHeaderLocation = MetaArea.AddSegment(headSegment); MetaArea.AddSegment(metaSegment); Type = (CacheFileType)values.GetInteger("type"); var headerGroup = new FileSegmentGroup(); headerGroup.AddSegment(segmenter.WrapSegment(0, HeaderSize, 1, SegmentResizeOrigin.None)); StringIDCount = (int)values.GetInteger("string table count"); var sidDataSize = (int)values.GetInteger("string table size"); StringIDData = segmenter.WrapSegment((int)values.GetInteger("string table offset"), sidDataSize, 1, SegmentResizeOrigin.End); StringIDIndexTable = segmenter.WrapSegment((int)values.GetInteger("string index table offset"), StringIDCount * 4, 4, SegmentResizeOrigin.End); if (values.HasInteger("file table count")) { FileNameCount = (int)values.GetInteger("file table count"); var fileDataSize = (int)values.GetInteger("file table size"); FileNameData = segmenter.WrapSegment((int)values.GetInteger("file table offset"), fileDataSize, 1, SegmentResizeOrigin.End); FileNameIndexTable = segmenter.WrapSegment((int)values.GetInteger("file index table offset"), FileNameCount * 4, 4, SegmentResizeOrigin.End); } InternalName = values.GetString("internal name"); ScenarioName = values.GetString("scenario name"); StringArea = new FileSegmentGroup(); if (values.HasInteger("string block offset")) { StringArea.AddSegment(segmenter.WrapSegment((int)values.GetInteger("string block offset"), StringIDCount * 0x80, 0x80, SegmentResizeOrigin.End)); } StringArea.AddSegment(StringIDIndexTable); StringArea.AddSegment(StringIDData); StringIDIndexTableLocation = SegmentPointer.FromOffset(StringIDIndexTable.Offset, StringArea); StringIDDataLocation = SegmentPointer.FromOffset(StringIDData.Offset, StringArea); if (FileNameIndexTable != null) { StringArea.AddSegment(FileNameIndexTable); StringArea.AddSegment(FileNameData); FileNameIndexTableLocation = SegmentPointer.FromOffset(FileNameIndexTable.Offset, StringArea); FileNameDataLocation = SegmentPointer.FromOffset(FileNameData.Offset, StringArea); } int rawTableOffset; int rawTableSize; if (values.HasInteger("raw table offset")) { rawTableOffset = (int)values.GetInteger("raw table offset"); rawTableSize = (int)values.GetInteger("raw table size"); // It is apparently possible to create a cache without a raw table, but -1 gets written as the offset if (rawTableOffset != -1) { RawTable = segmenter.WrapSegment(rawTableOffset, rawTableSize, 0x80, SegmentResizeOrigin.End); } } Checksum = (uint)values.GetInteger("checksum"); // Set up a bogus partition table Partitions = new Partition[1]; Partitions[0] = new Partition(SegmentPointer.FromOffset(MetaArea.Offset, MetaArea), (uint)MetaArea.Size); }
/* * private void LoadInteropData(StructureValueCollection map_values, StructureValueCollection tag_values) * { * // TODO: fix this shit for the h3beta * //SectionOffsetMasks = headerValues.GetArray("offset masks").Select(v => v.GetInteger("mask")).ToArray(); * //Sections = headerValues.GetArray("sections").Select(v => new FourthGenInteropSection(v)).ToArray(); * * //DebugPointerConverter = MakePointerConverter(FourthGenInteropSectionType.Debug); * //ResourcePointerConverter = MakePointerConverter(FourthGenInteropSectionType.Resource); * //TagBufferPointerConverter = MakePointerConverter(FourthGenInteropSectionType.Tag); * //LocalePointerConverter = MakePointerConverter(FourthGenInteropSectionType.Localization); * } */ /* * private BasedPointerConverter MakePointerConverter(uint tags_data_size) * { * * if (Sections[(int) section].Size == 0) * return null; * * uint baseAddress = Sections[(int) section].VirtualAddress; * uint mask = SectionOffsetMasks[(int) section]; * return new BasedPointerConverter(baseAddress, (int) (baseAddress + mask)); * * return new BasedPointerConverter(0, 0); * } */ /* * private FileSegment CalculateRawTableSegment(FileSegmenter segmenter) * { * if (ResourcePointerConverter != null) * { * int rawTableOffset = ResourcePointerConverter.PointerToOffset(ResourcePointerConverter.BasePointer); * var rawTableSize = (int) Sections[(int) FourthGenInteropSectionType.Resource].Size; * return segmenter.WrapSegment(rawTableOffset, rawTableSize, 0x1000, SegmentResizeOrigin.End); * } * return null; * } */ /* * // TODO: Replace this function with the ability to parse the tags.dat file for this information. * private FileSegment CalculateTagDataSegment(StructureValueCollection values, FileSegmenter segmenter) * { * int tagDataOffset = (int)values.GetInteger("tag buffer offset"); * * * * if (TagBufferPointerConverter != null) * { * int tagDataOffset = TagBufferPointerConverter.PointerToOffset(TagBufferPointerConverter.BasePointer); * var tagDataSize = (int) values.GetInteger("virtual size"); * return segmenter.WrapSegment(tagDataOffset, tagDataSize, 0x10000, SegmentResizeOrigin.Beginning); * } * return null; * } */ private void CalculateStringGroup(StructureValueCollection values, FileSegmenter segmenter) { if (DebugPointerConverter == null) { return; } StringArea = new FileSegmentGroup(DebugPointerConverter); // StringIDs StringIDCount = (int)values.GetInteger("string table count"); if (StringIDCount > 0) { int sidIndexTableOff = DebugPointerConverter.PointerToOffset(values.GetInteger("string index table offset")); int sidDataOff = DebugPointerConverter.PointerToOffset(values.GetInteger("string table offset")); var sidTableSize = (int)values.GetInteger("string table size"); StringIDIndexTable = segmenter.WrapSegment(sidIndexTableOff, StringIDCount * 4, 4, SegmentResizeOrigin.End); StringIDData = segmenter.WrapSegment(sidDataOff, sidTableSize, 1, SegmentResizeOrigin.End); StringIDIndexTableLocation = StringArea.AddSegment(StringIDIndexTable); StringIDDataLocation = StringArea.AddSegment(StringIDData); // idk what this is, but H3Beta has it if (values.HasInteger("string block offset")) { int sidBlockOff = DebugPointerConverter.PointerToOffset(values.GetInteger("string block offset")); StringBlock = segmenter.WrapSegment(sidBlockOff, StringIDCount * 0x80, 0x80, SegmentResizeOrigin.End); StringBlockLocation = StringArea.AddSegment(StringBlock); } } /* * // Tag names * FileNameCount = (int) values.GetInteger("file table count"); * if (FileNameCount > 0) * { * int nameIndexTableOff = DebugPointerConverter.PointerToOffset(values.GetInteger("file index table offset")); * int nameDataOff = DebugPointerConverter.PointerToOffset(values.GetInteger("file table offset")); * * var fileTableSize = (int) values.GetInteger("file table size"); * FileNameIndexTable = segmenter.WrapSegment(nameIndexTableOff, FileNameCount*4, 4, SegmentResizeOrigin.End); * FileNameData = segmenter.WrapSegment(nameDataOff, fileTableSize, 1, SegmentResizeOrigin.End); * * FileNameIndexTableLocation = StringArea.AddSegment(FileNameIndexTable); * FileNameDataLocation = StringArea.AddSegment(FileNameData); * } */ /* * // Some H4-only unknown table * if (values.HasInteger("unknown table count") && values.HasInteger("unknown table offset")) * { * UnknownCount = (int) values.GetInteger("unknown table count"); * if (UnknownCount > 0) * { * int unknownOff = DebugPointerConverter.PointerToOffset(values.GetInteger("unknown table offset")); * UnknownTable = segmenter.WrapSegment(unknownOff, UnknownCount*0x10, 0x10, SegmentResizeOrigin.End); * UnknownTableLocation = StringArea.AddSegment(UnknownTable); * } * } */ }
private static void DecompressSecondGen(string file, StructureValueCollection headerValues) { using (MemoryStream msOutput = new MemoryStream()) { using (FileStream fsInput = new FileStream(file, FileMode.Open)) { using (BinaryReader brInput = new BinaryReader(fsInput)) { //constants int headerSize = (int)headerValues.GetInteger("_header_length_"); int chunkSize = headerValues.HasInteger("compression data chunk size") ? (int)headerValues.GetInteger("compression data chunk size") : 0x40000; uint chunkTableOffset = headerValues.HasInteger("compression chunk table offset") ? (uint)headerValues.GetInteger("compression chunk table offset") : (uint)headerSize; int chunkCount = headerValues.HasInteger("compression chunk table count") ? (int)headerValues.GetInteger("compression chunk table count") : 0x400; //header is uncompressed msOutput.Write(brInput.ReadBytes(headerSize), 0, headerSize); List <Tuple <int, int> > Chunks = new List <Tuple <int, int> >(); fsInput.Seek(chunkTableOffset, SeekOrigin.Begin); for (int i = 0; i < chunkCount; i++) { int csize = brInput.ReadInt32(); int offset = brInput.ReadInt32(); if (csize == 0) { break; } if (offset >= fsInput.Length) { throw new ArgumentException("Chunk " + i + " has an offset past the end of the file."); } Chunks.Add(new Tuple <int, int>(csize, offset)); } //Decompress and write each chunk for (int i = 0; i < Chunks.Count; i++) { //check for faux-compression some other tools use if (Chunks[i].Item1 < 0) { int invertedSize = -Chunks[i].Item1; byte[] aaa = new byte[invertedSize]; fsInput.Seek(Chunks[i].Item2, SeekOrigin.Begin); int readSize = fsInput.Read(aaa, 0, invertedSize); msOutput.Write(aaa, 0, readSize); } else { fsInput.Seek(Chunks[i].Item2 + 2, SeekOrigin.Begin); int realsize = chunkSize; byte[] chunkData = new byte[realsize]; using (DeflateStream ds = new DeflateStream(fsInput, CompressionMode.Decompress, true)) { realsize = ds.Read(chunkData, 0, chunkData.Length); } msOutput.Write(chunkData, 0, realsize); } } //clear compressed bit so it can run ingame if (headerValues.HasInteger("flags")) { fsInput.Seek((long)headerValues.GetInteger("_header_flags_"), SeekOrigin.Begin); int flags = brInput.ReadInt16(); flags &= 0x7FFFFFFE; msOutput.Seek((long)headerValues.GetInteger("_header_flags_"), SeekOrigin.Begin); msOutput.Write(BitConverter.GetBytes((short)flags), 0, 2); } } } File.WriteAllBytes(file, msOutput.ToArray()); } }
private static void CompressSecondGen(string file, StructureValueCollection headerValues) { using (MemoryStream msOutput = new MemoryStream()) { using (BinaryWriter bwOutput = new BinaryWriter(msOutput)) { using (FileStream fsInput = new FileStream(file, FileMode.Open)) { List <Tuple <int, int> > Chunks = new List <Tuple <int, int> >(); //constants int headerSize = (int)headerValues.GetInteger("_header_length_"); int chunkSize = 0x40000; int chunkSizeMask = 0x3FFFF; bool newFormat = headerValues.HasInteger("compression data chunk size"); uint dataStart = newFormat ? (uint)headerSize : 0x3000; //header is uncompressed byte[] header = new byte[headerSize]; fsInput.Read(header, 0, headerSize); msOutput.Write(header, 0, headerSize); int datalength = (int)fsInput.Length - headerSize; int chunkcount = ((datalength + chunkSizeMask) & ~chunkSizeMask) / chunkSize; msOutput.Position = dataStart; while (fsInput.Position < fsInput.Length) { int size = chunkSize; if (fsInput.Length - fsInput.Position < size) { size = datalength % chunkSize; } int start = (int)msOutput.Position; // 1) deflatestream doesnt write a header. // 2) this specific header (x2815) is whats used internally, and h2 mcc wont load without it, regardless of the actual data bwOutput.Write((short)5416); using (DeflateStream ds = new DeflateStream(msOutput, CompressionMode.Compress, true)) { byte[] chunkData = new byte[size]; fsInput.Read(chunkData, 0, size); ds.Write(chunkData, 0, chunkData.Length); } int complength = (int)msOutput.Position - start; Chunks.Add(new Tuple <int, int>(complength, start)); //each chunk is padded long remainder = complength % 0x80; msOutput.Seek(0x80 - remainder, SeekOrigin.Current); } uint tableOffset = newFormat ? (uint)msOutput.Position : (uint)headerSize; int tableSize = chunkcount * 8; msOutput.Position = tableOffset; for (int i = 0; i < chunkcount; i++) { bwOutput.Write(Chunks[i].Item1); bwOutput.Write(Chunks[i].Item2); } if (newFormat) { //table is padded in the new format long remainder = tableSize % 0x80; msOutput.Seek(0x80 - remainder - 1, SeekOrigin.Current); bwOutput.Write((byte)0); //write info to header msOutput.Seek((long)headerValues.GetInteger("_header_chunk_size_"), SeekOrigin.Begin); bwOutput.Write(chunkSize); msOutput.Seek((long)headerValues.GetInteger("_header_data_offset_"), SeekOrigin.Begin); bwOutput.Write(headerSize); msOutput.Seek((long)headerValues.GetInteger("_header_chunks_offset_"), SeekOrigin.Begin); bwOutput.Write(tableOffset); msOutput.Seek((long)headerValues.GetInteger("_header_chunk_count_"), SeekOrigin.Begin); bwOutput.Write(chunkcount); //write compressed bit int flags = BitConverter.ToInt16(header, (int)headerValues.GetInteger("_header_flags_")); flags |= 1; msOutput.Seek((long)headerValues.GetInteger("_header_flags_"), SeekOrigin.Begin); bwOutput.Write((short)flags); } } File.WriteAllBytes(file, msOutput.ToArray()); } } }
private void Load(StructureValueCollection values, FileSegmenter segmenter) { _eofSegment = segmenter.WrapEOF((int)values.GetInteger("file size")); var metaOffset = (int)values.GetInteger("meta offset"); int metaSize; if (values.HasInteger("tag data offset")) { metaSize = (int)values.GetInteger("tag data offset") + (int)values.GetInteger("tag data size"); } else { metaSize = (int)values.GetInteger("meta size"); } // store the stock meta size since xbox's size is virtual //todo: figure out how this is calculated instead of doing a hack _saved_meta_size_hack = (uint)values.GetInteger("meta size"); var metaSegment = new FileSegment( segmenter.DefineSegment(metaOffset, metaSize, 0x4, SegmentResizeOrigin.Beginning), segmenter); uint metaOffsetMask; if (values.HasInteger("xbox meta offset mask")) { metaOffsetMask = (uint)values.GetInteger("xbox meta offset mask"); } else { metaOffsetMask = (uint)(values.GetInteger("tag table offset") - values.GetInteger("meta header size")); } MetaArea = new FileSegmentGroup(new MetaOffsetConverter(metaSegment, metaOffsetMask)); IndexHeaderLocation = MetaArea.AddSegment(metaSegment); Type = (CacheFileType)values.GetInteger("type"); var headerGroup = new FileSegmentGroup(); headerGroup.AddSegment(segmenter.WrapSegment(0, HeaderSize, 1, SegmentResizeOrigin.None)); //h2 alpha forcing this to be shoved in if (values.HasInteger("string table count")) { StringIDCount = (int)values.GetInteger("string table count"); var sidDataSize = (int)values.GetInteger("string table size"); StringIDData = segmenter.WrapSegment((int)values.GetInteger("string table offset"), sidDataSize, 1, SegmentResizeOrigin.End); StringIDIndexTable = segmenter.WrapSegment((int)values.GetInteger("string index table offset"), StringIDCount * 4, 4, SegmentResizeOrigin.End); StringArea = new FileSegmentGroup(); if (values.HasInteger("string block offset")) { StringArea.AddSegment(segmenter.WrapSegment((int)values.GetInteger("string block offset"), StringIDCount * 0x80, 0x80, SegmentResizeOrigin.End)); } StringArea.AddSegment(StringIDIndexTable); StringArea.AddSegment(StringIDData); StringIDIndexTableLocation = SegmentPointer.FromOffset(StringIDIndexTable.Offset, StringArea); StringIDDataLocation = SegmentPointer.FromOffset(StringIDData.Offset, StringArea); } else { //dummy StringIDCount = 0; StringIDData = _eofSegment; StringIDIndexTable = _eofSegment; } InternalName = values.GetString("internal name"); Checksum = (uint)values.GetInteger("checksum"); // dummy partition Partitions = new Partition[1]; Partitions[0] = new Partition(SegmentPointer.FromOffset(MetaArea.Offset, MetaArea), (uint)MetaArea.Size); }