Esempio n. 1
0
        /// <summary>
        /// Perform raw encode using provided buffers for "Deltas" and "Recents" values with specified <see cref="LookupScheme"/>.
        /// </summary>
        /// <param name="src">Source buffer.</param>
        /// <param name="dst">Destination buffer.</param>
        /// <param name="recents">Provided buffer for storing Recents.</param>
        /// <param name="windowBuf">Provided buffer for storing Deltas.</param>
        /// <param name="lookupScheme">Scheme to use for lookups.</param>
        /// <returns>Length of encoded bytes.</returns>
        public static int EncodeRaw_Internal(
            ReadOnlySpan <byte> src,
            Span <byte> dst,
            Span <int> recents,
            Span <int> windowBuf,
            LookupScheme lookupScheme = LookupScheme.LookAhead)
        {
            // Variables to keep track of indexes for src/dst buffers, and code byte.
            int codeBytePlace = 0, commandBit = 0, dstPlace = 0, srcPlace = 0;

            // Helper for tracking state of "Deltas" revolving buffer.
            var window = new RevolvingBufferTracker <int>(windowBuf);

            // Recent lookup result.
            var result = LookupResult.NoneFound();

            // Whether or not to use LookAhead lookup scheme.
            bool useLookAheadScheme = lookupScheme == LookupScheme.LookAhead;

            while (srcPlace < src.Length)
            {
                if (commandBit == 0)
                {
                    // Reserve code byte location for modifying.
                    codeBytePlace      = dstPlace++;
                    dst[codeBytePlace] = 0;
                }

                // Perform lookup if result does not have a valid offset from previous loop.
                if (!result.Found)
                {
                    if (useLookAheadScheme)
                    {
                        // Perform lookup for both current byte and next byte.
                        result = LookupWithAhead(src, srcPlace, ref window, recents);
                    }
                    else
                    {
                        // Perform standard lookup for only the current byte.
                        result = Lookup(src, srcPlace, ref window, recents);
                    }
                }

                // Append to Deltas window and Recents.
                Remember(src, srcPlace, ref window, recents);

                // If found chunk in lookup, encode information about it.
                if (!result.SkipByte && result.Found)
                {
                    // Calculate distance between current src offset and chunk offset.
                    var distance = srcPlace - result.Offset - 1;

                    // Write bytes to indicate RLE copy.
                    // Encodes differently depending on chunk length.
                    if (result.Length < 0x12)
                    {
                        // Encode for chunk size smaller than 0x12. Uses 2 bytes.
                        dst[dstPlace]     = (byte)(((result.Length - 2) << 4) | (distance >> 8));
                        dst[dstPlace + 1] = (byte)(distance & 0xFF);
                        dstPlace         += 2;
                    }
                    else
                    {
                        // Encode for chunk size 0x12 or larger (up to 0x111). Uses 3 bytes.
                        dst[dstPlace]     = (byte)(distance >> 8);
                        dst[dstPlace + 1] = (byte)(distance & 0xFF);
                        dst[dstPlace + 2] = (byte)(result.Length - 0x12);
                        dstPlace         += 3;
                    }

                    // Would like to call method WriteRLEIndicator instead of above code, but it causes a performance hit.
                    // dstPlace += WriteRLEIndicator(dst, dstPlace, distance, result.Length);

                    // Go through each matched byte and append to delta window.
                    // Todo: Maybe don't do this if already finished encoding?
                    for (int j = 1; j < result.Length; j++)
                    {
                        Remember(src, srcPlace + j, ref window, recents);
                    }

                    srcPlace += result.Length;
                }
                else
                {
                    // If no result from lookup, set bit for direct copy.
                    dst[codeBytePlace] |= (byte)(1 << (7 - commandBit));
                    dst[dstPlace++]     = src[srcPlace++];
                }

                // Update result state.
                result = LookupResult.ClearIfNotSkipped(ref result);

                // Update command bit index.
                commandBit = (commandBit + 1) % 8;
            }

            return(dstPlace);
        }
Esempio n. 2
0
        /// <summary>
        /// Perform raw encode using provided buffers for "Deltas" and "Recents" values with specified <see cref="LookupScheme"/>.
        /// </summary>
        /// <param name="src">Source buffer.</param>
        /// <param name="dst">Destination buffer.</param>
        /// <param name="recents">Provided buffer for storing Recents.</param>
        /// <param name="windowBuf">Provided buffer for storing Deltas.</param>
        /// <returns>Length of encoded bytes.</returns>
        public static int EncodeRaw(ReadOnlySpan <byte> src, Span <byte> dst, Span <int> recents, Span <int> windowBuf, LookupScheme lookupScheme = LookupScheme.LookAhead)
        {
            if (recents.Length < 0x100)
            {
                ThrowArgumentOutOfRangeExceptionForRecents("recents");
            }

            if (windowBuf.Length > 0x1000)
            {
                ThrowArgumentOutOfRangeExceptionForDeltas("windowBuf");
            }

            return(EncodeRaw_Internal(src, dst, recents, windowBuf, lookupScheme));
        }