VCDiffResult DecodeCopy(int size, byte mode, ByteBuffer addresses) { long here = window.SourceLength + decodedOnly; long decoded = addressCache.DecodeAddress(here, mode, addresses); switch ((VCDiffResult)decoded) { case VCDiffResult.ERRROR: return(VCDiffResult.ERRROR); case VCDiffResult.EOD: return(VCDiffResult.EOD); default: if (decoded < 0 || decoded > here) { return(VCDiffResult.ERRROR); } break; } if (decoded + size <= window.SourceLength) { dict.Position = decoded; byte[] rbytes = dict.ReadBytes(size); sout.writeBytes(rbytes); targetData.AddRange(rbytes); decodedOnly += size; return(VCDiffResult.SUCCESS); } ///will come back to this once ///target data reading is implemented /*if(decoded < window.SourceLength) * { * long partial = window.SourceLength - decoded; * dict.Position = decoded; * sout.writeBytes(dict.ReadBytes((int)partial)); * bytesWritten += partial; * size -= (int)partial; * } * * decoded -= window.SourceLength; * * while(size > (bytesDecoded - decoded)) * { * long partial = bytesDecoded - decoded; * target.Position = decoded; * sout.writeBytes(target.ReadBytes((int)partial)); * decoded += partial; * size -= (int)partial; * bytesWritten += partial; * } * * target.Position = decoded; * sout.writeBytes(target.ReadBytes(size));*/ return(VCDiffResult.ERRROR); }
private VCDiffResult DecodeCopy(int size, byte mode, ByteBuffer addresses) { long hereAddress = window.SourceSegmentLength + this.TotalBytesDecoded; long decodedAddress = addressCache.DecodeAddress(hereAddress, mode, addresses); switch ((VCDiffResult)decodedAddress) { case VCDiffResult.ERROR: return(VCDiffResult.ERROR); case VCDiffResult.EOD: return(VCDiffResult.EOD); default: if (decodedAddress < 0 || decodedAddress > hereAddress) { return(VCDiffResult.ERROR); } break; } // Copy all data from source segment if (decodedAddress + size <= window.SourceSegmentLength) { source.Position = decodedAddress + window.SourceSegmentOffset; var rbytes = source.ReadBytes(size).Span; //outputStream.Write(rbytes); targetData.Write(rbytes); this.TotalBytesDecoded += size; return(VCDiffResult.SUCCESS); } // Copy some data from target window... if (decodedAddress < window.SourceSegmentLength) { // ... plus some data from source segment long partialCopySize = window.SourceSegmentLength - decodedAddress; source.Position = decodedAddress + +window.SourceSegmentOffset; var rbytes = source.ReadBytes((int)partialCopySize).Span; //outputStream.Write(rbytes); targetData.Write(rbytes); this.TotalBytesDecoded += partialCopySize; decodedAddress += partialCopySize; size -= (int)partialCopySize; } decodedAddress -= window.SourceSegmentLength; bool overlap = decodedAddress + size >= this.TotalBytesDecoded; if (overlap) { int availableData = (int)(this.TotalBytesDecoded - decodedAddress); for (int i = 0; i < size; i += availableData) { int toCopy = (size - i < availableData) ? size - i : availableData; var tbytesBuf = targetData.GetBuffer().AsSpan((int)decodedAddress + i, toCopy); //outputStream.Write(tbytesBuf); targetData.Write(tbytesBuf); this.TotalBytesDecoded += toCopy; } } else { var fbytes = targetData.GetBuffer().AsSpan((int)decodedAddress, size); //outputStream.Write(fbytes); targetData.Write(fbytes); this.TotalBytesDecoded += size; } return(VCDiffResult.SUCCESS); }
/// <summary> /// Reads and decodes a window, returning whether or not there was /// any more data to read. /// </summary> /// <returns> /// Whether or not the delta stream had reached the end of its data. /// </returns> private bool DecodeWindow() { int windowIndicator = delta.ReadByte(); // Have we finished? if (windowIndicator == -1) { return(false); } // The stream to load source data from for this window, if any Stream sourceStream; // Where to reposition the source stream to after reading from it, if anywhere int sourceStreamPostReadSeek = -1; // xdelta3 uses an undocumented extra bit which indicates that there are an extra // 4 bytes at the end of the encoding for the window bool hasAdler32Checksum = ((windowIndicator & 4) == 4); // Get rid of the checksum bit for the rest windowIndicator &= 0xfb; // Work out what the source data is, and detect invalid window indicators switch (windowIndicator & 3) { // No source data used in this window case 0: sourceStream = null; break; // Source data comes from the original stream case 1: if (original == null) { throw new VcdiffFormatException ("Source stream requested by delta but not provided by caller."); } sourceStream = original; break; case 2: sourceStream = output; sourceStreamPostReadSeek = (int)output.Position; break; case 3: throw new VcdiffFormatException ("Invalid window indicator - bits 0 and 1 both set."); default: throw new VcdiffFormatException("Invalid window indicator - bits 3-7 not all zero."); } // Read the source data, if any byte[] sourceData = null; int sourceLength = 0; if (sourceStream != null) { sourceLength = IOHelper.ReadBigEndian7BitEncodedInt(delta); int sourcePosition = IOHelper.ReadBigEndian7BitEncodedInt(delta); sourceStream.Position = sourcePosition; sourceData = IOHelper.CheckedReadBytes(sourceStream, sourceLength); // Reposition the source stream if appropriate if (sourceStreamPostReadSeek != -1) { sourceStream.Position = sourceStreamPostReadSeek; } } // Read how long the delta encoding is - then ignore it IOHelper.ReadBigEndian7BitEncodedInt(delta); // Read how long the target window is int targetLength = IOHelper.ReadBigEndian7BitEncodedInt(delta); byte[] targetData = new byte[targetLength]; MemoryStream targetDataStream = new MemoryStream(targetData, true); // Read the indicator and the lengths of the different data sections byte deltaIndicator = IOHelper.CheckedReadByte(delta); if (deltaIndicator != 0) { throw new VcdiffFormatException("VcdiffDecoder is unable to handle compressed delta sections."); } int addRunDataLength = IOHelper.ReadBigEndian7BitEncodedInt(delta); int instructionsLength = IOHelper.ReadBigEndian7BitEncodedInt(delta); int addressesLength = IOHelper.ReadBigEndian7BitEncodedInt(delta); // If we've been given a checksum, we have to read it and we might as well // use it to check the data. int checksumInFile = 0; if (hasAdler32Checksum) { byte[] checksumBytes = IOHelper.CheckedReadBytes(delta, 4); checksumInFile = (checksumBytes[0] << 24) | (checksumBytes[1] << 16) | (checksumBytes[2] << 8) | checksumBytes[3]; } // Read all the data for this window byte[] addRunData = IOHelper.CheckedReadBytes(delta, addRunDataLength); byte[] instructions = IOHelper.CheckedReadBytes(delta, instructionsLength); byte[] addresses = IOHelper.CheckedReadBytes(delta, addressesLength); int addRunDataIndex = 0; MemoryStream instructionStream = new MemoryStream(instructions, false); _cache.Reset(addresses); while (true) { int instructionIndex = instructionStream.ReadByte(); if (instructionIndex == -1) { break; } for (int i = 0; i < 2; i++) { Instruction instruction = _codeTable[instructionIndex, i]; int size = instruction.Size; if (size == 0 && instruction.Type != InstructionType.NoOp) { size = IOHelper.ReadBigEndian7BitEncodedInt(instructionStream); } switch (instruction.Type) { case InstructionType.NoOp: break; case InstructionType.Add: targetDataStream.Write(addRunData, addRunDataIndex, size); addRunDataIndex += size; break; case InstructionType.Copy: int addr = _cache.DecodeAddress((int)targetDataStream.Position + sourceLength, instruction.Mode); if (sourceData != null && addr < sourceData.Length) { targetDataStream.Write(sourceData, addr, size); } else // Data is in target data { // Get rid of the offset addr -= sourceLength; // Can we just ignore overlap issues? if (addr + size < targetDataStream.Position) { targetDataStream.Write(targetData, addr, size); } else { for (int j = 0; j < size; j++) { targetDataStream.WriteByte(targetData[addr++]); } } } break; case InstructionType.Run: byte data = addRunData[addRunDataIndex++]; for (int j = 0; j < size; j++) { targetDataStream.WriteByte(data); } break; default: throw new VcdiffFormatException("Invalid instruction type found."); } } } output.Write(targetData, 0, targetLength); if (hasAdler32Checksum) { int actualChecksum = Adler32.ComputeChecksum(1, targetData); if (actualChecksum != checksumInFile) { throw new VcdiffFormatException("Invalid checksum after decoding window"); } } return(true); }