reSIProcate/stack  9373
Classes | Public Types | Public Member Functions | Static Public Member Functions | Private Member Functions | Static Private Member Functions | Private Attributes | Friends
resip::XMLCursor Class Reference

#include <XMLCursor.hxx>

Collaboration diagram for resip::XMLCursor:
Collaboration graph
[legend]

List of all members.

Classes

class  AttributeValueEqual
class  Node

Public Types

enum  { WhitespaceSignificant = false }
typedef HashMap< Data, DataAttributeMap

Public Member Functions

 XMLCursor (const ParseBuffer &pb)
 ~XMLCursor ()
bool nextSibling ()
bool firstChild ()
bool parent ()
void reset ()
bool atRoot () const
bool atLeaf () const
const DatagetTag () const
const AttributeMapgetAttributes () const
const DatagetValue () const

Static Public Member Functions

static EncodeStreamencode (EncodeStream &strm, const AttributeMap &attrs)

Private Member Functions

void parseNextRootChild ()
 XMLCursor (const XMLCursor &)
XMLCursoroperator= (const XMLCursor &)

Static Private Member Functions

static void skipProlog (ParseBuffer &pb)
static void decode (Data &)
static void decodeName (Data &)

Private Attributes

NodemRoot
NodemCursor
Data mTag
Data mData
Data mValue
AttributeMap mAttributes
bool mAttributesSet

Friends

class Node
EncodeStreamoperator<< (EncodeStream &, const XMLCursor &)
EncodeStreamoperator<< (EncodeStream &, const XMLCursor::Node &)

Detailed Description

Definition at line 96 of file XMLCursor.hxx.


Member Typedef Documentation

Definition at line 115 of file XMLCursor.hxx.


Member Enumeration Documentation

anonymous enum
Enumerator:
WhitespaceSignificant 

Definition at line 101 of file XMLCursor.hxx.


Constructor & Destructor Documentation

XMLCursor::XMLCursor ( const ParseBuffer pb)

Definition at line 54 of file XMLCursor.cxx.

References COMMENT_START(), resip::Data::data(), resip::ParseBuffer::data(), decodeName(), resip::ParseBuffer::end(), resip::ParseBuffer::eof(), resip::XMLCursor::Node::extractTag(), resip::ParseBuffer::fail(), InfoLog, resip::Symbols::LA_QUOTE, mCursor, mData, resip::XMLCursor::Node::mPb, mRoot, mTag, resip::XMLCursor::Node::mTag, Node, resip::ParseBuffer::position(), resip::Symbols::RA_QUOTE, resip::Data::reserve(), resip::ParseBuffer::reset(), resip::Data::size(), resip::ParseBuffer::skipChar(), resip::XMLCursor::Node::skipComments(), skipProlog(), resip::ParseBuffer::skipToChar(), resip::ParseBuffer::skipToChars(), resip::ParseBuffer::skipWhitespace(), resip::Symbols::SLASH, StackLog, resip::ParseBuffer::start(), and WhitespaceSignificant.

   : mRoot(0),
     mCursor(0),
     mAttributesSet(false)
{
   ParseBuffer lPb(pb);

   skipProlog(lPb);
   const char* start = lPb.position();

   lPb.skipToChars(COMMENT_START);
   if (!lPb.eof())
   {
      StackLog(<< "removing comments");
      lPb.reset(start);
      mData.reserve(lPb.end() - lPb.start());

      const char* anchor = start;
      {
         DataStream str(mData);
         Data temp;
         while (true)
         {
            lPb.skipToChars(COMMENT_START);
            if (!lPb.eof())
            {
               lPb.data(temp, anchor);
               str << temp;
               anchor = Node::skipComments(lPb);
            }
            else
            {
               lPb.data(temp, anchor);
               str << temp;
               break;
            }
         }
      }
      mRoot = new Node(ParseBuffer(mData.data(), mData.size()));
   }
   else
   {
      mRoot = new Node(ParseBuffer(start, pb.end() - start));
   }
   mCursor = mRoot;

   if (mRoot->extractTag())
   {
      InfoLog(<< "XML: empty element no a legal root");
      mRoot->mPb.fail(__FILE__, __LINE__);
   }

   mTag = mRoot->mTag;
   decodeName(mRoot->mTag);

   // check for # & and note -- make decode, decodeName do stuff if set

   //<top></top> // no children
   ParseBuffer pbtemp(mRoot->mPb);
   pbtemp.skipToChar(Symbols::RA_QUOTE[0]);
   pbtemp.skipChar();
   if (!WhitespaceSignificant)
   {
      pbtemp.skipWhitespace();
   }
   if (*pbtemp.position() == Symbols::LA_QUOTE[0] &&
       *(pbtemp.position()+1) == Symbols::SLASH[0])
   {
      pbtemp.skipChar();
      pbtemp.skipChar();
      if (strncmp(mRoot->mTag.data(), pbtemp.position(), mRoot->mTag.size()) == 0)
      {
         // no children ever
         mRoot->mPb.reset(mRoot->mPb.end());
         return;
      }
   }
}

Here is the call graph for this function:

XMLCursor::~XMLCursor ( )

Definition at line 133 of file XMLCursor.cxx.

References mRoot.

{
   delete mRoot;
}
resip::XMLCursor::XMLCursor ( const XMLCursor ) [private]

Member Function Documentation

bool XMLCursor::atLeaf ( ) const

Definition at line 324 of file XMLCursor.cxx.

References mCursor, and resip::XMLCursor::Node::mIsLeaf.

Referenced by getAttributes(), getValue(), and main().

{
   return mCursor->mIsLeaf;
}
bool XMLCursor::atRoot ( ) const

Definition at line 318 of file XMLCursor.cxx.

References mCursor, and mRoot.

Referenced by firstChild(), main(), nextSibling(), and parent().

{
   return mCursor == mRoot;
}
void XMLCursor::decode ( Data text) [static, private]

Definition at line 158 of file XMLCursor.cxx.

Referenced by getAttributes(), and getValue().

{
}
void XMLCursor::decodeName ( Data name) [static, private]

Definition at line 163 of file XMLCursor.cxx.

Referenced by getAttributes(), resip::XMLCursor::Node::skipToEndTag(), and XMLCursor().

{
}
EncodeStream & XMLCursor::encode ( EncodeStream strm,
const AttributeMap attrs 
) [static]

Definition at line 422 of file XMLCursor.cxx.

{
   for(AttributeMap::const_iterator i = attrs.begin();
       i != attrs.end(); ++i)
   {
      if (i != attrs.begin())
      {
         str << " ";
      }
      // !dlb! some sort of character encoding required here
      str << i->first << "=\"" << i->second << "\"";
   }

   return str;
}
bool XMLCursor::firstChild ( )

Definition at line 274 of file XMLCursor.cxx.

References atRoot(), mAttributesSet, resip::XMLCursor::Node::mChildren, mCursor, resip::XMLCursor::Node::mNext, mRoot, and parseNextRootChild().

Referenced by main(), resip::Pidf::parse(), and traverse().

{
   if (atRoot() &&
       mRoot->mChildren.empty())
   {
      parseNextRootChild();
   }

   if (mCursor->mChildren.empty())
   {
      return false;
   }
   else
   {
      // mNext always points after cursored child
      mCursor->mNext = mCursor->mChildren.begin();
      mCursor->mNext++;
      mCursor = mCursor->mChildren.front();
      mAttributesSet = false;
      return true;
   }
}

Here is the call graph for this function:

const XMLCursor::AttributeMap & XMLCursor::getAttributes ( ) const

Definition at line 344 of file XMLCursor.cxx.

References atLeaf(), resip::Data::clear(), resip::ParseBuffer::data(), decode(), decodeName(), resip::Symbols::DOUBLE_QUOTE, resip::ParseBuffer::eof(), resip::Symbols::EQUALS, resip::ParseBuffer::fail(), InfoLog, mAttributes, mAttributesSet, mCursor, resip::XMLCursor::Node::mPb, resip::ParseBuffer::position(), resip::Symbols::RA_QUOTE, RA_QUOTE_SLASH, resip::ParseBuffer::reset(), resip::ParseBuffer::skipChar(), resip::ParseBuffer::skipToChar(), resip::ParseBuffer::skipToOneOf(), resip::ParseBuffer::skipWhitespace(), resip::Symbols::SLASH, StackLog, resip::ParseBuffer::start(), value, and resip::ParseBuffer::Whitespace.

Referenced by interpretRlmi(), main(), and resip::Pidf::parse().

{
   if (!atLeaf() &&
       !mAttributesSet)
   {
      mAttributes.clear();
      mAttributesSet = true;
   
      ParseBuffer pb(mCursor->mPb);
      pb.reset(mCursor->mPb.start());

      Data attribute;
      Data value;

      pb.skipToOneOf(ParseBuffer::Whitespace, RA_QUOTE_SLASH);

      while (!pb.eof() && 
             *pb.position() != Symbols::RA_QUOTE[0] &&
             *pb.position() != Symbols::SLASH[0])
      {
         attribute.clear();
         value.clear();

         const char* anchor = pb.skipWhitespace();
         pb.skipToOneOf(ParseBuffer::Whitespace, Symbols::EQUALS);
         pb.data(attribute, anchor);
         XMLCursor::decodeName(attribute);

         StackLog(<< "attribute: " << attribute);

         pb.skipWhitespace();
         pb.skipToChar(Symbols::EQUALS[0]);
         pb.skipChar();
         pb.skipWhitespace();
         if (!pb.eof())
         {
            const char quote = *pb.position();

            StackLog(<< "quote is <" << quote << ">");
            
            if (quote != Symbols::DOUBLE_QUOTE[0] &&
                quote != '\'')
            {
               InfoLog(<< "XML: badly quoted attribute value");
               pb.fail(__FILE__, __LINE__);
            }
            anchor = pb.skipChar();
            pb.skipToChar(quote);
            pb.data(value, anchor);
            XMLCursor::decode(value);
            pb.skipChar();
            mAttributes[attribute] = value;
         }
         pb.skipWhitespace();
      }
   }

   return mAttributes;
}

Here is the call graph for this function:

const Data & XMLCursor::getTag ( ) const

Definition at line 330 of file XMLCursor.cxx.

References mCursor, and resip::XMLCursor::Node::mTag.

Referenced by interpretRlmi(), main(), resip::Pidf::parse(), and traverse().

{
   return mCursor->mTag;
}
const Data & XMLCursor::getValue ( ) const

Definition at line 405 of file XMLCursor.cxx.

References atLeaf(), resip::Data::clear(), resip::ParseBuffer::data(), decode(), mCursor, resip::XMLCursor::Node::mPb, mValue, resip::ParseBuffer::skipToEnd(), and resip::ParseBuffer::start().

Referenced by main(), and resip::Pidf::parse().

{
   if (atLeaf())
   {
      ParseBuffer pb(mCursor->mPb);
      pb.skipToEnd();
      mValue = pb.data(pb.start());
      XMLCursor::decode(mValue);
   }
   else
   {
      mValue.clear();
   }
   return mValue;
}

Here is the call graph for this function:

bool XMLCursor::nextSibling ( )

Definition at line 247 of file XMLCursor.cxx.

References atRoot(), mAttributesSet, resip::XMLCursor::Node::mChildren, mCursor, resip::XMLCursor::Node::mNext, resip::XMLCursor::Node::mParent, mRoot, parseNextRootChild(), and StackLog.

Referenced by main(), resip::Pidf::parse(), and traverse().

{
   if (atRoot())
   {
      StackLog(<< "XMLCursor::nextSibling" << *this->mCursor << " <<root>>");
      return false;
   }

   StackLog(<< "XMLCursor::nextSibling" << *this->mCursor << " " << *this->mCursor->mParent);
   if (mCursor->mParent == mRoot)
   {
      parseNextRootChild();
   }

   if (mCursor->mParent->mNext != mCursor->mParent->mChildren.end())
   {
      mCursor = *((mCursor->mParent->mNext)++);
      mAttributesSet = false;
      return true;
   }
   else
   {
      return false;
   }
}

Here is the call graph for this function:

XMLCursor& resip::XMLCursor::operator= ( const XMLCursor ) [private]
bool XMLCursor::parent ( )

Definition at line 298 of file XMLCursor.cxx.

References atRoot(), mAttributesSet, mCursor, and resip::XMLCursor::Node::mParent.

Referenced by main(), resip::Pidf::parse(), and traverse().

{
   if (atRoot())
   {
      return false;
   }

   mCursor = mCursor->mParent;
   mAttributesSet = false;
   return true;
}

Here is the call graph for this function:

void XMLCursor::parseNextRootChild ( ) [private]

Definition at line 168 of file XMLCursor.cxx.

References resip::XMLCursor::Node::addChild(), resip::Data::data(), resip::ParseBuffer::end(), resip::ParseBuffer::eof(), InfoLog, resip::Symbols::LA_QUOTE, resip::XMLCursor::Node::mChildren, resip::XMLCursor::Node::mIsLeaf, resip::XMLCursor::Node::mNext, resip::XMLCursor::Node::mPb, mRoot, mTag, resip::XMLCursor::Node::mTag, Node, resip::ParseBuffer::position(), resip::Symbols::RA_QUOTE, resip::ParseBuffer::reset(), resip::Data::size(), resip::ParseBuffer::skipChar(), resip::ParseBuffer::skipToChar(), resip::ParseBuffer::skipToEnd(), resip::XMLCursor::Node::skipToEndTag(), resip::ParseBuffer::skipWhitespace(), resip::Symbols::SLASH, resip::ParseBuffer::start(), and WhitespaceSignificant.

Referenced by firstChild(), and nextSibling().

{
   // no next child to parse?
   if (mRoot->mPb.eof())
   {
      return;
   }

   // next child already parsed?
   if (mRoot->mNext != mRoot->mChildren.end())
   {
      return;
   }

   // skip self tag
   if (mRoot->mPb.position() == mRoot->mPb.start())
   {
      mRoot->mPb.skipToChar(Symbols::RA_QUOTE[0]);
      mRoot->mPb.skipChar();
   }

   if (!WhitespaceSignificant)
   {
      mRoot->mPb.skipWhitespace();
   }

   // root end tag?
   if (*mRoot->mPb.position() == Symbols::LA_QUOTE[0])
   {
      ParseBuffer pb(mRoot->mPb.position(), 
                     mRoot->mPb.end() - mRoot->mPb.position());
      pb.skipChar();
      if (!pb.eof() && *pb.position() == Symbols::SLASH[0])
      {
         pb.skipChar();
         // CodeWarrior isn't helpful enough to pick the "obvious" operator definition
         // so we add volatile here so CW is completely unconfused what to do.
                 // second note - MSVC 7.0 won't compile the volatile - tried the following to fix
                 const char* end = pb.position();
         if ( (const char*)pb.end() < end + mTag.size() )
         {
            InfoLog(<< "XML: unexpected end");
            pb.fail(__FILE__, __LINE__);
         }
         
         if (strncmp(mTag.data(), pb.position(), mRoot->mTag.size()) == 0)
         {
            mRoot->mPb.skipToEnd();
            return;
         }
      }
   }

   // leaf?
   if (*mRoot->mPb.position() != Symbols::LA_QUOTE[0])
   {
      const char* anchor = mRoot->mPb.position();
      mRoot->mPb.skipToChar(Symbols::LA_QUOTE[0]);
      Node* leaf = new Node(ParseBuffer(anchor, mRoot->mPb.position() - anchor));
      leaf->mIsLeaf = true;
      mRoot->addChild(leaf);
   }
   else
   {
      Node* child = new Node(mRoot->mPb);
      child->skipToEndTag();

      // leave the parse buffer after the child
      mRoot->mPb.reset(child->mPb.end());

      mRoot->addChild(child);
   }

   // mNext always points at cursored child
   mRoot->mNext = mRoot->mChildren.end();
   mRoot->mNext--;
}

Here is the call graph for this function:

void XMLCursor::reset ( )

Definition at line 311 of file XMLCursor.cxx.

References mAttributesSet, mCursor, and mRoot.

Referenced by main().

{
   mCursor = mRoot;
   mAttributesSet = false;
}
void XMLCursor::skipProlog ( ParseBuffer pb) [static, private]

Definition at line 140 of file XMLCursor.cxx.

References resip::ParseBuffer::eof(), resip::ParseBuffer::position(), QUESTION_RA_QUOTE, resip::ParseBuffer::reset(), resip::ParseBuffer::skipN(), resip::ParseBuffer::skipToChars(), and resip::ParseBuffer::skipWhitespace().

Referenced by XMLCursor().

{
   //'<?xml' VersionInfo '<xml?' EncodingDecl '?>'? '<?xml' SDDecl '?>'? S? '?>

   // !dlb! much more complicated than this.. can contain comments
   const char* start = pb.position();
   pb.skipToChars(QUESTION_RA_QUOTE);
   if(pb.eof()) 
   {
      // No Prolog
      pb.reset(start);
      return;
   }
   pb.skipN(2);
   pb.skipWhitespace();
}

Here is the call graph for this function:


Friends And Related Function Documentation

friend class Node [friend]
EncodeStream& operator<< ( EncodeStream ,
const XMLCursor  
) [friend]
EncodeStream& operator<< ( EncodeStream ,
const XMLCursor::Node  
) [friend]

Member Data Documentation

Definition at line 151 of file XMLCursor.hxx.

Referenced by getAttributes().

bool resip::XMLCursor::mAttributesSet [mutable, private]

Definition at line 152 of file XMLCursor.hxx.

Referenced by firstChild(), getAttributes(), nextSibling(), parent(), and reset().

Definition at line 146 of file XMLCursor.hxx.

Referenced by XMLCursor().

Data resip::XMLCursor::mValue [mutable, private]

Definition at line 149 of file XMLCursor.hxx.

Referenced by getValue().


The documentation for this class was generated from the following files: