private static void AlignMajorRecordsByRules( IMutagenReadStream inputStream, MutagenWriter writer, AlignmentRules alignmentRules, RecordLocator.FileLocations fileLocs) { 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.Remaining; } inputStream.WriteTo(writer.BaseStream, (int)noRecordLength); // If complete overall, return if (inputStream.Complete) { break; } var recType = HeaderTranslation.ReadNextRecordType( inputStream, out var len); IEnumerable <RecordType>?stopMarkers; if (!alignmentRules.StopMarkers.TryGetValue(recType, out stopMarkers)) { stopMarkers = null; } if (!alignmentRules.Alignments.TryGetValue(recType, out var alignments)) { throw new ArgumentException($"Encountered an unknown record: {recType}"); } writer.Write(recType.TypeInt); writer.Write(len); inputStream.WriteTo(writer.BaseStream, 12); var endPos = inputStream.Position + len; Dictionary <RecordType, byte[]> dataDict = new Dictionary <RecordType, byte[]>(); ReadOnlyMemorySlice <byte>? rest = null; while (inputStream.Position < endPos) { var subType = HeaderTranslation.GetNextSubrecordType( inputStream, out var subLen); if (stopMarkers?.Contains(subType) ?? false) { rest = inputStream.ReadMemory((int)(endPos - inputStream.Position), readSafe: true); break; } if (!alignments.TryGetValue(subType, out var rule)) { throw new ArgumentException($"Encountered an unknown record: {subType}"); } dataDict[subType] = rule.GetBytes(inputStream); } foreach (var alignment in alignmentRules.Alignments[recType]) { if (dataDict.TryGetValue( alignment.Key, out var data)) { writer.Write(data); dataDict.Remove(alignment.Key); } } if (dataDict.Count > 0) { throw new ArgumentException($"Encountered an unknown record: {dataDict.First().Key}"); } if (rest != null) { writer.Write(rest.Value); } } }
private static void AlignGroupsByRules( MutagenBinaryReadStream inputStream, MutagenWriter writer, AlignmentRules alignmentRules, RecordLocator.FileLocations 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 - 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(); } inputStream.WriteTo(writer.BaseStream, checked ((int)groupMeta.HeaderLength)); if (!alignmentRules.GroupTypeAlignment.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), readSafe: true); 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); } } }
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; } } }