예제 #1
0
        public static long Recreate(IStorage fragmentMeta, FileStream writer, IFileSystem newBaseFolderFs)
        {
            var Segments = new List<DeltaFragmentSegment>();
            if (fragmentMeta.GetSize() < 0x40)
            {
                throw new InvalidDataException("Delta file is too small.");
            }

            var magic = new byte[4];
            fragmentMeta.Read(magic, 0, 4, 0);
            var reader = new FileReader(new StorageFile(fragmentMeta, OpenMode.Read));

            if (Utils.ArraysEqual(magic, DeltaTools.LCA3Macic))
            {
                reader.Position = DeltaTools.LCA3Macic.Length;
                var linkedNcaFilenameSize = reader.ReadUInt8();
                var linkedNcafilename =
                    Encoding.ASCII.GetString(reader.ReadBytes(DeltaTools.LCA3Macic.Length + 1, linkedNcaFilenameSize,
                        true));

                var newLinkedFile = newBaseFolderFs.OpenFile(linkedNcafilename, OpenMode.Read).AsStream();
                newLinkedFile.CopyStream(writer, newLinkedFile.Length);
                return reader.Position;
            }

            var Header = new DeltaFragmentHeader(new StorageFile(fragmentMeta, OpenMode.Read));

            reader.Position = 0;
            if (Header.Magic == DeltaTools.Tdv0Magic)
            {
                var headerData = reader.ReadBytes(0, (int) Header.FragmentHeaderSize, true);
                headerData[0] = 0x4E; //N (TDV0 to NDV0)
                writer.Write(headerData, 0, (int) Header.FragmentHeaderSize);
            }
            else if (Header.Magic == DeltaTools.Cdv0Magic)
            {
                reader.Position = 4;
            }
            else
            {
                throw new InvalidDataException("TDV0/CDV0 magic value is missing.");
            }

            var pos = reader.Position;
            var baseNcaFilenameSize = reader.ReadUInt8();
            var filenameOffset =
                Encoding.ASCII.GetString(reader.ReadBytes(pos + 1, baseNcaFilenameSize, true)).Split(':');

            var newBaseFile = newBaseFolderFs.OpenFile(filenameOffset[0], OpenMode.Read).AsStream();

            long offset = 0;
            var endOffset = Header.NewSize;
            if (filenameOffset.Length > 2)
            {
                offset = long.Parse(filenameOffset[1], NumberStyles.HexNumber);
                endOffset = long.Parse(filenameOffset[2], NumberStyles.HexNumber);
            }

            const int maxBS = 10485760; //10 MB
            int bs;
            var FragmentBlock = new byte[maxBS];

            while (offset < endOffset)
            {
                Console.WriteLine($"ReadSegmentHeader on {offset}");
                ReadSegmentHeader(reader, writer, out var size, out var seek);
                Console.WriteLine($"size: {size}, seek: {seek}, readerPos: {reader.Position}, writerPos: {writer.Position}");
                if (seek > 0)
                {
                    var segment = new DeltaFragmentSegment
                    {
                        SourceOffset = offset,
                        Size = seek,
                        IsInOriginal = true
                    };

                    Segments.Add(segment);
                    offset += seek;
                }

                if (size > 0)
                {
                    var segment = new DeltaFragmentSegment
                    {
                        SourceOffset = reader.Position,
                        Size = size,
                        IsInOriginal = false
                    };

                    newBaseFile.Position = offset;
                    var fragmentOffsetEnd = offset + segment.Size;
                    while (newBaseFile.Position < fragmentOffsetEnd)
                    {
                        bs = (int) Math.Min(fragmentOffsetEnd - newBaseFile.Position, maxBS);
                        newBaseFile.Read(FragmentBlock, 0, bs);
                        writer.Write(FragmentBlock, 0, bs);
                    }

                    Segments.Add(segment);
                    offset += size;
                }
            }

            newBaseFile.Dispose();
            return reader.Position;
        }
예제 #2
0
        public static long Save(IStorage delta, FileStream writer, string foundBaseNCA)
        {
            var filenameOffset = foundBaseNCA.Split(':');

            if (delta.GetSize() < 0x40)
            {
                throw new InvalidDataException("Delta file is too small.");
            }

            if (foundBaseNCA.Length > 255)
            {
                throw new IndexOutOfRangeException("Base NCA filename isn't allowed to be longer then 255 characters");
            }

            var Header = new DeltaFragmentHeader(new StorageFile(delta, OpenMode.Read));

            var reader = new FileReader(new StorageFile(delta, OpenMode.Read));

            reader.Position = 0;

            if (filenameOffset.Length == 1 && Header.Magic != DeltaTools.Ndv0Magic)
            {
                writer.Write(DeltaTools.LCA3Macic, 0, DeltaTools.LCA3Macic.Length);
                writer.WriteByte((byte)foundBaseNCA.Length);
                writer.Write(Encoding.ASCII.GetBytes(foundBaseNCA), 0, foundBaseNCA.Length);
                return(0);
            }

            if (Header.Magic == DeltaTools.Ndv0Magic)
            {
                var fragmentSize = Header.FragmentHeaderSize + Header.FragmentBodySize;
                //if (!isSplitNdv0 && delta.Length < fragmentSize)
                //{
                //	throw new InvalidDataException(
                //		$"Delta file is smaller than the header indicates. (0x{fragmentSize} bytes)");
                //}

                var headerData = reader.ReadBytes((int)Header.FragmentHeaderSize);
                headerData[0] = 0x54;                 //T (NDV0 to TDV0)
                writer.Write(headerData, 0, (int)Header.FragmentHeaderSize);
            }
            else
            {
                writer.Write(Encoding.ASCII.GetBytes(DeltaTools.Cdv0Magic), 0, DeltaTools.Cdv0Magic.Length);
            }

            writer.WriteByte((byte)foundBaseNCA.Length);
            writer.Write(Encoding.ASCII.GetBytes(foundBaseNCA), 0, foundBaseNCA.Length);
            var foundBaseNCAEndOffsetPos = foundBaseNCA.LastIndexOf(':') + 1;
            var foundBaseNCAEndOffsetLen = foundBaseNCA.Length - foundBaseNCAEndOffsetPos;
            var SplitNdv0EndOffsetPos    = writer.Position - foundBaseNCAEndOffsetLen;

            long offset    = 0;
            long deltaSize = delta.GetSize();

            Console.WriteLine($"reader={reader.Position} writer={writer.Position}");
            while (reader.Position < deltaSize)
            {
                ReadSegmentHeader(reader, writer, out var size, out var seek);

                if (seek > 0)
                {
                    offset += seek;
                }

                if (size > 0)
                {
                    offset += size;
                }

                reader.Position += size;
            }

            if (reader.Position == deltaSize)
            {
                if (filenameOffset.Length > 2)
                {
                    var startOffset   = long.Parse(filenameOffset[1], NumberStyles.HexNumber);
                    var endOffset     = startOffset + offset;
                    var realEndOffset = endOffset.ToString($"X{foundBaseNCAEndOffsetLen}");
                    var posReal       = writer.Position;
                    writer.Position = SplitNdv0EndOffsetPos;
                    writer.Write(Encoding.ASCII.GetBytes(realEndOffset), 0, realEndOffset.Length);
                    writer.Position = posReal;
                }

                //Size of data untimmed in this function call
                return(offset);
            }

            throw new InvalidDataException("Fragment file seems to be corrupted!");
        }