public MutagenInterfaceReadStream( IBinaryReadStream stream, ParsingBundle metaData, long offsetReference = 0) { _readStream = stream; this.MetaData = metaData; this.OffsetReference = offsetReference; }
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)); }
public BinaryOverlayFactoryPackage(ParsingBundle metaData) { this.MetaData = metaData; this.FormVersion = null; }
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)); } } }
/// <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); } }
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); } }
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; } } }