public async Task <Result> Convert(CancellationToken token, Stream source, Stream destination, long size, bool skipZeroFilled = false) { var stopwatch = new Stopwatch(); stopwatch.Start(); source.Seek(0, SeekOrigin.Begin); destination.Seek(0, SeekOrigin.Begin); var dataSectorReader = new DataSectorReader(source, bufferSize: bufferSize); var bytesProcessed = 0L; long bytesRead = 0; SectorResult sectorResult; do { if (token.IsCancellationRequested) { return(new Result <Error>(new Error("Cancelled"))); } sectorResult = await dataSectorReader.ReadNext(); bytesRead += sectorResult.BytesRead; if (skipZeroFilled) { foreach (var sector in sectorResult.Sectors.Where(x => x.Start < size)) { destination.Seek(sector.Start, SeekOrigin.Begin); await destination.WriteAsync(sector.Data, 0, sector.Data.Length, token); } } else { var length = sectorResult.End > size ? size - sectorResult.Start : sectorResult.Data.Length; await destination.WriteAsync(sectorResult.Data, 0, System.Convert.ToInt32(length), token); } var sectorBytesProcessed = sectorResult.End >= size ? size - sectorResult.Start : sectorResult.BytesRead; bytesProcessed += sectorBytesProcessed; var bytesRemaining = size - bytesProcessed; var percentComplete = bytesProcessed == 0 ? 0 : Math.Round((double)100 / size * bytesProcessed, 1); var timeElapsed = stopwatch.Elapsed; var timeRemaining = TimeHelper.CalculateTimeRemaining(percentComplete, timeElapsed); var timeTotal = timeElapsed + timeRemaining; OnDataProcessed(percentComplete, bytesProcessed, bytesRemaining, size, timeElapsed, timeRemaining, timeTotal); } while (sectorResult.BytesRead == bufferSize && bytesRead < size && !sectorResult.EndOfSectors); return(new Result()); }
public async Task WhenReadNextThenDataSectorsAreReturned() { var sector1 = CreateSector(); var sector2 = CreateSector(); var sector3 = CreateSector(); var sector4 = CreateSector(); var sector5 = CreateSector(1); var sector6 = CreateSector(2); var disk = new List <byte>(); disk.AddRange(sector1); disk.AddRange(sector2); disk.AddRange(sector3); disk.AddRange(sector4); disk.AddRange(sector5); disk.AddRange(sector6); var stream = new MemoryStream(disk.ToArray()); // create data sector reader var reader = new DataSectorReader(stream, SectorSize, SectorSize * 3); // read next sectors var result1 = await reader.ReadNext(); // assert result Assert.False(result1.EndOfSectors); var sectors = result1.Sectors.ToList(); Assert.Equal(3, sectors.Count); // assert sector 1 var sector = sectors[0]; Assert.Equal(0, sector.Start); Assert.Equal(SectorSize - 1, sector.End); Assert.True(sector.IsZeroFilled); Assert.Empty(sector.Data); // assert sector 2 sector = sectors[1]; Assert.Equal(SectorSize, sector.Start); Assert.Equal(2 * SectorSize - 1, sector.End); Assert.True(sector.IsZeroFilled); Assert.Empty(sector.Data); // assert sector 3 sector = sectors[2]; Assert.Equal(2 * SectorSize, sector.Start); Assert.Equal(3 * SectorSize - 1, sector.End); Assert.True(sector.IsZeroFilled); Assert.Empty(sector.Data); // read next sectors var result2 = await reader.ReadNext(); // assert result Assert.False(result2.EndOfSectors); sectors = result2.Sectors.ToList(); Assert.Equal(3, sectors.Count); // assert sector 4 sector = sectors[0]; Assert.Equal(3 * SectorSize, sector.Start); Assert.Equal(4 * SectorSize - 1, sector.End); Assert.True(sector.IsZeroFilled); Assert.Empty(sector.Data); // assert sector 5 sector = sectors[1]; Assert.Equal(4 * SectorSize, sector.Start); Assert.Equal(5 * SectorSize - 1, sector.End); Assert.False(sector.IsZeroFilled); Assert.Equal(sector.Data, sector5); // assert sector 6 sector = sectors[2]; Assert.Equal(5 * SectorSize, sector.Start); Assert.Equal(6 * SectorSize - 1, sector.End); Assert.False(sector.IsZeroFilled); Assert.Equal(sector.Data, sector6); // read next sectors var result3 = await reader.ReadNext(); // assert result Assert.True(result3.EndOfSectors); Assert.Empty(result3.Sectors); }
public YukaScript Disassemble() { Stream.Seek(0); var r = Stream.NewReader(); var header = ReadHeader(r); // read instructions var code = new uint[header.InstrCount]; Stream.Seek(header.InstrOffset); for (int i = 0; i < header.InstrCount; i++) { code[i] = r.ReadUInt32(); } // prepare data buffer var dataBuffer = new byte[header.DataLength]; Stream.Seek(header.DataOffset).Read(dataBuffer, 0, (int)header.DataLength); // read index var index = new DataElement[header.IndexCount]; Stream.Seek(header.IndexOffset); using (var dataSector = new DataSectorReader(dataBuffer, header.Encryption == 1)) { for (int i = 0; i < header.IndexCount; i++) { var type = (DataElementType)r.ReadUInt32(); uint field1 = r.ReadUInt32(); uint field2 = r.ReadUInt32(); uint field3 = r.ReadUInt32(); index[i] = DataElement.Create(type, field1, field2, field3, dataSector); } //foreach(var e in index) Console.WriteLine(e); // needed to assign a unique id to each label int currentLabelId = 0; // disassemble instructions var instructions = new InstructionList(header.MaxLocals); for (uint i = 0; i < code.Length; i++) { var dataElement = index[code[i]]; switch (dataElement) { case DataElement.Func func: uint argCount = code[++i]; var arguments = new DataElement[argCount]; for (int j = 0; j < argCount; j++) { var argument = index[code[++i]]; if (argument is DataElement.Ctrl ctrl) { int argLink = dataSector.GetInteger(ctrl.LinkOffset).IntValue; if (argLink != -1 && argLink < code.Length) { ctrl.LinkedElement = index[code[argLink]] as DataElement.Ctrl; } else { if (argLink == Format.Yks.OperatorLink) { Debug.Assert(Format.Yks.Operators.Contains(ctrl.Name.StringValue)); } //Console.WriteLine("Unlinked control element: " + ctrl); } } arguments[j] = argument; } instructions.Add(new CallInstruction(func, arguments, instructions)); break; case DataElement.Ctrl ctrl: // assign a unique id to this label ctrl.Id = currentLabelId++; // link the label int link = dataSector.GetInteger(ctrl.LinkOffset).IntValue; if (link != -1) { ctrl.LinkedElement = index[code[link]] as DataElement.Ctrl; } //else Console.WriteLine("Unlinked control element: " + ctrl); instructions.Add(new LabelInstruction(ctrl, instructions)); break; case DataElement.SStr _: case DataElement.VInt _: case DataElement.VLoc _: case DataElement.VStr _: instructions.Add(new TargetInstruction(dataElement, instructions)); break; case DataElement.CInt cint: cint.Value.PointerId = _flagPointerId++; // Console.WriteLine("WARNING: Constant element gets assigned! Unexpected behavior may occur."); instructions.Add(new TargetInstruction(dataElement, instructions)); break; case DataElement.CStr cstr: throw new InvalidOperationException($"Assignment to string constants is not supported by the disassembler: '{cstr.Value.StringValue}'"); default: throw new FormatException("Invalid instruction type: " + dataElement.Type); } } return(new YukaScript(FileName, instructions)); } }