File:  [ELWIX - Embedded LightWeight unIX -] / gpl / axl / src / axl_doc.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Fri Feb 17 12:50:03 2012 UTC (12 years, 4 months ago) by misho
Branches: axl, MAIN
CVS tags: HEAD, AXL0_6_7
version 0.6.7

    1: /*
    2:  *  LibAxl:  Another XML library
    3:  *  Copyright (C) 2006 Advanced Software Production Line, S.L.
    4:  *
    5:  *  This program is free software; you can redistribute it and/or
    6:  *  modify it under the terms of the GNU Lesser General Public License
    7:  *  as published by the Free Software Foundation; either version 2.1 of
    8:  *  the License, or (at your option) any later version.
    9:  *
   10:  *  This program is distributed in the hope that it will be useful,
   11:  *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
   12:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
   13:  *  GNU Lesser General Public License for more details.
   14:  *
   15:  *  You should have received a copy of the GNU Lesser General Public
   16:  *  License along with this program; if not, write to the Free
   17:  *  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   18:  *  02111-1307 USA
   19:  *  
   20:  *  You may find a copy of the license under this software is released
   21:  *  at COPYING file. This is LGPL software: you are welcome to
   22:  *  develop proprietary applications using this library without any
   23:  *  royalty or fee but returning back any change, improvement or
   24:  *  addition in the form of source code, project image, documentation
   25:  *  patches, etc. 
   26:  *
   27:  *  For commercial support on build XML enabled solutions contact us:
   28:  *          
   29:  *      Postal address:
   30:  *         Advanced Software Production Line, S.L.
   31:  *         Edificio Alius A, Oficina 102,
   32:  *         C/ Antonio Suarez Nº 10,
   33:  *         Alcalá de Henares 28802 Madrid
   34:  *         Spain
   35:  *
   36:  *      Email address:
   37:  *         info@aspl.es - http://www.aspl.es/xml
   38:  */
   39: 
   40: /**
   41:  * @internal
   42:  * @brief XML 1.0 Third edition grammar
   43:  *
   44:  * [1]  document       ::=   prolog element Misc*
   45:  * [1]  status: partially
   46:  *
   47:  * [2]  Char           ::=   \x9 | \xA | \xD | \x20-\xD7FF | \xE000-\xFFFD | \x10000-\10FFFF
   48:  * [2]  status: not implemented 
   49:  *
   50:  * [3]  S              ::= ( \x20 | \x9 | \xD | \xA)
   51:  * [3]  status: ok
   52:  *
   53:  * [4]  NameChar       ::=   Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender
   54:  * [4]  status: not implemented
   55:  *
   56:  * [5]  Name           ::= ( Letter | '_' | ':' |) ( NameChar )*
   57:  * [5]  status: not implemented
   58:  *
   59:  * [6]  Names          ::=   Name ( \x20 Name )*
   60:  * [6]  status: not implemented
   61:  *
   62:  * [7]  Nmtoken        ::= ( NameChar ) +
   63:  * [7]  status: not implemented
   64:  *
   65:  * [8]  Nmtokens       ::=   Nmtoken (\x20 Nmtoken)*
   66:  * [8]  status: not implemented
   67:  *
   68:  * [9]  EntityValue    ::=   '"' ( [^%&"] | PEReference | Reference )* '"' | "'" ( [^%&'] ! PEReference | Reference )* "'"
   69:  * [9]  status: not implemented
   70:  *
   71:  * [10] AttValue       ::=   '"' ( [^<&"] | Reference)*  '"' | "'" ( [^<&'] | Reference )* "'"
   72:  * [10]  status: not implemented
   73:  *
   74:  * [11] SystemLiteral  ::= ( '"' [^"]* '"') | ("'" [^']* "'")
   75:  * [11]  status: not implemented
   76:  *
   77:  * [12] PubidLiteral   ::=   '"' PubidChar* '"' | "'" (PubidChar - "'") * "'"
   78:  * [12]  status: not implemented
   79:  *
   80:  * [13] PubidChar      ::=   \x20 | \xD | \xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%]
   81:  * [13]  status: not implemented
   82:  *
   83:  * [14] CharData       ::=   [^<&]* - ([^<&]* ']]>' [^<&]*)
   84:  * [14]  status: not implemented
   85:  *
   86:  * [15] Comments       ::=   '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
   87:  * [15]  status: not implemented
   88:  *
   89:  * [16] PI             ::=   '<?' PITarget (S (Char* - (Char* '?<' Char*)))? '?>'
   90:  * [16]  status: not implemented
   91:  *
   92:  * [17] PITarget       ::=   Name - (('X' | 'x') ('M' | 'm') | ('L' | 'l'))
   93:  * [17]  status: not implemented
   94:  *
   95:  * [18] CDsect         ::=   CDStart CData CDend
   96:  * [18]  status: not implemented
   97:  *
   98:  * [19] CDStart        ::=   '<![CDATA['
   99:  * [19]  status: not implemented
  100:  *
  101:  * [20] CData          ::=   (Char* - (Char* ']]>' Char*))
  102:  * [20]  status: not implemented
  103:  *
  104:  * [21] CDEnd          ::=   ']]>'
  105:  * [21]  status: not implemented
  106:  *
  107:  * [22] prolog         ::=   XMLDecl? Misc* (doctypedecl Misc*)?
  108:  * [22]  status: partially
  109:  *
  110:  * [23] XMLDecl        ::=   '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
  111:  * [23]  status: ok
  112:  *
  113:  * [24] VersionInfo    ::=   S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"')
  114:  * [24]  status: ok
  115:  *
  116:  * [25] Eq             ::=   S? '=' S?
  117:  * [25]  status: ok
  118:  *
  119:  * [26] VersionNum     ::=   '1.0'
  120:  * [26]  status: ok
  121:  *
  122:  * [27] Misc           ::=   Comment | PI | S
  123:  * [27]  status: not implemented
  124:  *
  125:  * [28] doctypedecl    ::=   '<!DOCTYPE' S Name (S ExternalID)? S? ('[' intSubsect ']' S?)? '>'
  126:  * [28]  status: not implemented
  127:  *
  128:  * [28a] DeclSep       ::=   PEReference | S
  129:  * [28a]  status: not implemented
  130:  *
  131:  * [28b] intSubset     ::=   (markupdecl | DeclSep)*
  132:  * [28b]  status: not implemented
  133:  *
  134:  * [29] markupdecl     ::=   elementdecl | AttlistDecl | EntityDecl | NotationDecl | PI | Comment
  135:  * [29]  status: not implemented
  136:  *
  137:  * [30] extSubset      ::=   TextDecl? extSubsetDecl
  138:  * [30]  status: not implemented
  139:  *
  140:  * [31] extSubsetDecl  ::=   ( markupdecl | conditionalSect | DeclSep) *
  141:  * [31]  status: not implemented
  142:  *
  143:  * [32] SDDecl          ::=   S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"'" ('yes' | 'no') '"'))
  144:  * [32]  status: ok
  145:  *
  146:  * 
  147:  * ** productions 33 through 39 have been removed. It seems that this
  148:  * ** productions were supporting xml:lang stuff that is easily
  149:  * ** supported by using directily the xml standard rather than
  150:  * ** mention it as an special production inside the language.
  151:  *  
  152:  * [39] element        ::=   EmptyElemTag | Stag content ETag
  153:  * [39]  status: not implemented
  154:  *
  155:  * [40] Stag           ::=   '<' Name (S Attribute)* S? '>'
  156:  * [40]  status: not implemented
  157:  *
  158:  * [41] Attribute      ::=   Name Eq AttValue
  159:  * [41]  status: not implemented
  160:  *
  161:  * [42] ETag           ::=   '</' Name S? '>'
  162:  * [42]  status: not implemented
  163:  *
  164:  * [43] content        ::=   CharData? ((element | Reference | CDSect | PI | Comment) CharData?)*
  165:  * [43]  status: not implemented
  166:  *
  167:  * [44] EmptyElemTag   ::=   '<' Name (S Attribute)* S? '/>'
  168:  * [44]  status: not implemented
  169:  *
  170:  * [45] elementdecl    ::=   '<!ELEMENT' S Name S contentspec S? '>' 
  171:  * [45]  status: not implemented
  172:  *
  173:  * [46] contentspec    ::=   'EMPTY' | 'ANY' | Mixed | children
  174:  * [46]  status: not implemented
  175:  *
  176:  * [47] children       ::=   (choice | seq) ('?' | '*' | '+')? 
  177:  * [47]  status: not implemented
  178:  *
  179:  * [48] cp             ::=   (Name | choice | seq) ('?' | '*' | '+')? 
  180:  * [48]  status: not implemented
  181:  *
  182:  * [49] choice         ::=   '(' S? cp ( S? '|' S? cp)+ S? ')'
  183:  * [49]  status: not implemented
  184:  *
  185:  * [50] seq            ::=   '(' S? cp ( S? ',' S? cp )* S? ')'
  186:  * [50]  status: not implemented
  187:  *
  188:  * [51] Mixed          ::=   '(' '#PCDATA' (S? '|' S? Name)* S? ')*' | '(' S? '#PCDATA' S? ')'
  189:  * [51]  status: not implemented
  190:  *
  191:  * [52] AttlistDecl    ::=   '<!ATTLIST' S Name AttDef* S? '>'
  192:  * [52]  status: not implemented
  193:  *
  194:  * [53] AttDef         ::=   S Name S AttType S DefaultDecl
  195:  * [53]  status: not implemented
  196:  *
  197:  * [54] AttType        ::=   Stringtype | TokenizedType | Enumeratedtype
  198:  * [54]  status: not implemented
  199:  *
  200:  * [55] StringType     ::=   'CDATA'
  201:  * [55]  status: not implemented
  202:  *
  203:  * [56] tokenized      ::=   'ID' | 'IDREF' | 'IDREFS' | 'ENTITY' | 'ENTITIES' | 'NMTOKEN' | 'NMTOKENS'
  204:  * [56]  status: not implemented
  205:  *
  206:  * [57] EnumeratedType ::=   NotationType | Enumeration
  207:  * [57]  status: not implemented
  208:  *
  209:  * [58] NotationType   ::=   'NOTATION' S '(' S? Name (S? Name (S? '|' S? Name)* S? ')'
  210:  * [58]  status: not implemented
  211:  *
  212:  * [59] Enumeration    ::=   '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
  213:  * [59]  status: not implemented
  214:  *
  215:  * [60] DefaultDecl    ::=   '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
  216:  * [60]  status: not implemented
  217:  *
  218:  * [61] conditionalSect  ::= includeSect | ignoreSect
  219:  * [61]  status: not implemented
  220:  *
  221:  * [62] includeSect    ::= '<![' S? 'INCLUDE S? '[' extSubsetDecl ']]>'
  222:  * [62]  status: not implemented
  223:  *
  224:  * [63] ignoreSect     ::=  <![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>'
  225:  * [63]  status: not implemented
  226:  *
  227:  * [64] ignoreSectContents ::=  Ignore ('<![' ignoreSectContents ']]>' Ignore) *
  228:  * [64]  status: not implemented
  229:  *
  230:  * [65] Ignore         ::=  Char * - (Char * ('<!' | ']]>') Char *)
  231:  * [65]  status: not implemented
  232:  *
  233:  * [66] CharRef        ::=  '&#' [0-9]+ ';' | '&#x' [0-9a-FA-F]+ ';'
  234:  * [66]  status: not implemented
  235:  *
  236:  * [67] Reference      ::=  EntityRef | CharRef
  237:  * [67]  status: not implemented
  238:  *
  239:  * [68] EntityRef      ::=  '&' Name ';'
  240:  * [68]  status: not implemented
  241:  *
  242:  * [69] PEReference    ::=  '%' Name ';'
  243:  * [69]  status: not implemented
  244:  *
  245:  * [70] EntityDecl     ::=  GEDecl | PEDecl
  246:  * [70]  status: not implemented
  247:  *
  248:  * [71] GEDecl         ::=  '<!ENTITY' S Name S EntityDef S? '>'
  249:  * [71]  status: not implemented
  250:  *
  251:  * [72] PEDecl         ::=  '<!ENTITY' S '%' S Name S PEDef S? '>'
  252:  * [72]  status: not implemented
  253:  *
  254:  * [73] EntityDef      ::=  EntityValue | (ExternalID NDataDecl?)
  255:  * [73]  status: not implemented
  256:  *
  257:  * [74] PEDef          ::=  EntityValue | ExternalID
  258:  * [74]  status: not implemented
  259:  *
  260:  * [75] ExternalID     ::=  'SYSTEM' S SystemLiteral | 'PUBLIC' S PubidLiteral S SystemLiteral
  261:  * [75]  status: not implemented
  262:  *
  263:  * [76] NDataDecl      ::=  S 'NData' S Name
  264:  * [76]  status: not implemented
  265:  *
  266:  * [77] TextDecl       ::=  '<?xml' VersionInfo? EncodingDecl S? '?>'
  267:  * [77]  status: not implemented
  268:  *
  269:  * [78] extParseEnt    ::=  TextDecl? content
  270:  * [78]  status: not implemented
  271:  *
  272:  * [80] EncodingDecl   ::=  S 'encoding' Eq ( '"' EncName '"' | "'" EncName "'" )
  273:  * [80]  status: ok
  274:  *
  275:  * [81] EncName        ::=  [A-Za-z] ([A-Za-z0-9._] | '-')*
  276:  * [81]  status: ok
  277:  *
  278:  * [82] NotationalDecl ::=  '<!NOTATION' S Name S (ExternalID | PublicID) S? '>' 
  279:  * [82]  status: not implemented
  280:  *
  281:  * [83] PublicID       ::=  'PUBLIC' S PubidLiteral
  282:  * [83]  status: not implemented
  283:  *
  284:  * 
  285:  * 
  286:  * 
  287:  */
  288: 
  289: /**
  290:  * \defgroup axl_doc_module Axl Doc: XML Documents related functions, loading XML documents and using them.
  291:  */
  292: 
  293: /** 
  294:  * \addtogroup axl_doc_module
  295:  * @{
  296:  */
  297: 
  298: #include <axl.h>
  299: #include <sys/stat.h>
  300: #include <sys/types.h>
  301: #include <fcntl.h>
  302: 
  303: 
  304: #define LOG_DOMAIN "axl-doc"
  305: 
  306: struct _axlDoc {
  307: 	/** 
  308: 	 * @internal
  309: 	 * @brief A reference to the very first axlNode this axlDoc
  310: 	 * has. 
  311: 	 */
  312: 	axlNode * rootNode;
  313: 
  314: 	/** 
  315: 	 * @internal
  316: 	 * The document version.
  317: 	 */
  318: 	char * version;
  319: 
  320: 	/** 
  321: 	 * @internal
  322: 	 * @brief Current xml encoding document.
  323: 	 */
  324: 	char        * encoding;
  325: 	/**
  326: 	 * @internal
  327: 	 * @brief Current entity encoding detected.
  328: 	 */ 
  329: 	const char  * detected_encoding;
  330: 	
  331: 	/** 
  332: 	 * @internal If the document was found in a different encoding
  333: 	 * than utf-8, this variable will hold its associated value to
  334: 	 * allow returning to the original encoding.
  335: 	 */
  336: 	char        * encoding_found;
  337: 	
  338: 	/** 
  339: 	 * @internal
  340: 	 * @brief Current standalone configuration of the given \ref
  341: 	 * axlDoc object.
  342: 	 */
  343: 	axl_bool    standalone;
  344: 
  345: 	/** 
  346: 	 * @internal
  347: 	 *
  348: 	 * @brief Parent node stack. This stack is used to control how
  349: 	 * are nested nodes while creating/parsing xml files. This
  350: 	 * nesting allows to not only properly contruct the xml but
  351: 	 * also to check if it is well balanced.
  352: 	 */
  353: 	axlStack  * parentNode;
  354: 
  355: 	/** 
  356: 	 * @internal Binary stack to hold the xml:space preserve
  357: 	 * status on each level (associated to the current node).
  358: 	 */
  359: 	axlBinaryStack * xmlPreserve;
  360: 
  361: 	/** 
  362: 	 * @internal
  363: 	 * 
  364: 	 * @brief Internal list to hold all PI targets readed.
  365: 	 */
  366: 	axlList   * piTargets;
  367: 
  368: 	/** 
  369: 	 * @internal
  370: 	 *
  371: 	 * @brief Instruct the \ref axlDoc instance to notify that the
  372: 	 * xml header have been defined. This helps to allow define PI
  373: 	 * instruction that are only found inside the root document,
  374: 	 * or after the xml header definition.
  375: 	 */
  376: 	axl_bool    headerProcess;
  377: 
  378: 	/** 
  379: 	 * @internal Factory to create items in a memory efficient
  380: 	 * manner.
  381: 	 */
  382: 	axlFactory * item_factory;
  383: 
  384: 	/** 
  385: 	 * @internal Factory to create nodes in a memory efficient
  386: 	 * manner.
  387: 	 */
  388: 	axlFactory    * node_factory;
  389: 
  390: 	/** 
  391: 	 * @internal Factory to create nodes to hold content elements.
  392: 	 */
  393: 	axlFactory    * content_factory;
  394: 
  395: 	/** 
  396: 	 * @internal Factory to create nodes to hold attribute
  397: 	 * elements.
  398: 	 */
  399: 	axlFactory    * attr_factory;
  400: 
  401: 	/** 
  402: 	 * @internal Factory to alloc strings.
  403: 	 */
  404: 	axlStrFactory * str_factory;
  405: };
  406: 
  407: struct _axlPI {
  408: 	/** 
  409: 	 * @internal
  410: 	 * 
  411: 	 * @brief PI Target name.
  412: 	 */
  413: 	char * name;
  414: 	/** 
  415: 	 * @internal
  416: 	 * 
  417: 	 * @brief PI target content.
  418: 	 */
  419: 	char * content;
  420: };
  421: 
  422: /* global references to handlers and user defined configuration */
  423: axlDocDetectCodification detect_codification_func;
  424: axlPointer               detect_codification_data;
  425: 
  426: axlDocConfigureCodification configure_codification_func;
  427: axlPointer                  configure_codification_data;
  428: 
  429: /** 
  430:  * @internal
  431:  *
  432:  * @brief Creates a new empty \ref axlDoc reference.
  433:  *
  434:  * Creates the parent stack used for parsing functions.
  435:  * 
  436:  * @return A newly allocated \ref axlDoc reference.
  437:  */
  438: axlDoc * __axl_doc_new (axl_bool create_parent_stack) 
  439: {
  440: 	axlDoc    * result = axl_new (axlDoc, 1);
  441: 
  442: 	/* check allocated value */
  443: 	if (result == NULL)
  444: 		return NULL;
  445: 
  446: 	/* default container lists */
  447: 	result->parentNode   = axl_stack_new (NULL);
  448: 	result->piTargets    = axl_list_new (axl_list_always_return_1, (axlDestroyFunc) axl_pi_free);
  449: 	result->xmlPreserve  = axl_binary_stack_new ();
  450: 
  451: 	/* create factories */
  452: 	result->item_factory    = axl_item_factory_create ();
  453: 	result->node_factory    = axl_node_factory_create ();
  454: 	result->content_factory = axl_item_content_factory_create ();
  455: 	result->attr_factory    = axl_item_attr_factory_create ();
  456: 	result->str_factory     = axl_string_factory_create ();
  457: 
  458: 	/* check memory allocation problem */
  459: 	if (result->parentNode      == NULL || 
  460: 	    result->piTargets       == NULL || 
  461: 	    result->xmlPreserve     == NULL || 
  462: 	    result->item_factory    == NULL || 
  463: 	    result->node_factory    == NULL ||
  464: 	    result->content_factory == NULL ||
  465: 	    result->attr_factory    == NULL ||
  466: 	    result->str_factory     == NULL) {
  467: 		axl_doc_free (result);
  468: 		return NULL;
  469: 	}
  470: 
  471: 	return result;
  472: }
  473: 
  474: /** 
  475:  * @internal
  476:  *
  477:  * Clears internal axlDoc variables used mainly to parse documents.
  478:  * 
  479:  * @param doc The \ref axlDoc to clear
  480:  */
  481: void __axl_doc_clean (axlDoc * doc)
  482: {
  483: 	/* release memory used by the parser */
  484: 	if (doc->parentNode != NULL) {
  485: 		axl_stack_free (doc->parentNode);
  486: 		doc->parentNode = NULL;
  487: 	}
  488: 
  489: 	return;
  490: }
  491: 
  492: /** 
  493:  * @internal Function used by the axl doc module to allocate memory to
  494:  * be used by the axl stream. Currently this is used to alloc xml node
  495:  * names and xml attribute key and its value. The rest of items are
  496:  * allocated by the system memory allocation.
  497:  * 
  498:  * @param size The size that is required by the axl stream to be allocated.
  499:  *
  500:  * @param doc The axlDoc reference, which contains a reference to the
  501:  * string factory used to allocate memory.
  502:  * 
  503:  * @return A reference to the allocated memory. 
  504:  */
  505: char * __axl_doc_alloc (int size, axlDoc * doc)
  506: {
  507: 	/* just return a piece of memory */
  508: 	return axl_string_factory_alloc (doc->str_factory, size);
  509: }
  510: 
  511: /** 
  512:  * @internal Internal function that tries to check encoding found to
  513:  * configure the proper set of functions to translate from and to
  514:  * utf-8.
  515:  * 
  516:  * @param doc The document being configured.
  517:  *
  518:  * @param error An optional error that will be filled in the case an
  519:  * error is found.
  520:  * 
  521:  * @return axl_true if the operation was completed, otherwise axl_false is
  522:  * returned.
  523:  */
  524: axl_bool axl_doc_configure_encoding (axlDoc * doc, axlStream * stream, axlError ** error)
  525: {
  526: 	char     * encoding = NULL;
  527: 	axl_bool   result;
  528: 	
  529: 	/* normalize encoding found */
  530: 	if (doc->encoding) {
  531: 		/* copy encoding */
  532: 		encoding = axl_strdup (doc->encoding);
  533: 
  534: 		/* trim encoding */
  535: 		axl_stream_trim (encoding);
  536: 
  537: 		/* remove characters not required */
  538: 		axl_stream_remove (encoding, "-", axl_false);
  539: 		axl_stream_remove (encoding, "_", axl_false); 
  540: 
  541: 		/* make it lower case */
  542: 		axl_stream_to_lower (encoding);
  543: 		
  544: 	} /* end if */
  545: 	
  546: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "configuring final document enconding, previously detected=%s, declared=%s",
  547: 		   doc->detected_encoding ? doc->detected_encoding : "none",
  548: 		   encoding ? encoding : "none");
  549: 
  550: 	/* do not perform any configuration if nothing is defined */
  551: 	if (! configure_codification_func) {
  552: 		axl_free (encoding);
  553: 		return axl_true;
  554: 	}
  555: 
  556: 	/* call to configure encoding */
  557: 	result = configure_codification_func (stream, encoding, doc->detected_encoding, configure_codification_data, error);
  558: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "result from configure encoding function=%d", result);
  559: 
  560: 	if (result) {
  561: 		/* encoding was fine, that means we are working in
  562: 		 * utf-8, udate document internals to move encoding to
  563: 		 * utf-8 */
  564: 		doc->encoding_found = encoding;
  565: 		encoding            = NULL;
  566: 
  567: 		/* reset encoding found to the new value */
  568: 		if (doc->encoding)
  569: 			axl_free (doc->encoding);
  570: 		doc->encoding       = axl_strdup ("utf-8");
  571: 	}
  572: 	axl_free (encoding);
  573: 
  574: 	return result;
  575: }
  576: 
  577: /** 
  578:  * @internal
  579:  * 
  580:  * @brief Support for parsing the xml entity header 
  581:  * 
  582:  * @param stream The axlStream where is expected to receive the xml
  583:  * header
  584:  *
  585:  * @param doc The axlDoc where the header configuration will be
  586:  * placed.
  587:  *
  588:  * @param error An optional error that will be filled in the case an
  589:  * error is found.
  590:  *
  591:  * @return It is supposed that the function return \ref axl_true, an
  592:  * not deallocation is performed, and all elements were parsed
  593:  * properly. In the case \ref axl_false is returned, memory associated
  594:  * with the given stream will be released. If the document is
  595:  * associated, it will also be released.
  596:  */
  597: axl_bool __axl_doc_parse_xml_header (axlStream * stream, axlDoc * doc, axlError ** error)
  598: {
  599: 	char      * string_aux;
  600: 	int         size;
  601: 
  602: 	/* check if the user is defining the header many times */
  603: 	if (doc->headerProcess) {
  604: 		axl_error_new (-1, "Found a new xml header expecification. Only one header is allowed for each xml document.", stream, error);
  605: 		axl_stream_free (stream);
  606: 		return axl_false;
  607: 	}
  608: 
  609: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "looking for an xml header declaration");
  610: 
  611: 	/* check for initial XMLDec (production 23) */
  612: 	if (axl_stream_inspect (stream, "<?", 2)) {
  613: 		
  614: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found xml declaration");
  615: 
  616: 		/* check initial <?xml xml header */
  617: 		if (! (axl_stream_inspect (stream, "xml", 3) > 0)) {
  618: 			axl_error_new (-2, "expected initial <?xml declaration, not found.", stream, error);
  619: 			axl_stream_free (stream);
  620: 			return axl_false;
  621: 		}
  622: 		
  623: 		/* consume spaces */
  624: 		AXL_CONSUME_SPACES (stream);
  625: 
  626: 		if (! axl_stream_inspect (stream, "version=", 8)) {
  627: 			axl_error_new (-2, "expected to find 'version=' declaration, not found.", stream, error);
  628: 			axl_stream_free (stream);
  629: 			return axl_false;
  630: 		}
  631: 
  632: 		/* consume spaces */
  633: 		AXL_CONSUME_SPACES (stream);
  634: 
  635: 		/* check for " or ' */
  636: 		if (! axl_stream_inspect_several (stream, 2, "\"1.0\"", 5, "'1.0'", 5)) {
  637: 			axl_error_new (-2, "expected to find either \" or ' while procesing version number, not found.", stream, error);
  638: 			axl_stream_free (stream);
  639: 			return axl_false;
  640: 		}
  641: 
  642: 		/* check for an space */
  643: 		AXL_CONSUME_SPACES(stream);
  644: 
  645: 		/* now check for encoding */
  646: 		if (axl_stream_inspect_several (stream, 2, "encoding=\"", 10, "encoding='", 10) > 0) {
  647: 
  648: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found encoding declaration");
  649: 
  650: 			/* found encoding instruction */
  651: 			string_aux = axl_stream_get_until (stream, NULL, NULL, axl_true, 2, "'", "\"");
  652: 			if (string_aux == NULL) {
  653: 				axl_error_new (-2, "expected encoding value, not found.", stream, error);
  654: 				axl_stream_free (stream);
  655: 				return axl_false;
  656: 			}
  657: 
  658: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "encoding found=%s", string_aux);
  659: 
  660: 			/* set document encoding: do not allocate
  661: 			 * twice the string returned, just nullify
  662: 			 * stream internal reference and use the same
  663: 			 * reference */
  664: 			axl_stream_nullify (stream, LAST_CHUNK);
  665: 			doc->encoding = string_aux;
  666: 
  667: 		}
  668: 
  669: 		/* check for an space */
  670: 		AXL_CONSUME_SPACES(stream);
  671: 
  672: 		/* get standalone configuration */
  673: 		if ((axl_stream_inspect_several (stream, 2, "standalone=\"", 12, "standalone='", 12) > 0)) {
  674: 			
  675: 			/* found standalone instruction */
  676: 			string_aux = axl_stream_get_until (stream, NULL, NULL, axl_true, 2, "'", "\"");
  677: 			if (string_aux == NULL) {
  678: 				axl_error_new (-2, "expected to receive standalone value, not found.", stream, error);
  679: 				axl_stream_free (stream);
  680: 				return axl_false;
  681: 			}
  682: 
  683: 			/* set standalone configuration */
  684: 			if (memcmp ("yes", string_aux, 3))
  685: 				doc->standalone = axl_false;
  686: 			else
  687: 				doc->standalone = axl_true;
  688: 		}
  689: 		
  690: 		/* check for an space */
  691: 		AXL_CONSUME_SPACES(stream);
  692: 
  693: 		/* get the trailing header */
  694: 		if (! (axl_stream_inspect (stream, "?>", 2) > 0)) {
  695: 			axl_error_new (-2, "expected to receive the xml trailing header ?>, not found.", stream, error);
  696: 			axl_stream_free (stream);
  697: 			return axl_false;
  698: 		}
  699: 
  700: 		/* consume a possible comment */
  701: 		if (! axl_doc_consume_comments (doc, stream, error))
  702: 			return axl_false;
  703: 	}
  704: 
  705: 	/* configure encoding again, now we could have more data */
  706: 	if (! axl_doc_configure_encoding (doc, stream, error)) {
  707: 		axl_stream_free (stream);
  708: 		return axl_false;
  709: 	}
  710: 
  711: 	/* now process the document type declaration */
  712: 	if (axl_stream_inspect (stream, "<!DOCTYPE", 9) > 0) {
  713: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found doc type declaration..");
  714: 		/* found document type declaration, just skip it for
  715: 		 * now */
  716: 		axl_stream_get_until_ref (stream, NULL, NULL, axl_true, &size, 1, ">");
  717: 
  718: 		/* consume a possible comment */
  719: 		if (! axl_doc_consume_comments (doc, stream, error))
  720: 			return axl_false;
  721: 	}
  722: 
  723: 	/* return AXL_TRUE value */
  724: 	return axl_true;
  725: }
  726: 
  727: /** 
  728:  * @internal
  729:  *
  730:  * @brief Tries to parse the first (and compulsory) node that the xml
  731:  * document must have.
  732:  *
  733:  * The very minimal expresion of an xml document is the one defined by
  734:  * only one node, with no content and no attributes. This minimal xml
  735:  * could be defined as:
  736:  *
  737:  * \code
  738:  *   <hello/>
  739:  * \endcode
  740:  *
  741:  * Or the other form accepted:
  742:  *
  743:  * \code
  744:  *   <hello />
  745:  * \endcode
  746:  *
  747:  * 
  748:  * 
  749:  * 
  750:  * @param stream The \ref axlStream object where is expected to find
  751:  * the xml node content.
  752:  *
  753:  * @param doc The \ref axlDoc object where node read will be placed
  754:  * inside.
  755:  * 
  756:  * @param node The node that has been added due to calling to this
  757:  * function.
  758:  *
  759:  * @param error An optional error reporting variable to used to report
  760:  * upper level the error found.
  761:  * 
  762:  * @return axl_true if the first node was successfully parsed or
  763:  * axl_false if not. If the function find something wrong the document
  764:  * is unrefered.
  765:  */
  766: axl_bool __axl_doc_parse_node (axlStream   * stream, 
  767: 			       axlDoc      * doc, 
  768: 			       axlNode    ** calling_node, 
  769: 			       axl_bool    * is_empty, 
  770: 			       axlError   ** error)
  771: {
  772: 	char    * string_aux;
  773: 	char    * string_aux2;
  774: 	axlNode * node;
  775: 	int       matched_chunk;
  776: 	int       length;
  777: 	axl_bool  delim;
  778: 	
  779: 	/* consume a possible comment */
  780: 	if (! axl_doc_consume_comments (doc, stream, error))
  781: 		return axl_false;
  782: 
  783: 	/* check for initial < definition */
  784: 	if (! (axl_stream_inspect (stream, "<", 1) > 0)  && ! axl_stream_remains (stream)) {
  785: 		/* check if we are reading the first node node */
  786: 		if (doc->rootNode == NULL)
  787: 			axl_error_new (-2, "expected initial < for a root node definition, not found. An xml document must have, at least, one node definition.", 
  788: 				       stream, error);
  789: 		else
  790: 			axl_error_new (-2, "expected initial < for a node definition, not found.", stream, error);
  791: 		axl_stream_free (stream);
  792: 		return axl_false;
  793: 	}
  794: 
  795: 	/* get node name, keeping in mind the following:
  796: 	 * chunk_matched
  797: 	 * >  : 0
  798: 	 * /> : 1
  799: 	 * " ": 2
  800: 	 *
  801: 	 * We also reconfigure the alloc method used by the axl stream
  802: 	 * to ensure that the module name is allocated through the
  803: 	 * string factory.
  804: 	 */
  805: 	axl_stream_set_buffer_alloc (stream, (axlStreamAlloc)__axl_doc_alloc, doc);
  806: 	string_aux = axl_stream_get_until (stream, NULL, &matched_chunk, axl_true, 2, ">", " ");
  807: 
  808: 	/* nullify */
  809: 	axl_stream_nullify (stream, LAST_CHUNK);
  810: 
  811: 	if (AXL_IS_STR_EMPTY (string_aux)) {
  812: 		/* use alloc though string factory */
  813: 		axl_stream_set_buffer_alloc (stream, NULL, NULL);
  814: 
  815: 		axl_error_new (-2, "expected an non empty content for the node name not found.", stream, error);
  816: 		axl_stream_free (stream);
  817: 		return axl_false;
  818: 	}
  819: 	
  820: 	/* if found a '/', it is matched as 1 */
  821: 	if (matched_chunk == 1)
  822: 		matched_chunk = 2;
  823: 	else {
  824: 		/* get the string length */
  825: 		length = strlen (string_aux);
  826: 
  827: 		/* if matched / it means that it was readed />, remove
  828: 		 * it and all white spaces */
  829: 		if (string_aux[length - 1] == '/') {
  830: 			/* flag as matched /> */
  831: 			matched_chunk          = 1;
  832: 			string_aux[length - 1] = 0;
  833: 		} /* end if */
  834: 	} /* end if */
  835: 
  836: 	/* create the node and associate it the node name found */
  837: 	node = axl_node_factory_get (doc->node_factory);
  838: 	axl_node_set_name_from_factory (node, string_aux); 
  839: 
  840: 	if (doc->rootNode == NULL) {
  841: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "setting as first node found, the root node: <%s>", string_aux);
  842: 
  843: 		doc->rootNode  = node;
  844: 		
  845: 		/* set the node read, the root one, to be the parent */
  846: 		axl_stack_push (doc->parentNode, node);
  847: 
  848: 		/* configure the node */
  849: 		axl_node_set_doc (node, doc);
  850: 
  851: 	} else {
  852: 		/* or set the node as a child of the current parent */
  853: 		axl_doc_set_child_current_parent (doc, node);
  854: 	}
  855: 
  856: 	/* set the node created to the calling node, so the caller
  857: 	 * could get a reference */
  858: 	if (calling_node != NULL)
  859: 		*calling_node = node;
  860: 
  861: 	/* only consume white spaces if matched_chunk is 2 */
  862: 	if (matched_chunk == 2) {
  863: 		/* get rid from spaces */
  864: 		AXL_CONSUME_SPACES (stream);
  865: 	}
  866: 
  867: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node found: [%s]", string_aux);
  868: 
  869: 
  870: 	/* now, until the node ends, we have to find the node
  871: 	 * attributes or the node defintion end */
  872: 	while (1) {
  873: 		/* check if we have an attribute for the node, or the node
  874: 		 * definition have ended or the node definition is an empty
  875: 		 * one 
  876: 		 * 
  877: 		 * the following code that relies on matched_chunk is
  878: 		 * done due to previous call to get_until function. If
  879: 		 * the value 0 or 1 was matched, this means that we
  880: 		 * are on "/>" case */
  881: 		if ((matched_chunk == 1) ||
  882: 		    axl_stream_inspect (stream, "/>", 2) > 0) {
  883: 			/* use alloc though string factory */
  884: 			axl_stream_set_buffer_alloc (stream, NULL, NULL);
  885: 
  886: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found end xml node definition '/>'");
  887: 
  888: 			/* empty node configuration found */
  889: 			*is_empty = axl_true;
  890: 			/* axl_node_set_is_empty (node, axl_true); */
  891: 
  892: 			/* make this node to be completed and no child
  893: 			 * could be set. */
  894: 			axl_stack_pop (doc->parentNode);
  895: 
  896: 			/* set the parent node to receive all content
  897: 			 * found in the next parsing elements because
  898: 			 * the element found is totally empty */
  899: 			*calling_node = axl_stack_peek (doc->parentNode);
  900: 			return axl_true;
  901: 		}
  902: 		
  903: 		/* check if we have an attribute for the node, or the node
  904: 		 * definition have ended or the node definition is an empty
  905: 		 * one 
  906: 		 * 
  907: 		 * the following code that relies on matched_chunk is
  908: 		 * done due to previous call to get_until function. If
  909: 		 * the value 2 or 3 was matched, this means that we
  910: 		 * are on ">" case */
  911: 		if ((matched_chunk == 0) ||
  912: 		    (axl_stream_inspect (stream, ">", 1) > 0)) {
  913: 			/* use alloc though string factory */
  914: 			axl_stream_set_buffer_alloc (stream, NULL, NULL);
  915: 			
  916: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found [end] xml node definition '>', for node: [%s]",
  917: 				   axl_node_get_name (node));
  918: 
  919: 			/* flag that the node is an empty definition */
  920: 			*is_empty = axl_false;
  921: 
  922: 			/* this node is ended */
  923: 			return axl_true;
  924: 		}
  925: 		
  926: 		/* get rid from spaces */
  927: 		AXL_CONSUME_SPACES (stream);
  928: 
  929: 		/* found attribute declaration, try to read it.
  930: 		 *
  931: 		 * We also reconfigure the alloc method used by the
  932: 		 * axl stream to ensure that xml node attributes are
  933: 		 * allocated through the string factory.
  934: 		 */
  935: 		string_aux = axl_stream_get_until (stream, NULL, NULL, axl_true, 1, "=");
  936: 		if (string_aux != NULL) {
  937: 			/* nullify internal reference to the stream:
  938: 			 * now we have inside string_aux the attribute
  939: 			 * name */
  940: 			axl_stream_nullify (stream, LAST_CHUNK);
  941: 
  942: 			/* check for empty values at the attribute definition */
  943: 			if (string_aux [0] == 0) {
  944: 				axl_error_new (-5, "Expected to find an attribute name (but found an empty value)", stream, error);
  945: 				axl_stream_free (stream);
  946: 				return axl_false;
  947: 			} /* end if */
  948: 
  949: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "attribute found: [%s]", string_aux);
  950: 
  951: 			/* remove next " and ' if defined */
  952: 			/* flag the we are looking for a " */
  953: 			delim = axl_true;
  954: 			if (! ((axl_stream_inspect (stream, "\"", 1) > 0))) {
  955: 				/* seems it is not found, flag we are
  956: 				 * looking for ' */
  957: 				delim = axl_false;
  958: 				if (! (axl_stream_inspect (stream, "\'", 1) > 0)) {
  959: 					/* use alloc though string factory */
  960: 					axl_stream_set_buffer_alloc (stream, NULL, NULL);
  961: 
  962: 					axl_error_new (-2, "Expected to find an attribute value initiator (\") or ('), every attribute value must start with them", 
  963: 						       stream, error);
  964: 					axl_stream_free (stream);
  965: 					return axl_false;
  966: 				}
  967: 			}
  968: 			
  969: 			
  970: 			/* now get the attribute value */
  971: 			if (delim)
  972: 				string_aux2 = axl_stream_get_until (stream, NULL, NULL, axl_true, 1, "\"");
  973: 			else
  974: 				string_aux2 = axl_stream_get_until (stream, NULL, NULL, axl_true, 1, "'");
  975: 
  976: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "value found: [%s]", string_aux2);
  977: 			
  978: 			/* nullify internal reference so we have the
  979: 			 * only one reference to attribute value
  980: 			 * inside string_aux2 */
  981: 			axl_stream_nullify (stream, LAST_CHUNK);
  982: 
  983: 			if (axl_node_has_attribute (node, string_aux)) {
  984: 				/* parse error */
  985: 				axl_error_new (-3, "Unable to add attribute to node which already has this attribute. Duplicate attribute error.", stream, error);
  986: 				axl_stream_free (stream);
  987: 				return axl_false;
  988: 			} /* end if */
  989: 			
  990: 			/* set a new attribute for the given node */
  991: 			axl_node_set_attribute_from_factory (doc->attr_factory, node, string_aux, string_aux2);
  992: 
  993: 			/* check xml:space configuration and update binary stack */
  994: 			if (axl_cmp (string_aux, "xml:space")) {
  995: 				if (axl_cmp (string_aux2, "preserve")) {
  996: 					__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found xml:space=preseve, notifying..");
  997: 
  998: 					/* 1: xml:space=preserve (found)
  999: 					 * make current node and all its childs to preserve (by
 1000: 					 * default) all white spaces found */
 1001: 					axl_binary_stack_push (doc->xmlPreserve, axl_true);
 1002: 
 1003: 				} else if (axl_cmp (string_aux2, "default")) {
 1004: 					__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found xml:space=default, notifying..");
 1005: 
 1006: 					/* 2: xml:space=default  (found)
 1007: 					 * make current node and all its childs to not
 1008: 					 * preserve white spaces (by default) */
 1009: 					axl_binary_stack_push (doc->xmlPreserve, axl_false);
 1010: 				} else {
 1011: 					/* parse error */
 1012: 					axl_error_new (-2, "xml:space attribute found with other value than 'preserve' or 'default', this is not allowed.", stream, error);
 1013: 					axl_stream_free (stream);
 1014: 					return axl_false;
 1015: 
 1016: 				} /* end if */
 1017: 			} else {
 1018: 				/* 3: xml:space (not found) 
 1019: 				 * make the current node to inherint
 1020: 				 * default from parent */
 1021: 				if (axl_binary_stack_is_empty (doc->xmlPreserve))
 1022: 					axl_binary_stack_push (doc->xmlPreserve, axl_false);
 1023: 				else
 1024: 					axl_binary_stack_push_the_same (doc->xmlPreserve);
 1025: 			} /* end if */
 1026: 
 1027: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "attribute installed..");
 1028: 
 1029: 			/* get rid from spaces */
 1030: 			AXL_CONSUME_SPACES (stream);
 1031: 			continue;
 1032: 		}
 1033: 		
 1034: 		/* if reached this point, error found */
 1035: 		axl_error_new (-2, "Parse error while reading a node being opened", stream, error);
 1036: 		axl_stream_free (stream);
 1037: 		return axl_false;
 1038: 
 1039: 	} /* end while */
 1040: 	
 1041: 	/* node properly parsed  */
 1042: 	return axl_true;
 1043: }
 1044: 
 1045: /** 
 1046:  * @internal
 1047:  * @brief Perform the close node operation.
 1048:  *
 1049:  */
 1050: axl_bool __axl_doc_parse_close_node (axlStream * stream, axlDoc * doc, axlNode ** _node, axlError ** error)
 1051: {
 1052: 	char    * string;
 1053: 	int       result_size = -1;
 1054: 	axlNode * node;
 1055: 
 1056: 	/* get the node being closed to check to the current parent */
 1057: 	string = axl_stream_get_until_ref (stream, NULL, NULL, axl_true, &result_size, 1, ">");
 1058: 	if (string == NULL) {
 1059: 		axl_error_new (-1, "An error was found while closing the xml node", stream, error);
 1060: 		axl_stream_free (stream);
 1061: 		return axl_false;
 1062: 	}
 1063: 
 1064: 	/* check for optional white space inside the trailing result */
 1065: 	if (axl_stream_is_white_space (string + result_size - 1)) {
 1066: 		/* nullify to remove the optional white spaces */
 1067: 		string [result_size - 1] = 0;
 1068: 	} /* end if */
 1069: 
 1070: 	/* get current parent node */
 1071: 	node   = axl_stack_peek (doc->parentNode);
 1072: 	if (node == NULL) {
 1073: 		axl_error_new (-1, "Found that the stack doesn't have any node opened, this means either an libaxl error or the xml being read is closing a node not opened",
 1074: 			       stream, error);
 1075: 		axl_stream_free (stream);
 1076: 		return axl_false;
 1077: 	}
 1078: 	
 1079: 	/* check current axl node name against closed string */
 1080: 	if (axl_cmp (axl_node_get_name (node), string)) { 
 1081: 
 1082: 		/* ok, axl node to be closed is the one expected */
 1083: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "closing xml node, that matched with parent opened");
 1084: 
 1085: 		return axl_true;
 1086: 	}
 1087: 
 1088: 	/* seems that the node being closed doesn't match */
 1089: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "xml node names to be closed doesn't matched (%s != %s), current node stack status:",
 1090: 		 axl_node_get_name (node), string);
 1091: 
 1092: 	node = axl_stack_pop (doc->parentNode);
 1093: 	while (node != NULL) {
 1094: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "<%s>", axl_node_get_name (node));
 1095: 		node = axl_stack_pop (doc->parentNode);
 1096: 	}
 1097: 
 1098: 	axl_error_new (-1, "An error was found while closing the opened xml node, parent opened and xml node being closed doesn't match",
 1099: 		       stream, error);
 1100: 	axl_stream_free (stream);
 1101: 
 1102: 	return axl_false;
 1103: }
 1104: 
 1105: /** 
 1106:  * @internal
 1107:  * 
 1108:  * Internal function which works as a common base for all functions
 1109:  * that parse XML documents from different inputs.
 1110:  */
 1111: axlDoc * __axl_doc_parse_common (const char * entity, int entity_size, 
 1112:                                  const char * file_path, int fd_handle, 
 1113: 			         axlError ** error)
 1114: {
 1115: 	axlStream * stream        = NULL;
 1116: 	axlDoc    * doc           = NULL;
 1117: 	axlNode   * node          = NULL;
 1118: 	char      * string        = NULL;
 1119: 	int         index;
 1120: 	axl_bool    is_empty      = axl_false;
 1121: 	
 1122: 	/* create the xml stream using provided data */
 1123: 	stream         = axl_stream_new (entity, entity_size, file_path, fd_handle, error);
 1124: 	axl_return_val_if_fail (stream, NULL);
 1125: 
 1126: 	/* create a document reference */
 1127: 	doc            = __axl_doc_new (axl_true);
 1128: 	axl_stream_link (stream, doc, (axlDestroyFunc) axl_doc_free);
 1129: 
 1130: 	/* detect transitional entity codification to configure built
 1131: 	 * decoder (only if defined handler found) */
 1132: 	if (detect_codification_func) {
 1133: 		if (! detect_codification_func (stream, &doc->detected_encoding, detect_codification_data, error)) {
 1134: 			axl_stream_free (stream);
 1135: 			return NULL; 
 1136: 		}
 1137: 	} /* end if */
 1138: 
 1139: 	/* parse initial xml header */
 1140: 	if (!__axl_doc_parse_xml_header (stream, doc, error))
 1141: 		return NULL;
 1142: 
 1143: 	/* signal that this document have processed its header */
 1144: 	doc->headerProcess = axl_true;
 1145: 	
 1146: 	/* parse the rest of the document, setting as parent NULL
 1147: 	 * because still no parent is found. */
 1148: 	if (!__axl_doc_parse_node (stream, doc, &node, &is_empty, error))
 1149: 		return NULL;
 1150: 
 1151: 	/* if the node returned is not empty */
 1152: 	if (! is_empty) {
 1153: 
 1154: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "the first node ready, have content, reading it");
 1155: 
 1156: 		/* while the stream have data */
 1157: 		while (axl_stream_remains (stream)) {
 1158: 
 1159: 			/* get current index */
 1160: 			index = axl_stream_get_index (stream);
 1161: 
 1162: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "current index: %d (global: %d)", index,
 1163: 				   axl_stream_get_global_index (stream));
 1164: 			
 1165: 			/* get rid from spaces according to the
 1166: 			 * xml:space configuration */
 1167: 			if (! axl_binary_stack_peek (doc->xmlPreserve)) {
 1168: 				AXL_CONSUME_SPACES(stream);
 1169: 			} /* end if */
 1170: 
 1171: 			/* consume a possible comment and process instructions */
 1172: 			if (axl_stream_peek (stream, "<?", 2) > 0 || axl_stream_peek (stream, "<!--", 4) > 0) {
 1173: 				if (! axl_doc_consume_comments (doc, stream, error))
 1174: 					return NULL;
 1175: 				
 1176: 				/* continue on the next index */
 1177: 				continue;
 1178: 			} /* end if */
 1179: 			
 1180: 			if ((axl_stream_peek (stream, "</", 2) > 0)) {
 1181: 				/* accept previous peek */
 1182: 				axl_stream_accept (stream);
 1183: 
 1184: 				__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found a node termination signal");
 1185: 
 1186: 				/* seems that a node is being closed */
 1187: 				if (! __axl_doc_parse_close_node (stream, doc, &node, error))
 1188: 					return NULL;
 1189: 
 1190: 				/* because the xml node have been
 1191: 				 * closed, make the parent to be the
 1192: 				 * previous one */
 1193: 				axl_stack_pop (doc->parentNode);
 1194: 
 1195: 				/* get the new parent */
 1196: 				node = axl_stack_peek (doc->parentNode);
 1197: 
 1198: 				/* restore previous xml:space value */
 1199: 				axl_binary_stack_pop (doc->xmlPreserve);
 1200: 
 1201: 				__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node properly closed, current parent node stack size: %d, parent=<%s>",
 1202: 					   axl_stack_size (doc->parentNode), (node != NULL) ? axl_node_get_name (node) : "--no parent--");
 1203: 
 1204: 				if (axl_stack_size (doc->parentNode) > 0)
 1205: 					continue;
 1206: 				break;
 1207: 			} /* end if */
 1208: 
 1209: 			/* check here for CDATA section. This is done
 1210: 			 * here because the following checking could
 1211: 			 * be mixed because they starts with the same:
 1212: 			 * < */
 1213: 			if ((axl_stream_peek (stream, "<![CDATA[", 9) > 0)) {
 1214: 				/* accet previous peek */
 1215: 				axl_stream_accept (stream);
 1216: 
 1217: 				/* found CDATA section, get current content */
 1218: 				axl_stream_set_buffer_alloc (stream, (axlStreamAlloc)__axl_doc_alloc, doc);
 1219: 				string = axl_stream_get_until (stream, NULL, NULL, axl_true, 1, "]]>");
 1220: 				axl_stream_set_buffer_alloc (stream, NULL, NULL);
 1221: 				if (string == NULL) {
 1222: 					axl_error_new (-1, "Unable to get CDATA content. There was an error.", stream, error);
 1223: 					axl_stream_free (stream);
 1224: 					return NULL;
 1225: 				}
 1226: 
 1227: 				/* nullify internal reference to the
 1228: 				 * string_aux so we can use that
 1229: 				 * memory allocated as our
 1230: 				 * reference */
 1231: 				axl_stream_nullify (stream, LAST_CHUNK);
 1232: 
 1233: 				/* set current data */
 1234: 				/* axl_node_set_content_ref (node, string, -1);  */
 1235: 				axl_node_set_cdata_content_from_factory (doc->content_factory, node, string, -1);
 1236: 				continue;
 1237: 			} /* end if */
 1238: 
 1239: 
 1240: 			if ((axl_stream_peek (stream, "<", 1) > 0)) {
 1241: 				/* accept previous peek */
 1242: 				axl_stream_accept (stream);
 1243: 
 1244: 				__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found a new node being opened");
 1245: 
 1246: 				/* seems that another node is being opened */
 1247: 				if (!__axl_doc_parse_node (stream, doc, &node, &is_empty, error))
 1248: 					return NULL;
 1249: 
 1250: 				__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "finished parsing opened node, current parent=<%s>",
 1251: 					   axl_node_get_name (node));
 1252: 
 1253: 				continue;
 1254: 			}
 1255: 			
 1256: 			/* restore index position previous to the axl
 1257: 			 * space consuming */
 1258: 			if (axl_stream_get_index (stream) > index) {
 1259: 				axl_stream_move (stream, index);
 1260: 			}
 1261: 			
 1262: 			/* found node content */
 1263: 			axl_stream_set_buffer_alloc (stream, (axlStreamAlloc)__axl_doc_alloc, doc);
 1264: 			string = axl_stream_get_until (stream, NULL, NULL, axl_false, 1, "<");
 1265: 			axl_stream_set_buffer_alloc (stream, NULL, NULL);
 1266: 			
 1267: 			/* check for a null content found */
 1268: 			if (string == NULL) {
 1269: 				axl_error_new (-1, "an error was found while reading the xml node content", stream, error);
 1270: 				axl_stream_free (stream);
 1271: 				return NULL;
 1272: 			}
 1273: 
 1274: 			/* nullify internal stream reference to have
 1275: 			 * the unique reference */
 1276: 			axl_stream_nullify (stream, LAST_CHUNK);
 1277: 
 1278: 			/* set current data */
 1279: 			/* axl_node_set_content_ref (node, string, -1); */
 1280: 			axl_node_set_content_from_factory (doc->content_factory, node, string, -1); 
 1281: 
 1282: 			/* keep on looping */
 1283: 		}
 1284: 	}
 1285: 
 1286: 	/* pop axl parent */
 1287: 	if (! axl_stack_is_empty (doc->parentNode)) {
 1288: 		
 1289: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, 
 1290: 			   "current parent stack size shows that not all opened nodes were closed. This means that the XML document is not properly balanced (stack size: %d)",
 1291: 			   axl_stack_size (doc->parentNode));
 1292: 
 1293: 		/* notify error */
 1294: 		axl_error_new (-1, "XML document is not balanced, still remains xml nodes", stream, error);
 1295: 		axl_stream_free (stream);
 1296: 
 1297: 		return NULL;
 1298: 	}
 1299: 
 1300: 	/* parse complete */
 1301: 	axl_stream_unlink (stream);
 1302: 	axl_stream_free (stream);
 1303: 
 1304: 	/* clean document internal variables */
 1305: 	__axl_doc_clean (doc);
 1306: 
 1307: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "xml document parse COMPLETED"); 
 1308: 
 1309: 	return doc;
 1310: }
 1311: 
 1312: /** 
 1313:  * @brief Creates a new empty xml document, especifying options to be
 1314:  * used in the header.
 1315:  *
 1316:  * This function allows to create the xml document representation the
 1317:  * must be used to add childs to it.
 1318:  *
 1319:  * The following is a simple example that creates a xml document (\ref
 1320:  * axlDoc) with a single root node (\ref axlNode):
 1321:  * \code
 1322:  * // some variables 
 1323:  * axlDoc  * doc;
 1324:  * axlNode * node;
 1325:  *
 1326:  * // dump content variables
 1327:  * char    * content;
 1328:  * int       content_size;
 1329:  *
 1330:  * // create the document 
 1331:  * doc = axl_doc_create (NULL, NULL, axl_true);
 1332:  *
 1333:  * // create the root document node
 1334:  * node = axl_node_create ("root-node");
 1335:  * 
 1336:  * // configure it as the root 
 1337:  * axl_doc_set_root (doc, node);
 1338:  *
 1339:  * // dump pretty
 1340:  * axl_doc_dump_pretty (doc, &content, &content_size, 4);
 1341:  *
 1342:  * // print the content and free
 1343:  * printf ("document size=%d, content: %s\n", content_size, content);
 1344:  * axl_free (content);
 1345:  * \endcode
 1346:  * 
 1347:  * @param version The xml document version. This value is optional. If
 1348:  * NULL is used, the library will use "1.0" as version value.
 1349:  *
 1350:  * @param encoding The document encoding to be used. This value is
 1351:  * optional, if NULL is provided, no encoding specification will be
 1352:  * used.
 1353:  *
 1354:  * @param standalone Standalone configuration flag. By default, use
 1355:  * axl_false.
 1356:  * 
 1357:  * @return Returns a newly allocated \ref axlDoc instance that must be
 1358:  * deallocated by using \ref axl_doc_free.
 1359:  */
 1360: axlDoc  * axl_doc_create                   (const char     * version, 
 1361: 					    const char     * encoding,
 1362: 					    axl_bool         standalone)
 1363: {
 1364: 	axlDoc * doc;
 1365: 
 1366: 	/* create a new reference, without creating  */
 1367: 	doc = __axl_doc_new (axl_false);
 1368: 	
 1369: 	/* save the version */
 1370: 	if (version != NULL)
 1371: 		doc->version  = axl_strdup (version);
 1372: 
 1373: 	/* save encoding value */
 1374: 	if (encoding != NULL)
 1375: 		doc->encoding = axl_strdup (encoding);
 1376: 
 1377: 	/* save standalone configuration */
 1378: 	doc->standalone       = standalone;
 1379: 	
 1380: 	/* return the reference created */
 1381: 	return doc;
 1382: }
 1383: 
 1384: /** 
 1385:  * @internal Returns how many bytes will hold the document provided.
 1386:  * 
 1387:  * @param doc The document to measure.
 1388:  *
 1389:  * @param pretty_print If pretty print is activated.
 1390:  * 
 1391:  * @return The number of bytes or -1 if it fails.
 1392:  */
 1393: int __axl_doc_get_flat_size_common (axlDoc * doc, axl_bool pretty_print, int tabular) 
 1394: {
 1395: 	
 1396: 	int result;
 1397: 	axl_return_val_if_fail (doc, -1);
 1398: 
 1399: 	/* count the xml header: 
 1400: 	 *
 1401: 	 * "<?xml version='1.0'" = 19 characters 
 1402: 	 * " standalone='yes'"   = 17 characters
 1403: 	 * " encoding='enc'"     = 12 characters + strlen (enc)
 1404: 	 * " ?>"                 = 3  characters
 1405: 	 *
 1406: 	 * if pretty print add: "\r\n" +2 on windows
 1407: 	 * and \n on unix.
 1408: 	 */
 1409: 	result = 22;
 1410: 
 1411: 	if (pretty_print)
 1412: #ifdef __AXL_OS_WIN32__
 1413: 		result += 2;
 1414: #else
 1415: 	        result += 1;
 1416: #endif
 1417: 
 1418: 	if (doc->standalone)
 1419: 		result += 17;
 1420: 	
 1421: 	if (doc->encoding != NULL) {
 1422: 		result += 12 + strlen (doc->encoding);
 1423: 	}
 1424: 	
 1425: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "xml document header size=%d",
 1426: 		   result);
 1427: 
 1428: 	/* now, count every node that the document have */
 1429: 	result += axl_node_get_flat_size (doc->rootNode, pretty_print, 0, tabular);
 1430: 
 1431: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "xml document body size=%d",
 1432: 		   result);
 1433: 	
 1434: 	/* return current result */
 1435: 	return result;
 1436: }
 1437: 
 1438: /** 
 1439:  * @internal
 1440:  * Common implementation for the dumping functions.
 1441:  */
 1442: axl_bool __axl_doc_dump_common (axlDoc * doc, char ** content, int * size, axl_bool pretty_print, int tabular, axlError ** err)
 1443: {
 1444: 
 1445: 	char * result;
 1446: 	int    index;
 1447: 
 1448: 	/* nullify before returning */
 1449: 	if (content)
 1450: 		*content = NULL;
 1451: 	if (size)
 1452: 		*size = 0;
 1453: 
 1454: 	/* perform some envrironmental checks */
 1455: 	if (doc == NULL) {
 1456: 		axl_error_report (err, -1, "Received null doc reference to perform dump operation.");
 1457: 		return axl_false;
 1458: 	} else if (content == NULL) {
 1459: 		axl_error_report (err, -2, "Received null content reference to perform dump operation. To dump the content it is required a valid memory reference to place the content.");
 1460: 		return axl_false;
 1461: 	} else if (size == NULL) {
 1462: 		axl_error_report (err, -3, "Received null size reference to perform dump operation. To dump the content it is required a valid memory reference to report size");
 1463: 		return axl_false;
 1464: 	}
 1465: 
 1466: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "getting document size..");
 1467: 
 1468: 	/* get the about of memory to allocate so the whole xml
 1469: 	 * document fit in only one memory block */
 1470: 	(* size)    = __axl_doc_get_flat_size_common (doc, pretty_print, tabular);
 1471: 	(* content) = NULL;
 1472: 
 1473: 	/* check returned size */
 1474: 	if ((* size) == -1) {
 1475: 		axl_error_report (err, -4, "Failed to perform dump operation, unable to calculate document size to perform dump.");
 1476: 		return axl_false;
 1477: 	}
 1478: 
 1479: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "document dump size: %d", *size);
 1480: 	
 1481: 	/* allocate the memory block required */
 1482: 	result = axl_new (char, (*size) + 1);
 1483: 	if (result == NULL) {
 1484: 		axl_error_report (err, -5, "Failed to allocate memory to dump document.");
 1485: 		return axl_false;
 1486: 	}
 1487: 
 1488: 	/* xml document header */
 1489: 	index = 0;
 1490: 	memcpy (result, "<?xml version='1.0' ", 20);
 1491: 	index = 20;
 1492: 
 1493: 	/* encoding declaration */
 1494: 	if (doc->encoding) {
 1495: 		/* initial encoding declaration */
 1496: 		memcpy (result + index, "encoding='", 10);
 1497: 		index += 10;
 1498: 
 1499: 		/* copy encoding content */
 1500: 		memcpy (result + index, doc->encoding, strlen (doc->encoding));
 1501: 		index += strlen (doc->encoding);
 1502: 
 1503: 		/* encoding trailing */
 1504: 		memcpy (result + index, "' ", 2);
 1505: 		index += 2;
 1506: 	}
 1507: 
 1508: 	/* standalone attribute */
 1509: 	if (doc->standalone) {
 1510: 		memcpy (result + index, "standalone='yes' ", 17); 
 1511: 		index += 17;
 1512: 	}
 1513: 
 1514: 	/* header trailing */
 1515: 	memcpy (result + index, "?>", 2);
 1516: 	index += 2;
 1517: 
 1518: 	if (pretty_print) {
 1519: #ifdef __AXL_OS_WIN32__
 1520: 		memcpy (result + index, "\r\n", 2);
 1521: 		index += 2;
 1522: #else
 1523: 		memcpy (result + index, "\n", 1);
 1524: 		index += 1;
 1525: #endif
 1526: 	}
 1527: 	
 1528: 	/* dump node information */
 1529: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "starting dump at: %d", index);
 1530: 	index    = axl_node_dump_at (doc->rootNode, result, index, pretty_print, 0, tabular);
 1531: 
 1532: 	/* check dump size */
 1533: 	if (*size != index) {
 1534: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "internal dump error, inconsitent size: calculated=%d != returned=%d",
 1535: 			   *size, index);
 1536: 
 1537: 		axl_error_report (err, -5, "Internal dump error, inconsistent size: calculated=%d != returned=%d",
 1538: 				  *size, index);
 1539: 
 1540: 		/* free allocated result */
 1541: 		axl_free (result);
 1542: 
 1543: 		*size    = -1;
 1544: 		*content = NULL;
 1545: 
 1546: 		return axl_false;
 1547: 	}
 1548: 
 1549: 	/* set results */
 1550: 	*content = result;
 1551: 	*size    = index;
 1552: 	
 1553: 	return axl_true;
 1554: }
 1555: /** 
 1556:  * @brief Allows to get the xml representation for the provided \ref
 1557:  * axlDoc reference.
 1558:  *
 1559:  * Given the \ref axlDoc reference, which represents a XML document,
 1560:  * this function allows to get its stringify representation.
 1561:  * 
 1562:  * @param doc The \ref axlDoc to stringify
 1563:  *
 1564:  * @param content The reference where the result will be returned.
 1565:  *
 1566:  * @param size The reference where the document content size will be
 1567:  * returned.
 1568:  *
 1569:  * @return The function returns \ref axl_true if the dump operation was
 1570:  * performed. Otherwise \ref axl_false is returned.
 1571:  */
 1572: axl_bool      axl_doc_dump                     (axlDoc  * doc, 
 1573: 						char   ** content, 
 1574: 						int     * size)
 1575: {
 1576: 	/* use common implementation */
 1577: 	return __axl_doc_dump_common (doc, content, size, axl_false, 0, NULL);
 1578: }
 1579: 
 1580: 
 1581: /** 
 1582:  * @brief Allows to perform a dump operation like \ref axl_doc_dump,
 1583:  * but making the output to be pretty printed.
 1584:  * 
 1585:  * @param doc The \ref axlDoc reference to be dumped.
 1586:  *
 1587:  * @param content The reference that will hold the dumped information.
 1588:  *
 1589:  * @param size Result size for the dumped information.
 1590:  *
 1591:  * @param tabular The tabular size basic unit used for level
 1592:  * tabulation. An appropiate value could be 4.
 1593:  * 
 1594:  * @return \ref axl_true if the document was dumped, \ref axl_false if
 1595:  * something has failed.
 1596:  */
 1597: axl_bool      axl_doc_dump_pretty              (axlDoc  * doc,
 1598: 						char   ** content,
 1599: 						int     * size,
 1600: 						int       tabular)
 1601: {
 1602: 	/* use common implementation */
 1603: 	return __axl_doc_dump_common (doc, content, size, axl_true, tabular, NULL);
 1604: }
 1605: 
 1606: /** 
 1607:  * @brief Allows to dump a xml document directly to the file located
 1608:  * at the file path.
 1609:  *
 1610:  * This function saves you the round trip to declare variables to hold
 1611:  * the memory, open a file, dump the content and properly close the
 1612:  * output file. The function works the same as \ref axl_doc_dump but
 1613:  * doing the extra job to transfer the xml document into a file.
 1614:  *
 1615:  * See also \ref axl_doc_dump_pretty_to_file to get a version dumps
 1616:  * the content doing some pretty printing operations.
 1617:  * 
 1618:  * @param doc The document to be dumped into a file.
 1619:  *
 1620:  * @param file_path The file path where the output will be placed. The
 1621:  * function will require to have access rights to the file (or to
 1622:  * create a new file if it doesnt exists). The default behaviour is to
 1623:  * overwrite the file found if exists. So, if you don't want to get
 1624:  * content overwrited, you must provide the enough code to avoid such
 1625:  * situations prior calling to this function.
 1626:  * 
 1627:  * @return \ref axl_true if the dump operation was ok, otherwisde \ref
 1628:  * axl_false is returned.
 1629:  */
 1630: axl_bool      axl_doc_dump_to_file             (axlDoc      * doc,
 1631: 						const char  * file_path)
 1632: {
 1633: 	char * content = NULL;
 1634: 	int    size    = -1;
 1635: 	int    written = -1;
 1636: 	FILE * fd      = NULL;
 1637: 
 1638: 	/* dump content and check result */
 1639: 	if (! __axl_doc_dump_common (doc, &content, &size, axl_false, 0, NULL)) {
 1640: 		/* no dump operation done */
 1641: 		return axl_false;
 1642: 	}
 1643: 
 1644: 	/* open the file and check */
 1645: #if defined(AXL_OS_WIN32) && ! defined(__GNUC__)
 1646: 	if (fopen_s (&fd, file_path, "w") != 0) {
 1647: #else
 1648: 	if ((fd = fopen (file_path, "w")) == NULL) {
 1649: #endif
 1650: 		/* failed to open the file to dump the content */
 1651: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "failed to dump document due to an error on fopen() call.");
 1652: 		axl_free (content);
 1653: 
 1654: 		return axl_false;
 1655: 	}
 1656: 
 1657: 	/* dump the content */
 1658: 	written = fwrite (content, 1, size, fd);
 1659: 
 1660: 	/* free the content */
 1661: 	axl_free (content);
 1662: 
 1663: 	/* close file */
 1664: 	fclose (fd);
 1665: 
 1666: 	/* return if we have failed to dump all the content to the
 1667: 	 * file or not. */
 1668: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "returning that the dump was: %s (written:%d == size:%d)", 
 1669: 		   (written == size) ? "OK" : "FAILED", 
 1670: 		   written, size);
 1671: 		   
 1672: 	return (written == size);
 1673: }
 1674: 
 1675: /** 
 1676:  * @brief Allows to dump a xml document directly to the file located
 1677:  * at the file path, doing pretty printing operations.
 1678:  *
 1679:  * This function saves you the round trip to declare variables to hold
 1680:  * the memory, open a file, dump the content and properly close the
 1681:  * output file. The function works the same as \ref axl_doc_dump but
 1682:  * doing the extra job to transfer the xml document into a file.
 1683:  *
 1684:  * See also \ref axl_doc_dump_to_file to get a version dumps the
 1685:  * content without doing pretty printing operations.
 1686:  * 
 1687:  * @param doc The document to be dumped into a file.
 1688:  *
 1689:  * @param file_path The file path where the output will be placed. The
 1690:  * function will require to have access rights to the file (or to
 1691:  * create a new file if it doesnt exists). The default behaviour is to
 1692:  * overwrite the file found if exists. So, if you don't want to get
 1693:  * content overwrited, you must provide the enough code to avoid such
 1694:  * situations prior calling to this function.
 1695:  * 
 1696:  * @param tabular The amount of white spaces to introduce as tabular
 1697:  * for each level found inside the xml.
 1698:  * 
 1699:  * @return \ref axl_true if the dump operation was ok, otherwisde \ref
 1700:  * axl_false is returned.
 1701:  */
 1702: axl_bool      axl_doc_dump_pretty_to_file      (axlDoc      * doc,
 1703: 						const char  * file_path,
 1704: 						int           tabular)
 1705: {
 1706: 	char     * content = NULL;
 1707: 	int        size    = -1;
 1708: 	int        written = -1;
 1709: 	FILE     * fd      = NULL;
 1710: 	axlError * err     = NULL;
 1711: 
 1712: 	/* dump content and check result */
 1713: 	if (! __axl_doc_dump_common (doc, &content, &size, axl_true, tabular, &err)) {
 1714: 		/* no dump operation done */
 1715: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "failed to perform dump operation. Internal error found: %s",
 1716: 			   axl_error_get (err));
 1717: 		axl_error_free (err);
 1718: 		return axl_false;
 1719: 	} /* end if */
 1720: 
 1721: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "document dumped, now transfer that content to a file");
 1722: 
 1723: 	/* open the file and check */
 1724: #if defined(AXL_OS_WIN32) && ! defined(__GNUC__)
 1725: 	if (fopen_s (&fd, file_path, "w") != 0) {
 1726: #else
 1727: 	if ((fd = fopen (file_path, "w")) == NULL) {
 1728: #endif
 1729: 		/* failed to open the file to dump the content */
 1730: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "failed to dump document due to an error on fopen() call.");
 1731: 		axl_free (content);
 1732: 
 1733: 		return axl_false;
 1734: 	}
 1735: 
 1736: 	/* dump the content */
 1737: 	written = fwrite (content, 1, size, fd);
 1738: 
 1739: 	/* free the content */
 1740: 	axl_free (content);
 1741: 
 1742: 	/* close file */
 1743: 	fclose (fd);
 1744: 
 1745: 	/* return if we have failed to dump all the content to the
 1746: 	 * file or not. */
 1747: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "returning that the dump was: %s (written:%d == size:%d)", 
 1748: 		   (written == size) ? "OK" : "FAILED", 
 1749: 		   written, size);
 1750: 	return (written == size);
 1751: }
 1752: 
 1753: /** 
 1754:  * @brief Allows to get how much will take the \ref axlDoc instance
 1755:  * represented as an XML document in an storage device (like memory).
 1756:  *
 1757:  * @param doc The \ref axlDoc reference that is being requested to return its size.
 1758:  * 
 1759:  * @return The size the \ref axlDoc will represent, in a
 1760:  * octect-counting, or -1 if fails. The function will only fail if the
 1761:  * provided reference is NULL.
 1762:  */
 1763: int axl_doc_get_flat_size (axlDoc * doc)
 1764: {
 1765: 	/* use common implementation */
 1766: 	return __axl_doc_get_flat_size_common (doc, axl_false, 0);
 1767: }
 1768: 
 1769: /** 
 1770:  * @brief Allows to get how much will take the \ref axlDoc instance
 1771:  * represented as an XML document in an storage device (like memory) using pretty print format.
 1772:  *
 1773:  * @param doc The \ref axlDoc reference that is being requested to return its size.
 1774:  *
 1775:  * @param tabular The amount of whitespaces to use for each single
 1776:  * tabular unit.
 1777:  * 
 1778:  * @return The size the \ref axlDoc will represent, in a
 1779:  * octect-counting, or -1 if fails. The function will only fail if the
 1780:  * provided reference is NULL.
 1781:  */
 1782: int axl_doc_get_flat_size_pretty (axlDoc * doc, int tabular)
 1783: {
 1784: 	/* use common implementation */
 1785: 	return __axl_doc_get_flat_size_common (doc, axl_true, tabular);
 1786: }
 1787: 
 1788: 
 1789: /** 
 1790:  * @brief Parse an XML entity that is hold inside the memory pointed
 1791:  * by <b>entity</b> and limited by <b>entity_size</b>.
 1792:  *
 1793:  * The function parses the XML document inside the memory hold inside
 1794:  * the given reference. The function returns an XML document,
 1795:  * represented by \ref axlDoc.
 1796:  *
 1797:  * The function, optionall, could report error found inside the given
 1798:  * \ref axlError variable. In the case the function returns a NULL
 1799:  * value, this variable is filled containing the a textual diagnostic
 1800:  * error to be showed to the user interface and an error code.
 1801:  *
 1802:  * Here is an example:
 1803:  * \code
 1804:  * // axl document representation 
 1805:  * axlDoc   * doc;
 1806:  * axlError * error;
 1807:  *	
 1808:  *
 1809:  * // parse the given string 
 1810:  * doc = axl_doc_parse ("<?xml version='1.0' ?><axldoc />", 32, &error);
 1811:  * if (doc == NULL) {
 1812:  *      printf ("Error found: %s\n", axl_error_get (error));
 1813:  *      axl_error_free (error);
 1814:  *      return axl_false;
 1815:  * }
 1816:  *
 1817:  * // release document parsed 
 1818:  * axl_doc_free (doc);	
 1819:  * \endcode
 1820:  * 
 1821:  * @param entity The XML document to load.
 1822:  *
 1823:  * @param entity_size The XML document size to load. If a <b>-1</b> is
 1824:  * provided, strlen function is used to figure out current document
 1825:  * size. This is not recomended while using xml documents that include
 1826:  * binary data, that maybe comes inside the CDATA section or because
 1827:  * an utf caracter used that includes the \\0 inside its value.
 1828:  *
 1829:  * @param error Optional \ref axlError reference that will be used to
 1830:  * report errors found while processing xml into the \ref axlDoc
 1831:  * instance.
 1832:  * 
 1833:  * @return A newly allocated Axl Document, that must be deallocated
 1834:  * using \ref axl_doc_free, when no longer needed. The function could
 1835:  * return NULL if the document is not loaded properly.
 1836:  *
 1837:  * In the case an error is found while procesing the document, error
 1838:  * variable will be filled, if defined. -1 will be returned is
 1839:  * received parameter are wrong. -2 will be returned if there some
 1840:  * error is found while processing the document.
 1841:  */
 1842: axlDoc * axl_doc_parse (const char * entity, int entity_size, axlError ** error)
 1843: {
 1844: 	return __axl_doc_parse_common (entity, entity_size, NULL, -1, error);
 1845: }
 1846: 
 1847: /** 
 1848:  * @internal
 1849:  * 
 1850:  * Allows to get current file size, in bytes, of the provided file
 1851:  * located at the given file path.
 1852:  */
 1853: int __axl_doc_get_file_size (char * file_path)
 1854: {
 1855: 	struct stat buf;
 1856: 
 1857: 	axl_return_val_if_fail (file_path, -1);
 1858: 	
 1859: 	/* clear the memory hold */
 1860: 	memset (&buf, 0, sizeof (struct stat));
 1861: 
 1862: 	/* return current file size */
 1863: 	if (stat ((const char *) file_path, &buf) < 0)
 1864: 		return -1;
 1865: 	
 1866: 	/* return the file size */
 1867: 	return buf.st_size;
 1868: 	
 1869: }
 1870: 
 1871: /** 
 1872:  * @brief Allows to parse an xml document from the given file path
 1873:  * location.
 1874:  *
 1875:  * This function works the same way like \ref axl_doc_parse and \ref
 1876:  * axl_doc_parse_strings, but using as an input, the selected file
 1877:  * provided by the path. In fact, all this function, use the same xml
 1878:  * parse engine. The advantage of this function is that it is more
 1879:  * efficient while reading huge xml files. 
 1880:  *
 1881:  * Here is an example:
 1882:  * \code
 1883:  * axlDoc   * doc = NULL;
 1884:  * axlError * error = NULL;
 1885:  *
 1886:  * // parse the provide file
 1887:  * doc = axl_doc_parse_from_file ("test.xml", &error);
 1888:  * if (doc == NULL) {
 1889:  *    // check error found
 1890:  *    printf ("ERROR: (code: %d) %s\n",
 1891:  *            axl_error_get_code (error),
 1892:  *            axl_error_get (error));
 1893:  *    axl_error_free (error);
 1894:  *    return -1;
 1895:  * }
 1896:  *
 1897:  * // do some stuff with the readed document
 1898:  * 
 1899:  * // release it once no longer needed
 1900:  * axl_doc_free (doc);
 1901:  * \endcode
 1902:  * 
 1903:  * @param file_path The file path to report.
 1904:  *
 1905:  * @param error The \ref axlError where errors found will be reported.
 1906:  * 
 1907:  * @return 
 1908:  */
 1909: axlDoc  * axl_doc_parse_from_file          (const char * file_path,
 1910: 					    axlError  ** error)
 1911: {
 1912: 	return __axl_doc_parse_common (NULL, -1, file_path, -1, error);
 1913: }
 1914: 
 1915: 
 1916: /** 
 1917:  * @brief Allows to parse an xml document that is provided as a set of
 1918:  * strings ended by a NULL reference.
 1919:  *
 1920:  * This function works the same way like \ref axl_doc_parse function,
 1921:  * but allowing to provide a set of strings. Here is an example:
 1922:  * 
 1923:  * \code
 1924:  * // a document reference
 1925:  * axlDoc   * doc;
 1926:  *
 1927:  * // note that the error is optional, and, if provided, it is not
 1928:  * // required to initialize it.
 1929:  * axlError * error;
 1930:  * 
 1931:  * // parse the following set of strings
 1932:  * doc = axl_doc_parse_strings (&error, 
 1933:  *                              "<?xml version='1.0' standalone='yes' ?>",
 1934:  *                              "<complex>",
 1935:  *                              "  <data>",
 1936:  *                              "     <row>",
 1937:  *                              "       <td>",
 1938:  *                              "          <value attr='10'/>
 1939:  *                              "       </td>",
 1940:  *                              "     </row>",
 1941:  *                              "  </data>",
 1942:  *                              "</complex>",
 1943:  *                              NULL); // last null reference 
 1944:  * // check for an error
 1945:  * if (doc == NULL) {
 1946:  *      printf ("There was an error while parsing the document: (code: %d) %s\n",
 1947:  *              axl_error_get_code (error), axl_error_get (error));
 1948:  *      axl_error_free (error);
 1949:  * }
 1950:  * \endcode
 1951:  * 
 1952:  * @param error An optional \ref axlError reference where a textual
 1953:  * diagnostic will be provided.
 1954:  * 
 1955:  * @return A newly created \ref axlDoc reference that must be
 1956:  * deallocated by using \ref axl_doc_free when no longer needed.
 1957:  */
 1958: axlDoc  * axl_doc_parse_strings            (axlError ** error,
 1959: 					    ...)
 1960: {
 1961: 	axlDoc   * doc;
 1962: 	va_list    args;
 1963: 	char     * string     = NULL;
 1964: 	char     * stream     = NULL;
 1965: 	char     * stream_aux = NULL;
 1966: 	
 1967: 	/* check incoming data */
 1968: 	axl_return_val_if_fail (error, NULL);
 1969: 	
 1970: 	/* open the stdargs */
 1971: 	va_start (args, error);
 1972: 	
 1973: 	while ((string = va_arg (args, char *)) != NULL) {
 1974: 		stream_aux = stream;
 1975: 		stream = axl_stream_concat (stream, string);
 1976: 		if (stream_aux != NULL) {
 1977: 			axl_free (stream_aux);
 1978: 			stream_aux = NULL;
 1979: 		}
 1980: 	}
 1981: 
 1982: 	/* close the stdargs */
 1983: 	va_end (args);
 1984: 
 1985: 	/* check that we have received, at least, an string
 1986: 	 * parseable */
 1987: 	if (stream == NULL)
 1988: 		return NULL;
 1989: 
 1990: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "string to parse: %s", stream);
 1991: 
 1992: 	/* parse the string */
 1993: 	doc = axl_doc_parse (stream, -1, error);
 1994: 
 1995: 	/* free the stream */
 1996: 	axl_free (stream);
 1997: 
 1998: 	return doc;
 1999: }
 2000: 
 2001: /** 
 2002:  * @internal 
 2003:  * 
 2004:  * Internal support function which checks the provided child and its
 2005:  * childs are equal.
 2006:  */
 2007: axl_bool __axl_doc_are_equal (axlNode * node, axlNode * node2, axl_bool trimmed, axlError ** error)
 2008: {
 2009: 	int       length;
 2010: 	int       length2;
 2011: 
 2012: 	axlItem * child;
 2013: 	axlItem * child2;
 2014: 	
 2015: 	/* check if parent nodes are equal */
 2016: 	if (! axl_node_are_equal (node, node2))
 2017: 		return axl_false;
 2018: 
 2019: 	/* iterate over all childs inside the node */
 2020: 	length   = axl_node_get_child_num (node);
 2021: 	length2  = axl_node_get_child_num (node2);
 2022: 
 2023: 	if (length != length2) {
 2024: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "child number differs, documents aren't equal");
 2025: 		axl_error_report (error, -1,  "child number differs, documents aren't equal");
 2026: 		return axl_false;
 2027: 	}
 2028: 
 2029: 	/* get the first item inside the node */
 2030: 	child  = axl_item_get_first_child (node);
 2031: 	child2 = axl_item_get_first_child (node2);
 2032: 
 2033: 	/* for each item child found in both nodes */
 2034: 	while (child != NULL && child2 != NULL) {
 2035: 		
 2036: 		if (child == NULL)  {
 2037: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "child from the first document is null..");
 2038: 			axl_error_report (error, -1, "child from the first document is null..");
 2039: 		}
 2040: 
 2041: 		if (child2 == NULL) {
 2042: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "child from the second document is null..");
 2043: 			axl_error_report (error, -1,  "child from the second document is null..");
 2044: 		}
 2045: 
 2046: 		/* check if these nodes are also equal */
 2047: 		if (! axl_item_are_equal_full (child, child2, trimmed, error)) {
 2048: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "items  aren't equal, document is not equal");
 2049: 			return axl_false;
 2050: 		}
 2051: 
 2052: 		/* check its childs in the case the axl item is
 2053: 		 * representing an item node */
 2054: 		if (axl_item_get_type (child) == ITEM_NODE) {
 2055: 			/* get a reference */
 2056: 			node  = axl_item_get_data (child);
 2057: 			node2 = axl_item_get_data (child2);
 2058: 
 2059: 			if (! __axl_doc_are_equal (node, node2, trimmed, error)) {
 2060: 				__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "nodes <%s> and <%s> aren't equal, document is not equal", 
 2061: 					   axl_node_get_name (node), axl_node_get_name (node2));
 2062: 				return axl_false;
 2063: 			} /* end if */
 2064: 		}
 2065: 
 2066: 		/* get a referece to the next childs to check */
 2067: 		child  = axl_item_get_next (child);
 2068: 		child2 = axl_item_get_next (child2);
 2069: 		
 2070: 	} /* end while */
 2071: 
 2072: 	/* the nodes recieved are equal */
 2073: 	return (child == NULL && child2 == NULL);
 2074: }
 2075: 
 2076: /** 
 2077:  * @internal Common implementation for equal documents.
 2078:  */
 2079: axl_bool      axl_doc_are_equal_common (axlDoc    * doc,
 2080: 					axlDoc    * doc2,
 2081: 					axl_bool    trimmed,
 2082: 					axlError ** error)
 2083: {
 2084: 	axlNode * node;
 2085: 	axlNode * node2;
 2086: 
 2087: 	/* check first reference */
 2088: 	if (doc == NULL) {
 2089: 		axl_error_report (error, -1, "Documents differs because first document reference is null");
 2090: 		return axl_false;
 2091: 	}
 2092: 	/* check second reference */
 2093: 	if (doc2 == NULL) {
 2094: 		axl_error_report (error, -1, "Documents differs because second document reference is null");
 2095: 		return axl_false;
 2096: 	}
 2097: 
 2098: 	/* first, check the document root */
 2099: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "checking that both documents are equal");
 2100: 
 2101: 	node  = axl_doc_get_root (doc);
 2102: 	if (node == NULL) {
 2103: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "document(a) doesn't have document root ..");
 2104: 	}
 2105: 	node2 = axl_doc_get_root (doc2);
 2106: 	if (node2 == NULL) {
 2107: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "document(b) doesn't have document root ..");
 2108: 	}
 2109: 
 2110: 	/* call to common implemenation, activating triming */
 2111: 	return __axl_doc_are_equal (node, node2, trimmed, error);
 2112: }
 2113: 
 2114: /** 
 2115:  * @brief Allows to perform a document equal check against order,
 2116:  * relaxing the checking done to contet found inside nodes.
 2117:  *
 2118:  * This function works the same as \ref axl_doc_are_equal but
 2119:  * considering that two content are equal no matter which is the
 2120:  * number of white spaces (in the W3C, ' ', \\t, \\r and \\n) are
 2121:  * found starting and ending the content.
 2122:  *
 2123:  * Under this approach the both document aren't exactly the same, but
 2124:  * usually, white spaces found starting and ending content have no
 2125:  * meaning for the application processing xml. In the case you want a
 2126:  * fully equal document checking you must \ref axl_doc_are_equal
 2127:  *
 2128:  * @param doc The document to check.
 2129:  * @param doc2 The second document to check
 2130:  * 
 2131:  * @return \ref axl_true if both documents are equal in the sense
 2132:  * described, otherwise \ref axl_false is returned.
 2133:  */
 2134: axl_bool      axl_doc_are_equal_trimmed        (axlDoc * doc,
 2135: 						axlDoc * doc2)
 2136: {
 2137: 	/* call to common implemenation, activating triming */
 2138: 	return axl_doc_are_equal_common (doc, doc2, axl_true, NULL);
 2139: }
 2140: 
 2141: /** 
 2142:  * @brief Allows to check if the provided two references represents
 2143:  * equivalent xml documents.
 2144:  *
 2145:  * There is an alternative document checking function (\ref
 2146:  * axl_doc_are_equal_trimmed) which considered that content found
 2147:  * inside a xml node is equal if they share the same information
 2148:  * without considering white spaces found starting and ending both
 2149:  * elements being checked.
 2150:  *
 2151:  * This function considers that two documents are equal only and only
 2152:  * if all nodes, attributes and content found is exactly, byte by
 2153:  * byte, as found in the other document.
 2154:  * 
 2155:  * @param doc The first XML document to check.
 2156:  * @param doc2 The second XML document to check.
 2157:  * 
 2158:  * @return axl_true if both documents represents the same document,
 2159:  * axl_false if not.
 2160:  */
 2161: axl_bool      axl_doc_are_equal                (axlDoc * doc, 
 2162: 						axlDoc * doc2)
 2163: {
 2164: 	/* call to common implemenation, activating triming */
 2165: 	return axl_doc_are_equal_common (doc, doc2, axl_true, NULL);
 2166: }
 2167: 
 2168: /** 
 2169:  * @brief Allows to check if the provided two references represents
 2170:  * equivalent xml documents.
 2171:  *
 2172:  * There is an alternative document checking function (\ref
 2173:  * axl_doc_are_equal_trimmed) which considered that content found
 2174:  * inside a xml node is equal if they share the same information
 2175:  * without considering white spaces found starting and ending both
 2176:  * elements being checked.
 2177:  *
 2178:  * This function considers that two documents are equal only and only
 2179:  * if all nodes, attributes and content found is exactly, byte by
 2180:  * byte, as found in the other document.
 2181:  * 
 2182:  * @param doc The first XML document to check.
 2183:  *
 2184:  * @param doc2 The second XML document to check.
 2185:  *
 2186:  * @param trimmed Allows to configure if node content must be trimmed
 2187:  * before checking them (\ref axl_doc_are_equal_trimmed).
 2188:  *
 2189:  * @param error An optional reference to an \ref axlError node where
 2190:  * difference information will be reported.
 2191:  * 
 2192:  * @return axl_true if both documents represents the same document,
 2193:  * axl_false if not.
 2194:  */
 2195: axl_bool      axl_doc_are_equal_full           (axlDoc    * doc, 
 2196: 						axlDoc    * doc2,
 2197: 						axl_bool    trimmed,
 2198: 						axlError ** error)
 2199: {
 2200: 	/* call to common implemenation, activating triming */
 2201: 	return axl_doc_are_equal_common (doc, doc2, trimmed, error);
 2202: }
 2203: 
 2204: 
 2205: 
 2206: 
 2207: /** 
 2208:  * @brief Allows to get current root node for the given xml document,
 2209:  * represented by the \ref axlDoc instance.
 2210:  *
 2211:  * Every XML document has a very first node, which enclose all childs
 2212:  * found inside the document, that is called the root node. This xml
 2213:  * node, 
 2214:  *
 2215:  * This function couldn't return NULL because every well opened xml
 2216:  * document, always have a root node. However, the function could
 2217:  * return a NULL value if the document received is a null reference.
 2218:  * 
 2219:  * @param doc The xml document (\ref axlDoc) where the root node will
 2220:  * be returned. 
 2221:  * 
 2222:  * @return The root node (\ref axlNode) or NULL if fails.
 2223:  */
 2224: axlNode * axl_doc_get_root                 (axlDoc * doc)
 2225: {
 2226: 	axl_return_val_if_fail (doc, NULL);
 2227: 	
 2228: 	/* return current root node */
 2229: 	return doc->rootNode;
 2230: }
 2231: 
 2232: /** 
 2233:  * @internal
 2234:  *
 2235:  * @brief An always return 1 to make the list to store elements append
 2236:  * at the end.
 2237:  */
 2238: int __axl_doc_get_are_equal (axlPointer a, axlPointer b)
 2239: {
 2240: 	return 1;
 2241: }
 2242: 
 2243: /** 
 2244:  * @brief Allows to get a particular node (or list of nodes) that are
 2245:  * located at a selected path.
 2246:  *
 2247:  * Providing a path, the function lookups for nodes stored on the
 2248:  * selected location inside the provided document. The path provided
 2249:  * doesn't follow the XPath extension. 
 2250:  *
 2251:  * Taking as a reference for the xml to be explained on the following
 2252:  * rules:
 2253:  * \code
 2254:  * <complex>
 2255:  *     <data>
 2256:  *       <node>
 2257:  *          <row>10</row>
 2258:  *       </node>
 2259:  *     </data>
 2260:  * </complex>
 2261:  * \endcode
 2262:  *
 2263:  *
 2264:  * Here is how the path works:
 2265:  * 
 2266:  * - If provided a "/", the root node is returned. This is same than
 2267:  * provided the root node name, like "/complex", when it is expected
 2268:  * to find as root node &lt;complex>. However, providing a particular
 2269:  * node to search allows to get ensure that the root node is the one
 2270:  * looked up.
 2271:  *
 2272:  * - To select nodes inside the first root node, in a generic way,
 2273:  * without providing details about the root node name, you could use
 2274:  * "//\*". This will provide all nodes that are found inside the root
 2275:  * node, whatever it is called. If it is required to get all nodes,
 2276:  * inside the root node, ensuring that the root one is called
 2277:  * "complex" you should use: "/complex/\*"
 2278:  *
 2279:  * - If it is required to get a selected node inside the root node,
 2280:  * that is called in a particular way you can use: //data. Again, if
 2281:  * it is required to ensure that a particular node exists, from the
 2282:  * top level down the leaf node, it will required to write something
 2283:  * like: "/complex/data". 
 2284:  *
 2285:  * - Remember that is totally different to query for "/complex/data"
 2286:  * than "/complex/data/\*". The first one, returns the node, or nodes,
 2287:  * called <b>data</b> that are inside the root node called
 2288:  * <b>complex</b>, while the second one says: return all nodes inside
 2289:  * the node <b>data</b> that is inside the root node called
 2290:  * <b>complex</b>
 2291:  *
 2292:  * Finally, keep in mind that this function only returns nodes. To get
 2293:  * node content, attributes or anything else, you'll have to get the
 2294:  * node first and then operate with it.
 2295:  *
 2296:  *
 2297:  *
 2298:  * @param doc The \ref axlDoc reference where the lookup will be
 2299:  * performed.
 2300:  *
 2301:  * @param path_to A path to the node (nodes) that are inside the path
 2302:  * especifyied.
 2303:  * 
 2304:  * @return A list of nodes (\ref axlNode) if the case something is
 2305:  * found or NULL if fails to find something at the given path. If the
 2306:  * path is right but no node match with it or there is no node, the
 2307:  * function will return NULL reference rather a list with no
 2308:  * nodes. Returned value must be deallocated by using \ref
 2309:  * axl_list_free.
 2310:  */
 2311: axlList * axl_doc_get_list                  (axlDoc * doc, const char * path_to)
 2312: {
 2313: 	axlList  * nodes;
 2314: 	axlNode  * node     = NULL;
 2315: 	int        iterator = 0;
 2316: 	char    ** paths    = 0;
 2317: 	
 2318: 
 2319: 	axl_return_val_if_fail (doc, NULL);
 2320: 	axl_return_val_if_fail (path_to, NULL);
 2321: 	axl_return_val_if_fail (path_to[0] == '/', NULL);
 2322: 
 2323: 	/* create the axl list */
 2324: 	nodes = axl_list_new (__axl_doc_get_are_equal, NULL);
 2325: 	
 2326: 	/* split paths */
 2327: 	paths = axl_stream_split (path_to, 1, "/");
 2328: 	axl_return_val_if_fail (paths, nodes);
 2329: 
 2330: 	/* get a reference to the root node */
 2331: 	node = doc->rootNode;
 2332: 
 2333: 	/* basic case, check for the root node */
 2334: 	if (strlen (paths[1]) != 0) {
 2335: 		/* check the node is the one requested */
 2336: 		if (! NODE_CMP_NAME (node, paths[1])) {
 2337: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "requested root node = %s wasn't found, current root %s", paths[1],
 2338: 				   axl_node_get_name (doc->rootNode));
 2339: 			axl_list_free (nodes);
 2340: 			axl_stream_freev (paths);
 2341: 			return NULL;
 2342: 		}
 2343: 	}
 2344: 
 2345: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found node: %s for path=%s", paths[1], path_to);
 2346: 
 2347: 	/* now the general case */
 2348: 	iterator = 2;
 2349: 	while ((paths[iterator] != NULL) && (strlen (paths[iterator]) > 0)) {
 2350: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "checking path item %s", paths[iterator]);
 2351: 		
 2352: 		/* check that the last path is used */
 2353: 		if (axl_cmp (paths[iterator], "*") && 
 2354: 		    (axl_stream_strv_num (paths) != iterator + 1)) {
 2355: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "using the '*' at that path different from the last one.", paths[iterator]);
 2356: 			axl_list_free (nodes);
 2357: 			axl_stream_freev (paths);
 2358: 			return NULL;
 2359: 		}
 2360: 
 2361: 		/* get a reference to the node searched */
 2362: 		node = axl_node_get_child_called (node, paths[iterator]);
 2363: 		if (node == NULL) {
 2364: 			__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "the node located at %s wasn't found.", path_to);
 2365: 
 2366: 			axl_list_free (nodes);
 2367: 			axl_stream_freev (paths);
 2368: 			return NULL;
 2369: 		}
 2370: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found node: %s", paths[iterator]);
 2371: 
 2372: 		/* update iterator value */
 2373: 		iterator++;
 2374: 	}
 2375: 
 2376: 	/* add the node found */
 2377: 	axl_list_add (nodes, node);
 2378: 
 2379: 	/* free paths */
 2380: 	axl_stream_freev (paths);
 2381: 
 2382: 	/* return the node found */
 2383: 	return nodes;
 2384: }
 2385: 
 2386: /** 
 2387:  * @brief Allows to return only one node for the selected path.
 2388:  *
 2389:  * This function works the same way like \ref axl_doc_get_list but
 2390:  * extracting the first node reference found inside the list returned
 2391:  * by the previous function, and returning it.
 2392:  *
 2393:  * Many times, a path is selected because it is know that under that
 2394:  * location couldn't be more than one element. However, using \ref
 2395:  * axl_doc_get_list function makes this task really anoying because
 2396:  * you have to get the list, extract the node, from the list, and
 2397:  * releasing the list reference to actually get access to the node
 2398:  * looked up.
 2399:  *
 2400:  * This function allows you to get access to the node stored on the
 2401:  * selected location, and, if a path that provides several nodes is
 2402:  * returned, only the first node found on that list is returned.
 2403:  * 
 2404:  * @param doc The \ref axlDoc document where the node will be returned.
 2405:  * @param path_to A path to the node to get.
 2406:  * 
 2407:  * @return A reference to a \ref axlNode instace, or NULL if
 2408:  * fails. Returned reference must not be deallocated.
 2409:  */
 2410: axlNode * axl_doc_get                      (axlDoc * doc, const char * path_to)
 2411: {
 2412: 	axlList * list = NULL;
 2413: 	axlNode * node = NULL;
 2414: 	
 2415: 	axl_return_val_if_fail (doc, NULL);
 2416: 	axl_return_val_if_fail (path_to, NULL);
 2417: 
 2418: 	/* get the list of nodes */
 2419: 	list = axl_doc_get_list (doc, path_to);
 2420: 	if (list == NULL)
 2421: 		return NULL;
 2422: 	
 2423: 	/* get the node requested */
 2424: 	if (axl_list_length (list) > 0)
 2425: 		node = axl_list_get_nth (list, 0);
 2426: 
 2427: 	axl_list_free (list);
 2428: 	return node;
 2429: 	
 2430: }
 2431: 
 2432: /** 
 2433:  * @brief Allows to get the node content for the final node provided
 2434:  * by the path.
 2435:  * 
 2436:  * @param doc The (\ref axlDoc) xml document where the content will be
 2437:  * looked up.
 2438:  *
 2439:  * @param path_to Path to the node where the content will be returned.
 2440:  *
 2441:  * @param content_size An optional reference to a variable to store
 2442:  * the size of the content returned. If the function receives NULL,
 2443:  * the content size will not be returned.
 2444:  * 
 2445:  * @return A reference to the content that the node have or NULL if
 2446:  * fails. The function could fail either because the node doesn't have
 2447:  * content or because the node identified by the path doesn't
 2448:  * exist. The result returned must not be deallocated.
 2449:  */
 2450: const char    * axl_doc_get_content_at     (axlDoc     * doc,
 2451: 					    const char * path_to,
 2452: 					    int        * content_size)
 2453: {
 2454: 
 2455: 	axlNode * node;
 2456: 
 2457: 	/* get the node reference */
 2458: 	node = axl_doc_get (doc, path_to);
 2459: 	axl_return_val_if_fail (node, NULL);
 2460: 
 2461: 	/* return the content requested */
 2462: 	return axl_node_get_content (node, content_size);
 2463: 	
 2464: }
 2465: 
 2466: /** 
 2467:  * @brief Gets current axl Document encoding.
 2468:  * 
 2469:  * @param doc The document where the encoding will be retrieved.
 2470:  * 
 2471:  * @return A valid \ref axlDoc reference. NULL is returned in the case
 2472:  * a NULL \ref axlDoc reference is received. The value returned by
 2473:  * this function must not be deallocated.
 2474:  */
 2475: const char * axl_doc_get_encoding (axlDoc * doc)
 2476: {
 2477: 	/* check parameter received */
 2478: 	axl_return_val_if_fail (doc, NULL);
 2479: 	
 2480: 	return (doc->encoding != NULL) ? doc->encoding : "";
 2481: }
 2482: 
 2483: /** 
 2484:  * @brief Allows to get current standalone configuration for the given
 2485:  * axlDoc document.
 2486:  * 
 2487:  * @param doc The \ref axlDoc document where the standalone value will
 2488:  * be retreived.
 2489:  * 
 2490:  * @return \ref axl_true if the standalone configuration, found inside
 2491:  * the xml header is set to AXL_TRUE. Otherwise \ref axl_false is
 2492:  * returned. Keep in mind that the function will return an \ref
 2493:  * axl_false value if a null reference is received.
 2494:  */
 2495: axl_bool     axl_doc_get_standalone (axlDoc * doc)
 2496: {
 2497: 	axl_return_val_if_fail (doc, axl_false);
 2498: 
 2499: 	/* return current configuration */
 2500: 	return doc->standalone;
 2501: }
 2502: 
 2503: /** 
 2504:  * @brief Allows to configure the document root for the given \ref
 2505:  * axlDoc instance.
 2506:  *
 2507:  * Every xml document has a xml node root. This is the first node,
 2508:  * that holds all childs. This function allows to configure that xml
 2509:  * document root. See also \ref axl_doc_get_root.
 2510:  *
 2511:  * Remember that previous document root will not be deallocated so,
 2512:  * the user space must take care about previous reference.
 2513:  *
 2514:  * @param doc The \ref axlDoc where the document root will be
 2515:  * configured.
 2516:  *
 2517:  * @param root The \ref axlNode used to configure the new document
 2518:  * root. The reference received can be null. In this case, it is
 2519:  * considered that the root node is being unset.
 2520:  */
 2521: void    axl_doc_set_root (axlDoc * doc, axlNode * root)
 2522: {
 2523: 	axl_return_if_fail (doc);
 2524: 
 2525: 	/* set the new root */
 2526: 	doc->rootNode = root;
 2527: 
 2528: 	/* if the reference received is null, just return */
 2529: 	if (root == NULL)
 2530: 		return;
 2531: 
 2532: 	/* set a refeference to the document root */
 2533: 	axl_node_set_doc (root, doc);
 2534: 
 2535: 	return;
 2536: }
 2537: 
 2538: /** 
 2539:  * @internal
 2540:  *
 2541:  * @brief Allows to set the given axlNode to be child of the current
 2542:  * parent.
 2543:  *
 2544:  * @param doc The \ref axlDoc reference where the \ref axlNode will be
 2545:  * configured.
 2546:  *
 2547:  * @param node The \ref axlNode reference to set as a child for the
 2548:  * parent node.
 2549:  */
 2550: void     axl_doc_set_child_current_parent (axlDoc * doc, axlNode * node)
 2551: {
 2552: 	axlNode * parent;
 2553: 
 2554: 	/* perform some environment checks */
 2555: 	axl_return_if_fail (doc);
 2556: 	axl_return_if_fail (node);
 2557: 	
 2558: 	parent = axl_stack_peek (doc->parentNode);
 2559: 	axl_return_if_fail (parent);
 2560: 
 2561: 	/* set the child for the current parent */
 2562: 	axl_node_set_child (parent, node);
 2563: 
 2564: 	/* set the new parent */
 2565: 	axl_stack_push (doc->parentNode, node);
 2566: 
 2567: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "pushed a new parent into the stack <%s>, current status after operation: %d",
 2568: 		   axl_node_get_name (node), axl_stack_size (doc->parentNode));
 2569: 	
 2570: 	return;
 2571: }
 2572: 
 2573: /** 
 2574:  * @internal Allows to make current \ref axlDoc to pop current parent
 2575:  * node, making the new parent node the previously opened.
 2576:  *
 2577:  * This API is deprecated (internal function used in the past).
 2578:  * 
 2579:  * @param doc The \ref axlDoc where the pop operation will be
 2580:  * performed.
 2581:  */
 2582: void     axl_doc_pop_current_parent       (axlDoc * doc)
 2583: {
 2584: 	return;
 2585: }
 2586: 
 2587: /** 
 2588:  * @brief Allows to configure a PI target, with its content, on the given \ref axlDoc.
 2589:  *
 2590:  * A PI is a process instruction that is passed to the
 2591:  * application. This process instruction has a target name, which
 2592:  * acording to the standard is the application which should receive
 2593:  * the target content and an optional target content associated.
 2594:  *
 2595:  * This function allows to configure (add) a new PI item inside the
 2596:  * given xml document (\ref axlDoc). The PI content is optional. If
 2597:  * provided NULL, the PI will only contain as information the PI
 2598:  * target.
 2599:  *
 2600:  * Here is how a process instruction is used inside a xml document:
 2601:  * \code
 2602:  * <?xml version='1.0'>
 2603:  * <?launch "some command" ?>
 2604:  * <complex>
 2605:  *    <?data "some data" ?>
 2606:  *    <?data "more data" ?>
 2607:  *    <data>
 2608:  *       <row attr="20" />
 2609:  *    </data>
 2610:  * </complex>
 2611:  * \endcode
 2612:  *
 2613:  * Previous example shows how to use PI (process instructions) from
 2614:  * outside the xml root node (<b>complex</b>, and also how it is used
 2615:  * from inside a xml node definition <b>complex</b>. 
 2616:  *
 2617:  * As you can see, PI elements could be used as many times as you want
 2618:  * and places allowed to do so are just right before begining with the
 2619:  * root node and inside xml node definitions.
 2620:  * 
 2621:  * @param doc The axlDocument where the PI will be added.
 2622:  * @param target The PI target name.
 2623:  * @param content The PI content (optional value).
 2624:  */
 2625: void      axl_doc_add_pi_target            (axlDoc * doc, 
 2626: 					    char * target, 
 2627: 					    char * content)
 2628: {
 2629: 	axlPI * pi;
 2630: 
 2631: 	/* perform some environmental checks */
 2632: 	axl_return_if_fail (doc);
 2633: 	axl_return_if_fail (target);
 2634: 
 2635: 	/* create the PI element */
 2636: 	pi = axl_pi_create (target, content);
 2637: 
 2638: 	/* add the PI */
 2639: 	axl_list_add (doc->piTargets, pi);
 2640: 
 2641: 	return;
 2642: }
 2643: 
 2644: /** 
 2645:  * @brief Allows to check if the provided Processing instruction
 2646:  * target is defined on the given xml document (\ref axlDoc).
 2647:  *
 2648:  * Processing instruction are a way to configure the xml document with
 2649:  * processing information to instruct the application level that is
 2650:  * going to consume the XML information.
 2651:  *
 2652:  * @param doc The document where the processing instruction will be read.
 2653:  *
 2654:  * @param pi_target The process instruction name.
 2655:  * 
 2656:  * @return axl_true is the processing instruction is defined,
 2657:  * otherwise axl_false is returned.
 2658:  */
 2659: axl_bool      axl_doc_has_pi_target            (axlDoc * doc, char * pi_target)
 2660: {
 2661: 	axlPI * pi;
 2662: 	int     iterator = 0;
 2663: 	int     length   = 0;
 2664: 
 2665: 	
 2666: 	axl_return_val_if_fail (doc,       axl_false);
 2667: 	axl_return_val_if_fail (pi_target, axl_false);
 2668: 
 2669: 	/* get the length for the items inserted */
 2670: 	length = axl_list_length (doc->piTargets);
 2671: 	while (iterator < length) {
 2672: 		/* for each item inserted */
 2673: 		pi = axl_list_get_nth (doc->piTargets, iterator);
 2674: 		/* only check the first ocurrency */
 2675: 		if (axl_cmp (pi->name, pi_target))
 2676: 			return axl_true;
 2677: 
 2678: 		iterator++;
 2679: 	}
 2680: 	
 2681: 	return axl_false;
 2682: }
 2683: 
 2684: /** 
 2685:  * @brief Allows to get current processing instruction content.
 2686:  * 
 2687:  * @param doc The document where the processing instruction is placed.
 2688:  *
 2689:  * @param pi_target The processing instruction target to get current
 2690:  * content.
 2691:  * 
 2692:  * @return An internal reference to the process instruction target
 2693:  * content. Value returned mustn't be deallocated
 2694:  */
 2695: char    * axl_doc_get_pi_target_content    (axlDoc * doc, char * pi_target)
 2696: {
 2697: 	axlPI * pi;
 2698: 	int     iterator = 0;
 2699: 	int     length   = 0;
 2700: 
 2701: 	axl_return_val_if_fail (doc,       NULL);
 2702: 	axl_return_val_if_fail (pi_target, NULL);
 2703: 
 2704: 	/* get the length for the items inserted */
 2705: 	length = axl_list_length (doc->piTargets);
 2706: 	while (iterator < length) {
 2707: 		/* for each item inserted */
 2708: 		pi = axl_list_get_nth (doc->piTargets, iterator);
 2709: 		/* only check the first ocurrency */
 2710: 		if (axl_cmp (pi->name, pi_target))
 2711: 			return pi->content;
 2712: 
 2713: 		iterator++;
 2714: 	}
 2715: 
 2716: 	return NULL;
 2717: }
 2718: 
 2719: /** 
 2720:  * @brief Allows to get a list which contains \ref axlPI nodes,
 2721:  * representing all process instruction that the document has.
 2722:  *
 2723:  * While using PI, you can use the following functions to get PI
 2724:  * information:
 2725:  * 
 2726:  *  - \ref axl_doc_has_pi_target
 2727:  *  - \ref axl_doc_get_pi_target_content
 2728:  *
 2729:  * However, this function will return first ocurrency for PI found
 2730:  * inside the xml document. If you don't use repeated PI elements, you
 2731:  * won't find problems, but, if you need to iterate ever all PI found
 2732:  * or you are using repeated PI, you can use this function as follows
 2733:  * to get current pi elements:
 2734:  * \code
 2735:  * void show_all_pi (axlDoc * doc) 
 2736:  * {
 2737:  *      int       iterator;
 2738:  *      axlPI   * pi;
 2739:  *      axlList * PIs;
 2740:  *
 2741:  *      // get all PI target that the document has
 2742:  *      PIs      = axl_doc_get_pi_target_list (doc);
 2743:  *      iterator = 0;
 2744:  *
 2745:  *      while (iterator < axl_list_length (PIs)) {
 2746:  *            // get next pi stored 
 2747:  *            pi = axl_list_get_nth (PIs, iterator);
 2748:  *
 2749:  *            // do some stuff 
 2750:  *            printf ("PI found target name=%s, content=%s\n",
 2751:  *                    axl_pi_get_name (pi),
 2752:  *                    axl_pi_get_content (pi));
 2753:  *            
 2754:  *            // update the iterator
 2755:  *            iterator++;
 2756:  *      }
 2757:  *      return;
 2758:  * }
 2759:  * \endcode
 2760:  * 
 2761:  * @param doc The xml document (\ref axlDoc) where the process
 2762:  * instruction will be returned.
 2763:  * 
 2764:  * @return A reference to the list of processing instruction that the
 2765:  * xml document (\ref axlDoc) has.
 2766:  */
 2767: axlList * axl_doc_get_pi_target_list       (axlDoc * doc)
 2768: {
 2769: 	axl_return_val_if_fail (doc,       NULL);
 2770: 
 2771: 	return doc->piTargets;
 2772: }
 2773: 
 2774: /** 
 2775:  *
 2776:  * @brief Allows to create a new \ref axlPI element. 
 2777:  * 
 2778:  * @param name The PI target name.
 2779:  * @param content The PI content.
 2780:  * 
 2781:  * @return A newly allocated \ref axlPI element.
 2782:  */
 2783: axlPI * axl_pi_create (char * name, char * content)
 2784: {
 2785: 	axlPI * pi;
 2786: 
 2787: 	/* create the PI */
 2788: 	pi          = axl_new (axlPI, 1);
 2789: 	/* check allocated value */
 2790: 	if (pi == NULL)
 2791: 		return NULL;
 2792: 	pi->name    = axl_strdup (name);
 2793: 	/* check allocated value */
 2794: 	if (name && pi->name == NULL) {
 2795: 		axl_free (pi);
 2796: 		return NULL;
 2797: 	}
 2798: 		
 2799: 	/* copy the content if defined */
 2800: 	if (content != NULL) {
 2801: 		pi->content = axl_strdup (content);
 2802: 
 2803: 		/* check allocated value */
 2804: 		if (pi->content == NULL) {
 2805: 			/* free pi */
 2806: 			axl_pi_free (pi);
 2807: 			return NULL;
 2808: 		}
 2809: 			
 2810: 	}
 2811: 
 2812: 	return pi;
 2813: }
 2814: 
 2815: /** 
 2816:  * @brief Returns a newly allocated copy representing the same value
 2817:  * as the provided \ref axlPI reference.
 2818:  * 
 2819:  * @param pi The pi reference received.
 2820:  * 
 2821:  * @return A reference to the \ref axlPI element or null if it fails.
 2822:  */
 2823: axlPI   * axl_pi_copy                      (axlPI  * pi)
 2824: {
 2825: 	axlPI * _pi;
 2826: 
 2827: 	axl_return_val_if_fail (pi, NULL);
 2828: 
 2829: 	/* create the PI */
 2830: 	_pi          = axl_new (axlPI, 1);
 2831: 	/* check allocated value */
 2832: 	if (_pi == NULL)
 2833: 		return NULL;
 2834: 	_pi->name    = axl_strdup (pi->name);
 2835: 	/* check allocated value */
 2836: 	if (pi->name && _pi->name == NULL) {
 2837: 		axl_free (_pi);
 2838: 		return NULL;
 2839: 	}
 2840: 	
 2841: 	/* copy the content if defined */
 2842: 	if (pi->content != NULL) {
 2843: 		_pi->content = axl_strdup (pi->content);
 2844: 		/* check allocated value */
 2845: 		if (_pi->content == NULL) {
 2846: 			/* free pi */
 2847: 			axl_pi_free (_pi);
 2848: 			return NULL;
 2849: 		}
 2850: 	}
 2851: 
 2852: 	return _pi;
 2853: }
 2854: 
 2855: /** 
 2856:  * @brief Allows to check if both provided process instructions are
 2857:  * equal.
 2858:  * 
 2859:  * @param pi First process instruction to check.
 2860:  * @param pi2 Second process instructions to check.
 2861:  * 
 2862:  * @return \ref axl_true if both process instructions are equal. If some
 2863:  * of parameters received are NULL, the function will always return
 2864:  * \ref axl_false.
 2865:  */
 2866: axl_bool      axl_pi_are_equal                 (axlPI * pi, 
 2867: 						axlPI * pi2)
 2868: {
 2869: 	/* basic null reference check */
 2870: 	axl_return_val_if_fail (pi, axl_false);
 2871: 	axl_return_val_if_fail (pi2, axl_false);
 2872: 
 2873: 	/* check internal data */
 2874: 	if (! axl_cmp (pi->name, pi2->name))
 2875: 		return axl_false;
 2876: 
 2877: 	/* final check, both content must be equal */
 2878: 	return axl_cmp (pi->content, pi2->content);
 2879: }
 2880: 
 2881: /** 
 2882:  * @brief Allows to get current pi name from the given \ref axlPI
 2883:  * reference.
 2884:  *
 2885:  * @param pi The PI reference where the name will returned.
 2886:  * 
 2887:  * @return A string representing the PI name. Returned value shouldn't
 2888:  * be deallocated.
 2889:  */
 2890: char    * axl_pi_get_name                  (axlPI  * pi)
 2891: {
 2892: 	axl_return_val_if_fail (pi, NULL);
 2893: 
 2894: 	/* return current PI name */
 2895: 	return pi->name;
 2896: }
 2897: 
 2898: /** 
 2899:  * @brief Allows to get current optinal PI content.
 2900:  * 
 2901:  * @param pi The PI where the content will be returned.
 2902:  * 
 2903:  * @return A string representing the PI content. This value could be
 2904:  * NULL because it is optional to be defined. Returned value must not
 2905:  * be deallocated.
 2906:  */
 2907: char    * axl_pi_get_content               (axlPI  * pi)
 2908: {
 2909: 	axl_return_val_if_fail (pi, NULL);
 2910: 	
 2911: 	/* return current PI content */
 2912: 	return pi->content;
 2913: }
 2914: 
 2915: /** 
 2916:  * @brief Deallocates memory used by the \ref axlPI target.
 2917:  * 
 2918:  * @param pi The target to destroy.
 2919:  */
 2920: void axl_pi_free (axlPI * pi)
 2921: {
 2922: 	if (pi == NULL)
 2923: 		return;
 2924: 
 2925: 	/* free PI target */
 2926: 	axl_free (pi->name);
 2927: 	axl_free (pi->content);
 2928: 	axl_free (pi);
 2929: 	return;
 2930: }
 2931: 
 2932: /** 
 2933:  * @internal Allows to get the number of bytes that the process
 2934:  * instruction will take.
 2935:  * 
 2936:  * @param pi The process instruction.
 2937:  * 
 2938:  * @return A size or -1 if it fails.
 2939:  */
 2940: int       axl_pi_get_size                  (axlPI  * pi)
 2941: {
 2942: 	axl_return_val_if_fail (pi, -1);
 2943: 
 2944: 	/* <?name content?> */
 2945: 	return strlen (pi->name) + strlen (pi->content) + 5;
 2946: }
 2947: 
 2948: /** 
 2949:  * @internal
 2950:  *
 2951:  * Common implementation for \ref axl_doc_iterate and \ref axl_doc_iterate2.
 2952:  */
 2953: axl_bool __axl_doc_iterate_common (axlDoc            * doc, 
 2954: 				   axlNode           * root,
 2955: 				   AxlIterationMode    mode, 
 2956: 				   axlIterationFunc    func, 
 2957: 				   axlIterationFunc2   func2, 
 2958: 				   axlPointer          ptr, 
 2959: 				   axlPointer          ptr2)
 2960: {
 2961: 	int        iterator;
 2962: 	axl_bool   was_removed = axl_false;
 2963: 
 2964: 	axlNode  * node;
 2965: 	axlNode  * nodeAux;
 2966: 
 2967: 	axlList  * pending;
 2968: 
 2969: 	/* check first node */
 2970: 	axl_return_val_if_fail (root, axl_false);
 2971: 
 2972: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "notifying first node inside the iteration");
 2973: 
 2974: 	/* notify first node found we pass in a null value because it
 2975: 	   doesn't have a * parent. */
 2976: 	if (func && ! func (root, NULL, doc, &was_removed, ptr))
 2977: 		return axl_false;
 2978: 	if (func2 && ! func2 (root, NULL, doc, &was_removed, ptr, ptr2)) 
 2979: 		return axl_false;
 2980: 
 2981: 	/* if the root node was removed, don't continue */
 2982: 	if (was_removed)
 2983: 		return axl_false;
 2984: 
 2985: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "continuing with next nodes");
 2986: 	
 2987: 	/* get childs */
 2988: 	pending  = axl_node_get_childs (root);
 2989: 
 2990: 	/* for each pending node */
 2991: 	while (axl_list_length (pending) > 0) {
 2992: 
 2993: 		/* get the first node inside the pending list */
 2994: 		node = axl_list_get_first (pending);
 2995: 
 2996: 		/* remove the node node from the pending list and add
 2997: 		 * all childs */
 2998: 		axl_list_remove_first (pending);
 2999: 
 3000: 		/* notify node found */
 3001: 		was_removed = axl_false;
 3002: 		if (func && ! func (node, axl_node_get_parent (node), doc, &was_removed, ptr)) {
 3003: 			axl_list_free (pending);
 3004: 			return axl_false;
 3005: 		}
 3006: 
 3007: 		/* notify node found */
 3008: 		if (func2 && ! func2 (node, axl_node_get_parent (node), doc, &was_removed, ptr, ptr2)) {
 3009: 			axl_list_free (pending);
 3010: 			return axl_false;
 3011: 		}
 3012: 
 3013: 		/* add all its childs */
 3014: 		if (!was_removed && axl_node_have_childs (node)) {
 3015: 			
 3016: 			/* get first child */
 3017: 			nodeAux = axl_node_get_first_child (node);
 3018: 
 3019: 			/* get all items of the next level and add
 3020: 			 * them properly */
 3021: 			iterator = 0;
 3022: 			while (nodeAux != NULL) {
 3023: 
 3024: 				/* add to the pending list */
 3025: 				switch (mode) {
 3026: 				case DEEP_ITERATION:
 3027: 					/* add the element */
 3028: 					axl_list_add_at (pending, nodeAux, iterator);
 3029: 					
 3030: 					/* update the iterator */
 3031: 					iterator++;
 3032: 					break;
 3033: 
 3034: 				case WIDE_ITERATION:
 3035: 					/* add to the pending list */
 3036: 					axl_list_add (pending, nodeAux);
 3037: 					break;
 3038: 				} /* end switch */
 3039: 	
 3040: 
 3041: 				/* update to the next */
 3042: 				nodeAux = axl_node_get_next (nodeAux);
 3043: 				
 3044: 			} /* end while */
 3045: 		} /* end if */
 3046: 
 3047: 		
 3048: 	} /* end while */
 3049: 
 3050: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "terminated iteration process, deallocating list: %d",
 3051: 		   axl_list_length (pending));
 3052: 	
 3053: 	axl_list_free (pending);
 3054: 	
 3055: 	/* iteration performed completely */
 3056: 	return axl_true;
 3057: }
 3058: 
 3059: /** 
 3060:  * @brief Allows to perform an iteration over the documented provided,
 3061:  * visiting all nodes inside it.
 3062:  *
 3063:  * The function allows to configure the iteration module using \ref
 3064:  * AxlIterationMode (mode variable) and providing a callback function
 3065:  * that will be called for each node found (\ref axlIterationFunc).
 3066:  *
 3067:  * The function, optionall, allows to provide a user pointer that will
 3068:  * be passed to the callback function. See documentation for the
 3069:  * callback and the iteration module for more details.
 3070:  *
 3071:  * Here is an example:
 3072:  * \code
 3073:  * void perform_iteration (axlDoc * doc)
 3074:  * {
 3075:  *     // call to iterate
 3076:  *     axl_doc_iterate (doc, 
 3077:  *                      // visit childs before brothers
 3078:  *                      DEEP_ITERATION, 
 3079:  *                      // the func to execute: see below
 3080:  *                      show_node_found, 
 3081:  *                      // optional user pointer
 3082:  *                      NULL);
 3083:  * }
 3084:  *
 3085:  * axl_bool show_node_found (axlNode * node, axlNode * parent,
 3086:  *                       axlDoc  * doc, axl_bool * was_removed, 
 3087:  *                       axlPointer ptr)
 3088:  * {
 3089:  *      // Show node found 
 3090:  *      printf ("Node found: %s\n", axl_node_get_name (node));
 3091:  *
 3092:  *      // If the node is removed inside the iteration
 3093:  *      // using axl_node_remove or axl_node_replace, you
 3094:  *      // must notify the iteration system using was_removed
 3095:  *      // as follow: (* was_removed) = axl_true;
 3096:  *      //
 3097:  *      // If you don't remove anything, you don't need to do
 3098:  *      // anything especial with was_removed.
 3099:  *
 3100:  *      // don't stop iteration
 3101:  *      return axl_true;
 3102:  * }
 3103:  * \endcode
 3104:  *
 3105:  * See also alternative APIs:
 3106:  * 
 3107:  *   - \ref axl_doc_iterate_full
 3108:  *   - \ref axl_doc_iterate_full_from
 3109:  * 
 3110:  * @param doc The xml document that will be iterated.
 3111:  *
 3112:  * @param mode The iterarion type to be performed.
 3113:  *
 3114:  * @param func The function to be called for each node found.
 3115:  *
 3116:  * @param ptr An user defined pointer that will be passed to the
 3117:  * callback function.
 3118:  *
 3119:  * @return The function returns \ref axl_true if the iteration was
 3120:  * performed over all nodes or \ref axl_false it it was stoped by the
 3121:  * iteration function (by returning \ref axl_false to stop the
 3122:  * iteration). The function also axl_false if the parameters provided doc
 3123:  * or func are not defined.
 3124:  */
 3125: axl_bool      axl_doc_iterate                  (axlDoc           * doc,
 3126: 						AxlIterationMode   mode,
 3127: 						axlIterationFunc   func,
 3128: 						axlPointer         ptr)
 3129: {
 3130: 	axlNode * root;
 3131: 
 3132: 	/* check basic data */
 3133: 	axl_return_val_if_fail (doc, axl_false);
 3134: 	axl_return_val_if_fail (func, axl_false);
 3135: 
 3136: 	/* get the root node where the iteration will start */
 3137: 	root = axl_doc_get_root (doc);
 3138: 
 3139: 	/* call to common implementation */
 3140: 	return __axl_doc_iterate_common (doc, root, mode, func, NULL, ptr, NULL);
 3141: 
 3142: }
 3143: 
 3144: 
 3145: /** 
 3146:  * @brief Allows to perform an iteration over the documented provided,
 3147:  * visiting all nodes inside it (with two user defined pointers support).
 3148:  *
 3149:  * The function allows to configure the iteration module using \ref
 3150:  * AxlIterationMode (mode variable) and providing a callback function
 3151:  * that will be called for each node found (\ref axlIterationFunc).
 3152:  *
 3153:  * The function, optionall, allows to provide two user pointer that will
 3154:  * be passed to the callback function. See documentation for the
 3155:  * callback and the iteration module for more details. See also \ref axl_doc_iterate.
 3156:  *
 3157:  * 
 3158:  * @param doc The xml document that will be iterated.
 3159:  *
 3160:  * @param mode The iterarion type to be performed.
 3161:  *
 3162:  * @param func The function to be called for each node found.
 3163:  *
 3164:  * @param ptr An user defined pointer that will be passed to the
 3165:  * callback function.
 3166:  *
 3167:  * @param ptr2 Second user defined pointer that will be passed to the
 3168:  * callback function.
 3169:  * 
 3170:  *
 3171:  * @return The function returns \ref axl_true if the iteration was
 3172:  * performed over all nodes or \ref axl_false it it was stoped by the
 3173:  * iteration function (by returning \ref axl_false to stop the
 3174:  * iteration). The function also axl_false if the parameters provided doc
 3175:  * or func are not defined.
 3176:  */
 3177: axl_bool      axl_doc_iterate_full             (axlDoc            * doc,
 3178: 						AxlIterationMode    mode,
 3179: 						axlIterationFunc2   func,
 3180: 						axlPointer          ptr,
 3181: 						axlPointer          ptr2)
 3182: 
 3183: {
 3184: 	axlNode * root;
 3185: 
 3186: 	/* check basic data */
 3187: 	axl_return_val_if_fail (doc, axl_false);
 3188: 	axl_return_val_if_fail (func, axl_false);
 3189: 
 3190: 	/* get the root node where the iteration will start */
 3191: 	root = axl_doc_get_root (doc);
 3192: 	
 3193: 	/* call to common implementation */
 3194: 	return __axl_doc_iterate_common (doc, root, mode, NULL, func, ptr, ptr2);
 3195: }
 3196: 
 3197: /** 
 3198:  * @brief Allows to perform a iteration operation but configuring
 3199:  * where to start, discarding the rest content.
 3200:  *
 3201:  * See \ref axl_doc_iterate and \ref axl_doc_iterate_full for more
 3202:  * details. This function works the same like previous but, unlike
 3203:  * previous, this function doesn't use the default starting point: the
 3204:  * root node (\ref axl_doc_get_root). The function allows to configure
 3205:  * the node where to start the iteration operation. 
 3206:  *
 3207:  * This function is equivalent to \ref axl_doc_iterate_full calling if
 3208:  * it use the root node document as value for <b>starting_from</b>.
 3209:  * 
 3210:  * @param doc The xml document that will be iterated.
 3211:  *
 3212:  * @param starting_from The \ref axlNode where the operation will
 3213:  * start, discarding all content from ascending nodes, previous
 3214:  * siblings and following sibligins. From a iteration perspective, the
 3215:  * iteration opeeration.
 3216:  *
 3217:  * @param mode The iterarion type to be performed.
 3218:  *
 3219:  * @param func The function to be called for each node found.
 3220:  *
 3221:  * @param ptr An user defined pointer that will be passed to the
 3222:  * callback function.
 3223:  *
 3224:  * @param ptr2 Second user defined pointer that will be passed to the
 3225:  * callback function.
 3226:  * 
 3227:  *
 3228:  * @return The function returns \ref axl_true if the iteration was
 3229:  * performed over all nodes or \ref axl_false it it was stoped by the
 3230:  * iteration function (by returning \ref axl_false to stop the
 3231:  * iteration). The function also axl_false if the parameters provided doc
 3232:  * or func are not defined.
 3233:  */
 3234: axl_bool      axl_doc_iterate_full_from        (axlDoc           * doc,
 3235: 						axlNode          * starting_from,
 3236: 						AxlIterationMode   mode,
 3237: 						axlIterationFunc2  func,
 3238: 						axlPointer         ptr,
 3239: 						axlPointer         ptr2)
 3240: {
 3241: 	/* check basic data */
 3242: 	axl_return_val_if_fail (doc, axl_false);
 3243: 	axl_return_val_if_fail (func, axl_false);
 3244: 
 3245: 	/* call to common implementation */
 3246: 	return __axl_doc_iterate_common (doc, starting_from, mode, NULL, func, ptr, ptr2);
 3247: }
 3248: 
 3249: 
 3250: /** 
 3251:  * @brief Releases memory allocated by the \ref axlDoc object.
 3252:  * 
 3253:  * @param doc The \ref axlDoc object to unref.
 3254:  */
 3255: void     axl_doc_free         (axlDoc * doc)
 3256: {
 3257: 	/* do not complain if an axlDoc reference is received */
 3258: 	if (doc == NULL)
 3259: 		return;
 3260: 
 3261: 	/* free first root node */
 3262: 	if (doc->rootNode != NULL)
 3263: 		axl_node_free (doc->rootNode);
 3264: 
 3265: 	/* free node hierarchy */
 3266: 	if (doc->parentNode != NULL)
 3267: 		axl_stack_free (doc->parentNode);
 3268: 
 3269: 	/* free xml:space hierarchy */
 3270: 	if (doc->xmlPreserve != NULL)
 3271: 		axl_binary_stack_free (doc->xmlPreserve);
 3272: 
 3273: 	/* free item factory */
 3274: 	if (doc->item_factory != NULL)
 3275: 		axl_factory_free (doc->item_factory);
 3276: 
 3277: 	/* free content holding nodes factory */
 3278: 	if (doc->content_factory != NULL)
 3279: 		axl_factory_free (doc->content_factory);
 3280: 
 3281: 	/* free attribute holding factory */
 3282: 	if (doc->attr_factory != NULL)
 3283: 		axl_factory_free (doc->attr_factory);
 3284: 
 3285: 	/* free node factory */
 3286: 	if (doc->node_factory != NULL)
 3287: 		axl_factory_free (doc->node_factory);
 3288: 
 3289: 	if (doc->str_factory != NULL)
 3290: 		axl_string_factory_free (doc->str_factory);
 3291: 
 3292: 	/* free pi targets read */
 3293: 	if (doc->piTargets != NULL)
 3294: 		axl_list_free (doc->piTargets);
 3295: 
 3296: 	/* free enconding allocated */
 3297: 	axl_free (doc->encoding);
 3298: 	axl_free (doc->encoding_found);
 3299: 	
 3300: 	/* free allocated version value */
 3301: 	axl_free (doc->version);
 3302: 
 3303: 	/* free document allocated */
 3304: 	axl_free (doc);
 3305: 
 3306: 	return;
 3307: }
 3308: 
 3309: /** 
 3310:  * @internal
 3311:  *
 3312:  * @brief Allows to consume comments found while reading xml files.
 3313:  * 
 3314:  * @param stream The axlStream where the comment is spected to be read.
 3315:  *
 3316:  * @param error An optional axlError where problem will be reported.
 3317:  */
 3318: axl_bool      axl_doc_consume_comments         (axlDoc * doc, axlStream * stream, axlError ** error)
 3319: {
 3320: 
 3321: 	axl_bool     found_item;
 3322: 	char       * content;
 3323: 	int          size;
 3324: 
 3325: 	/* get current parent node */
 3326: 	axlNode * parent = (doc != NULL) ? axl_stack_peek (doc->parentNode) : NULL;
 3327: 
 3328: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "checking for comemnts");
 3329: 
 3330: 	/* know, try to read comments a process instructions.  Do this
 3331: 	 * until both fails. Do this until one of them find
 3332: 	 * something. */
 3333: 	do {
 3334: 		/* flag the loop to end, and only end if both,
 3335: 		 * comments matching and PI matching fails. */
 3336: 		found_item = axl_false;
 3337: 		
 3338: 		/* get rid from spaces */
 3339: 		AXL_CONSUME_SPACES(stream);
 3340: 
 3341: 		/* check for comments */
 3342: 		if (axl_stream_inspect (stream, "<!--", 4) > 0) {
 3343: 
 3344: 			/* get comment content */
 3345: 			content = axl_stream_get_until_ref (stream, NULL, NULL, axl_true, &size, 1, "-->");
 3346: 			if (content == NULL) {
 3347: 				axl_error_new (-1, "detected an opened comment but not found the comment ending",
 3348: 					       stream, error);
 3349: 				axl_stream_free (stream);
 3350: 				return axl_false;
 3351: 			} 
 3352: 
 3353: 			/* store it */
 3354: 			if (parent != NULL)
 3355: 				axl_node_set_comment (parent, content, size);
 3356: 			
 3357: 			/* flag that we have found a comment */
 3358: 			found_item = axl_true;
 3359: 		}
 3360: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "now see for process instructions");
 3361: 	
 3362: 		/* get rid from spaces */
 3363: 		AXL_CONSUME_SPACES(stream);
 3364: 
 3365: 		/* check for PI, only once the xml header have been processed */
 3366: 		if ((doc != NULL) && doc->headerProcess && (axl_stream_peek (stream, "<?", 2) > 0)) {
 3367: 			
 3368: 			if (! axl_doc_consume_pi (doc, axl_stack_peek (doc->parentNode), stream, error))
 3369: 				return axl_false;
 3370: 			found_item = axl_true;
 3371: 		}
 3372: 		
 3373: 		/* do not consume spaces if an item was found because
 3374: 		 * it is done again at the begin of the loop */
 3375: 		if (! found_item) {
 3376: 			/* get rid from spaces */
 3377: 			AXL_CONSUME_SPACES(stream);
 3378: 		}
 3379: 		
 3380: 		/* check to break-the-loop */
 3381: 	}while (found_item);
 3382: 
 3383: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "comments and pi parsed");
 3384: 
 3385: 	/* axl_true value */
 3386: 	return axl_true;
 3387: }
 3388: 
 3389: /** 
 3390:  * @internal
 3391:  *
 3392:  * @brie Consumes Processing intructions that are directed to the
 3393:  * application ans configuration or processing instructions.
 3394:  * 
 3395:  * @param doc The document there the information will be placed.
 3396:  * 
 3397:  * @param stream The stream where the data is being read.
 3398:  *
 3399:  * @param error An optional axlError where the information will be
 3400:  * reported.
 3401:  * 
 3402:  * @return axl_true if not error was found, otherwise AXL_FASLSE is
 3403:  * returned.
 3404:  */
 3405: axl_bool      axl_doc_consume_pi (axlDoc * doc, axlNode * node, 
 3406: 				  axlStream * stream, axlError ** error)
 3407: {
 3408: 	char  * string_aux;
 3409: 	char  * string_aux2;
 3410: 	int     matched_chunk;
 3411: 	
 3412: 	
 3413: 	/* check if a PI target was found */
 3414: 
 3415: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "calling to consume PI..");
 3416: 
 3417: 
 3418: 	if (axl_stream_peek (stream, "<?", 2) > 0) {
 3419: 
 3420: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found a process instruction initialization");
 3421: 
 3422: 		/* found a pi target initialization */
 3423: 		axl_stream_accept (stream);
 3424: 		
 3425: 		string_aux = axl_stream_get_until (stream, NULL, &matched_chunk, axl_true, 3, 
 3426: 						   " ?>", "?>", " ");
 3427: 		/* check error reported */
 3428: 		if (string_aux == NULL) {
 3429: 			axl_error_new (-1, "Found a error while reading the PI target name", stream, error);
 3430: 			axl_stream_free (stream);
 3431: 			return axl_false;
 3432: 		}
 3433: 
 3434: 		/* check that the reserved xml word is not used for the PI target */
 3435: 		string_aux2 = axl_strdup (string_aux);
 3436: 		if (axl_cmp (axl_stream_to_lower (string_aux2), "xml")) {
 3437: 			axl_free (string_aux2);
 3438: 			axl_error_new (-1, "Using a reserved PI target name (xml), not allowed", stream, error);
 3439: 			axl_stream_free (stream);
 3440: 			return axl_false;
 3441: 		}
 3442: 		axl_free (string_aux2);
 3443: 
 3444: 
 3445: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found PI target name: %s (terminator matched: %d)", 
 3446: 			   string_aux, matched_chunk);
 3447: 
 3448: 		/* check which was the matched string */
 3449: 		if (matched_chunk == 0 || matched_chunk == 1) {
 3450: 			/* seems that the PI target doesn't have more data associated, craete and return */
 3451: 			if (node != NULL) {
 3452: 				axl_node_add_pi_target (node, string_aux, NULL);
 3453: 				return axl_true;
 3454: 			}
 3455: 			
 3456: 			if (doc != NULL)
 3457: 				axl_doc_add_pi_target (doc, string_aux, NULL);
 3458: 			return axl_true;
 3459: 		}
 3460: 
 3461: 		/* seems that we have additional content to be read */
 3462: 		if (matched_chunk == 2) {
 3463: 			/* make a local copy for the PI target name
 3464: 			 * read previously */
 3465: 			string_aux  = axl_strdup (string_aux);
 3466: 			
 3467: 			/* get the PI content */
 3468: 			string_aux2 = axl_stream_get_until (stream, NULL, NULL, axl_true, 2, " ?>", "?>");
 3469: 
 3470: 			/* check error reported */
 3471: 			if (string_aux2 == NULL) {
 3472: 				axl_free (string_aux);
 3473: 				axl_error_new (-1, "Found a error while reading the PI content", stream, error);
 3474: 				axl_stream_free (stream);
 3475: 				return axl_false;
 3476: 			}
 3477: 
 3478: 			/* check the destination for the pi */			
 3479: 			if (node != NULL) {
 3480: 				__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "PI processing finished, adding PI (node) and its content");
 3481: 
 3482: 				axl_node_add_pi_target (node, string_aux, string_aux2);
 3483: 				axl_free (string_aux);
 3484: 				return axl_true;
 3485: 			}
 3486: 
 3487: 
 3488: 			if (doc != NULL) {
 3489: 				__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "PI processing finished, adding PI (doc) and its content");
 3490: 				axl_doc_add_pi_target (doc, string_aux, string_aux2);
 3491: 				axl_free (string_aux);
 3492: 				return axl_true;
 3493: 			}
 3494: 
 3495: 		}
 3496: 
 3497: 		/* check error reported */
 3498: 		axl_error_new (-1, "Found a error while reading the PI target name, unable to find PI terminator ?>", stream, error);
 3499: 		axl_stream_free (stream);
 3500: 		return axl_false;
 3501: 	}
 3502: 
 3503: 	
 3504: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "PI processing finished");
 3505: 
 3506: 
 3507: 	return axl_true;
 3508: }
 3509: 
 3510: /** 
 3511:  * @internal Function that allows to get axlFactory associated to
 3512:  * the provided document.
 3513:  * 
 3514:  * @param doc The axl document that is requested to return its item
 3515:  * factory.
 3516:  * 
 3517:  * @return An internal reference to the item factory. Do not dealloc.
 3518:  */
 3519: axlFactory * axl_doc_get_item_factory  (axlDoc * doc)
 3520: {
 3521: 	return doc->item_factory;
 3522: }
 3523: 
 3524: /** 
 3525:  * @brief Allows to configure a handler that implements document
 3526:  * detection and in such cases reconfigure \ref axlStream to act an a
 3527:  * proper manner.
 3528:  * 
 3529:  * @param func The function to be configured.
 3530:  *
 3531:  * @param user_data User defined data to be provide to the function.
 3532:  *
 3533:  * @return A reference to the previously configured function.
 3534:  */
 3535: axlDocDetectCodification axl_doc_set_detect_codification_func (axlDocDetectCodification func, 
 3536: 							       axlPointer user_data)
 3537: {
 3538: 	axlDocDetectCodification previous;
 3539: 	
 3540: 	/* configure handler and user defined pointer */
 3541: 	previous                 = detect_codification_func;
 3542: 	detect_codification_func = func;
 3543: 	detect_codification_data = user_data;
 3544: 
 3545: 	return previous;
 3546: }
 3547: 
 3548: /** 
 3549:  * @brief Allows to configure the handler used to finally configure
 3550:  * codification to be used for a particular \ref axlStream.
 3551:  * 
 3552:  * @param func The function to be called to configure codification.
 3553:  *
 3554:  * @param user_data A reference to user defined data to be passed to
 3555:  * the function.
 3556:  * 
 3557:  * @return A refernece to the previous handler configured.
 3558:  */
 3559: axlDocConfigureCodification axl_doc_set_configure_codification_func (axlDocConfigureCodification func, 
 3560: 								     axlPointer user_data)
 3561: {
 3562: 	axlDocConfigureCodification previous;
 3563: 	
 3564: 	/* configure handler and user defined pointer */
 3565: 	previous                    = configure_codification_func;
 3566: 	configure_codification_func = func;
 3567: 	configure_codification_data = user_data;
 3568: 
 3569: 	return previous;
 3570: }
 3571: 
 3572: /* @} */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>