Пример #1
0
            static partial void CustomBinaryEndImport(MutagenFrame frame, IWorldspaceInternal obj)
            {
                try
                {
                    if (!frame.Reader.TryReadGroup(out var groupHeader))
                    {
                        return;
                    }
                    if (groupHeader.GroupType == (int)GroupTypeEnum.WorldChildren)
                    {
                        obj.SubCellsTimestamp = BinaryPrimitives.ReadInt32LittleEndian(groupHeader.LastModifiedData);
                        var formKey = FormKeyBinaryTranslation.Instance.Parse(groupHeader.ContainedRecordTypeData, frame.MetaData.MasterReferences !);
                        if (formKey != obj.FormKey)
                        {
                            throw new ArgumentException("Cell children group did not match the FormID of the parent worldspace.");
                        }
                    }
                    else
                    {
                        frame.Reader.Position -= groupHeader.HeaderLength;
                        return;
                    }
                    var subFrame = MutagenFrame.ByLength(frame.Reader, groupHeader.ContentLength);
                    for (int i = 0; i < 3; i++)
                    {
                        if (subFrame.Complete)
                        {
                            return;
                        }
                        var subType = HeaderTranslation.GetNextSubrecordType(frame.Reader, out var subLen);
                        switch (subType.TypeInt)
                        {
                        case 0x44414F52:     // "ROAD":
                            obj.Road = Road.CreateFromBinary(subFrame);
                            break;

                        case 0x4C4C4543:     // "CELL":
                            obj.TopCell = Cell.CreateFromBinary(subFrame);
                            break;

                        case 0x50555247:     // "GRUP":
                            obj.SubCells.SetTo(
                                Mutagen.Bethesda.Binary.ListBinaryTranslation <WorldspaceBlock> .Instance.Parse(
                                    frame: frame,
                                    triggeringRecord: RecordTypes.GRUP,
                                    transl: LoquiBinaryTranslation <WorldspaceBlock> .Instance.Parse));
                            break;

                        default:
                            return;
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw RecordException.Enrich(ex, obj);
                }
            }
Пример #2
0
        private static void AlignGroupsByRules(
            MutagenBinaryReadStream inputStream,
            MutagenWriter writer,
            AlignmentRules alignmentRules,
            RecordLocatorResults fileLocs)
        {
            while (!inputStream.Complete)
            {
                // Import until next listed major record
                long noRecordLength;
                if (fileLocs.GrupLocations.TryGetInDirection(
                        inputStream.Position,
                        higher: true,
                        result: out var nextRec))
                {
                    noRecordLength = nextRec.Value.Location.Min - inputStream.Position;
                }
                else
                {
                    noRecordLength = inputStream.Remaining;
                }
                inputStream.WriteTo(writer.BaseStream, (int)noRecordLength);

                // If complete overall, return
                if (inputStream.Complete)
                {
                    break;
                }
                var groupMeta = inputStream.GetGroup();
                if (!groupMeta.IsGroup)
                {
                    throw new ArgumentException();
                }
                writer.Write(inputStream.ReadSpan(groupMeta.HeaderLength));

                if (!alignmentRules.GroupAlignment.TryGetValue(groupMeta.GroupType, out var groupRules))
                {
                    continue;
                }

                var storage = new Dictionary <RecordType, List <ReadOnlyMemorySlice <byte> > >();
                var rest    = new List <ReadOnlyMemorySlice <byte> >();
                using (var frame = MutagenFrame.ByLength(inputStream, groupMeta.ContentLength))
                {
                    while (!frame.Complete)
                    {
                        var majorMeta = inputStream.GetMajorRecord();
                        var bytes     = inputStream.ReadMemory(checked ((int)majorMeta.TotalLength));
                        var type      = majorMeta.RecordType;
                        if (groupRules.Contains(type))
                        {
                            storage.GetOrAdd(type).Add(bytes);
                        }
                        else
                        {
                            rest.Add(bytes);
                        }
                    }
                }
                foreach (var rule in groupRules)
                {
                    if (storage.TryGetValue(rule, out var storageBytes))
                    {
                        foreach (var item in storageBytes)
                        {
                            writer.Write(item);
                        }
                    }
                }
                foreach (var item in rest)
                {
                    writer.Write(item);
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Decompresses mod stream into an output.
        /// Will open up two input streams, so a Func factory is given as input.
        /// </summary>
        /// <param name="streamCreator">A func to create an input stream</param>
        /// <param name="outputStream">Stream to write output to</param>
        /// <param name="interest">Optional specification of which record types to process</param>
        public static void Decompress(
            Func <IMutagenReadStream> streamCreator,
            Stream outputStream,
            RecordInterest?interest = null)
        {
            using var inputStream         = streamCreator();
            using var inputStreamJumpback = streamCreator();
            using var writer = new System.IO.BinaryWriter(outputStream, Encoding.Default, leaveOpen: true);

            long runningDiff = 0;
            var  fileLocs    = RecordLocator.GetFileLocations(
                inputStream,
                interest: interest,
                additionalCriteria: (stream, recType, len) =>
            {
                return(stream.GetMajorRecord().IsCompressed);
            });

            // Construct group length container for later use
            Dictionary <long, (uint Length, long Offset)> grupMeta = new Dictionary <long, (uint Length, long Offset)>();

            inputStream.Position = 0;
            while (!inputStream.Complete)
            {
                // Import until next listed major record
                long noRecordLength;
                if (fileLocs.ListedRecords.TryGetInDirection(
                        inputStream.Position,
                        higher: true,
                        result: out var nextRec))
                {
                    var recordLocation = fileLocs.ListedRecords.Keys[nextRec.Key];
                    noRecordLength = recordLocation - inputStream.Position;
                }
                else
                {
                    noRecordLength = inputStream.Length - inputStream.Position;
                }
                inputStream.WriteTo(outputStream, (int)noRecordLength);

                // If complete overall, return
                if (inputStream.Complete)
                {
                    break;
                }
                var majorMeta = inputStream.ReadMajorRecord(readSafe: true);
                var len       = majorMeta.ContentLength;
                using (var frame = MutagenFrame.ByLength(
                           reader: inputStream,
                           length: len))
                {
                    // Decompress
                    var decompressed    = frame.Decompress();
                    var decompressedLen = decompressed.TotalLength;
                    var lengthDiff      = decompressedLen - len;
                    var majorMetaSpan   = majorMeta.HeaderData.ToArray();

                    // Write major Meta
                    var writableMajorMeta = inputStream.MetaData.Constants.MajorRecordWritable(majorMetaSpan.AsSpan());
                    writableMajorMeta.IsCompressed  = false;
                    writableMajorMeta.ContentLength = (uint)(len + lengthDiff);
                    writer.Write(majorMetaSpan);
                    writer.Write(decompressed.ReadRemainingSpan(readSafe: false));

                    // If no difference in lengths, move on
                    if (lengthDiff == 0)
                    {
                        continue;
                    }

                    // Modify parent group lengths
                    foreach (var grupLoc in fileLocs.GetContainingGroupLocations(nextRec.Value.FormKey))
                    {
                        if (!grupMeta.TryGetValue(grupLoc, out var loc))
                        {
                            loc.Offset = runningDiff;
                            inputStreamJumpback.Position = grupLoc + 4;
                            loc.Length = inputStreamJumpback.ReadUInt32();
                        }
                        grupMeta[grupLoc] = ((uint)(loc.Length + lengthDiff), loc.Offset);
                    }
                    runningDiff += lengthDiff;
                }
            }

            foreach (var item in grupMeta)
            {
                var grupLoc = item.Key;
                outputStream.Position = grupLoc + 4 + item.Value.Offset;
                writer.Write(item.Value.Length);
            }
        }