Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 3
0
        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));
            }
        }