Exemple #1
0
        private unsafe void CaptureStateDelta(byte[] currentState)
        {
            // Keep in mind that everything captured here is intended to be played back in
            // reverse. The goal is, given the current state, how to get back to the previous
            // state. That's why the data portion of the delta comes from the previous state,
            // and also why the previous state is used if we have to bail out and capture the
            // full state instead.
            if (currentState.Length != _lastState.Length)
            {
                // If the state sizes mismatch, capture a full state rather than trying to do anything clever
                goto CaptureFullState;
            }

            if (currentState.Length == 0)
            {
                // handle empty states as a "full" (empty) state
                goto CaptureFullState;
            }

            int  index                         = 0;
            int  stateLength                   = Math.Min(currentState.Length, _lastState.Length);
            bool inChangeSequence              = false;
            int  changeSequenceStartOffset     = 0;
            int  lastChangeSequenceStartOffset = 0;

            if (_deltaBuffer.Length < stateLength + 1)
            {
                _deltaBuffer = new byte[stateLength + 1];
            }

            _deltaBuffer[index++] = 0;             // Full state = false (i.e. delta)

            fixed(byte *pCurrentState = &currentState[0])
            fixed(byte *pLastState = &_lastState[0])
            for (int i = 0; i < stateLength; i++)
            {
                bool thisByteMatches = *(pCurrentState + i) == *(pLastState + i);

                if (inChangeSequence == false)
                {
                    if (thisByteMatches)
                    {
                        continue;
                    }

                    inChangeSequence          = true;
                    changeSequenceStartOffset = i;
                }

                if (thisByteMatches || i == stateLength - 1)
                {
                    const int MaxHeaderSize = 10;
                    int       length        = i - changeSequenceStartOffset + (thisByteMatches ? 0 : 1);

                    if (index + length + MaxHeaderSize >= stateLength)
                    {
                        // If the delta ends up being larger than the full state, capture the full state instead
                        goto CaptureFullState;
                    }

                    // Offset Delta
                    VLInteger.WriteUnsigned((uint)(changeSequenceStartOffset - lastChangeSequenceStartOffset), _deltaBuffer, ref index);

                    // Length
                    VLInteger.WriteUnsigned((uint)length, _deltaBuffer, ref index);

                    // Data
                    Buffer.BlockCopy(_lastState, changeSequenceStartOffset, _deltaBuffer, index, length);
                    index += length;

                    inChangeSequence = false;
                    lastChangeSequenceStartOffset = changeSequenceStartOffset;
                }
            }

            _rewindBuffer.Push(new ArraySegment <byte>(_deltaBuffer, 0, index));

            UpdateLastState(currentState);
            return;

CaptureFullState:
            CaptureStateNonDelta(_lastState);
            UpdateLastState(currentState);
        }
Exemple #2
0
        private unsafe void CaptureRewindStateDelta(byte[] currentState)
        {
            // in case the state sizes mismatch, capture a full state rather than trying to do anything clever
            if (currentState.Length != _lastState.Length)
            {
                CaptureRewindStateNonDelta(_lastState);
                UpdateLastState(currentState);
                return;
            }

            int  index                         = 0;
            int  stateLength                   = Math.Min(currentState.Length, _lastState.Length);
            bool inChangeSequence              = false;
            int  changeSequenceStartOffset     = 0;
            int  lastChangeSequenceStartOffset = 0;

            if (_deltaBuffer.Length < stateLength)
            {
                _deltaBuffer = new byte[stateLength];
            }

            _deltaBuffer[index++] = 0;             // Full state = false (i.e. delta)

            fixed(byte *pCurrentState = &currentState[0])
            fixed(byte *pLastState = &_lastState[0])
            for (int i = 0; i < stateLength; i++)
            {
                bool thisByteMatches = *(pCurrentState + i) == *(pLastState + i);

                if (inChangeSequence == false)
                {
                    if (thisByteMatches)
                    {
                        continue;
                    }

                    inChangeSequence          = true;
                    changeSequenceStartOffset = i;
                }

                if (thisByteMatches || i == stateLength - 1)
                {
                    const int maxHeaderSize = 10;
                    int       length        = i - changeSequenceStartOffset + (thisByteMatches ? 0 : 1);

                    if (index + length + maxHeaderSize >= stateLength)
                    {
                        // If the delta ends up being larger than the full state, capture the full state instead
                        CaptureRewindStateNonDelta(_lastState);
                        UpdateLastState(currentState);
                        return;
                    }

                    // Offset Delta
                    VLInteger.WriteUnsigned((uint)(changeSequenceStartOffset - lastChangeSequenceStartOffset), _deltaBuffer, ref index);

                    // Length
                    VLInteger.WriteUnsigned((uint)length, _deltaBuffer, ref index);

                    // Data
                    Buffer.BlockCopy(_lastState, changeSequenceStartOffset, _deltaBuffer, index, length);
                    index += length;

                    inChangeSequence = false;
                    lastChangeSequenceStartOffset = changeSequenceStartOffset;
                }
            }

            _rewindBuffer.Push(new ArraySegment <byte>(_deltaBuffer, 0, index));

            UpdateLastState(currentState);
        }