コード例 #1
0
 public MutagenInterfaceReadStream(
     IBinaryReadStream stream,
     ParsingBundle metaData,
     long offsetReference = 0)
 {
     _readStream          = stream;
     this.MetaData        = metaData;
     this.OffsetReference = offsetReference;
 }
コード例 #2
0
 public void Setup()
 {
     _data[0]       = (byte)'A';
     _data[1]       = (byte)'M';
     _data[2]       = (byte)'M';
     _data[3]       = (byte)'O';
     _parsingBundle = new ParsingBundle(GameRelease.Oblivion, _masterRefs);
     _frame         = new MutagenFrame(new MutagenMemoryReadStream(_data, _parsingBundle));
 }
コード例 #3
0
 public BinaryOverlayFactoryPackage(ParsingBundle metaData)
 {
     this.MetaData    = metaData;
     this.FormVersion = null;
 }
コード例 #4
0
        public static void Align(
            ModPath inputPath,
            FilePath outputPath,
            GameRelease release,
            AlignmentRules alignmentRules,
            TempFolder?temp = null)
        {
            var interest = new RecordInterest(alignmentRules.Alignments.Keys)
            {
                EmptyMeansInterested = false
            };
            var parsingBundle = new ParsingBundle(GameConstants.Get(release), MasterReferenceReader.FromPath(inputPath, release));
            var fileLocs      = RecordLocator.GetFileLocations(inputPath.Path, release, interest);

            temp ??= new TempFolder();
            using (temp)
            {
                var alignedMajorRecordsFile = Path.Combine(temp.Dir.Path, "alignedRules");
                using (var inputStream = new MutagenBinaryReadStream(inputPath.Path, parsingBundle))
                {
                    using var writer = new MutagenWriter(new FileStream(alignedMajorRecordsFile, FileMode.Create), release);
                    AlignMajorRecordsByRules(inputStream, writer, alignmentRules, fileLocs);
                }

                var alignedGroupsFile = Path.Combine(temp.Dir.Path, "alignedGroups");
                using (var inputStream = new MutagenBinaryReadStream(alignedMajorRecordsFile, parsingBundle))
                {
                    using var writer = new MutagenWriter(new FileStream(alignedGroupsFile, FileMode.Create), release);
                    AlignGroupsByRules(inputStream, writer, alignmentRules, fileLocs);
                }

                fileLocs = RecordLocator.GetFileLocations(alignedGroupsFile, release, interest);
                var alignedCellsFile = Path.Combine(temp.Dir.Path, "alignedCells");
                using (var mutaReader = new BinaryReadStream(alignedGroupsFile))
                {
                    using var writer = new MutagenWriter(alignedCellsFile, release);
                    foreach (var grup in fileLocs.GrupLocations)
                    {
                        if (grup <= mutaReader.Position)
                        {
                            continue;
                        }
                        var noRecordLength = grup - mutaReader.Position;
                        mutaReader.WriteTo(writer.BaseStream, (int)noRecordLength);

                        // If complete overall, return
                        if (mutaReader.Complete)
                        {
                            break;
                        }

                        mutaReader.WriteTo(writer.BaseStream, 12);
                        var grupType = (GroupTypeEnum)mutaReader.ReadUInt32();
                        writer.Write((int)grupType);
                        switch (grupType)
                        {
                        case GroupTypeEnum.CellChildren:
                            AlignCellChildren(mutaReader, writer);
                            break;

                        default:
                            break;
                        }
                    }
                    mutaReader.WriteTo(writer.BaseStream, checked ((int)mutaReader.Remaining));
                }

                fileLocs = RecordLocator.GetFileLocations(alignedCellsFile, release, interest);
                using (var mutaReader = new MutagenBinaryReadStream(alignedCellsFile, parsingBundle))
                {
                    using var writer = new MutagenWriter(outputPath.Path, GameConstants.Get(release));
                    foreach (var grup in fileLocs.GrupLocations)
                    {
                        if (grup <= mutaReader.Position)
                        {
                            continue;
                        }
                        var noRecordLength = grup - mutaReader.Position;
                        mutaReader.WriteTo(writer.BaseStream, (int)noRecordLength);

                        // If complete overall, return
                        if (mutaReader.Complete)
                        {
                            break;
                        }

                        mutaReader.WriteTo(writer.BaseStream, 12);
                        var grupType = (GroupTypeEnum)mutaReader.ReadUInt32();
                        writer.Write((int)grupType);
                        switch (grupType)
                        {
                        case GroupTypeEnum.WorldChildren:
                            AlignWorldChildren(mutaReader, writer);
                            break;

                        default:
                            break;
                        }
                    }
                    mutaReader.WriteTo(writer.BaseStream, checked ((int)mutaReader.Remaining));
                }
            }
        }
コード例 #5
0
ファイル: ModDecompressor.cs プロジェクト: halgari/Mutagen
        /// <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="gameMode">Type of game the mod stream is reading</param>
        /// <param name="interest">Optional specification of which record types to process</param>
        public static void Decompress(
            Func <Stream> streamCreator,
            Stream outputStream,
            GameMode gameMode,
            RecordInterest?interest = null)
        {
            var meta = new ParsingBundle(GameConstants.Get(gameMode));

            using var inputStream         = new MutagenBinaryReadStream(streamCreator(), meta);
            using var inputStreamJumpback = new MutagenBinaryReadStream(streamCreator(), meta);
            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();
                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.Span.ToArray();

                    // Write major Meta
                    var writableMajorMeta = meta.Constants.MajorRecordWritable(majorMetaSpan.AsSpan());
                    writableMajorMeta.IsCompressed = false;
                    writableMajorMeta.RecordLength = (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.FormID))
                    {
                        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);
            }
        }
コード例 #6
0
ファイル: ModRecordSorter.cs プロジェクト: halgari/Mutagen
        public static void Sort(
            Func <Stream> streamCreator,
            Stream outputStream,
            GameMode gameMode)
        {
            var meta = new ParsingBundle(GameConstants.Get(gameMode));

            using var inputStream   = new MutagenBinaryReadStream(streamCreator(), meta);
            using var locatorStream = new MutagenBinaryReadStream(streamCreator(), meta);
            using var writer        = new MutagenWriter(outputStream, gameMode, dispose: false);
            while (!inputStream.Complete)
            {
                long noRecordLength;
                foreach (var grupLoc in RecordLocator.IterateBaseGroupLocations(locatorStream))
                {
                    noRecordLength = grupLoc.Value - inputStream.Position;
                    inputStream.WriteTo(writer.BaseStream, (int)noRecordLength);

                    // If complete overall, return
                    if (inputStream.Complete)
                    {
                        return;
                    }

                    var groupMeta = inputStream.GetGroup();
                    if (!groupMeta.IsGroup)
                    {
                        throw new ArgumentException();
                    }

                    var storage = new Dictionary <FormID, List <ReadOnlyMemorySlice <byte> > >();
                    using (var grupFrame = new MutagenFrame(inputStream).SpawnWithLength(groupMeta.TotalLength))
                    {
                        inputStream.WriteTo(writer.BaseStream, meta.Constants.GroupConstants.HeaderLength);
                        locatorStream.Position = grupLoc.Value;
                        foreach (var rec in RecordLocator.ParseTopLevelGRUP(locatorStream))
                        {
                            MajorRecordHeader majorMeta = inputStream.GetMajorRecord();
                            storage.TryCreateValue(rec.FormID).Add(inputStream.ReadMemory(checked ((int)majorMeta.TotalLength), readSafe: true));
                            if (grupFrame.Complete)
                            {
                                continue;
                            }
                            GroupHeader subGroupMeta = inputStream.GetGroup();
                            if (subGroupMeta.IsGroup)
                            {
                                storage.TryCreateValue(rec.FormID).Add(inputStream.ReadMemory(checked ((int)subGroupMeta.TotalLength), readSafe: true));
                            }
                        }
                    }

                    foreach (var item in storage.OrderBy((i) => i.Key.ID))
                    {
                        foreach (var bytes in item.Value)
                        {
                            writer.Write(bytes);
                        }
                    }
                }

                inputStream.WriteTo(writer.BaseStream, (int)inputStream.Remaining);
            }
        }
コード例 #7
0
ファイル: Processor.cs プロジェクト: erri120/Mutagen
        public async Task Process(
            TempFolder tmpFolder,
            Subject <string> logging,
            ModPath sourcePath,
            string preprocessedPath,
            string outputPath)
        {
            this.Logging          = logging;
            this.TempFolder       = tmpFolder;
            this.SourcePath       = sourcePath;
            this.Masters          = MasterReferenceReader.FromPath(SourcePath, GameRelease);
            this.Bundle           = new ParsingBundle(GameRelease, Masters);
            this._NumMasters      = GetNumMasters();
            this._AlignedFileLocs = RecordLocator.GetFileLocations(new ModPath(ModKey, preprocessedPath), this.GameRelease);

            var preprocessedBytes = File.ReadAllBytes(preprocessedPath);

            IMutagenReadStream streamGetter() => new MutagenMemoryReadStream(preprocessedBytes, Bundle);

            using (var stream = streamGetter())
            {
                lock (_lengthTracker)
                {
                    foreach (var grup in this._AlignedFileLocs.GrupLocations.And(this._AlignedFileLocs.ListedRecords.Keys))
                    {
                        stream.Position           = grup + 4;
                        this._lengthTracker[grup] = stream.ReadUInt32();
                    }
                }

                await this.PreProcessorJobs(streamGetter);

                await Task.WhenAll(ExtraJobs(streamGetter));

                this.AddDynamicProcessorInstructions();
                Parallel.ForEach(this.DynamicProcessors.Keys
                                 .And(this.DynamicStreamProcessors.Keys)
                                 .And(RecordType.Null)
                                 .Distinct(),
                                 ParallelOptions,
                                 type => ProcessDynamicType(type, streamGetter));

                lock (_lengthTracker)
                {
                    foreach (var grup in this._lengthTracker)
                    {
                        stream.Position = grup.Key + 4;
                        if (grup.Value == stream.ReadUInt32())
                        {
                            continue;
                        }
                        this._Instructions.SetSubstitution(
                            loc: grup.Key + 4,
                            sub: BitConverter.GetBytes(grup.Value));
                    }
                }
            }

            var config = this._Instructions.GetConfig();

            using (var processor = new BinaryFileProcessor(
                       new FileStream(preprocessedPath, FileMode.Open, FileAccess.Read),
                       config))
            {
                try
                {
                    using var outStream = new FileStream(outputPath, FileMode.Create, FileAccess.Write);
                    processor.CopyTo(outStream);
                }
                catch (Exception)
                {
                    if (File.Exists(outputPath))
                    {
                        File.Delete(outputPath);
                    }
                    throw;
                }
            }
        }