Esempio n. 1
0
        public static EndianWriterEx CreateWriter(this ICacheFile cache, Stream stream, bool leaveOpen)
        {
            var writer = new EndianWriterEx(stream, cache.ByteOrder, leaveOpen);

            if (cache.CacheType >= CacheType.Halo2Xbox)
            {
                writer.RegisterType <Matrix4x4>((m, v) =>
                {
                    writer.Write(m.M11);
                    writer.Write(m.M12);
                    writer.Write(m.M13);

                    writer.Write(m.M21);
                    writer.Write(m.M22);
                    writer.Write(m.M23);

                    writer.Write(m.M31);
                    writer.Write(m.M32);
                    writer.Write(m.M33);

                    writer.Write(m.M41);
                    writer.Write(m.M42);
                    writer.Write(m.M43);
                });
            }

            return(writer);
        }
Esempio n. 2
0
        void IMetadataStream.ResizeTagBlock(EndianWriterEx writer, ref TagBlock block, int entrySize, int newCount)
        {
            if (newCount == block.Count)
            {
                return;
            }

            var sourceAddress = (int)block.Pointer.Address;
            var sourceSize    = entrySize * block.Count;
            var newSize       = entrySize * newCount;

            if (newCount < block.Count)
            {
                block = new TagBlock(newCount, block.Pointer);
                tracker.Release(sourceAddress + newSize, sourceSize - newSize);
                return;
            }

            //release before find, in case the release creates a bigger contiguous chunk
            tracker.Release(sourceAddress, sourceSize);

            int newAddress;

            if (!tracker.Find(newSize, out newAddress))
            {
                //if there isnt space then make some
                int freeStart, freeCount;
                segmenter.AddMetadata(writer, newSize, out freeStart, out freeCount);
                ShiftAllocations(freeCount);
                tracker.Insert(freeStart, freeCount);
                if (!tracker.Find(newSize, out newAddress)) //should always return true
                {
                    throw new InvalidDataException("Could not find free space after expanding map!");
                }
            }

            var translator = SourceItem.CacheFile.DefaultAddressTranslator;
            var expander   = (SourceItem.CacheFile as IMccCacheFile)?.PointerExpander;

            var newPointer = translator.GetPointer(newAddress);

            if (expander != null)
            {
                newPointer = expander.Contract(newPointer);
            }

            block = new TagBlock(newCount, new Pointer((int)newPointer, block.Pointer));
            tracker.Allocate(newAddress, newSize);
        }
Esempio n. 3
0
        public void Commit(EndianWriterEx writer)
        {
            if (!hasChanged)
            {
                return;
            }

            if (BlockRef != null && EntryCount != BlockRef.Count)
            {
                stream.ResizeTagBlock(writer, ref blockRef, EntrySize, EntryCount);

                //we dont know if our parent has already been written (or even will be)
                //just to be sure, we need to go back and update it with the new reference
                var refOffset = ParentBlock.EntrySize * ParentEntryIndex + OffsetInParent;
                writer.Seek(ParentBlock.PhysicalAddress + refOffset, SeekOrigin.Begin);
                BlockRef.Write(writer, null);
            }

            var rootAddress = BlockRef?.Pointer.Address ?? OffsetInParent;

            if (EntryCount > 0)
            {
                writer.Seek(rootAddress, SeekOrigin.Begin);
                writer.Write(data); //this writes our virtual pointers to disk (fix them below)
            }

            //the block references in our data array currently use virtual pointers
            //this restores the original pointers that got overwritten above
            foreach (var child in ChildBlocks)
            {
                writer.Seek(rootAddress + EntrySize * child.ParentEntryIndex + child.OffsetInParent + 4, SeekOrigin.Begin);
                writer.Write(child.BlockRef.Pointer.Value);
            }

            hasChanged = false;
        }
        public void AddMetadata(EndianWriterEx writer, int length, out int insertedAt, out int insertedCount)
        {
            length = metadataSegment.Expand(length);

            cache.Header.FileSize = eofSegment.Offset;

            var debugTranslator = new SectionAddressTranslator(cache, 0);
            //var metadataTranslator = new SectionAddressTranslator(cache, 2);
            var localeTranslator = new SectionAddressTranslator(cache, 3);

            var remaining = metadataSegment.AvailableSize - cache.Header.PartitionTable.Skip(1).Sum(p => (int)p.Size);
            var pointer   = cache.DefaultAddressTranslator.GetPointer(metadataSegment.Offset) - length; //DefaultAddressTranslator should always be the MetadataTranslator

            cache.Header.PartitionTable[0].Size    = (ulong)remaining;
            cache.Header.PartitionTable[0].Address = (ulong)pointer;

            var debugSection    = cache.Header.SectionTable[0];
            var resourceSection = cache.Header.SectionTable[1];
            var metadataSection = cache.Header.SectionTable[2];
            var localesSection  = cache.Header.SectionTable[3];

            resourceSection.Size = (uint)resourceSegment.AvailableSize;

            localesSection.Address = resourceSection.Address + resourceSection.Size;
            localesSection.Size    = (uint)localesGroup.AvailableSize;

            metadataSection.Address = resourceSection.Address + resourceSection.Size + localesSection.Size;
            metadataSection.Size    = (uint)metadataSegment.AvailableSize;

            debugSection.Address = resourceSection.Address + resourceSection.Size + localesSection.Size + metadataSection.Size;
            debugSection.Size    = (uint)stringsGroup.AvailableSize;

            if (debugSection.Address != 0 && cache.Header.SectionOffsetTable[0] != 0)
            {
                debugSection.Address -= (uint)cache.Header.PartitionTable[0].Size;
            }

            var offsets = cache.Header.SectionOffsetTable;

            offsets[0] = (uint)(stringsGroup.Offset - debugSection.Address);
            offsets[1] = (uint)(resourceSegment.Offset - resourceSection.Address);
            offsets[2] = (uint)(metadataSegment.Offset - metadataSection.Address);
            offsets[3] = (uint)(localesGroup.Offset - localesSection.Address);

            cache.Header.TagDataAddress     = (int)metadataSection.Address;
            cache.Header.VirtualBaseAddress = pointer;
            //index header address
            cache.Header.VirtualSize = metadataSegment.AvailableSize;

            pointer = debugTranslator.GetPointer(stringSegments[0].Offset);
            cache.Header.StringTableIndexPointer = new Pointer((int)pointer, cache.Header.StringTableIndexPointer);

            pointer = debugTranslator.GetPointer(stringSegments[1].Offset);
            cache.Header.StringTablePointer = new Pointer((int)pointer, cache.Header.StringTablePointer);

            pointer = debugTranslator.GetPointer(stringSegments[2].Offset);
            cache.Header.FileTableIndexPointer = new Pointer((int)pointer, cache.Header.FileTableIndexPointer);

            pointer = debugTranslator.GetPointer(stringSegments[3].Offset);
            cache.Header.FileTablePointer = new Pointer((int)pointer, cache.Header.FileTablePointer);

            //only exists in mcc reach (U3+)
            var mcc3 = cache.Header as IMccGen3Header;

            if (mcc3?.StringNamespaceCount > 0)
            {
                pointer = debugTranslator.GetPointer(stringSegments[4].Offset);
                mcc3.StringNamespaceTablePointer = new Pointer((int)pointer, mcc3.StringNamespaceTablePointer);
            }

            var gen4 = cache.Header as IGen4Header;

            if (gen4?.UnknownTableSize > 0)
            {
                pointer = debugTranslator.GetPointer(stringSegments[5].Offset);
                gen4.UnknownTablePointer = new Pointer((int)pointer, gen4.UnknownTablePointer);
            }

            foreach (var pair in localeSegments)
            {
                var def  = cache.LocaleIndex.Languages[pair.Key];
                var segs = pair.Value;

                def.IndicesOffset = (int)localeTranslator.GetPointer(segs[0].Offset);
                def.StringsOffset = (int)localeTranslator.GetPointer(segs[1].Offset);
            }

            insertedAt    = metadataSegment.Offset;
            insertedCount = length;

            writer.Seek(0, SeekOrigin.Begin);
            writer.WriteObject(cache.Header, (int)cache.CacheType);

            writer.Seek(metadataSegment.Offset, SeekOrigin.Begin);
            writer.Insert(0, length);

            var globalsTag = cache.TagIndex.GetGlobalTag("matg");

            writer.Seek(globalsTag.MetaPointer.Address, SeekOrigin.Begin);
            writer.WriteObject(cache.LocaleIndex);
        }