XMLTag* XMLTag::GetEmbeddedTagByNameAndAttr(const char* tagName, const char* attrName, const char* attrValue, const UInt32 index) { if (fEmbeddedTags.GetLength() <= index) return NULL; XMLTag* result = NULL; UInt32 curIndex = 0; for (OSQueueIter iter(&fEmbeddedTags); !iter.IsDone(); iter.Next()) { XMLTag* temp = (XMLTag*)iter.GetCurrent()->GetEnclosingObject(); if (!strcmp(temp->GetTagName(), tagName) && (temp->GetAttributeValue(attrName) != NULL) && (!strcmp(temp->GetAttributeValue(attrName), attrValue))) { if (curIndex == index) { result = temp; break; } curIndex++; } } return result; }
bool XMLTag::ParseTag(StringParser* parser, DTDVerifier* verifier, char* errorBuffer, int errorBufferSize) { while (true) { if (!parser->GetThru(NULL, '<')) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize, "Couldn't find a valid tag"); return false; // couldn't find beginning of tag } char c = parser->PeekFast(); if (c == '/') { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize, "End tag with no begin tag on line %d", parser->GetCurrentLineNumber()); return false; // we shouldn't be seeing a close tag here } if ((c != '!') && (c != '?')) break; // this should be the beginning of a regular tag ConsumeIfComment(parser); // otherwise this is a processing instruction or a c-data, so look for the next tag } int tagStartLine = parser->GetCurrentLineNumber(); StrPtrLen temp; parser->ConsumeUntil(&temp, sNonNameMask); if (temp.Len == 0) { if (errorBuffer != NULL) { if (parser->GetDataRemaining() == 0) qtss_snprintf(errorBuffer, errorBufferSize, "Unexpected end of file on line %d", parser->GetCurrentLineNumber()); else qtss_snprintf(errorBuffer, errorBufferSize,"Unexpected character (%c) on line %d", parser->PeekFast(), parser->GetCurrentLineNumber()); } return false; // bad file } fTag = temp.GetAsCString(); parser->ConsumeWhitespace(); while ((parser->PeekFast() != '>') && (parser->PeekFast() != '/')) { // we must have an attribute value for this tag XMLAttribute* attr = new XMLAttribute; fAttributes.EnQueue(&attr->fElem); parser->ConsumeUntil(&temp, sNonNameMask); if (temp.Len == 0) { if (errorBuffer != NULL) { if (parser->GetDataRemaining() == 0) qtss_snprintf(errorBuffer, errorBufferSize, "Unexpected end of file on line %d", parser->GetCurrentLineNumber()); else qtss_snprintf(errorBuffer, errorBufferSize,"Unexpected character (%c) on line %d", parser->PeekFast(), parser->GetCurrentLineNumber()); } return false; // bad file } attr->fAttrName = temp.GetAsCString(); if (!parser->Expect('=')) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize,"Missing '=' after attribute %s on line %d", attr->fAttrName, parser->GetCurrentLineNumber()); return false; // bad attribute specification } if (!parser->Expect('"')) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize,"Attribute %s value not in quotes on line %d", attr->fAttrName, parser->GetCurrentLineNumber()); return false; // bad attribute specification } parser->ConsumeUntil(&temp, '"'); attr->fAttrValue = temp.GetAsCString(); if (!parser->Expect('"')) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize, "Attribute %s value not in quotes on line %d", attr->fAttrName, parser->GetCurrentLineNumber()); return false; // bad attribute specification } if (verifier && !verifier->IsValidAttributeName(fTag, attr->fAttrName)) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize, "Attribute %s not allowed in tag %s on line %d", attr->fAttrName, fTag, parser->GetCurrentLineNumber()); return false; // bad attribute specification } if (verifier && !verifier->IsValidAttributeValue(fTag, attr->fAttrName, attr->fAttrValue)) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize,"Bad value for attribute %s on line %d", attr->fAttrName, parser->GetCurrentLineNumber()); return false; // bad attribute specification } parser->ConsumeWhitespace(); } if (parser->PeekFast() == '/') { // this is an empty element tag, i.e. no contents or end tag (e.g <TAG attr="value" /> parser->Expect('/'); if (!parser->Expect('>')) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize,"'>' must follow '/' on line %d", parser->GetCurrentLineNumber()); return false; // bad attribute specification } return true; // we're done with this tag } if (!parser->Expect('>')) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize,"Bad format for tag <%s> on line %d", fTag, parser->GetCurrentLineNumber()); return false; // bad attribute specification } while(true) { parser->ConsumeUntil(&temp, '<'); // this is either value or whitespace if (parser->GetDataRemaining() < 4) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize, "Reached end of file without end for tag <%s> declared on line %d", fTag, tagStartLine); return false; } if ((*parser)[1] == '/') { // we'll only assign a value if there were no embedded tags if (fEmbeddedTags.GetLength() == 0 && (!verifier || verifier->CanHaveValue(fTag))) fValue = temp.GetAsCString(); else { // otherwise this needs to have been just whitespace StringParser tempParser(&temp); tempParser.ConsumeWhitespace(); if (tempParser.GetDataRemaining() > 0) { if (errorBuffer) { if (fEmbeddedTags.GetLength() > 0) qtss_snprintf(errorBuffer, errorBufferSize,"Unexpected text outside of tag on line %d", tagStartLine); else qtss_snprintf(errorBuffer, errorBufferSize, "Tag <%s> on line %d not allowed to have data", fTag, tagStartLine); } } } break; // we're all done with this tag } if (((*parser)[1] != '!') && ((*parser)[1] != '?')) { // this must be the beginning of an embedded tag XMLTag* tag = NEW XMLTag(); fEmbeddedTags.EnQueue(&tag->fElem); if (!tag->ParseTag(parser, verifier, errorBuffer, errorBufferSize)) return false; if (verifier && !verifier->IsValidSubtag(fTag, tag->GetTagName())) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize, "Tag %s not allowed in tag %s on line %d", tag->GetTagName(), fTag, parser->GetCurrentLineNumber()); return false; // bad attribute specification } } else { parser->ConsumeLength(NULL, 1); // skip '<' ConsumeIfComment(parser); } } parser->ConsumeLength(NULL, 2); // skip '</' parser->ConsumeUntil(&temp, sNonNameMask); if (!temp.Equal(fTag)) { char* newTag = temp.GetAsCString(); if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize,"End tag </%s> on line %d doesn't match tag <%s> declared on line %d", newTag, parser->GetCurrentLineNumber(),fTag, tagStartLine); delete newTag; return false; // bad attribute specification } if (!parser->GetThru(NULL, '>')) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize,"Couldn't find end of tag <%s> declared on line %d", fTag, tagStartLine); return false; // bad attribute specification } return true; }