public string GetValue(int i) { if (i < values.Count) { TBJSONValue attribute = values [i]; if (attribute.valueIdx == 0) { return(null); } return(System.Text.UTF8Encoding.Default.GetString(tbxml.bytes, (int)attribute.valueIdx, (int)tbxml.strlen(attribute.valueIdx))); } return(null); }
private void DecodeBytes(Action <TBJSONElement, TBJSONElement, int> onStartElement, Action <TBJSONElement, TBJSONElement, int> onEndElement) { byte[] localBytes = bytes; long localBytesLength = bytesLength; Stack <TBJSONElement> elementStack = new Stack <TBJSONElement> (); Stack <TBJSONElement> freeElementList = new Stack <TBJSONElement> (); TBJSONValue xmlAttribute = new TBJSONValue(); // set elementStart pointer to the start of our xml long currentIdx = 0; TBJSONElement xmlElement = null; // find next element start while ((currentIdx = strskip(currentIdx, (byte)' ', (byte)'\t', (byte)'\n', (byte)'\r', (byte)',')) < localBytesLength) { // ok, so the main algorithm is fairly simple. At this point, we've identified the start of an object enclosure, an array enclosure, or the start of a string // make an element for this and put it on the stack long nextCurrentIdx = currentIdx + 1; if (localBytes [currentIdx] == (byte)'}' || localBytes [currentIdx] == (byte)']') { xmlElement = EndElement(elementStack, freeElementList, onEndElement); } else if (localBytes [currentIdx] == (byte)'{' || localBytes [currentIdx] == (byte)'[') { // we've found the start of a new object int parentIdx = -1; TBJSONElement parentElement = null; // this is not the root element, so we need an attribute to link it if (xmlAttribute.nameIdx != 0) { parentElement = xmlElement; parentIdx = xmlElement.values.Count; xmlAttribute.type = ValueType.Element; xmlAttribute.element = xmlElement; xmlElement.values.Add(xmlAttribute); xmlAttribute.Clear(); } if (freeElementList.Count > 0) { xmlElement = freeElementList.Pop(); } else { xmlElement = new TBJSONElement(); xmlElement.tbxml = this; } if (localBytes [currentIdx] == (byte)'{') { xmlElement.type = ElementType.Object; } else { xmlElement.type = ElementType.Array; } elementStack.Push(xmlElement); onStartElement(xmlElement, parentElement, parentIdx); } else if (xmlElement.type == ElementType.Object && localBytes [currentIdx] == (byte)'\"' || localBytes [currentIdx] == (byte)'\'') { // We've found the name portiong of a KVP if (xmlAttribute.nameIdx == 0) { // Set the attribute name index xmlAttribute.nameIdx = currentIdx + 1; // Find the name of the name string and null terminate it nextCurrentIdx = strstrNoEscaped(xmlAttribute.nameIdx, localBytes [currentIdx]); localBytes [nextCurrentIdx] = 0; // Find the ':' nextCurrentIdx = strstrNoEscaped(nextCurrentIdx + 1, (byte)':') + 1; // skip whitespace nextCurrentIdx = strskip(nextCurrentIdx, (byte)' ', (byte)'\t', (byte)'\n', (byte)'\r'); // advance forward until we find the start of the next thing if (localBytes [nextCurrentIdx] == (byte)'\"' || localBytes [nextCurrentIdx] == (byte)'\'') { // our value is a string xmlAttribute.type = ValueType.String; xmlAttribute.valueIdx = nextCurrentIdx + 1; nextCurrentIdx = strstrNoEscaped(xmlAttribute.valueIdx, localBytes [nextCurrentIdx]); localBytes [nextCurrentIdx] = 0; nextCurrentIdx++; xmlElement.values.Add(xmlAttribute); xmlAttribute.Clear(); } else if (localBytes [nextCurrentIdx] == (byte)'{' || localBytes [nextCurrentIdx] == (byte)'[') { // our value is an array or an object; we will process it next time through the main loop //nextCurrentIdx = nextCurrentIdx - 1; } else if (localBytes [nextCurrentIdx] == (byte)'n' && localBytes [nextCurrentIdx + 1] == (byte)'u' && localBytes [nextCurrentIdx + 2] == (byte)'l' && localBytes [nextCurrentIdx + 3] == (byte)'l') { // our value is null; pick up at the end of it xmlAttribute.type = ValueType.Null; nextCurrentIdx += 4; xmlElement.values.Add(xmlAttribute); xmlAttribute.Clear(); } else { // our value is likely a number; capture it then advance to the next ',' or '}' or whitespace xmlAttribute.type = ValueType.Int; xmlAttribute.valueIdx = nextCurrentIdx; while (localBytes [nextCurrentIdx] != ' ' && localBytes [nextCurrentIdx] != '\t' && localBytes [nextCurrentIdx] != '\n' && localBytes [nextCurrentIdx] != '\r' && localBytes [nextCurrentIdx] != ',' && localBytes [nextCurrentIdx] != '}' && localBytes [nextCurrentIdx] != ']') { if (localBytes [nextCurrentIdx] == '.') { xmlAttribute.type = ValueType.Double; } nextCurrentIdx++; } xmlElement.values.Add(xmlAttribute); xmlAttribute.Clear(); if (localBytes [nextCurrentIdx] == (byte)']') { localBytes [nextCurrentIdx] = 0; xmlElement = EndElement(elementStack, freeElementList, onEndElement); } localBytes [nextCurrentIdx] = 0; nextCurrentIdx++; } } else { // We found the value portion of a KVP nextCurrentIdx = strstrNoEscaped(currentIdx, localBytes [currentIdx]); localBytes [nextCurrentIdx] = 0; // Find the ':' nextCurrentIdx = strstrNoEscaped(nextCurrentIdx, (byte)':'); // create new attribute xmlAttribute.nameIdx = currentIdx; } } else { if (xmlElement.type == ElementType.Array) { // this could be an array element... nextCurrentIdx = strskip(currentIdx, (byte)' ', (byte)'\t', (byte)'\n', (byte)'\r'); // advance forward until we find the start of the next thing if (localBytes [nextCurrentIdx] == (byte)'\"' || localBytes [nextCurrentIdx] == (byte)'\'') { // our value is a string xmlAttribute.type = ValueType.String; xmlAttribute.valueIdx = nextCurrentIdx + 1; nextCurrentIdx = strstrNoEscaped(xmlAttribute.valueIdx, localBytes [nextCurrentIdx]); localBytes [nextCurrentIdx] = 0; nextCurrentIdx++; xmlElement.values.Add(xmlAttribute); xmlAttribute.Clear(); } else if (localBytes [nextCurrentIdx] == (byte)'{' || localBytes [nextCurrentIdx] == (byte)'[') { // our value is an array or an object; we will process it next time through the main loop //nextCurrentIdx = nextCurrentIdx - 1; } else if (localBytes [nextCurrentIdx] == (byte)'n' && localBytes [nextCurrentIdx + 1] == (byte)'u' && localBytes [nextCurrentIdx + 2] == (byte)'l' && localBytes [nextCurrentIdx + 3] == (byte)'l') { // our value is null; pick up at the end of it xmlAttribute.type = ValueType.Null; nextCurrentIdx += 4; xmlElement.values.Add(xmlAttribute); xmlAttribute.Clear(); } else { // our value is likely a number; capture it then advance to the next ',' or '}' or whitespace xmlAttribute.type = ValueType.Int; xmlAttribute.valueIdx = nextCurrentIdx; while (localBytes [nextCurrentIdx] != ' ' && localBytes [nextCurrentIdx] != '\t' && localBytes [nextCurrentIdx] != '\n' && localBytes [nextCurrentIdx] != '\r' && localBytes [nextCurrentIdx] != ',' && localBytes [nextCurrentIdx] != '}' && localBytes [nextCurrentIdx] != ']') { if (localBytes [nextCurrentIdx] == '.') { xmlAttribute.type = ValueType.Double; } nextCurrentIdx++; } xmlElement.values.Add(xmlAttribute); xmlAttribute.Clear(); if (localBytes [nextCurrentIdx] == (byte)']') { localBytes [nextCurrentIdx] = 0; xmlElement = EndElement(elementStack, freeElementList, onEndElement); } localBytes [nextCurrentIdx] = 0; nextCurrentIdx++; } } } currentIdx = nextCurrentIdx; } while (elementStack.Count > 0) { xmlElement = EndElement(elementStack, freeElementList, onEndElement); } }