/// <summary> /// Parses an array from the current parsing position. /// The prerequisite for calling this method is, that an array begin token has been read. /// </summary> /// <returns>The array found at the parsing position.</returns> NSArray ParseArray() { //Skip begin token int startPosition = this.index; Skip(); SkipWhitespacesAndComments(); List <NSObject> objects = new List <NSObject>(); while (!Accept(ARRAY_END_TOKEN)) { objects.Add(ParseObject()); SkipWhitespacesAndComments(); if (Accept(ARRAY_ITEM_DELIMITER_TOKEN)) { Skip(); } else { break; //must have reached end of array } SkipWhitespacesAndComments(); } //parse end token Read(ARRAY_END_TOKEN); return(new NSArray(objects.ToArray(), BinaryOrigin.FromRange(startPosition, this.index))); }
/// <summary> /// Parses the NSObject found at the current position in the property list /// data stream. /// </summary> /// <returns>The parsed NSObject.</returns> /// <seealso cref="ASCIIPropertyListParser.index"/> NSObject ParseObject() { switch (data[index]) { case ARRAY_BEGIN_TOKEN: { return(ParseArray()); } case DICTIONARY_BEGIN_TOKEN: { return(ParseDictionary()); } case DATA_BEGIN_TOKEN: { return(ParseData()); } case QUOTEDSTRING_BEGIN_TOKEN: { int startIndex = this.index; string quotedString = ParseQuotedString(); //apple dates are quoted strings of length 20 and after the 4 year digits a dash is found if (quotedString.Length == 20 && quotedString[4] == DATE_DATE_FIELD_DELIMITER) { try { return(new NSDate(quotedString, BinaryOrigin.FromRange(startIndex, this.index))); } catch (Exception) { //not a date? --> return string return(new NSString(quotedString, BinaryOrigin.FromRange(startIndex, this.index))); } } return(new NSString(quotedString, BinaryOrigin.FromRange(startIndex, this.index))); } default: { //0-9 if (data[index] > 0x2F && data[index] < 0x3A) { //could be a date or just a string return(ParseDateString()); } else { //non-numerical -> string or boolean var startIndex = this.index; string parsedString = ParseString(); return(new NSString(parsedString, BinaryOrigin.FromRange(startIndex, this.index))); } } } }
/// <summary> /// Attempts to parse a plain string as a date if possible. /// </summary> /// <returns>A NSDate if the string represents such an object. Otherwise a NSString is returned.</returns> NSObject ParseDateString() { var startIndex = this.index; string numericalString = ParseString(); if (numericalString.Length > 4 && numericalString[4] == DATE_DATE_FIELD_DELIMITER) { try { return(new NSDate(numericalString, BinaryOrigin.FromRange(startIndex, this.index))); } catch (Exception) { //An exception occurs if the string is not a date but just a string } } return(new NSString(numericalString, BinaryOrigin.FromRange(startIndex, this.index))); }
/// <summary> /// Parses a dictionary from the current parsing position. /// The prerequisite for calling this method is, that a dictionary begin token has been read. /// </summary> /// <returns>The dictionary found at the parsing position.</returns> NSDictionary ParseDictionary() { //Skip begin token var origin = new BinaryOrigin(this.index, 0); Skip(); SkipWhitespacesAndComments(); NSDictionary dict = new NSDictionary(origin); while (!Accept(DICTIONARY_END_TOKEN)) { //Parse key string keyString; if (Accept(QUOTEDSTRING_BEGIN_TOKEN)) { keyString = ParseQuotedString(); } else { keyString = ParseString(); } SkipWhitespacesAndComments(); //Parse assign token Read(DICTIONARY_ASSIGN_TOKEN); SkipWhitespacesAndComments(); NSObject nso = ParseObject(); dict.Add(keyString, nso); SkipWhitespacesAndComments(); Read(DICTIONARY_ITEM_DELIMITER_TOKEN); SkipWhitespacesAndComments(); } //skip end token Skip(); origin.SetEndPosition(this.index); return(dict); }
/// <summary> /// Parses a data object from the current parsing position. /// This can either be a NSData object or a GnuStep NSNumber or NSDate. /// The prerequisite for calling this method is, that a data begin token has been read. /// </summary> /// <returns>The data object found at the parsing position.</returns> NSObject ParseData() { NSObject obj = null; //Skip begin token var origin = new BinaryOrigin(this.index, 0); Skip(); if (Accept(DATA_GSOBJECT_BEGIN_TOKEN)) { Skip(); Expect(DATA_GSBOOL_BEGIN_TOKEN, DATA_GSDATE_BEGIN_TOKEN, DATA_GSINT_BEGIN_TOKEN, DATA_GSREAL_BEGIN_TOKEN); if (Accept(DATA_GSBOOL_BEGIN_TOKEN)) { //Boolean Skip(); Expect(DATA_GSBOOL_TRUE_TOKEN, DATA_GSBOOL_FALSE_TOKEN); if (Accept(DATA_GSBOOL_TRUE_TOKEN)) { obj = new NSNumber(true, origin); } else { obj = new NSNumber(false, origin); } //Skip the parsed boolean token Skip(); } else if (Accept(DATA_GSDATE_BEGIN_TOKEN)) { //Date Skip(); string dateString = ReadInputUntil(DATA_END_TOKEN); obj = new NSDate(dateString, origin); } else if (Accept(DATA_GSINT_BEGIN_TOKEN, DATA_GSREAL_BEGIN_TOKEN)) { //Number Skip(); string numberString = ReadInputUntil(DATA_END_TOKEN); obj = new NSNumber(numberString, origin); } //parse data end token Read(DATA_END_TOKEN); } else { string dataString = ReadInputUntil(DATA_END_TOKEN); dataString = Regex.Replace(dataString, "\\s+", ""); int numBytes = dataString.Length / 2; byte[] bytes = new byte[numBytes]; for (int i = 0; i < bytes.Length; i++) { string byteString = dataString.Substring(i * 2, 2); int byteValue = Convert.ToInt32(byteString, 16); bytes[i] = (byte)byteValue; } obj = new NSData(bytes, origin); //skip end token Skip(); } origin.SetEndPosition(this.index); return(obj); }