Orb/Doxygen/src/dbusxmlscanner.cpp
changeset 0 42188c7ea2d9
child 4 468f4c8d3d5b
equal deleted inserted replaced
-1:000000000000 0:42188c7ea2d9
       
     1 /******************************************************************************
       
     2  *
       
     3  *
       
     4  *
       
     5  * Copyright (C) 2009 by Tobias Hunger <tobias@aquazul.com>
       
     6  *
       
     7  * Permission to use, copy, modify, and distribute this software and its
       
     8  * documentation under the terms of the GNU General Public License is hereby
       
     9  * granted. No representations are made about the suitability of this software
       
    10  * for any purpose. It is provided "as is" without express or implied warranty.
       
    11  * See the GNU General Public License for more details.
       
    12  *
       
    13  * Documents produced by Doxygen are derivative works derived from the
       
    14  * input used in their production; they are not affected by this license.
       
    15  *
       
    16  */
       
    17 
       
    18 #include "dbusxmlscanner.h"
       
    19 
       
    20 #include "commentscan.h"
       
    21 #include "entry.h"
       
    22 
       
    23 #include <qfile.h>
       
    24 #include <qxml.h>
       
    25 #include <qstring.h>
       
    26 
       
    27 #include "message.h"
       
    28 #include "util.h"
       
    29 
       
    30 // -----------------------------------------------------------------------
       
    31 // Convenience defines:
       
    32 // -----------------------------------------------------------------------
       
    33 
       
    34 #define CONDITION(cond, msg) \
       
    35     do {\
       
    36         if (cond)\
       
    37         {\
       
    38             if (m_errorString.isEmpty()) { m_errorString = msg; }\
       
    39             return false;\
       
    40         }\
       
    41     }\
       
    42     while (0)
       
    43 
       
    44 #define DOC_ERROR(msg) \
       
    45     warn_doc_error(m_fileName.utf8().data(), lineNumber(), msg.utf8().data())
       
    46 
       
    47 #define COND_DOC_ERROR(cond, msg) \
       
    48     do {\
       
    49         if (cond)\
       
    50         {\
       
    51              DOC_ERROR(msg);\
       
    52              return true;\
       
    53         }\
       
    54     }\
       
    55     while (0)
       
    56 
       
    57 #define DBUS(name) isDBusElement(namespaceURI, localName, qName, name)
       
    58 #define EXTENSION(name) isExtensionElement(namespaceURI, localName, qName, name)
       
    59 
       
    60 // -----------------------------------------------------------------------
       
    61 // DBusXMLHandler class
       
    62 // -----------------------------------------------------------------------
       
    63 
       
    64 const QString EXTENSION_URI("http://psiamp.org/dtd/doxygen_dbusxml.dtd");
       
    65 
       
    66 class DBusXMLHandler : public QXmlDefaultHandler
       
    67 {
       
    68 public:
       
    69     DBusXMLHandler(ParserInterface * parser,
       
    70                    QXmlSimpleReader * reader,
       
    71                    const char * file_name,
       
    72                    Entry * root) :
       
    73         m_parser(parser),
       
    74         m_locator(reader),
       
    75         m_currentEntry(0),
       
    76         m_currentInterface(0),
       
    77         m_currentMethod(0),
       
    78         m_currentArgument(0),
       
    79         m_currentProperty(0),
       
    80         m_currentEnum(0),
       
    81         m_fileName(file_name),
       
    82         m_currentComment(0)
       
    83     {
       
    84         setDocumentLocator(&m_locator);
       
    85 
       
    86         m_scopeCount = 0;
       
    87 
       
    88         // Set up stack cleanup:
       
    89         m_structStack.setAutoDelete(TRUE);
       
    90         m_elementStack.setAutoDelete(TRUE);
       
    91         m_scopeStack.setAutoDelete(TRUE);
       
    92 
       
    93         openScopes(root);
       
    94     }
       
    95 
       
    96     ~DBusXMLHandler()
       
    97     { closeScopes(); }
       
    98 
       
    99     QString errorString()
       
   100     { return m_errorString; }
       
   101 
       
   102     bool startElement(const QString &namespaceURI,
       
   103                       const QString &localName,
       
   104                       const QString &qName,
       
   105                       const QXmlAttributes &attributes)
       
   106     {
       
   107         // add to elements stack:
       
   108         m_elementStack.append(new ElementData(qName));
       
   109 
       
   110         // First we need a node.
       
   111         if (DBUS("node"))
       
   112         {
       
   113             CONDITION(!m_currentNode.isEmpty(), "Node inside a node.");
       
   114 
       
   115             const int idx(indexOf(attributes, "name"));
       
   116             COND_DOC_ERROR(idx < 0, QString("Anonymous node found."));
       
   117 
       
   118             m_currentNode = attributes.value(idx);
       
   119             // A node is actually of little interest, so do nothing here.
       
   120             return true;
       
   121         }
       
   122 
       
   123         // Then we need an interface.
       
   124         if (DBUS("interface"))
       
   125         {
       
   126             // We need a nodeName for interfaces:
       
   127             CONDITION(m_currentNode.isEmpty(), "Interface without a node.");
       
   128             CONDITION(m_currentInterface, "Interface within another interface.");
       
   129 
       
   130             const int idx(indexOf(attributes, "name"));
       
   131             COND_DOC_ERROR(idx < 0, QString("Interface without a name found."));
       
   132 
       
   133             // A interface is roughly equivalent to a class:
       
   134             m_currentInterface = createEntry();
       
   135 
       
   136             m_currentInterface->section = Entry::CLASS_SEC;
       
   137             m_currentInterface->spec |= Entry::Interface;
       
   138             m_currentInterface->type = "Interface";
       
   139             m_currentInterface->name = substitute(attributes.value(idx), ".", "::");
       
   140 
       
   141             openScopes(m_currentInterface);
       
   142 
       
   143             return true;
       
   144         }
       
   145 
       
   146         if (DBUS("method") || DBUS("signal"))
       
   147         {
       
   148             // We need a interfaceName for methods and signals:
       
   149             CONDITION(!m_currentInterface, "Method or signal found outside a interface.");
       
   150             CONDITION(m_currentMethod, "Method or signal found inside another method or signal.");
       
   151             CONDITION(m_currentProperty, "Methor or signal found inside a property.");
       
   152             CONDITION(!m_structStack.isEmpty(), "Method or signal found inside a struct.");
       
   153             CONDITION(m_currentEnum, "Methor or signal found inside a enum.");
       
   154 
       
   155             const int idx(indexOf(attributes, "name"));
       
   156             COND_DOC_ERROR(idx < 0, QString("Method or signal without a name found."));
       
   157 
       
   158             m_currentMethod = createEntry();
       
   159 
       
   160             m_currentMethod->section = Entry::FUNCTION_SEC;
       
   161             m_currentMethod->name = attributes.value(idx);
       
   162             m_currentMethod->mtype = Method;
       
   163             m_currentMethod->type = "void";
       
   164 
       
   165             if (DBUS("signal"))
       
   166             { m_currentMethod->mtype = Signal; }
       
   167         }
       
   168 
       
   169         if (DBUS("arg"))
       
   170         {
       
   171             // We need a method for arguments:
       
   172             CONDITION(!m_currentMethod, "Argument found outside a method or signal.");
       
   173             CONDITION(m_currentArgument, "Argument found inside another argument.");
       
   174 
       
   175             const int name_idx(indexOf(attributes, "name"));
       
   176             COND_DOC_ERROR(name_idx < 0, QString("Argument without a name found."));
       
   177             COND_DOC_ERROR(!hasType(attributes), QString("Argument without a type found."));
       
   178 
       
   179             const int direction_idx(indexOf(attributes, "direction"));
       
   180 
       
   181             if ((m_currentMethod->mtype == Signal &&
       
   182                  direction_idx >= 0 &&
       
   183                  attributes.value(direction_idx) != "in") ||
       
   184                 (m_currentMethod->mtype == Method &&
       
   185                  direction_idx >= 0 &&
       
   186                  attributes.value(direction_idx) != "in" &&
       
   187                  attributes.value(direction_idx) != "out"))
       
   188             {
       
   189                 m_errorString = "Invalid direction found.";
       
   190                 return false;
       
   191             }
       
   192 
       
   193             m_currentArgument = new Argument;
       
   194             m_currentArgument->type = getType(attributes);
       
   195             m_currentArgument->name = attributes.value(name_idx);
       
   196             if (direction_idx >= 0)
       
   197             { m_currentArgument->attrib = attributes.value(direction_idx); }
       
   198             else
       
   199             {
       
   200                 if (m_currentMethod->mtype == Signal)
       
   201                 { m_currentArgument->attrib = "in"; }
       
   202                 else
       
   203                 { m_currentArgument->attrib = "out"; }
       
   204             }
       
   205         }
       
   206 
       
   207         if (DBUS("property"))
       
   208         {
       
   209             CONDITION(m_currentMethod, "Property found inside a method or signal.");
       
   210             CONDITION(!m_currentInterface, "Property found outside an interface.");
       
   211             CONDITION(m_currentProperty, "Property found inside another property.");
       
   212             CONDITION(!m_structStack.isEmpty(), "Property found inside a struct.");
       
   213             CONDITION(m_currentEnum, "Property found inside a enum.");
       
   214 
       
   215             const int name_idx(indexOf(attributes, "name"));
       
   216             COND_DOC_ERROR(name_idx < 0, QString("Anonymous property found."));
       
   217             COND_DOC_ERROR(!hasType(attributes), QString("Property without a type found."));
       
   218 
       
   219             const int access_idx(indexOf(attributes, "access"));
       
   220             COND_DOC_ERROR(access_idx < 0, QString("Property without a access attribute found."));
       
   221             COND_DOC_ERROR(attributes.value(access_idx) != "read" &&
       
   222                            attributes.value(access_idx) != "write" &&
       
   223                            attributes.value(access_idx) != "readwrite",
       
   224                            QString("Property with invalid access attribute \"%1\" found.").
       
   225                            arg(attributes.value(access_idx)));
       
   226 
       
   227             m_currentProperty = createEntry();
       
   228 
       
   229             m_currentProperty->section = Entry::FUNCTION_SEC;
       
   230 
       
   231             if (attributes.value(access_idx) == "read" ||
       
   232                 attributes.value(access_idx) == "readwrite")
       
   233             { m_currentProperty->spec |= Entry::Readable; }
       
   234 
       
   235             if (attributes.value(access_idx) == "write" ||
       
   236                 attributes.value(access_idx) == "readwrite")
       
   237             { m_currentProperty->spec |= Entry::Writable; }
       
   238 
       
   239             m_currentProperty->name = attributes.value(name_idx);
       
   240             m_currentProperty->mtype = Property;
       
   241             m_currentProperty->type = getType(attributes);
       
   242         }
       
   243 
       
   244         if (EXTENSION("namespace"))
       
   245         {
       
   246             CONDITION(m_currentNode.isEmpty(), "Namespace found outside a node.");
       
   247             CONDITION(m_currentInterface, "Namespace found inside an interface.");
       
   248 
       
   249             const int idx(indexOf(attributes, "name"));
       
   250             COND_DOC_ERROR(idx < 0, QString("Anonymous namespace found."));
       
   251 
       
   252             m_namespaceStack.append(openNamespace(attributes.value(idx)));
       
   253             openScopes(m_namespaceStack.last());
       
   254         }
       
   255 
       
   256         if (EXTENSION("struct"))
       
   257         {
       
   258             CONDITION(m_currentMethod, "Struct found inside a method or signal.");
       
   259             CONDITION(m_currentProperty, "Struct found inside a property.");
       
   260             CONDITION(m_currentEnum, "Struct found inside an enum.");
       
   261 
       
   262             const int idx(indexOf(attributes, "name"));
       
   263             COND_DOC_ERROR(idx < 0, QString("Anonymous struct found."));
       
   264 
       
   265             Entry * current_struct = createEntry();
       
   266             current_struct->section = Entry::CLASS_SEC;
       
   267             current_struct->spec = Entry::Struct;
       
   268             current_struct->name = attributes.value(idx);
       
   269 
       
   270             openScopes(current_struct);
       
   271 
       
   272             current_struct->type = current_struct->name + " struct";
       
   273 
       
   274             m_structStack.append(new StructData(current_struct));
       
   275         }
       
   276 
       
   277         if (EXTENSION("member"))
       
   278         {
       
   279             CONDITION(m_structStack.isEmpty(), "Member found outside of struct.");
       
   280 
       
   281             const int name_idx(indexOf(attributes, "name"));
       
   282             COND_DOC_ERROR(name_idx < 0, QString("Anonymous member found."));
       
   283             COND_DOC_ERROR(!hasType(attributes), QString("Member without a type found."));
       
   284 
       
   285             createEntry();
       
   286 
       
   287             m_currentEntry->section = Entry::VARIABLE_SEC;
       
   288             m_currentEntry->name = attributes.value(name_idx);
       
   289             m_currentEntry->type = getType(attributes);
       
   290 
       
   291             QString type(getDBusType(m_currentEntry->type));
       
   292             m_structStack.last()->type.append(type);
       
   293         }
       
   294 
       
   295         if (EXTENSION("enum") || EXTENSION("flagset"))
       
   296         {
       
   297             CONDITION(m_currentMethod, "Enum found inside a method or signal.");
       
   298             CONDITION(m_currentProperty, "Enum found inside a property.");
       
   299 
       
   300             const int name_idx(indexOf(attributes, "name"));
       
   301             COND_DOC_ERROR(name_idx < 0, QString("Anonymous enum found."));
       
   302 
       
   303             const int type_idx(indexOf(attributes, "type"));
       
   304             QString type = "u";
       
   305             if (type_idx >= 0)
       
   306             { type = attributes.value(type_idx); }
       
   307             if (type != "y" && type != "q" && type != "u" && type != "t")
       
   308             { DOC_ERROR(QString("Invalid enum type \"%1\" found.").arg(type)); }
       
   309 
       
   310             m_currentEnum = createEntry();
       
   311             m_currentEnum->section = Entry::ENUM_SEC;
       
   312             m_currentEnum->name = attributes.value(name_idx);
       
   313 
       
   314             openScopes(m_currentEnum);
       
   315 
       
   316             m_currentEnum->type = m_currentEntry->name + " enum";
       
   317 
       
   318             addNamedType(type);
       
   319         }
       
   320 
       
   321         if (EXTENSION("value"))
       
   322         {
       
   323             CONDITION(!m_currentEnum, "Value found outside an enum.");
       
   324 
       
   325             const int name_idx(indexOf(attributes, "name"));
       
   326             COND_DOC_ERROR(name_idx < 0, QString("Anonymous value found."));
       
   327 
       
   328             const int value_idx(indexOf(attributes, "value"));
       
   329 
       
   330             createEntry();
       
   331 
       
   332             m_currentEntry->section = Entry::VARIABLE_SEC;
       
   333             m_currentEntry->name = attributes.value(name_idx);
       
   334             m_currentEntry->type = m_currentEnum->name; // "@"; // enum marker!
       
   335             if (value_idx >= 0)
       
   336             { m_currentEntry->initializer = attributes.value(value_idx); }
       
   337         }
       
   338 
       
   339         return true;
       
   340     }
       
   341 
       
   342     bool endElement(const QString &namespaceURI,
       
   343                     const QString &localName,
       
   344                     const QString &qName)
       
   345     {
       
   346         // Clean up elements stack:
       
   347         // Since we made sure to get the elements in the proper order when
       
   348         // adding we do not need to do so again here.
       
   349         COND_DOC_ERROR(m_elementStack.last()->element != qName,
       
   350                        QString("Malformed XML: Unexpected closing element found.").
       
   351                        arg(m_elementStack.last()->element));
       
   352         m_elementStack.removeLast();
       
   353 
       
   354         // Interface:
       
   355         if (DBUS("interface"))
       
   356         {
       
   357             CONDITION(m_currentInterface, "end of interface found without start.");
       
   358             m_currentInterface->endBodyLine = lineNumber();
       
   359             closeScopes();
       
   360             m_currentInterface = 0;
       
   361         }
       
   362 
       
   363         if (DBUS("method") || DBUS("signal"))
       
   364         {
       
   365             CONDITION(m_currentMethod, "end of method found without start.");
       
   366             CONDITION(m_currentInterface, "end of method found outside interface.");
       
   367             m_currentMethod->endBodyLine = lineNumber();
       
   368             m_currentInterface->addSubEntry(m_currentMethod);
       
   369             m_currentMethod = 0;
       
   370         }
       
   371 
       
   372         if (DBUS("property"))
       
   373         {
       
   374             CONDITION(m_currentMethod, "end of property found without start.");
       
   375             CONDITION(m_currentInterface, "end of property found outside interface.");
       
   376             m_currentProperty->endBodyLine = lineNumber();
       
   377             m_currentInterface->addSubEntry(m_currentProperty);
       
   378             m_currentProperty = 0;
       
   379         }
       
   380 
       
   381         if (DBUS("arg"))
       
   382         {
       
   383             CONDITION(m_currentMethod, "end of arg found outside method.");
       
   384             m_currentMethod->argList->append(m_currentArgument);
       
   385             m_currentArgument = 0;
       
   386         }
       
   387 
       
   388         if (EXTENSION("namespace"))
       
   389         {
       
   390             Entry * current = m_namespaceStack.last();
       
   391             CONDITION(current, "end of namespace without start.");
       
   392             m_namespaceStack.removeLast();
       
   393 
       
   394             current->endBodyLine = lineNumber();
       
   395             closeScopes();
       
   396         }
       
   397 
       
   398         if (EXTENSION("struct"))
       
   399         {
       
   400             StructData * data = m_structStack.last();
       
   401             CONDITION(data, "end of struct without start.");
       
   402 
       
   403             data->entry->endBodyLine = lineNumber();
       
   404 
       
   405             QString current_type;
       
   406             current_type.append(QString("("));
       
   407             current_type.append(data->type);
       
   408             current_type.append(QString(")"));
       
   409 
       
   410             addNamedType(current_type);
       
   411 
       
   412             closeScopes();
       
   413 
       
   414             m_structStack.removeLast();
       
   415         }
       
   416 
       
   417         if (EXTENSION("member"))
       
   418         {
       
   419            StructData * data = m_structStack.last();
       
   420            CONDITION(data, "end of struct without start");
       
   421            data->entry->addSubEntry(m_currentEntry);
       
   422         }
       
   423 
       
   424         if (EXTENSION("enum") || EXTENSION("flagset"))
       
   425         {
       
   426             CONDITION(m_currentEnum, "end of enum without start");
       
   427             m_currentEnum->endBodyLine = lineNumber();
       
   428             closeScopes();
       
   429 
       
   430             m_currentEnum = 0;
       
   431         }
       
   432 
       
   433         if (EXTENSION("value"))
       
   434         {
       
   435             CONDITION(m_currentEntry, "end of value without start");
       
   436             m_currentEntry->endBodyLine = lineNumber();
       
   437 
       
   438             m_currentEnum->addSubEntry(m_currentEntry);
       
   439         }
       
   440 
       
   441         return true;
       
   442     }
       
   443 
       
   444     bool characters(const QString & /*chars*/)
       
   445     { return true; }
       
   446 
       
   447     bool comment(const QString & comment_)
       
   448     {
       
   449         if (m_currentComment)
       
   450         { handleComment(); }
       
   451 
       
   452         m_currentComment = new CommentData(m_fileName, lineNumber(), comment_);
       
   453 
       
   454         if (!m_currentComment->shouldIgnore)
       
   455         {
       
   456             delete m_currentComment;
       
   457             m_currentComment = 0;
       
   458             return true;
       
   459         }
       
   460 
       
   461         if (m_currentComment->associateWithPrevious)
       
   462         { handleComment(); }
       
   463 
       
   464         return true;
       
   465     }
       
   466 
       
   467     void handleComment()
       
   468     {
       
   469         if (m_currentComment == 0 || m_currentEntry == 0)
       
   470         { return; }
       
   471 
       
   472         QCString text(m_currentComment->text);
       
   473 
       
   474         m_currentEntry->docFile = m_currentComment->fileName;
       
   475         m_currentEntry->docLine = m_currentComment->line;
       
   476 
       
   477         int position(0);
       
   478         bool needs_entry(false);
       
   479         bool brief(false);
       
   480         Protection prot(Public);
       
   481         int lineNr = lineNumber();
       
   482 
       
   483         while (parseCommentBlock(m_parser,
       
   484                                  m_currentEntry,
       
   485                                  text, m_fileName.utf8().data(), 
       
   486                                  lineNr,
       
   487                                  brief, m_currentComment->isJavaStyle,
       
   488                                  false,
       
   489                                  prot,
       
   490                                  position,
       
   491                                  needs_entry))
       
   492         {
       
   493             if (needs_entry) { createEntry(); }
       
   494         }
       
   495         if (needs_entry) { createEntry(); }
       
   496 
       
   497         delete m_currentComment;
       
   498         m_currentComment = 0;
       
   499     }
       
   500 
       
   501     QXmlLocator * locator()
       
   502     { return &m_locator; }
       
   503 
       
   504     int lineNumber()
       
   505     { return m_locator.lineNumber(); }
       
   506 
       
   507     void setSection()
       
   508     {
       
   509         Entry * current = createEntry();
       
   510         current->reset();
       
   511 
       
   512         current->name    = m_fileName.utf8();
       
   513         current->section = Entry::SOURCE_SEC;
       
   514 
       
   515         // Open/Close the scope to do the bookkeeping:
       
   516         openScopes(current);
       
   517         closeScopes();
       
   518     }
       
   519 
       
   520 private:
       
   521     bool isDBusElement(const QString & namespaceURI,
       
   522                        const QString & localName,
       
   523                        const QString & qName,
       
   524                        const QString & element)
       
   525     {
       
   526         return (namespaceURI.isEmpty() && localName == element && qName == element) ||
       
   527                (namespaceURI.isEmpty() && localName.isEmpty() && qName == element);
       
   528     }
       
   529 
       
   530     bool isExtensionElement(const QString & namespaceURI,
       
   531                             const QString & localName,
       
   532                             const QString & qName,
       
   533                             const QString & element)
       
   534     {
       
   535         // isNull happens in startelement if no URI is used.
       
   536         if (namespaceURI.isNull())
       
   537         { return false; }
       
   538 
       
   539         // We are in a endElement: URI is always empty there:-(
       
   540         if (namespaceURI.isEmpty())
       
   541         { return qName == m_scopeStack.last()->extensionPrefix + element; }
       
   542 
       
   543         // startElemennt: We need to save the qName prefix
       
   544         // since endElement will forget about the namespaceURi:-(
       
   545         if (namespaceURI == EXTENSION_URI)
       
   546         {
       
   547             int pos = qName.find(':');
       
   548             m_scopeStack.last()->extensionPrefix = qName.left(pos + 1);
       
   549         }
       
   550 
       
   551         return namespaceURI == EXTENSION_URI && localName == element;
       
   552     }
       
   553 
       
   554     bool hasType(const QXmlAttributes & attributes)
       
   555     {
       
   556         const int type_idx(indexOf(attributes, "type"));
       
   557         const int named_type_idx(indexOf(attributes, "named-type"));
       
   558 
       
   559         return named_type_idx >= 0 || type_idx >= 0;
       
   560     }
       
   561 
       
   562     QString getType(const QXmlAttributes & attributes)
       
   563     {
       
   564         const int type_idx(indexOf(attributes, "type"));
       
   565         const int named_type_idx(indexOf(attributes, "named-type"));
       
   566 
       
   567         QString type;
       
   568 
       
   569         if (named_type_idx >= 0)
       
   570         {
       
   571             type = attributes.value(named_type_idx);
       
   572             if (!type.startsWith("::"))
       
   573             { type = getCurrentScope(attributes.value(named_type_idx)); }
       
   574             else
       
   575             { type = type.mid(2); }
       
   576             if (m_namedTypeMap.contains(type))
       
   577             {
       
   578                 if (type_idx >= 0)
       
   579                 {
       
   580                     const QString dbus_type(attributes.value(type_idx));
       
   581                     if (dbus_type != m_namedTypeMap[type])
       
   582                     {
       
   583                         DOC_ERROR(QString("Type \"%1\" does not match up with "
       
   584                                           "previous definition of named type \"%2\" (which was \"%3\".").
       
   585                                           arg(dbus_type).
       
   586                                           arg(type).
       
   587                                           arg(m_namedTypeMap[type]));
       
   588                     }
       
   589                 }
       
   590                 return type;
       
   591             }
       
   592 
       
   593             DOC_ERROR(QString("Undefined named type \"%1\" used.").arg(type));
       
   594         }
       
   595 
       
   596         if (type_idx >= 0)
       
   597         {
       
   598             type = attributes.value(type_idx);
       
   599 
       
   600             QRegExp reg_exp(QString("(a?[ybnqiuxdtsogv]|a[{]sv[}])"));
       
   601             if (reg_exp.match(type))
       
   602             { return type; }
       
   603 
       
   604             DOC_ERROR(QString("Unnamed complex D-Bus type \"%1\" found.").arg(type));
       
   605         }
       
   606 
       
   607         return QString();
       
   608     }
       
   609 
       
   610     QString getDBusType(const QString & type)
       
   611     {
       
   612         QString scoped_type = type;
       
   613         if (!scoped_type.contains("::"))
       
   614         { scoped_type = getCurrentScope(type); }
       
   615 
       
   616         if (m_namedTypeMap.contains(scoped_type))
       
   617         { return m_namedTypeMap[scoped_type]; }
       
   618         else
       
   619         { return type; }
       
   620     }
       
   621 
       
   622     void addNamedType(const QString type)
       
   623     {
       
   624         QString scoped_name(getCurrentScope());
       
   625 
       
   626         if (m_namedTypeMap.contains(scoped_name))
       
   627         {
       
   628             DOC_ERROR(QString("Named type \"%1\" is already defined.").arg(scoped_name));
       
   629             return;
       
   630         }
       
   631 
       
   632         m_namedTypeMap.insert(scoped_name, type);
       
   633     }
       
   634 
       
   635     QString getCurrentScope(const QString & type = QString())
       
   636     {
       
   637         QString scoped_name;
       
   638         if (!m_scopeStack.isEmpty())
       
   639         {
       
   640             scoped_name = m_scopeStack.last()->scope->name;
       
   641             scoped_name.append("::");
       
   642         }
       
   643         if (!type.isEmpty())
       
   644         { scoped_name.append(type); }
       
   645         else
       
   646         { scoped_name = scoped_name.left(scoped_name.length() - 2); }
       
   647 
       
   648         return scoped_name;
       
   649     }
       
   650 
       
   651     int indexOf(const QXmlAttributes & attributes, const QString & name,
       
   652                  const QString & type = "CDATA", const bool mandatory = true)
       
   653     {
       
   654         const int idx(attributes.index(name));
       
   655         if (idx < 0 || idx > attributes.length()) { return -1; }
       
   656         if (attributes.type(idx) != type) { return -1; }
       
   657         if (mandatory && attributes.value(idx).isEmpty()) { return -1; }
       
   658 
       
   659         return idx;
       
   660     }
       
   661 
       
   662     Entry * createEntry()
       
   663     {
       
   664         Entry * entry = new Entry();
       
   665 
       
   666         entry->protection = Public ;
       
   667         entry->virt       = Normal;
       
   668         entry->stat       = false;
       
   669         entry->objc       = false;
       
   670         entry->spec       = 0;
       
   671 
       
   672         entry->fileName  = m_fileName;
       
   673         entry->startLine = lineNumber();
       
   674         entry->bodyLine = lineNumber();
       
   675 
       
   676         entry->callGraph = false;
       
   677         entry->callerGraph = false;
       
   678 
       
   679         initGroupInfo(entry);
       
   680 
       
   681         m_currentEntry = entry;
       
   682 
       
   683         handleComment();
       
   684 
       
   685         return entry;
       
   686     }
       
   687 
       
   688     void openScopes(Entry * object)
       
   689     {
       
   690         int cur_scope_separator_pos = 0;
       
   691         int last_scope_separator_pos = 0;
       
   692         while (0 <= (cur_scope_separator_pos = object->name.find("::", last_scope_separator_pos)))
       
   693         {
       
   694             QString scope = object->name.mid(last_scope_separator_pos,
       
   695                                              cur_scope_separator_pos - last_scope_separator_pos);
       
   696             last_scope_separator_pos = cur_scope_separator_pos + 2;
       
   697 
       
   698             Entry * current_namespace = openNamespace(scope);
       
   699 
       
   700             if (!m_scopeStack.isEmpty())
       
   701             { m_scopeStack.last()->scope->addSubEntry(current_namespace); }
       
   702 
       
   703             m_scopeStack.append(new ScopeData(current_namespace, m_scopeCount));
       
   704         }
       
   705 
       
   706         QString scoped_name(getCurrentScope());
       
   707         if (!scoped_name.isEmpty())
       
   708         { scoped_name.append("::"); }
       
   709         scoped_name.append(object->name.mid(last_scope_separator_pos));
       
   710 
       
   711         object->name = scoped_name;
       
   712 
       
   713         if (!m_scopeStack.isEmpty())
       
   714         { m_scopeStack.last()->scope->addSubEntry(object); }
       
   715         m_scopeStack.append(new ScopeData(object, m_scopeCount));
       
   716 
       
   717         ++m_scopeCount;
       
   718     }
       
   719 
       
   720     Entry * openNamespace(const QString & name)
       
   721     {
       
   722         Entry * current_namespace = createEntry();
       
   723         QString scoped_name(getCurrentScope());
       
   724         if (!scoped_name.isEmpty())
       
   725         { scoped_name.append("::"); }
       
   726         scoped_name.append(name);
       
   727         current_namespace->name = scoped_name;
       
   728         current_namespace->section = Entry::NAMESPACE_SEC;
       
   729         current_namespace->type = "namespace" ;
       
   730 
       
   731         return current_namespace;
       
   732     }
       
   733 
       
   734     void closeScopes()
       
   735     {
       
   736         const int current_scope_count(m_scopeStack.last()->count);
       
   737 
       
   738         // Do not close the root scope.
       
   739         if (current_scope_count == 0)
       
   740         { return; }
       
   741 
       
   742         while (current_scope_count == m_scopeStack.last()->count)
       
   743         { m_scopeStack.removeLast(); }
       
   744     }
       
   745 
       
   746     ParserInterface * m_parser;
       
   747 
       
   748     QXmlLocator m_locator;
       
   749     QString m_currentNode; // Nodes can not be nested, no entry necessary.
       
   750 
       
   751     struct ElementData
       
   752     {
       
   753         ElementData(const QString & e) :
       
   754             element(e)
       
   755         { }
       
   756         ~ElementData() { }
       
   757 
       
   758         QString element; //*< The element name
       
   759         QString extensionPrefix; //*< The prefix used for our extension.
       
   760         QString text; //*< The actual xml code.
       
   761     };
       
   762     QList<ElementData> m_elementStack;
       
   763 
       
   764     Entry * m_currentEntry; // The currently open entry.
       
   765 
       
   766     Entry * m_currentInterface; // Interfaces can not be nested.
       
   767     Entry * m_currentMethod; // Methods can not be nested.
       
   768     Argument * m_currentArgument; // Arguments can not be nested.
       
   769     Entry * m_currentProperty; // Properties can not be nested.
       
   770     Entry * m_currentEnum; // Enums can not be nested.
       
   771     QList<Entry> m_namespaceStack;
       
   772 
       
   773     struct StructData
       
   774     {
       
   775         StructData(Entry * e) : entry(e) { }
       
   776         ~StructData() { }
       
   777 
       
   778         QString type;
       
   779         Entry * entry;
       
   780     };
       
   781     QList<StructData> m_structStack; // Structs can be nested.
       
   782 
       
   783     struct ScopeData
       
   784     {
       
   785         ScopeData(Entry * s, int c) :
       
   786             scope(s),
       
   787             count(c)
       
   788         { }
       
   789         ~ScopeData() { }
       
   790 
       
   791         Entry * scope;
       
   792         QString extensionPrefix;
       
   793         int count;
       
   794     };
       
   795     QList<ScopeData> m_scopeStack; // Scopes are nested.
       
   796 
       
   797     QString m_fileName;
       
   798 
       
   799     struct CommentData
       
   800     {
       
   801         CommentData(const QString & f, const int l, const QString & t) :
       
   802             isJavaStyle(false),
       
   803             isQtStyle(false),
       
   804             line(l),
       
   805             fileName(f)
       
   806         {
       
   807             isJavaStyle = t.startsWith(QChar('*'));
       
   808             isQtStyle = t.startsWith(QChar('!'));
       
   809             shouldIgnore = (!isJavaStyle && !isQtStyle);
       
   810             associateWithPrevious = (t.at(1) == QChar('<'));
       
   811             if (associateWithPrevious)
       
   812             { text = t.mid(2); }
       
   813             else
       
   814             { text = t.mid(1); }
       
   815         }
       
   816         ~CommentData() { }
       
   817 
       
   818         QString text;
       
   819         bool isJavaStyle;
       
   820         bool isQtStyle;
       
   821         bool shouldIgnore;
       
   822         bool associateWithPrevious;
       
   823         int line;
       
   824         QString fileName;
       
   825     };
       
   826     CommentData * m_currentComment;
       
   827 
       
   828     int m_scopeCount; //*< unique scope id.
       
   829 
       
   830     QString m_errorString;
       
   831 
       
   832     QMap<QString, QString> m_namedTypeMap;
       
   833 };
       
   834 
       
   835 // -----------------------------------------------------------------------
       
   836 // DBusXMLScanner
       
   837 // -----------------------------------------------------------------------
       
   838 
       
   839 DBusXMLScanner::DBusXMLScanner()
       
   840 { }
       
   841 
       
   842 DBusXMLScanner::~DBusXMLScanner()
       
   843 { }
       
   844 
       
   845 void DBusXMLScanner::parseInput(const char * fileName,
       
   846                                 const char * /* fileBuf */,
       
   847                                 Entry * root)
       
   848 {
       
   849     QFile inputFile(fileName);
       
   850 
       
   851     QXmlInputSource inputSource(inputFile);
       
   852     QXmlSimpleReader reader;
       
   853 
       
   854     DBusXMLHandler handler(this, &reader, fileName, root);
       
   855     reader.setContentHandler(&handler);
       
   856     reader.setErrorHandler(&handler);
       
   857     reader.setLexicalHandler(&handler);
       
   858 
       
   859     groupEnterFile(fileName, 1);
       
   860     handler.setSection();
       
   861     reader.parse(inputSource);
       
   862 
       
   863     if (handler.errorString())
       
   864     { err("DBus XML Parser: Error at line %d: %s\n", 
       
   865         handler.locator()->lineNumber(),handler.errorString().utf8().data()); }
       
   866 
       
   867     groupLeaveFile(fileName, 1);
       
   868 }
       
   869 
       
   870 bool DBusXMLScanner::needsPreprocessing(const QCString & /* extension */)
       
   871 { return (false); }
       
   872 
       
   873 void DBusXMLScanner::parseCode(CodeOutputInterface & /* codeOutIntf */,
       
   874                                const char * /* scopeName */,
       
   875                                const QCString & /* input */,
       
   876                                bool /* isExampleBlock */,
       
   877                                const char * /* exampleName */,
       
   878                                FileDef * /* fileDef */,
       
   879                                int /* startLine */,
       
   880                                int /* endLine */,
       
   881                                bool /* inlineFragment */,
       
   882                                MemberDef * /* memberDef */)
       
   883 { }
       
   884 
       
   885 void DBusXMLScanner::resetCodeParserState()
       
   886 { }
       
   887 
       
   888 void DBusXMLScanner::parsePrototype(const char * /* text */)
       
   889 { }