private static decimal ReadRealNumber(CompactFontFormatData data)
        {
            var sb              = new StringBuilder();
            var done            = false;
            var exponentMissing = false;

            while (!done)
            {
                var b       = data.ReadByte();
                var nibble1 = b / 16;
                var nibble2 = b % 16;

                for (var i = 0; i < 2; i++)
                {
                    var nibble = i == 0 ? nibble1 : nibble2;

                    switch (nibble)
                    {
                    case 0x0:
                    case 0x1:
                    case 0x2:
                    case 0x3:
                    case 0x4:
                    case 0x5:
                    case 0x6:
                    case 0x7:
                    case 0x8:
                    case 0x9:
                        sb.Append(nibble);
                        exponentMissing = false;
                        break;

                    case 0xa:
                        sb.Append(".");
                        break;

                    case 0xb:
                        sb.Append("E");
                        exponentMissing = true;
                        break;

                    case 0xc:
                        sb.Append("E-");
                        exponentMissing = true;
                        break;

                    case 0xd:
                        break;

                    case 0xe:
                        sb.Append("-");
                        break;

                    case 0xf:
                        done = true;
                        break;

                    default:
                        throw new InvalidOperationException($"Did not expect nibble value: {nibble}.");
                    }
                }
            }

            if (exponentMissing)
            {
                // the exponent is missing, just append "0" to avoid an exception
                // not sure if 0 is the correct value, but it seems to fit
                // see PDFBOX-1522
                sb.Append("0");
            }

            if (sb.Length == 0)
            {
                return(0m);
            }

            return(decimal.Parse(sb.ToString()));
        }
        protected T ReadDictionary(T dictionary, CompactFontFormatData data, string[] stringIndex)
        {
            while (data.CanRead())
            {
                operands.Clear();
                var infiniteLoopProtection = 0;

                while (true)
                {
                    infiniteLoopProtection++;
                    // Avoid the library getting caught in an infinite loop, probably not possible.
                    // "An operator may be preceded by up to a maximum of 48 operands."
                    if (infiniteLoopProtection > 256)
                    {
                        throw new InvalidOperationException("Got caught in an infinite loop trying to read a CFF dictionary.");
                    }

                    var byte0 = data.ReadByte();

                    // Operands and operators are distinguished by the first byte, 0 - 21 specify operators
                    if (byte0 <= 21)
                    {
                        var key = byte0 == 12 ? new OperandKey(byte0, data.ReadByte()) : new OperandKey(byte0);

                        ApplyOperation(dictionary, operands, key, stringIndex);
                        break;
                    }

                    /*
                     * b0 value     value range         calculation
                     *  32 - 246      -107 - +107       b0 - 139
                     * 247 - 250      +108 - +1131      (b0 - 247)*256 + b1 + 108
                     * 251 - 254     -1131 - -108       -(b0 - 251)*256 - b1 - 108
                     *  28          -32768 - +32767     b1 << 8 | b2
                     *  29          -(2^31)-+(2^31-1)   b1 << 24 | b2 << 16 | b3 << 8 | b4
                     *
                     * A byte value of 30 defines a real number operand
                     */
                    if (byte0 == 28)
                    {
                        var value = data.ReadByte() << 8 | data.ReadByte();
                        operands.Add(new Operand(value));
                    }
                    else if (byte0 == 29)
                    {
                        var value = data.ReadByte() << 24 | data.ReadByte() << 16 |
                                    data.ReadByte() << 8 | data.ReadByte();
                        operands.Add(new Operand(value));
                    }
                    else if (byte0 == 30)
                    {
                        var realNumber = ReadRealNumber(data);
                        operands.Add(new Operand(realNumber));
                    }
                    else if (byte0 >= 32 && byte0 <= 246)
                    {
                        var value = byte0 - 139;
                        operands.Add(new Operand(value));
                    }
                    else if (byte0 >= 247 && byte0 <= 250)
                    {
                        var value = (byte0 - 247) * 256 + data.ReadByte() + 108;
                        operands.Add(new Operand(value));
                    }
                    else if (byte0 >= 251 && byte0 <= 254)
                    {
                        var value = -(byte0 - 251) * 256 - data.ReadByte() - 108;
                        operands.Add(new Operand(value));
                    }
                    else
                    {
                        throw new InvalidOperationException($"The first dictionary byte was not in the range 29 - 254. Got {byte0}.");
                    }
                }
            }

            return(dictionary);
        }