Esempio n. 1
0
        /// <returns>The first offset that was edited</returns>
        public static int ApplyIPSPatch(IDataModel model, byte[] patch, ModelDelta token)
        {
            // 5 byte header (PATCH) and 3 byte footer (EOF)
            // hunk type 1: offset (3 bytes), length (2 bytes), payload (length bytes). Write the payload at offset.
            // RLE hunk:    offset (3 bytes), 00 00, length (2 bytes), target (1 byte). Write the target, length times, at offset

            var start       = 5;
            var firstOffset = -1;

            while (patch.Length - start >= 6)
            {
                var offset = (patch[start] << 16) + (patch[start + 1] << 8) + patch[start + 2];
                if (firstOffset < 0)
                {
                    firstOffset = offset;
                }
                start += 3;
                var length = (patch[start] << 8) + patch[start + 1];
                start += 2;
                if (length > 0)
                {
                    // normal
                    model.ExpandData(token, offset + length - 1);
                    while (length > 0)
                    {
                        token.ChangeData(model, offset, patch[start]);
                        offset += 1;
                        start  += 1;
                        length -= 1;
                    }
                }
                else
                {
                    length = (patch[start] << 8) + patch[start + 1];
                    start += 2;
                    model.ExpandData(token, offset + length - 1);
                    // rle
                    while (length > 0)
                    {
                        token.ChangeData(model, offset, patch[start]);
                        offset += 1;
                        length -= 1;
                    }
                    start += 1;
                }
            }

            return(firstOffset);
        }
Esempio n. 2
0
        public virtual bool ChangeData(IDataModel model, int index, byte data)
        {
            if (model.Count > index && model[index] == data)
            {
                return(false);
            }
            if (!oldData.ContainsKey(index))
            {
                if (model.Count <= index)
                {
                    model.ExpandData(this, index);
                }
                oldData[index] = model[index];
            }

            var valueChanged = model[index] != data;

            model[index] = data;
            if (!HasDataChange)
            {
                HasDataChange = true;
                OnNewChange?.Invoke(this, EventArgs.Empty);
            }

            return(valueChanged);
        }
        public virtual void ChangeData(IDataModel model, int index, byte data)
        {
            if (!oldData.ContainsKey(index))
            {
                if (model.Count <= index)
                {
                    model.ExpandData(this, index);
                }
                oldData[index] = model[index];
            }

            model[index] = data;
            if (!HasDataChange)
            {
                HasDataChange = true;
                OnNewDataChange?.Invoke(this, EventArgs.Empty);
            }
        }
Esempio n. 4
0
        public ModelDelta Revert(IDataModel model)
        {
            var reverse = new ModelDelta {
                HasDataChange = HasDataChange
            };

            foreach (var kvp in oldData)
            {
                var(index, data)       = (kvp.Key, kvp.Value);
                reverse.oldData[index] = model.Count > index ? model[index] : (byte)0xFF;
                if (model.Count > index)
                {
                    model[index] = data;
                }
            }

            foreach (var kvp in addedRuns)
            {
                reverse.removedRuns[kvp.Key] = kvp.Value;
            }
            foreach (var kvp in removedRuns)
            {
                reverse.addedRuns[kvp.Key] = kvp.Value;
            }
            foreach (var kvp in addedNames)
            {
                reverse.removedNames[kvp.Key] = kvp.Value;
            }
            foreach (var kvp in removedNames)
            {
                reverse.addedNames[kvp.Key] = kvp.Value;
            }
            foreach (var kvp in addedLists)
            {
                reverse.removedLists[kvp.Key] = kvp.Value;
            }
            foreach (var kvp in removedLists)
            {
                reverse.addedLists[kvp.Key] = kvp.Value;
            }
            foreach (var kvp in addedMatchedWords)
            {
                reverse.removedMatchedWords[kvp.Key] = kvp.Value;
            }
            foreach (var kvp in removedMatchedWords)
            {
                reverse.addedMatchedWords[kvp.Key] = kvp.Value;
            }
            foreach (var kvp in addedOffsetPointers)
            {
                reverse.removedOffsetPointers[kvp.Key] = kvp.Value;
            }
            foreach (var kvp in removedOffsetPointers)
            {
                reverse.addedOffsetPointers[kvp.Key] = kvp.Value;
            }
            foreach (var kvp in addedUnmappedPointers)
            {
                reverse.removedUnmappedPointers[kvp.Key] = kvp.Value;
            }
            foreach (var kvp in removedUnmappedPointers)
            {
                reverse.addedUnmappedPointers[kvp.Key] = kvp.Value;
            }
            foreach (var kvp in addedUnmappedConstants)
            {
                reverse.removedUnmappedConstants[kvp.Key] = kvp.Value;
            }
            foreach (var kvp in removedUnmappedConstants)
            {
                reverse.addedUnmappedConstants[kvp.Key] = kvp.Value;
            }

            if (oldDataLength != -1 || newDataLength != -1)
            {
                model.ExpandData(reverse, oldDataLength - 1);
                model.ContractData(reverse, oldDataLength - 1);
            }

            model.MassUpdateFromDelta(addedRuns, removedRuns,
                                      addedNames, removedNames,
                                      addedUnmappedPointers, removedUnmappedPointers,
                                      addedMatchedWords, removedMatchedWords,
                                      addedOffsetPointers, removedOffsetPointers,
                                      addedUnmappedConstants, removedUnmappedConstants,
                                      addedLists, removedLists);

            return(reverse);
        }
Esempio n. 5
0
        // return -1 if the header is wrong (UPS1)
        // return -2 if the source file CRC doesn't match
        // return -3 if the patch file CRC doesn't match
        // return -4 if the source file size doesn't match
        // return -5 if the result file CRC doesn't match
        // return -6 if the UPS content didn't finish the last chunk with exactly 12 bytes left
        // return -7 if trying to write past the end of the destination file
        // returns a positive integer, the address of the first change, if everything worked correctly
        public static int ApplyUPSPatch(IDataModel model, byte[] patch, Func <ModelDelta> tokenFactory, bool ignoreChecksums, out UpsPatchDirection direction)
        {
            // 4 byte header: "UPS1"
            // variable width source-size
            // variable width destination-size
            // 12 byte footer: 3 CRC32 checksums. Source file, destination file, patch file (CRC of everything except the last 4 bytes)
            direction = UpsPatchDirection.Fail;

            // check header
            var headerMatches = patch.Take(4).Select(b => (char)b).SequenceEqual("UPS1");

            if (!headerMatches)
            {
                return(-1);
            }

            // check source CRC
            var currentCRC              = CalcCRC32(model.RawData);
            var patchSourceFileCRC      = patch.ReadMultiByteValue(patch.Length - 12, 4);
            var patchDestinationFileCRC = patch.ReadMultiByteValue(patch.Length - 8, 4);

            if (currentCRC == patchSourceFileCRC)
            {
                direction = UpsPatchDirection.SourceToDestination;
            }
            if (currentCRC == patchDestinationFileCRC)
            {
                direction = UpsPatchDirection.DestinationToSource;
            }
            if (direction == UpsPatchDirection.Fail && !ignoreChecksums)
            {
                return(-2);
            }
            if (direction == UpsPatchDirection.Fail)
            {
                direction = UpsPatchDirection.SourceToDestination;
            }

            // check patch CRC
            var patchWithoutCRC = new byte[patch.Length - 4];

            Array.Copy(patch, patchWithoutCRC, patchWithoutCRC.Length);
            var patchCRC = CalcCRC32(patchWithoutCRC);

            if (patchCRC != patch.ReadMultiByteValue(patch.Length - 4, 4))
            {
                return(-3);
            }

            // resize (bigger)
            int readIndex = 4, firstEdit = int.MaxValue;
            int sourceSize      = ReadVariableWidthInteger(patch, ref readIndex);
            int destinationSize = ReadVariableWidthInteger(patch, ref readIndex);
            int writeLength     = destinationSize;

            if (direction == UpsPatchDirection.DestinationToSource)
            {
                (sourceSize, destinationSize) = (destinationSize, sourceSize);
            }
            if (sourceSize != model.Count && !ignoreChecksums)
            {
                return(-4);
            }
            var token = tokenFactory.Invoke();

            model.ExpandData(token, destinationSize - 1);
            token.ChangeData(model, sourceSize, new byte[Math.Max(0, destinationSize - sourceSize)]);
            token.ChangeData(model, destinationSize, new byte[Math.Max(0, sourceSize - destinationSize)]);

            // run algorithm
            firstEdit = RunUPSPatchAlgorithm(model, patch, token, writeLength, destinationSize, ref readIndex);
            if (firstEdit < 0)
            {
                return(firstEdit);
            }

            // resize (smaller)
            model.ContractData(token, destinationSize - 1);

            // check result CRC
            if (!ignoreChecksums)
            {
                var finalCRC = CalcCRC32(model.RawData);
                if (direction == UpsPatchDirection.SourceToDestination && finalCRC != patchDestinationFileCRC)
                {
                    return(-5);
                }
                if (direction == UpsPatchDirection.DestinationToSource && finalCRC != patchSourceFileCRC)
                {
                    return(-5);
                }
            }

            // check that the chunk ended cleanly
            if (direction == UpsPatchDirection.SourceToDestination && readIndex != patch.Length - 12)
            {
                return(-6);
            }

            return(firstEdit);
        }