Exemplo n.º 1
0
        public unsafe Span <byte> Decode(string text)
        {
            Require.NotNull(text, nameof(text));
            int textLen = text.Length;

            if (textLen == 0)
            {
                return(new byte[0]);
            }

            char allZeroChar    = alphabet.AllZeroShortcut;
            char allSpaceChar   = alphabet.AllSpaceShortcut;
            bool checkZero      = allZeroChar != Base85Alphabet.NoShortcut;
            bool checkSpace     = allSpaceChar != Base85Alphabet.NoShortcut;
            bool usingShortcuts = checkZero || checkSpace;

            // allocate a larger buffer if we're using shortcuts
            int decodeBufferLen = getDecodeBufferLength(textLen, usingShortcuts);

            byte[] decodeBuffer = new byte[decodeBufferLen];
            byte[] table        = alphabet.ReverseLookupTable;
            fixed(char *inputPtr = text)
            fixed(byte *decodeBufferPtr = decodeBuffer)
            {
                byte *pDecodeBuffer = decodeBufferPtr;
                char *pInput        = inputPtr;
                char *pInputEnd     = pInput + textLen;

                int  blockIndex = 0;
                long value      = 0;

                while (pInput != pInputEnd)
                {
                    char c = *pInput++;

                    if (isWhiteSpace(c))
                    {
                        continue;
                    }

                    // handle shortcut characters
                    if (checkZero && c == allZeroChar)
                    {
                        writeShortcut(ref pDecodeBuffer, blockIndex, allZeroChar, 0);
                        continue;
                    }
                    if (checkSpace && c == allSpaceChar)
                    {
                        writeShortcut(ref pDecodeBuffer, blockIndex, allSpaceChar, allSpace);
                        continue;
                    }

                    // handle regular blocks
                    int x = table[c] - 1; // map character to byte value
                    if (x < 0)
                    {
                        throw alphabet.InvalidCharacter(c);
                    }
                    value       = value * baseLength + x;
                    blockIndex += 1;
                    if (blockIndex == stringBlockSize)
                    {
                        writeDecodedValue(ref pDecodeBuffer, value, byteBlockSize);
                        blockIndex = 0;
                        value      = 0;
                    }
                }
                if (blockIndex > 0)
                {
                    // handle padding by treating the rest of the characters
                    // as "u"s. so both big endianness and bit weirdness work out okay.
                    for (int i = 0; i < stringBlockSize - blockIndex; i++)
                    {
                        value = value * baseLength + (baseLength - 1);
                    }
                    writeDecodedValue(ref pDecodeBuffer, value, blockIndex - 1);
                }
                int actualOutputLength = (int)(pDecodeBuffer - decodeBufferPtr);

                return(new Span <byte>(decodeBufferPtr, actualOutputLength));
            }
        }