void BJson::_Parse(BMessage& message, BString& JSON) { BMessageBuilder builder(message); int32 pos = 0; int32 length = JSON.Length(); /* Locals used by the parser. */ // Keeps track of the hierarchy (e.g. "{[{{") that has // been read in. Allows the parser to verify that openbraces // match up to closebraces and so on and so forth. BString hierarchy(""); // Stores the key that was just read by the string parser, // in the case that we are parsing a map. BString key(""); // TODO: Check builder return codes and throw exception, or // change builder implementation/interface to throw exceptions // instead of returning errors. // TODO: Elimitate more duplicated code, for example by moving // more code into _ParseConstant(). while (pos < length) { switch (JSON[pos]) { case '{': hierarchy += "{"; if (hierarchy != "{") { if (builder.What() == JSON_TYPE_ARRAY) builder.PushObject(builder.CountNames()); else { builder.PushObject(key.String()); key = ""; } } builder.SetWhat(JSON_TYPE_MAP); break; case '}': if (hierarchy.EndsWith("{") && hierarchy.Length() != 1) { hierarchy.Truncate(hierarchy.Length() - 1); builder.PopObject(); } else if (hierarchy.Length() == 1) return; // End of the JSON data else throw ParseException(pos, "Unmatched closebrace }"); break; case '[': hierarchy += "["; if (builder.What() == JSON_TYPE_ARRAY) builder.PushObject(builder.CountNames()); else { builder.PushObject(key.String()); key = ""; } builder.SetWhat(JSON_TYPE_ARRAY); break; case ']': if (hierarchy.EndsWith("[")) { hierarchy.Truncate(hierarchy.Length() - 1); builder.PopObject(); } else { BString error("Unmatched closebrace ] hierarchy: "); error << hierarchy; throw ParseException(pos, error); } break; case 't': { if (builder.What() != JSON_TYPE_ARRAY && key.Length() == 0) { throw ParseException(pos, "'true' cannot be a key, it can only be a value"); } if (_ParseConstant(JSON, pos, "true")) { if (builder.What() == JSON_TYPE_ARRAY) key.SetToFormat("%" B_PRIu32, builder.CountNames()); builder.AddBool(key.String(), true); key = ""; } else throw ParseException(pos, "Unexpected 't'"); break; } case 'f': { if (builder.What() != JSON_TYPE_ARRAY && key.Length() == 0) { throw ParseException(pos, "'false' cannot be a key, it can only be a value"); } if (_ParseConstant(JSON, pos, "false")) { if (builder.What() == JSON_TYPE_ARRAY) key.SetToFormat("%" B_PRIu32, builder.CountNames()); builder.AddBool(key.String(), false); key = ""; } else throw ParseException(pos, "Unexpected 'f'"); break; } case 'n': { if (builder.What() != JSON_TYPE_ARRAY && key.Length() == 0) { throw ParseException(pos, "'null' cannot be a key, it can only be a value"); } if (_ParseConstant(JSON, pos, "null")) { if (builder.What() == JSON_TYPE_ARRAY) key.SetToFormat("%" B_PRIu32, builder.CountNames()); builder.AddPointer(key.String(), (void*)NULL); key = ""; } else throw ParseException(pos, "Unexpected 'n'"); break; } case '"': if (builder.What() != JSON_TYPE_ARRAY && key.Length() == 0) key = _ParseString(JSON, pos); else if (builder.What() != JSON_TYPE_ARRAY && key.Length() > 0) { builder.AddString(key, _ParseString(JSON, pos)); key = ""; } else if (builder.What() == JSON_TYPE_ARRAY) { key << builder.CountNames(); builder.AddString(key, _ParseString(JSON, pos)); key = ""; } else throw ParseException(pos, "Internal error at encountering \""); break; case '+': case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { if (builder.What() != JSON_TYPE_ARRAY && key.Length() == 0) { throw ParseException(pos, "Numbers cannot be keys, they can only be values"); } if (builder.What() == JSON_TYPE_ARRAY) key << builder.CountNames(); double number = _ParseNumber(JSON, pos); builder.AddDouble(key.String(), number); key = ""; break; } case ':': case ',': default: // No need to do anything here. break; } pos++; } throw ParseException(pos, "Unexpected end of document"); }
IMAPResult IMAPFetchParser::ParseCommand(const String &sCommand) { String sStringToParse = sCommand; IMAPResult result = _ValidateSyntax(sStringToParse); if (result.GetResult() != IMAPResult::ResultOK) return result; std::vector<String> vecResult = _ParseString(sStringToParse); std::vector<String>::iterator iter = vecResult.begin(); while (iter != vecResult.end()) { String sPart = (*iter); ePartType iType = _GetPartType(sPart); switch (iType) { case BODYPEEK: { IMAPFetchParser::BodyPart oPart = _ParseBODYPEEK(sPart); m_vecPartsToLookAt.push_back(oPart); break; } case ENVELOPE: { m_bShowEnvelope = true; break; } case RFC822SIZE: { m_bShowRFCSize = true; break; } case UID: { m_bShowUID = true; break; } case FLAGS: { m_bShowFlags = true; break; } case INTERNALDATE: { m_bShowInternalDate = true; break; } case BODYSTRUCTURE: { m_bShowBodyStructure = true; break; } case BODYSTRUCTURENONEXTENSIBLE: { m_bShowBodyStructureNonExtensible = true; break; } case BODY: { IMAPFetchParser::BodyPart oPart = _ParseBODY(sPart); m_vecPartsToLookAt.push_back(oPart); break; } case RFC822: { // Same as: IMAPFetchParser::BodyPart oPart = _ParseBODY(sPart); oPart.SetDescription("RFC822"); m_vecPartsToLookAt.push_back(oPart); break; } case ALL: { // ALL // Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE) m_bShowFlags = true; m_bShowInternalDate = true; m_bShowRFCSize = true; m_bShowEnvelope = true; break; } case FAST: { // FAST // Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE) m_bShowFlags = true; m_bShowInternalDate = true; m_bShowRFCSize = true; break; } case FULL: { // FULL // Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY) m_bShowFlags = true; m_bShowInternalDate = true; m_bShowRFCSize = true; m_bShowEnvelope = true; m_bShowBodyStructure = true; break; } case RFC822HEADER: { /* RFC822.HEADER Functionally equivalent to BODY.PEEK[HEADER], differing in the syntax of the resulting untagged FETCH data (RFC822.HEADER is returned). */ IMAPFetchParser::BodyPart oPart = _ParseBODYPEEK("BODY[HEADER]"); oPart.SetDescription("RFC822.HEADER"); m_vecPartsToLookAt.push_back(oPart); break; } case RFC822TEXT: { /* Functionally equivalent to BODY[TEXT], differing in the syntax of the resulting untagged FETCH data (RFC822.TEXT is returned). */ IMAPFetchParser::BodyPart oPart = _ParseBODY("BODY[TEXT]"); oPart.SetDescription("RFC822.TEXT"); m_vecPartsToLookAt.push_back(oPart); break; } } iter++; } return IMAPResult(); }