Esempio n. 1
0
        /// <summary>
        /// Decode a Base58 representation.
        /// </summary>
        /// <param name="text">Base58 encoded text.</param>
        /// <returns>Array of decoded bytes.</returns>
        public unsafe Span <byte> Decode(ReadOnlySpan <char> text)
        {
            int textLen = text.Length;

            if (textLen == 0)
            {
                return(Array.Empty <byte>());
            }

            fixed(char *inputPtr = text)
            {
                char *pEnd     = inputPtr + textLen;
                char *pInput   = inputPtr;
                char  zeroChar = this.Alphabet.Value[0];

                while (*pInput == zeroChar && pInput != pEnd)
                {
                    pInput++;
                }

                int numZeroes = (int)(pInput - inputPtr);

                if (pInput == pEnd)
                {
                    return(new byte[numZeroes]); // initialized to zero
                }

                int outputLen = Alphabet.GetSafeByteCountForDecoding(text);
                var table     = this.Alphabet.ReverseLookupTable;

                byte[] output = new byte[outputLen];
                fixed(byte *outputPtr = output)
                {
                    byte *pOutputEnd = outputPtr + outputLen - 1;
                    byte *pMinOutput = pOutputEnd;

                    while (pInput != pEnd)
                    {
                        char c     = *pInput;
                        int  carry = table[c] - 1;
                        if (carry < 0)
                        {
                            throw EncodingAlphabet.InvalidCharacter(c);
                        }

                        byte *pOutput = pOutputEnd;
                        for (; pOutput >= outputPtr; pOutput--)
                        {
                            carry += 58 * (*pOutput);
                            *pOutput = (byte)carry;
                            if (pMinOutput > pOutput && carry != 0)
                            {
                                pMinOutput = pOutput;
                            }

                            carry /= 256;
                        }

                        pInput++;
                    }

                    pMinOutput -= numZeroes;
                    return(output.AsSpan((int)(pMinOutput - outputPtr)));
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Decode given characters into bytes.
        /// </summary>
        /// <param name="text">Characters to decode.</param>
        /// <returns>Decoded bytes.</returns>
        public unsafe Span <byte> Decode(ReadOnlySpan <char> text)
        {
            int textLen = text.Length;

            if (textLen == 0)
            {
                return(Array.Empty <byte>());
            }

            char?allZeroChar    = this.Alphabet.AllZeroShortcut;
            char?allSpaceChar   = this.Alphabet.AllSpaceShortcut;
            bool checkZero      = allZeroChar.HasValue;
            bool checkSpace     = allSpaceChar.HasValue;
            bool usingShortcuts = checkZero || checkSpace;

            // allocate a larger buffer if we're using shortcuts
            int decodeBufferLen = Alphabet.GetSafeByteCountForDecoding(text);

            byte[] decodeBuffer = new byte[decodeBufferLen];
            var    table        = this.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, ref blockIndex, 0);
                        continue;
                    }

                    if (checkSpace && c == allSpaceChar)
                    {
                        writeShortcut(ref pDecodeBuffer, ref blockIndex, allSpace);
                        continue;
                    }

                    // handle regular blocks
                    int x = table[c] - 1; // map character to byte value
                    if (x < 0)
                    {
                        throw EncodingAlphabet.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));
            }
        }