Ejemplo n.º 1
0
        /// <summary>インラインテーブルを解析する。</summary>
        /// <param name="iter">イテレータ。</param>
        /// <returns>値情報。</returns>
        private ITomlValue GetInlineTable(TomlInnerBuffer.TomlIter iter)
        {
            var  table = new TomlTable();
            UTF8 c;

            while ((c = iter.GetChar(0)).ch1 != 0)
            {
                // 改行、空白部を取り除く
                iter.SkipLineFeedAndSpace();

                // キー/値部分を取り込む
                this.AnalisysKeyAndValue(iter, table, true);

                // インラインテーブルが閉じられているか確認
                //
                // 1. テーブルが閉じられている
                // 2. 次のキー/値を取得
                // 3. エラー
                switch (iter.CloseInlineTable())
                {
                case 1:                             // 1
                    return(table);

                case 2:                             // 2
                    // 空実装
                    break;

                default:                            // 3
                    break;
                }
            }
            throw new TomlAnalisysException(Resources.INLINE_TABLE_NOT_CLOSE_ERR, iter);
        }
 /// <summary>文字列を部分的に切り取り、数値表現か確認、取得する。</summary>
 /// <param name="iter">イテレータ。</param>
 /// <param name="nest">ネスト位置。</param>
 /// <param name="digit">必要桁数。</param>
 /// <param name="result">読込結果(戻り値)</param>
 /// <returns>取得できたら真。</returns>
 private static bool ConvertPartitionNumber(TomlInnerBuffer.TomlIter iter,
                                            int nest, int digit, out int result)
 {
     if (iter.RemnantLength < digit)
     {
         // 指定桁数未満の数値であるためエラー
         result = 0;
         return(false);
     }
     else
     {
         // 必要桁数分ループし、全てが数値表現であることを確認
         // 1. ループ
         // 2. 数値判定し、結果を作成する
         // 3. 結果を返す
         UTF8 c;
         int  num = 0;
         for (int i = 0; i < digit; ++i)         // 1
         {
             c = iter.GetChar(nest + i);
             if (c.ch1 >= '0' && c.ch1 <= '9')   // 2
             {
                 num = num * 10 + (c.ch1 - '0');
             }
             else
             {
                 result = 0;
                 return(false);
             }
         }
         result = num;                           // 3
         return(true);
     }
 }
        //---------------------------------------------------------------------
        // 文字解析
        //---------------------------------------------------------------------
        /// <summary>キー文字列の取得。</summary>
        /// <param name="buffer">内部バッファ。</param>
        /// <param name="iter">イテレータ。</param>
        /// <returns>キーリスト。</returns>
        internal static List <string> GetKeys(this TomlInnerBuffer.TomlIter iter)
        {
            var res = new List <string>();

            while (iter.GetChar(0).ch1 > 0)
            {
                iter.SkipSpace();               // 1

                var key = iter.GetKey();        // 2
                if (key != null)
                {
                    res.Add(key);
                    if (iter.GetChar(0).ch1 != '.')     // 3
                    {
                        break;
                    }
                    iter.Skip(1);
                }
                else
                {
                    break;
                }
            }
            return(res);
        }
Ejemplo n.º 4
0
        /// <summary>値の解析を行う。</summary>
        /// <param name="iter">イテレータ。</param>
        /// <returns>値情報。</returns>
        private ITomlValue AnalisysValue(TomlInnerBuffer.TomlIter iter)
        {
            ITomlValue value = null;

            // インラインテーブル、配列、日付の確認
            //
            // 1. インラインテーブルを解析する
            // 2. 配列を解析する
            // 3. 値を取得する
            iter.SkipSpace();
            if (iter.GetChar(0).ch1 == '{')         // 1
            {
                iter.Skip(1);
                value = this.GetInlineTable(iter);
            }
            else if (iter.GetChar(0).ch1 == '[')    // 2
            {
                iter.Skip(1);
                value = this.GetValueArray(iter);
            }
            else
            {
                value = this.ConvertValue(iter);    // 3
            }

            return(value);
        }
        /// <summary>数値(整数/実数)を取得する。</summary>
        /// <param name="iter">イテレータ。</param>
        /// <param name="numberSign">符号。</param>
        /// <returns>取得した値。</returns>
        internal static ITomlValue GetNumberValue(this TomlInnerBuffer.TomlIter iter, bool numberSign)
        {
            if (!numberSign &&
                iter.RemnantLength >= 3 &&
                iter.GetChar(0).ch1 == '0')
            {
                switch (iter.GetChar(1).ch1)
                {
                case (byte)'x':
                    iter.Skip(2);
                    return(Get16NumberValue(iter));

                case (byte)'o':
                    iter.Skip(2);
                    return(Get8NumberValue(iter));

                case (byte)'b':
                    iter.Skip(2);
                    return(Get2NumberValue(iter));

                default:
                    break;
                }
            }
            return(Get10NumberValue(iter, numberSign));
        }
        /// <summary>配列が閉じられていることを確認する。</summary>
        /// <param name="iter"></param>
        /// <returns>閉じられていたら 1、次のキー取得ならば 2。</returns>
        internal static int CloseValueArray(this TomlInnerBuffer.TomlIter iter)
        {
            UTF8 c;

            while ((c = iter.GetChar(0)).ch1 != 0)
            {
                iter.SkipLineFeedAndSpace();

                switch (iter.GetChar(0).ch1)
                {
                case (byte)']':
                    // 配列が閉じられた
                    iter.Skip(1);
                    return(1);

                case (byte)',':
                    // 続けて次のキー/値判定へ
                    iter.Skip(1);
                    return(2);

                default:
                    // インラインテーブルが閉じられていない
                    goto EXIT_WHILE;
                }
            }
EXIT_WHILE:
            throw new TomlAnalisysException(Resources.ARRAY_NOT_CLOSE_ERR, iter);
        }
        /// <summary>" で囲まれた文字列を取得する。</summary>
        /// <param name="iter">イテレータ。</param>
        /// <returns>取得した文字列。</returns>
        public static string GetStringValue(this TomlInnerBuffer.TomlIter iter)
        {
            var  buf = new List <byte>();
            UTF8 c;

            while ((c = iter.GetChar(0)).ch1 != 0)
            {
                switch (c.ch1)
                {
                case (byte)'"':
                    // " を取得したら文字列終了
                    iter.Skip(1);
                    return(buf.Count > 0 ? Encoding.UTF8.GetString(buf.ToArray()) : "");

                case (byte)'\\':
                    // \のエスケープ文字判定
                    AppendEscapeChar(iter, buf);
                    break;

                default:
                    // 上記以外は普通の文字として取得
                    c.Expand(buf);
                    iter.Skip(1);
                    break;
                }
            }
            // " で終了できなかったためエラー
            throw new TomlAnalisysException(Resources.QUOAT_STRING_ERR, iter);
        }
        /// <summary>数値(2進数)を取得する。</summary>
        /// <param name="iter">イテレータ。</param>
        /// <returns>数値。</returns>
        private static ITomlValue Get2NumberValue(TomlInnerBuffer.TomlIter iter)
        {
            ulong v  = 0;
            bool  ud = false;
            UTF8  c;
            int   point = iter.Pointer;

            // 数値を取得する
            while ((c = iter.GetChar(0)).ch1 != 0)
            {
                // 1. '_'の連続の判定
                // 2. 数値の計算をする
                //    2-1. 数値の有効範囲を超えるならばエラー
                if (c.ch1 == '_')
                {
                    if (ud)                                 // 1
                    {
                        throw new TomlAnalisysException(Resources.UNDERBAR_CONTINUE_ERR, iter);
                    }
                    ud = true;
                }
                else if (c.ch1 == '0' || c.ch1 == '1')
                {
                    if (v <= ulong.MaxValue / 2)            // 2
                    {
                        v = v * 2 + (ulong)(c.ch1 - '0');
                    }
                    else                                    // 2-1
                    {
                        throw new TomlAnalisysException(Resources.INTEGER_VALUE_RANGE_ERR, iter);
                    }
                    ud = false;
                }
                else
                {
                    break;
                }
                iter.Skip(1);
            }

            // 一文字の数値もなければ None値を返す
            if (iter.Pointer == point)
            {
                return(TomlValue.Empty);
            }

            if (v <= ulong.MaxValue)
            {
                return(TomlValue.Create(v));
            }
            else
            {
                throw new TomlAnalisysException(Resources.INTEGER_VALUE_RANGE_ERR, iter);
            }
        }
Ejemplo n.º 9
0
        //---------------------------------------------------------------------
        // テーブル解析
        //---------------------------------------------------------------------
        /// <summary>テーブルを作成する。</summary>
        /// <param name="iter">イテレータ。</param>
        /// <param name="table">カレントテーブル。</param>
        private void AnalisysTable(TomlInnerBuffer.TomlIter iter, TomlTable table)
        {
            // '.' で区切られたテーブル名を事前に収集する
            var keyPtr = iter.GetKeys();

            // テーブルが閉じられているか確認
            if (!iter.CloseTable())
            {
                throw new TomlAnalisysException(Resources.TABLE_SYNTAX_ERR, iter);
            }

            // テーブルを作成する
            //
            // 1. テーブル参照を取得
            // 2. エラーが有れば終了
            // 3. 既に作成済みならばカレントを変更
            // 4. 作成されていなければテーブルを作成し、カレントに設定
            TomlTable curTable = table;
            TomlTable newTable = null;

            foreach (var keystr in keyPtr)
            {
                switch (curTable.SearchPathTable(keystr, out newTable))      // 1
                {
                case 0:                                                      // 2
                    throw new TomlAnalisysException(Resources.TABLE_REDEFINITION_ERR, iter);

                case 1:
                    curTable = newTable;                                    // 3
                    break;

                default:
                    newTable = new TomlTable();                             // 4
                    curTable.AddKeyAndValue(keystr, newTable);
                    curTable = newTable;
                    break;
                }
            }

            // 空白は読み捨てておく
            iter.SkipSpace();

            // カレントのテーブルを設定
            this.current = curTable;
            if (!this.current.IsDefined)
            {
                this.current.IsDefined = true;
            }
            else
            {
                throw new TomlAnalisysException(Resources.DEFINED_KEY_ERR, iter);
            }
        }
        /// <summary>日付表現の日にち部分を解析する。</summary>
        /// <param name="iter">イテレータ。</param>
        /// <param name="year">年。</param>
        /// <returns>日付情報。</returns>
        private static TomlDate ConvertDateFormat(TomlInnerBuffer.TomlIter iter, int year)
        {
            int  month, day, hour;
            UTF8 c;

            // 月日の判定
            //
            // 1. 取得できたら格納
            // 2. 取得できなかったらエラーを返す
            if (ConvertPartitionNumber(iter, 5, 2, out month) &&    // 1
                iter.GetChar(7).ch1 == '-' &&
                ConvertPartitionNumber(iter, 8, 2, out day))
            {
                // 空実装
            }
            else                                                    // 2
            {
                throw new TomlAnalisysException(Resources.ANALISYS_DATE_ERR, iter);
            }

            // 'T' の指定がなければ日にちのみ、終了
            iter.Skip(10);
            c = iter.GetChar(0);
            if (c.ch1 != 'T' && c.ch1 != 't' && c.ch1 != ' ' &&
                (c.ch1 == '\t' || c.ch1 == '#' || c.ch1 == '\r' || c.ch1 == '\n'))
            {
                return(new TomlDate((ushort)year, (byte)month, (byte)day, 0, 0, 0, 0, 0, 0));
            }

            // 時間情報を判定して返す
            iter.Skip(1);
            if (ConvertPartitionNumber(iter, 0, 2, out hour) &&
                iter.GetChar(2).ch1 == ':')
            {
                var tm = ConvertTimeFormat(iter, hour);
                return(new TomlDate((ushort)year, (byte)month, (byte)day,
                                    tm.Hour, tm.Minute, tm.Second,
                                    tm.DecSecond, tm.ZoneHour, tm.ZoneMinute));
            }
            else if (c.ch1 == ' ')
            {
                return(new TomlDate((ushort)year, (byte)month, (byte)day, 0, 0, 0, 0, 0, 0));
            }
            else
            {
                throw new TomlAnalisysException(Resources.ANALISYS_DATE_ERR, iter);
            }
        }
Ejemplo n.º 11
0
        /// <summary>配列内の値の型が全て一致するか判定する。</summary>
        /// <param name="array">判定する配列参照。</param>
        /// <param name="iter">イテレータ。</param>
        /// <returns>配列情報。</returns>
        private ITomlValue CheckArrayValueType(List <ITomlValue> array,
                                               TomlInnerBuffer.TomlIter iter)
        {
            TomlValueType type = TomlValueType.TomlNoneValue;

            // 全ての要素の型が一致することを確認
            if (array.Count > 0)
            {
                type = array[0].ValueType;

                for (int i = 1; i < array.Count; ++i)
                {
                    if (type != array[i].ValueType)
                    {
                        throw new TomlAnalisysException(Resources.ARRAY_VALUE_DIFFERENT_ERR, iter);
                    }
                }
            }

            // 配列を作成して返す
            switch (type)
            {
            case TomlValueType.TomlBooleanValue:
                var bools = array.Select(x => (bool)x.Raw).ToArray();
                return(TomlValue.Create(bools));

            case TomlValueType.TomlDateValue:
                var dates = array.Select(x => (TomlDate)x.Raw).ToArray();
                return(TomlValue.Create(dates));

            case TomlValueType.TomlFloatValue:
                var floats = array.Select(x => (double)x.Raw).ToArray();
                return(TomlValue.Create(floats));

            case TomlValueType.TomlIntegerValue:
                var longs = array.Select(x => (long)x.Raw).ToArray();
                return(TomlValue.Create(longs));

            case TomlValueType.TomlStringValue:
                var strings = array.Select(x => (string)x.Raw).ToArray();
                return(TomlValue.Create(strings));

            default:
                return(TomlValue.Create(array.ToArray()));
            }
        }
Ejemplo n.º 12
0
        /// <summary>配列を解析する。</summary>
        /// <param name="iter">イテレータ。</param>
        /// <returns>値情報。</returns>
        private ITomlValue GetValueArray(TomlInnerBuffer.TomlIter iter)
        {
            var array = new List <ITomlValue>();

            while (iter.GetChar(0).ch1 != 0)
            {
                // 改行、空白部を取り除く
                iter.SkipLineFeedAndSpace();

                // 値を取り込む
                var value = this.AnalisysValue(iter);

                // 空値以外は取り込む
                if (value.ValueType != TomlValueType.TomlNoneValue)
                {
                    array.Add(value);
                }

                // 配列が閉じられているか確認
                //
                // 1. テーブルが閉じられている
                // 2. 次のキー/値を取得
                // 3. エラー
                switch (iter.CloseValueArray())
                {
                case 1:                             // 1
                    return(CheckArrayValueType(array, iter));

                case 2:                             // 2
                    if (value.ValueType != TomlValueType.TomlNoneValue)
                    {
                        break;
                    }
                    else
                    {
                        throw new TomlAnalisysException(Resources.EMPTY_COMMA_ERR, iter);
                    }

                default:                            // 3
                    break;
                }
            }
            // 配列が閉じられていない
            throw new TomlAnalisysException(Resources.ARRAY_NOT_CLOSE_ERR, iter);
        }
        /// <summary>"'" で囲まれた文字列を取得する。</summary>
        /// <param name="iter">イテレータ。</param>
        /// <returns>取得した文字列。</returns>
        internal static string GetMultiLiteralStringValue(this TomlInnerBuffer.TomlIter iter)
        {
            var  buf = new List <byte>();
            UTF8 c;
            bool eof;

            // 先頭の改行は取り除く
            iter.SkipHeadLineFeed();

            do
            {
                eof = iter.IsEndStream;

                while ((c = iter.GetChar(0)).ch1 != 0)
                {
                    switch (c.ch1)
                    {
                    case (byte)'\'':
                        // " を取得したら文字列終了
                        if (iter.GetChar(2).ch1 == '\'' &&
                            iter.GetChar(1).ch1 == '\'')
                        {
                            iter.Skip(3);
                            return(Encoding.UTF8.GetString(buf.ToArray()));
                        }
                        else
                        {
                            buf.Add(c.ch1);
                            iter.Skip(1);
                        }
                        break;

                    default:
                        // 上記以外は普通の文字として取得
                        c.Expand(buf);
                        iter.Skip(1);
                        break;
                    }
                }
                iter.ReadLine();
            } while (!eof);

            // " で終了できなかったためエラー
            throw new TomlAnalisysException(Resources.MULTI_LITERAL_STRING_ERR, iter);
        }
        /// <summary>行の開始を判定する。</summary>
        /// <returns>行のデータ種類。</returns>
        internal static TomlInnerBuffer.LineType CheckStartLineToken(this TomlInnerBuffer.TomlIter iter)
        {
            // テーブル配列の開始か判定する
            if (iter.RemnantLength >= 2)
            {
                if (iter.GetChar(0).ch1 == '[' && iter.GetChar(1).ch1 == '[')
                {
                    iter.Skip(2);
                    return(TomlInnerBuffer.LineType.TomlTableArrayLine);
                }
            }

            // その他の開始を判定する
            //
            // 1. テーブルの開始か判定する
            // 2. コメントの開始か判定する
            // 4. キーの開始か判定する
            // 5. それ以外はエラー
            if (iter.RemnantLength > 0)
            {
                switch (iter.GetChar(0).ch1)
                {
                case (byte)'[':               // 1
                    iter.Skip(1);
                    return(TomlInnerBuffer.LineType.TomlTableLine);

                case (byte)'#':               // 2
                    iter.Skip(1);
                    return(TomlInnerBuffer.LineType.TomlCommenntLine);

                case (byte)'\r':              // 3
                case (byte)'\n':
                case (byte)'\0':
                    return(TomlInnerBuffer.LineType.TomlLineNone);

                default:                    // 4
                    return(TomlInnerBuffer.LineType.TomlKeyValueLine);
                }
            }
            else                            // 5
            {
                return(TomlInnerBuffer.LineType.TomlLineNone);
            }
        }
        /// <summary>キー文字列を取得する。</summary>
        /// <param name="iter">イテレータ。</param>
        /// <returns>キー文字列。</returns>
        internal static string GetKey(this TomlInnerBuffer.TomlIter iter)
        {
            var  buf = new List <byte>();
            UTF8 c;

            // 空白を読み飛ばす
            iter.SkipSpace();

            // 範囲の開始、終了位置で評価
            //
            // 1. 一文字取得する
            // 2. キー使用可能文字か判定する
            // 3. " なら文字列としてキー文字列を取得する
            while ((c = iter.GetChar(0)).ch1 != 0)          // 1
            {
                if ((c.ch1 >= 'a' && c.ch1 <= 'z') ||       // 2
                    (c.ch1 >= 'A' && c.ch1 <= 'Z') ||
                    (c.ch1 >= '0' && c.ch1 <= '9') ||
                    c.ch1 == '_' || c.ch1 == '-')
                {
                    c.Expand(buf);
                    iter.Skip(1);
                }
                else if (c.ch1 == '"' && buf.Count <= 0)    // 3
                {
                    iter.Skip(1);
                    return(iter.GetStringValue());
                }
                else
                {
                    break;
                }
            }

            // バイトリストを文字列に変換して返す
            if (buf.Count > 0)
            {
                return(Encoding.UTF8.GetString(buf.ToArray()));
            }
            else
            {
                throw new TomlAnalisysException(Resources.KEY_ANALISYS_ERR, iter);
            }
        }
        /// <summary>']' の後、次が改行/終端/コメントならば真を返す。</summary>
        /// <param name="iter">イテレータ。</param>
        /// <returns>改行/終端/コメントならば真。</returns>
        internal static bool CloseTable(this TomlInnerBuffer.TomlIter iter)
        {
            UTF8 c;

            // 空白を読み飛ばす
            iter.SkipSpace();

            // ] の判定
            if (iter.GetChar(0).ch1 != ']')
            {
                return(false);
            }
            iter.Skip(1);

            // 空白を読み飛ばす
            iter.SkipSpace();

            // 文字を判定
            c = iter.GetChar(0);
            return(c.ch1 == '#' || c.ch1 == '\r' || c.ch1 == '\n' || c.ch1 == 0);
        }
        //-----------------------------------------------------------------------------
        // 数値/日付解析
        //-----------------------------------------------------------------------------
        /// <summary>数値(日付/整数/実数)を取得する。</summary>
        /// <param name="iter">イテレータ。</param>
        /// <returns>値。</returns>
        internal static ITomlValue GetNumberOrDateValue(this TomlInnerBuffer.TomlIter iter)
        {
            int year, hour;

            if (ConvertPartitionNumber(iter, 0, 4, out year) &&
                iter.GetChar(4).ch1 == '-')
            {
                // 日付(年月日)を取得する
                return(TomlValue.Create(ConvertDateFormat(iter, year)));
            }
            else if (ConvertPartitionNumber(iter, 0, 2, out hour) &&
                     iter.GetChar(2).ch1 == ':')
            {
                // 日付(時分秒)を取得する
                return(TomlValue.Create(ConvertTimeFormat(iter, hour)));
            }
            else
            {
                // 数値(整数/実数)を取得する
                return(iter.GetNumberValue(false));
            }
        }
        //---------------------------------------------------------------------
        // 文字列解析
        //---------------------------------------------------------------------
        /// <summary>""" で囲まれた文字列を取得する。</summary>
        /// <param name="iter">イテレータ。</param>
        /// <returns>取得した文字列。</returns>
        internal static string GetMultiStringValue(this TomlInnerBuffer.TomlIter iter)
        {
            var  buf = new List <byte>();
            UTF8 c, nc;
            bool eof;
            bool skipSpace = false;

            byte[] lastC = new byte[2];

            // 先頭の改行は取り除く
            iter.SkipHeadLineFeed();

            do
            {
                eof = iter.IsEndStream;

                while ((c = iter.GetChar(0)).ch1 != 0)
                {
                    switch (c.ch1)
                    {
                    case (byte)'"':
                        // " を取得したら文字列終了
                        if (iter.GetChar(2).ch1 == '"' &&
                            iter.GetChar(1).ch1 == '"')
                        {
                            iter.Skip(3);
                            return(Encoding.UTF8.GetString(buf.ToArray()));
                        }
                        else
                        {
                            buf.Add(c.ch1);
                            iter.Skip(1);
                        }
                        break;

                    case (byte)'\\':
                        // \のエスケープ文字判定
                        nc = iter.GetChar(1);
                        if ((nc.ch1 == '\r' || nc.ch1 == '\n' || nc.ch1 == '\t' || nc.ch1 == ' ') &&
                            iter.CheckLineEnd())
                        {
                            skipSpace = true;
                            iter.Skip(1);
                        }
                        else
                        {
                            AppendEscapeChar(iter, buf);
                        }
                        break;

                    case (byte)' ':
                    case (byte)'\t':
                        // 空白文字を追加する
                        if (!skipSpace)
                        {
                            buf.Add(c.ch1);
                        }
                        iter.Skip(1);
                        break;

                    default:
                        // 上記以外は普通の文字として取得
                        if (c.ch1 > 0x1f)
                        {
                            skipSpace = false;
                            c.Expand(buf);
                        }
                        else
                        {
                            lastC[1] = lastC[0];
                            lastC[0] = (byte)(c.ch1 & 0x1f);
                        }
                        iter.Skip(1);
                        break;
                    }
                }

                // 改行の読み飛ばし指定がなければ追加する
                if (!skipSpace)
                {
                    if (lastC[1] == '\r' && lastC[0] == '\n')
                    {
                        buf.Add((byte)'\r');
                        buf.Add((byte)'\n');
                    }
                    else if (lastC[0] == '\n')
                    {
                        buf.Add((byte)'\n');
                    }
                }
                iter.ReadLine();
            } while (!eof);

            // " で終了できなかったためエラー
            throw new TomlAnalisysException(Resources.MULTI_QUOAT_STRING_ERR, iter);
        }
        /// <summary>数値(整数/実数)を取得する。</summary>
        /// <param name="iter">イテレータ。</param>
        /// <param name="numberSign">符号。</param>
        /// <returns>数値。</returns>
        private static ITomlValue Get10NumberValue(TomlInnerBuffer.TomlIter iter,
                                                   bool numberSign)
        {
            ulong v  = 0;
            bool  ud = false;
            UTF8  c;
            int   point = iter.Pointer;
            int   digit = -1;
            int   expo = -1;
            int   exp_v = -1;
            bool  ld_zero = false, lst_zero = false;

            // 仮数部を取得する
            while ((c = iter.GetChar(0)).ch1 != 0)
            {
                // 1. '_'の連続の判定
                // 2. 数値の計算をする
                //    2-1. 数値の有効範囲を超えるならばエラー
                // 3. 小数点位置を取得する
                // 4. 指数部(e)を取得する
                if (c.ch1 == '_')
                {
                    if (ud)                             // 1
                    {
                        throw new TomlAnalisysException(Resources.UNDERBAR_CONTINUE_ERR, iter);
                    }
                    ud = true;
                }
                else if (c.ch1 >= '0' && c.ch1 <= '9')
                {
                    if (v < ulong.MaxValue / 10)        // 2
                    {
                        v = v * 10 + (ulong)(c.ch1 - '0');
                        if (digit >= 0)
                        {
                            digit++;
                            lst_zero = true;
                        }
                        else
                        {
                            ld_zero = true;
                        }
                    }
                    else                                // 2-1
                    {
                        throw new TomlAnalisysException(Resources.INTEGER_VALUE_RANGE_ERR, iter);
                    }
                    ud = false;
                }
                else if (c.ch1 == '.')                  // 3
                {
                    if (ld_zero && digit < 0)
                    {
                        digit = 0;
                    }
                    else if (ld_zero)
                    {
                        throw new TomlAnalisysException(Resources.MULTI_DECIMAL_ERR, iter);
                    }
                    else
                    {
                        throw new TomlAnalisysException(Resources.NO_LEADING_ZERO_ERR, iter);
                    }
                }
                else if (c.ch1 == 'e' || c.ch1 == 'E')
                {
                    expo = 0;                           // 4
                    break;
                }
                else
                {
                    break;
                }
                iter.Skip(1);
            }

            // 一文字の数値もなければ None値を返す
            if (iter.Pointer == point)
            {
                return(TomlValue.Empty);
            }

            // 仮数部を取得する
            CalcExponentConvert(iter, digit, expo, out exp_v);

            if (digit < 0 && expo < 0)
            {
                // 整数値を取得する
                //
                // 1. 負の整数変換
                // 2. 正の整数変換
                if (numberSign)
                {
                    if (v <= (ulong)long.MaxValue)          // 1
                    {
                        return(TomlValue.Create(-(long)v));
                    }
                    else if (v == (ulong)long.MaxValue + 1)
                    {
                        return(TomlValue.Create(long.MinValue));
                    }
                    else
                    {
                        throw new TomlAnalisysException(Resources.DOUBLE_VALUE_RANGE_ERR, iter);
                    }
                }
                else
                {
                    if (v <= long.MaxValue)                 //2
                    {
                        return(TomlValue.Create((long)v));
                    }
                    else
                    {
                        throw new TomlAnalisysException(Resources.DOUBLE_VALUE_RANGE_ERR, iter);
                    }
                }
            }
            else
            {
                if (digit >= 0 && !lst_zero)
                {
                    throw new TomlAnalisysException(Resources.NO_LAST_ZERO_ERR, iter);
                }

                // 実数値を取得する
                //
                // 1. 負の指数なら除算
                // 2. 正の指数なら積算
                // 3. 0の指数なら使用しない
                // 4. 値を保持
                double dv = 0;
                if (exp_v < 0)
                {
                    double abs_e = 1;                   // 1
                    for (int i = 0; i < Math.Abs(exp_v); ++i)
                    {
                        abs_e *= 10;
                    }
                    dv = (double)v / abs_e;
                }
                else if (exp_v > 0)
                {
                    double abs_e = 1;                   // 2
                    for (int i = 0; i < Math.Abs(exp_v); ++i)
                    {
                        abs_e *= 10;
                    }
                    dv = (double)v * abs_e;
                }
                else
                {
                    dv = (double)v;                     // 3
                }
                if (dv <= double.MaxValue)              // 4
                {
                    return(TomlValue.Create(numberSign ? (double)-dv : (double)dv));
                }
                else
                {
                    throw new TomlAnalisysException(Resources.DOUBLE_VALUE_RANGE_ERR, iter);
                }
            }
        }
Ejemplo n.º 20
0
        //---------------------------------------------------------------------
        // キー/値解析
        //---------------------------------------------------------------------
        /// <summary>キーと値のペアを取得する。</summary>
        /// <param name="iter">イテレータ。</param>
        /// <param name="table">対象テーブル。</param>
        /// <param name="lastNoCheck">改行確認するならば真。</param>
        /// <returns>追加できたならば真。</returns>
        private bool AnalisysKeyAndValue(TomlInnerBuffer.TomlIter iter,
                                         TomlTable table,
                                         bool lastNoCheck)
        {
            // キー文字列を取得する
            //
            // 1. キー文字列を取得
            // 2. キー以降の空白を読み飛ばす
            // 3. = で連結しているか確認
            var keyPtr = iter.GetKeys();            // 1

            iter.SkipSpace();                       // 2
            if (iter.GetChar(0).ch1 != '=')         // 3
            {
                throw new TomlAnalisysException(Resources.KEY_ANALISYS_ERR, iter);
            }

            // 値を取得する
            //
            // 1. 値が取得できるか
            // 2. 無効値であるか
            iter.Skip(1);
            var val = this.AnalisysValue(iter);     // 1

            if (val.ValueType == TomlValueType.TomlNoneValue)
            {
                return(false);                       // 2
            }

            // 改行まで確認
            if (!lastNoCheck && !iter.CheckLineEndOrComment())
            {
                throw new TomlAnalisysException(Resources.KEY_VALUE_ERR, iter);
            }

            // '.' で指定されたテーブル参照を収集する
            //
            // 1. テーブル参照を取得
            // 2. エラーが有れば終了
            // 3. 既に作成済みならばカレントを変更
            // 4. 作成されていなければテーブルを作成し、カレントに設定
            TomlTable curTable = table;
            TomlTable newTable = null;

            for (int i = 0; i < keyPtr.Count - 1; ++i)
            {
                var keystr = keyPtr[i];

                switch (curTable.SearchPathTable(keystr, out newTable))     // 1
                {
                case 0:                                                     // 2
                    throw new TomlAnalisysException(Resources.TABLE_REDEFINITION_ERR, iter);

                case 1:
                    curTable = newTable;                                    // 3
                    break;

                default:
                    newTable = new TomlTable();                             // 4
                    curTable.AddKeyAndValue(keystr, newTable);
                    curTable = newTable;
                    break;
                }
            }

            // 最終のテーブルに値を割り当てる
            var laststr = keyPtr[keyPtr.Count - 1];

            if (!curTable.Contains(laststr))
            {
                curTable.AddKeyAndValue(laststr, val);
                return(true);
            }
            else
            {
                throw new TomlAnalisysException(Resources.DEFINED_KEY_ERR, iter);
            }
        }
        /// <summary>日付表現の時間部分を解析する。</summary>
        /// <param name="iter">イテレータ。</param>
        /// <param name="hour">時値。</param>
        /// <returns>日付値。</returns>
        private static TomlDate ConvertTimeFormat(TomlInnerBuffer.TomlIter iter, int hour)
        {
            int  minute, second, decSec = 0, z_hor, z_min;
            UTF8 c;

            // 分、秒の判定
            //
            // 1. 取得できたら格納
            // 2. 取得できなかったらエラーを返す
            if (ConvertPartitionNumber(iter, 3, 2, out minute) &&   // 1
                iter.GetChar(5).ch1 == ':' &&
                ConvertPartitionNumber(iter, 6, 2, out second))
            {
                // 空実装
            }
            else                                                    // 2
            {
                throw new TomlAnalisysException(Resources.ANALISYS_TIME_ERR, iter);
            }

            // ミリ秒の解析
            //
            // 1. '.' があればミリ秒解析開始
            // 2. ミリ秒値を計算
            iter.Skip(8);
            if (iter.GetChar(0).ch1 == '.')             // 1
            {
                iter.Skip(1);
                while (iter.GetChar(0).ch1 >= '0' &&    // 2
                       iter.GetChar(0).ch1 <= '9')
                {
                    decSec = decSec * 10 + (iter.GetChar(0).ch1 - '0');
                    iter.Skip(1);
                }
            }

            // 時差の解析
            //
            // 1. UTC指定ならば終了
            // 2. 時差指定ならば、時刻を取り込む
            //    2-1. 時刻の書式に問題がなければ終了
            //    2-2. 時刻の書式に問題があればエラー
            // 3. 時差指定なし、正常終了
            c = iter.GetChar(0);
            if (c.ch1 == 'Z' || c.ch1 == 'z')                   // 1
            {
                iter.Skip(1);
                return(new TomlDate(0, 0, 0,
                                    (byte)hour, (byte)minute, (byte)second, (uint)decSec, 0, 0));
            }
            else if (c.ch1 == '+' || c.ch1 == '-')
            {
                if (ConvertPartitionNumber(iter, 1, 2, out z_hor) &&
                    iter.GetChar(3).ch1 == ':' &&
                    ConvertPartitionNumber(iter, 4, 2, out z_min))
                {
                    iter.Skip(6);
                    return(new TomlDate(0, 0, 0,
                                        (byte)hour, (byte)minute, (byte)second, (uint)decSec,
                                        (sbyte)(c.ch1 == '+' ? z_hor : -z_hor), (byte)z_min));
                }
                else
                {
                    throw new TomlAnalisysException(Resources.ANALISYS_TIME_DIFF_ERR, iter);
                }
            }
            else
            {
                return(new TomlDate(0, 0, 0,                    // 3
                                    (byte)hour, (byte)minute, (byte)second, (uint)decSec, 0, 0));
            }
        }
        /// <summary>実数の指数部を取得する。</summary>
        /// <param name="iter"></param>
        /// <param name="digit">小数点位置。</param>
        /// <param name="expo">指数(e)。</param>
        /// <param name="resExpo">指数値(戻り値)</param>
        private static void CalcExponentConvert(TomlInnerBuffer.TomlIter iter,
                                                int digit,
                                                int expo,
                                                out int resExpo)
        {
            bool ud = false;
            UTF8 c;
            bool sign  = false;
            int  exp_v = 0;
            int  point = iter.Pointer;

            if (expo >= 0)
            {
                // 符号を取得する
                iter.Skip(1);
                c = iter.GetChar(0);

                if (c.ch1 == '+')
                {
                    sign = false;
                    iter.Skip(1);
                }
                else if (c.ch1 == '-')
                {
                    sign = true;
                    iter.Skip(1);
                }

                ud = false;
                while ((c = iter.GetChar(0)).ch1 != 0)
                {
                    // 1. '_'の連続の判定
                    // 2. 指数部を計算する
                    if (c.ch1 == '_')
                    {
                        if (ud)                                 // 1
                        {
                            throw new TomlAnalisysException(Resources.UNDERBAR_CONTINUE_ERR, iter);
                        }
                        ud = true;
                    }
                    else if (c.ch1 >= '0' && c.ch1 <= '9')
                    {
                        exp_v = exp_v * 10 + (c.ch1 - '0');     // 2
                        if (exp_v >= 308)
                        {
                            throw new TomlAnalisysException(Resources.DOUBLE_VALUE_RANGE_ERR, iter);
                        }
                        ud = false;
                    }
                    else
                    {
                        break;
                    }
                    iter.Skip(1);
                }

                // 指数値を確認する
                // 1. 指数値が 0以下でないことを確認
                // 2. 指数値が '0'始まりでないことを確認
                if (exp_v <= 0)                                 // 1
                {
                    throw new TomlAnalisysException(Resources.DOUBLE_VALUE_RANGE_ERR, iter);
                }
                else if (iter.GetChar(0).ch1 == '0')            // 2
                {
                    throw new TomlAnalisysException(Resources.ZERO_NUMBER_ERR, iter);
                }
            }

            // 符号を設定
            if (sign)
            {
                exp_v = -exp_v;
            }

            // 小数点位置とマージ
            exp_v -= (digit > 0 ? digit : 0);
            if (exp_v > 308 || exp_v < -308)
            {
                throw new TomlAnalisysException(Resources.DOUBLE_VALUE_RANGE_ERR, iter);
            }

            resExpo = exp_v;
        }
Ejemplo n.º 23
0
        /// <summary>数値(整数/実数/日付)を取得する。</summary>
        /// <param name="iter">イテレータ。</param>
        /// <returns>値情報。</returns>
        private ITomlValue ConvertValue(TomlInnerBuffer.TomlIter iter)
        {
            ITomlValue value = null;

            // 値リテラルを解析する
            if (iter.AnalisysKeyword(out value))
            {
                return(value);
            }

            // 複数ライン文字列を返す
            if (iter.RemnantLength >= 3)
            {
                // 複数ライン文字列を返す
                if (iter.GetChar(2).ch1 == '"' &&
                    iter.GetChar(1).ch1 == '"' &&
                    iter.GetChar(0).ch1 == '"')
                {
                    iter.Skip(3);
                    return(TomlValue.Create(iter.GetMultiStringValue()));
                }

                // 複数ライン文字列(リテラル)を返す
                if (iter.GetChar(2).ch1 == '\'' &&
                    iter.GetChar(1).ch1 == '\'' &&
                    iter.GetChar(0).ch1 == '\'')
                {
                    iter.Skip(3);
                    return(TomlValue.Create(iter.GetMultiLiteralStringValue()));
                }
            }

            // 数値/日付/文字列
            if (iter.RemnantLength > 0)
            {
                switch (iter.GetChar(0).ch1)
                {
                case (byte)'"':
                    // 文字列を取得する
                    iter.Skip(1);
                    return(TomlValue.Create(iter.GetStringValue()));

                case (byte)'\'':
                    // リテラル文字列を取得する
                    iter.Skip(1);
                    return(TomlValue.Create(iter.GetLiteralStringValue()));

                case (byte)'#':
                    // コメントを取得する
                    iter.Skip(1);
                    return(null);

                case (byte)'+':
                    // 数値を取得する
                    iter.Skip(1);
                    return(iter.GetNumberValue(false));

                case (byte)'-':
                    // 数値を取得する
                    iter.Skip(1);
                    return(iter.GetNumberValue(true));

                default:
                    // 日付/数値を取得する
                    return(iter.GetNumberOrDateValue());
                }
            }
            else
            {
                throw new TomlAnalisysException(Resources.NOT_DEFINED_VALUE_ERR, iter);
            }
        }
        /// <summary>'\'エスケープ文字を取得する。</summary>
        /// <param name="iter">イテレータ。</param>
        /// <param name="buf">バイトリスト。</param>
        private static void AppendEscapeChar(TomlInnerBuffer.TomlIter iter, List <byte> buf)
        {
            if (iter.RemnantLength > 2)
            {
                UTF8 c = iter.GetChar(1);

                switch (c.ch1)
                {
                case (byte)'b':
                    buf.Add((byte)'\b');
                    iter.Skip(2);
                    break;

                case (byte)'t':
                    buf.Add((byte)'\t');
                    iter.Skip(2);
                    break;

                case (byte)'n':
                    buf.Add((byte)'\n');
                    iter.Skip(2);
                    break;

                case (byte)'f':
                    buf.Add((byte)'\f');
                    iter.Skip(2);
                    break;

                case (byte)'r':
                    buf.Add((byte)'\r');
                    iter.Skip(2);
                    break;

                case (byte)'"':
                    buf.Add((byte)'"');
                    iter.Skip(2);
                    break;

                case (byte)'/':
                    buf.Add((byte)'/');
                    iter.Skip(2);
                    break;

                case (byte)'\\':
                    buf.Add((byte)'\\');
                    iter.Skip(2);
                    break;

                case (byte)'u':
                    if (iter.RemnantLength >= 6)
                    {
                        iter.Skip(2);
                        AppendUnicode(iter, 4, buf);
                    }
                    break;

                case (byte)'U':
                    if (iter.RemnantLength >= 10)
                    {
                        iter.Skip(2);
                        AppendUnicode(iter, 8, buf);
                    }
                    break;

                default:
                    throw new TomlAnalisysException(Resources.INVALID_ESCAPE_CHAR_ERR, iter);
                }
            }
        }
        /// <summary>UNICODEエスケープ判定。</summary>
        /// <param name="iter">イテレータ。</param>
        /// <param name="len">読み込む文字数。</param>
        /// <param name="buf">バイトリスト。</param>
        private static void AppendUnicode(TomlInnerBuffer.TomlIter iter, int len, List <byte> buf)
        {
            // 16進数文字を判定し、数値化
            uint val = 0;

            for (int i = 0; i < len; ++i)
            {
                UTF8 c = iter.GetChar(i);
                val <<= 4;

                if (c.ch1 >= '0' && c.ch1 <= '9')
                {
                    val |= (uint)(c.ch1 - '0');
                }
                else if (c.ch1 >= 'a' && c.ch1 <= 'f')
                {
                    val |= (uint)(10 + c.ch1 - 'a');
                }
                else if (c.ch1 >= 'A' && c.ch1 <= 'F')
                {
                    val |= (uint)(10 + c.ch1 - 'A');
                }
                else
                {
                    throw new TomlAnalisysException(Resources.UNICODE_DEFINE_ERR, iter);
                }
            }

            // UTF8へ変換
            if (val < 0x80)
            {
                buf.Add((byte)(val & 0xff));
            }
            else if (val < 0x800)
            {
                buf.Add((byte)(0xc0 | (val >> 6)));
                buf.Add((byte)(0x80 | (val & 0x3f)));
            }
            else if (val < 0x10000)
            {
                buf.Add((byte)(0xe0 | (val >> 12)));
                buf.Add((byte)(0x80 | ((val >> 6) & 0x3f)));
                buf.Add((byte)(0x80 | (val & 0x3f)));
            }
            else if (val < 0x200000)
            {
                buf.Add((byte)(0xf0 | (val >> 18)));
                buf.Add((byte)(0x80 | ((val >> 12) & 0x3f)));
                buf.Add((byte)(0x80 | ((val >> 6) & 0x3f)));
                buf.Add((byte)(0x80 | (val & 0x3f)));
            }
            else if (val < 0x4000000)
            {
                buf.Add((byte)(0xf8 | (val >> 24)));
                buf.Add((byte)(0x80 | ((val >> 18) & 0x3f)));
                buf.Add((byte)(0x80 | ((val >> 12) & 0x3f)));
                buf.Add((byte)(0x80 | ((val >> 6) & 0x3f)));
                buf.Add((byte)(0x80 | (val & 0x3f)));
            }
            else
            {
                buf.Add((byte)(0xfc | (val >> 30)));
                buf.Add((byte)(0x80 | ((val >> 24) & 0x3f)));
                buf.Add((byte)(0x80 | ((val >> 18) & 0x3f)));
                buf.Add((byte)(0x80 | ((val >> 12) & 0x3f)));
                buf.Add((byte)(0x80 | ((val >> 6) & 0x3f)));
                buf.Add((byte)(0x80 | (val & 0x3f)));
            }
            iter.Skip(len);
        }
Ejemplo n.º 26
0
        /// <summary>テーブル配列を作成する。</summary>
        /// <param name="iter">イテレータ。</param>
        /// <param name="table">カレントテーブル。</param>
        private void AnalisysTableArray(TomlInnerBuffer.TomlIter iter, TomlTable table)
        {
            // '.' で区切られたテーブル名を事前に収集する
            var keyPtr = iter.GetKeys();

            // テーブル配列が閉じられているか確認
            if (!iter.CloseTableArray())
            {
                throw new TomlAnalisysException(Resources.TABLE_ARRAY_SYNTAX_ERR, iter);
            }

            // 最下層のテーブル以外のテーブル参照を収集する
            //
            // 1. テーブル参照を取得
            // 2. エラーが有れば終了
            // 3. 既に作成済みならばカレントを変更
            // 4. 作成されていなければテーブルを作成し、カレントに設定
            TomlTable curTable = table;
            TomlTable newTable = null;
            string    keystr   = "";

            for (int i = 0; i < keyPtr.Count - 1; ++i)
            {
                keystr = keyPtr[i];

                switch (curTable.SearchPathTable(keystr, out newTable))     // 1
                {
                case 0:                                                     // 2
                    throw new TomlAnalisysException(Resources.TABLE_REDEFINITION_ERR, iter);

                case 1:
                    curTable = newTable;                                    // 3
                    break;

                default:
                    newTable = new TomlTable();                             // 4
                    curTable.AddKeyAndValue(keystr, newTable);
                    curTable = newTable;
                    break;
                }
            }

            // 最下層のテーブルは新規作成となる
            //
            // 1. 登録する名前(キー文字列)を取得
            // 2. 親のテーブルに最下層のテーブル名が登録されている
            //    2-1. 登録されている名前のデータを取得する
            //    2-2. テーブル配列が登録されているならば、新規テーブルを作成し、カレントテーブルとする
            //    2-3. テーブル配列でないならばエラーとする
            // 3. 親のテーブルに最下層のテーブル名が登録されていない
            //    3-1. テーブル配列を作成し、テーブルを追加、追加されたテーブルが次のカレントテーブルになる
            keystr = keyPtr[keyPtr.Count - 1];                              // 1

            if (curTable.Contains(keystr))                                  // 2-1
            {
                var val = curTable.Member(keystr);
                if (val.ValueType == TomlValueType.TomlTableArrayValue)     // 2-2
                {
                    newTable = new TomlTable();
                    ((Array <TomlTable>)val).Add(newTable);
                }
                else                                                        // 2-3
                {
                    throw new TomlAnalisysException(Resources.DEFINED_KEY_ERR, iter);
                }
            }
            else
            {
                newTable = new TomlTable();                                 // 3-1
                var newArr = TomlValue.Create(new TomlTable[] { newTable });
                curTable.AddKeyAndValue(keystr, newArr);
            }

            // カレントのテーブルを作成したテーブルに変更
            this.current = newTable;
            iter.SkipSpace();
        }
        //---------------------------------------------------------------------
        // 定数リテラル解析
        //---------------------------------------------------------------------
        /// <summary>数値(定数)を取得する。</summary>
        /// <param name="iter">イテレータ。</param>
        /// <param name="value">値(戻り値)</param>
        /// <returns>値が取得できたならば真。</returns>
        internal static bool AnalisysKeyword(this TomlInnerBuffer.TomlIter iter, out ITomlValue value)
        {
            // 真偽値(偽)を返す
            if (iter.RemnantLength >= 5)
            {
                if (iter.GetChar(4).ch1 == 'e' &&
                    iter.GetChar(3).ch1 == 's' &&
                    iter.GetChar(2).ch1 == 'l' &&
                    iter.GetChar(1).ch1 == 'a' &&
                    iter.GetChar(0).ch1 == 'f')
                {
                    value = TomlValue.False;
                    iter.Skip(5);
                    return(true);
                }
            }

            if (iter.RemnantLength >= 4)
            {
                // 真偽値(真)を返す
                if (iter.GetChar(3).ch1 == 'e' &&
                    iter.GetChar(2).ch1 == 'u' &&
                    iter.GetChar(1).ch1 == 'r' &&
                    iter.GetChar(0).ch1 == 't')
                {
                    value = TomlValue.True;
                    iter.Skip(4);
                    return(true);
                }

                // 正の無限値を返す
                if (iter.GetChar(3).ch1 == 'f' &&
                    iter.GetChar(2).ch1 == 'n' &&
                    iter.GetChar(1).ch1 == 'i' &&
                    iter.GetChar(0).ch1 == '+')
                {
                    value = TomlValue.Create(double.PositiveInfinity);
                    iter.Skip(4);
                    return(true);
                }

                // 負の無限値を返す
                if (iter.GetChar(3).ch1 == 'f' &&
                    iter.GetChar(2).ch1 == 'n' &&
                    iter.GetChar(1).ch1 == 'i' &&
                    iter.GetChar(0).ch1 == '-')
                {
                    value = TomlValue.Create(double.NegativeInfinity);
                    iter.Skip(4);
                    return(true);
                }

                // 正の非数値を返す
                if (iter.GetChar(3).ch1 == 'n' &&
                    iter.GetChar(2).ch1 == 'a' &&
                    iter.GetChar(1).ch1 == 'n' &&
                    iter.GetChar(0).ch1 == '+')
                {
                    value = TomlValue.Create(double.NaN);
                    iter.Skip(4);
                    return(true);
                }

                // 負の非数値を返す
                if (iter.GetChar(3).ch1 == 'n' &&
                    iter.GetChar(2).ch1 == 'a' &&
                    iter.GetChar(1).ch1 == 'n' &&
                    iter.GetChar(0).ch1 == '-')
                {
                    value = TomlValue.Create(-double.NaN);
                    iter.Skip(4);
                    return(true);
                }
            }

            if (iter.RemnantLength >= 3)
            {
                // 無限値を返す
                if (iter.GetChar(2).ch1 == 'f' &&
                    iter.GetChar(1).ch1 == 'n' &&
                    iter.GetChar(0).ch1 == 'i')
                {
                    value = TomlValue.Create(double.PositiveInfinity);
                    iter.Skip(3);
                    return(true);
                }

                // 非数値を返す
                if (iter.GetChar(2).ch1 == 'n' &&
                    iter.GetChar(1).ch1 == 'a' &&
                    iter.GetChar(0).ch1 == 'n')
                {
                    value = TomlValue.Create(double.NaN);
                    iter.Skip(3);
                    return(true);
                }
            }

            value = null;
            return(false);
        }