// ==================================================================================================== // YAML Parser for the .NET Framework // ==================================================================================================== // // Copyright (c) 2006 // Christophe Lambrechts // Jonathan Slenders // // ==================================================================================================== // This file is part of the .NET YAML Parser. // // This .NET YAML parser is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation; either version 2.1 of the License, or // (at your option) any later version. // // The .NET YAML parser is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with Foobar; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USAusing System.Reflection; // ==================================================================================================== using System; namespace Yaml { /// /// Class for storing a Yaml Integer node /// uri: tag:yaml.org,2002:int /// public class Integer : Scalar { private long content; /// New Integer public Integer (long val) : base ("tag:yaml.org,2002:int", NodeType.Integer) { content = val; } /// Content public long Content { get { return content; } set { content = value; } } /// Parse an integer public Integer (ParseStream stream) : base ("tag:yaml.org,2002:int", NodeType.Integer) { short sign = 1; // Positive sign by default // Negative sign if (stream.Char == '-') { sign = -1; stream.Next (); } // Positive sign else if (stream.Char == '+') stream.Next (); try { // Determine base if (stream.Char == '0') { stream.Next (); // Base 2 if (stream.Char == 'b') { stream.Next (); content = ParseBase (stream, 2, sign); return; } // Base 16 else if (stream.Char == 'x') { stream.Next (); content = Parse16 (stream, sign); return; } // Base 8 else { content = ParseBase (stream, 8, sign); return; } } // Other base stream.BuildLookaheadBuffer (); // First, try to parse with base 10 try { content = ParseBase (stream, 10, sign); stream.DestroyLookaheadBuffer (); return; } catch { } // If not parseable with base 10, then try base 60 stream.RewindLookaheadBuffer (); stream.DestroyLookaheadBuffer (); content = Parse60 (stream, sign); } catch (Exception ex) { throw new ParseException (stream, ex.ToString ()); } } /// Hexadecimal string private static long Parse16 (ParseStream stream, short sign) { uint output = 0; while (! stream.EOF) { // 0 .. 9 if (stream.Char >= '0' && stream.Char <= '9') { output = (output * 16) + (uint) (stream.Char - '0'); OverflowTest (output, sign); } // a .. f else if (stream.Char >= 'a' && stream.Char <= 'f') { output = (output * 16) + (uint) (stream.Char - 'a') + 10; OverflowTest (output, sign); } // A .. F else if (stream.Char >= 'A' && stream.Char <= 'F') { output = (output * 16) + (uint) (stream.Char - 'A') + 10; OverflowTest(output, sign); } // Ignore underscores, other chars are not allowed else if (stream.Char != '_') throw new Exception ("Unknown char in base 16"); stream.Next (); } return (long) (sign * output); } /// Parses a string with a given base (maximum 10) /// /// This is not completly correct. For base10 the first char may not be a '_' /// The other bases allow this... /// private static long ParseBase (ParseStream stream, uint basis, short sign) { // Base must be <= 10 if (basis > 10) throw new Exception ("Base to large. Maximum 10"); ulong output = 0; char max = (char) ((basis - 1) + (int) '0'); // Parse while (! stream.EOF) { // Decimal if (stream.Char >= '0' && stream.Char <= max) { output = (output * basis) + (uint) (stream.Char - '0'); OverflowTest (output, sign); } // Ignore underscores, but other chars are not allowed // see remarks else if (stream.Char != '_') throw new Exception ("Unknown char in base " + basis); stream.Next (); } return sign * (long) output; } /// Parses a string with base 60, without sign private static long Parse60 (ParseStream stream, short sign) { ulong output = 0; // Parse ulong part = 0; bool firstPart = true; // Only the first part can be larger then 59 while (! stream.EOF) { // Decimal if (stream.Char >= '0' && stream.Char <= '9') part = (part * 10) + (uint) (stream.Char - '0'); // New part else if (stream.Char == ':') { // Only the first part can be largen then 60 if ( ! firstPart) if (part >= 60) throw new Exception ("Part of base 60 scalar is too large (max. 59)"); else firstPart = false; output = (output * 60) + part; OverflowTest(output, sign); part = 0; } // Ignore underscores, other chars are not allowed else if (stream.Char != '_') throw new Exception ("Unknown char in base 16"); stream.Next (); } // Add last part to the output if (!firstPart) if (part >= 60) throw new Exception ( "Part of base 60 scalar is too large (max. 59)"); else firstPart = false; output = (output * 60) + part; OverflowTest (output, sign); return sign * (long) output; } /// Test that the unsigned int fits in a signed int /// Value to test /// Sign of the int where it must fit in private static void OverflowTest (ulong number, short sign) { // NOTE: Negatif numbers can be one larger if ((sign >= 0 && number > System.Int64.MaxValue) || (sign < 0 && number > (ulong) System.Int64.MaxValue + 1) ) throw new Exception ("YAML overflow exception"); } /// To String public override string ToString () { return "[INTEGER]" + content.ToString () + "[/INTEGER]"; } /// Write to YAML protected internal override void Write (WriteStream stream) { stream.Append (content.ToString ()); } } }