mxml-file.c 78 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666
  1. /*
  2. * File loading code for Mini-XML, a small XML file parsing library.
  3. *
  4. * https://www.msweet.org/mxml
  5. *
  6. * Copyright © 2003-2021 by Michael R Sweet.
  7. *
  8. * Licensed under Apache License v2.0. See the file "LICENSE" for more
  9. * information.
  10. */
  11. /*
  12. * Include necessary headers...
  13. */
  14. #ifndef _WIN32
  15. # include <unistd.h>
  16. #endif /* !_WIN32 */
  17. #include "mxml-private.h"
  18. /*
  19. * Character encoding...
  20. */
  21. #define ENCODE_UTF8 0 /* UTF-8 */
  22. #define ENCODE_UTF16BE 1 /* UTF-16 Big-Endian */
  23. #define ENCODE_UTF16LE 2 /* UTF-16 Little-Endian */
  24. /*
  25. * Macro to test for a bad XML character...
  26. */
  27. #define mxml_bad_char(ch) ((ch) < ' ' && (ch) != '\n' && (ch) != '\r' && (ch) != '\t')
  28. /*
  29. * Types and structures...
  30. */
  31. typedef int (*_mxml_getc_cb_t)(void *, int *);
  32. typedef int (*_mxml_putc_cb_t)(int, void *);
  33. typedef struct _mxml_fdbuf_s /**** File descriptor buffer ****/
  34. {
  35. int fd; /* File descriptor */
  36. unsigned char *current, /* Current position in buffer */
  37. *end, /* End of buffer */
  38. buffer[8192]; /* Character buffer */
  39. } _mxml_fdbuf_t;
  40. typedef struct _mxml_streambuf_s /**** File descriptor buffer ****/
  41. {
  42. void * ctxt; /* File descriptor */
  43. mxml_read_stream_cb_t read;
  44. mxml_write_stream_cb_t write;
  45. unsigned char *current, /* Current position in buffer */
  46. *end, /* End of buffer */
  47. buffer[8192]; /* Character buffer */
  48. } _mxml_streambuf_t;
  49. /*
  50. * Local functions...
  51. */
  52. static int mxml_add_char(int ch, char **ptr, char **buffer, int *bufsize);
  53. static int mxml_fd_getc(void *p, int *encoding);
  54. static int mxml_fd_putc(int ch, void *p);
  55. static int mxml_fd_read(_mxml_fdbuf_t *buf);
  56. static int mxml_fd_write(_mxml_fdbuf_t *buf);
  57. static int mxml_stream_getc(void *p, int *encoding);
  58. static int mxml_stream_putc(int ch, void *p);
  59. static int mxml_stream_read(_mxml_streambuf_t *buf);
  60. static int mxml_stream_write(_mxml_streambuf_t *buf);
  61. static int mxml_file_getc(void *p, int *encoding);
  62. static int mxml_file_putc(int ch, void *p);
  63. static int mxml_get_entity(mxml_node_t *parent, void *p, int *encoding, _mxml_getc_cb_t getc_cb, int *line);
  64. static inline int mxml_isspace(int ch)
  65. {
  66. return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
  67. }
  68. static mxml_node_t *mxml_load_data(mxml_node_t *top, void *p, mxml_load_cb_t cb, _mxml_getc_cb_t getc_cb, mxml_sax_cb_t sax_cb, void *sax_data);
  69. static int mxml_parse_element(mxml_node_t *node, void *p, int *encoding, _mxml_getc_cb_t getc_cb, int *line);
  70. static int mxml_string_getc(void *p, int *encoding);
  71. static int mxml_string_putc(int ch, void *p);
  72. static int mxml_write_name(const char *s, void *p, _mxml_putc_cb_t putc_cb);
  73. static int mxml_write_node(mxml_node_t *node, void *p, mxml_save_cb_t cb, int col, _mxml_putc_cb_t putc_cb, _mxml_global_t *global, void *cb_ctx);
  74. static int mxml_write_string(const char *s, void *p, _mxml_putc_cb_t putc_cb);
  75. static int mxml_write_ws(mxml_node_t *node, void *p, mxml_save_cb_t cb, int ws, int col, _mxml_putc_cb_t putc_cb, void *cb_ctx);
  76. /*
  77. * 'mxmlLoadFd()' - Load a file descriptor into an XML node tree.
  78. *
  79. * The nodes in the specified file are added to the specified top node.
  80. * If no top node is provided, the XML file MUST be well-formed with a
  81. * single parent node like <?xml> for the entire file. The callback
  82. * function returns the value type that should be used for child nodes.
  83. * The constants @code MXML_INTEGER_CALLBACK@, @code MXML_OPAQUE_CALLBACK@,
  84. * @code MXML_REAL_CALLBACK@, and @code MXML_TEXT_CALLBACK@ are defined for
  85. * loading child (data) nodes of the specified type.
  86. *
  87. * Note: The most common programming error when using the Mini-XML library is
  88. * to load an XML file using the @code MXML_TEXT_CALLBACK@, which returns inline
  89. * text as a series of whitespace-delimited words, instead of using the
  90. * @code MXML_OPAQUE_CALLBACK@ which returns the inline text as a single string
  91. * (including whitespace).
  92. */
  93. mxml_node_t * /* O - First node or @code NULL@ if the file could not be read. */
  94. mxmlLoadFd(mxml_node_t *top, /* I - Top node */
  95. int fd, /* I - File descriptor to read from */
  96. mxml_load_cb_t cb) /* I - Callback function or constant */
  97. {
  98. _mxml_fdbuf_t buf; /* File descriptor buffer */
  99. /*
  100. * Initialize the file descriptor buffer...
  101. */
  102. buf.fd = fd;
  103. buf.current = buf.buffer;
  104. buf.end = buf.buffer;
  105. /*
  106. * Read the XML data...
  107. */
  108. return (mxml_load_data(top, &buf, cb, mxml_fd_getc, MXML_NO_CALLBACK, NULL));
  109. }
  110. /*
  111. * 'mxmlLoadFile()' - Load a file into an XML node tree.
  112. *
  113. * The nodes in the specified file are added to the specified top node.
  114. * If no top node is provided, the XML file MUST be well-formed with a
  115. * single parent node like <?xml> for the entire file. The callback
  116. * function returns the value type that should be used for child nodes.
  117. * The constants @code MXML_INTEGER_CALLBACK@, @code MXML_OPAQUE_CALLBACK@,
  118. * @code MXML_REAL_CALLBACK@, and @code MXML_TEXT_CALLBACK@ are defined for
  119. * loading child (data) nodes of the specified type.
  120. *
  121. * Note: The most common programming error when using the Mini-XML library is
  122. * to load an XML file using the @code MXML_TEXT_CALLBACK@, which returns inline
  123. * text as a series of whitespace-delimited words, instead of using the
  124. * @code MXML_OPAQUE_CALLBACK@ which returns the inline text as a single string
  125. * (including whitespace).
  126. */
  127. mxml_node_t * /* O - First node or @code NULL@ if the file could not be read. */
  128. mxmlLoadFile(mxml_node_t *top, /* I - Top node */
  129. FILE *fp, /* I - File to read from */
  130. mxml_load_cb_t cb) /* I - Callback function or constant */
  131. {
  132. /*
  133. * Read the XML data...
  134. */
  135. return (mxml_load_data(top, fp, cb, mxml_file_getc, MXML_NO_CALLBACK, NULL));
  136. }
  137. /*
  138. * 'mxmlLoadString()' - Load a string into an XML node tree.
  139. *
  140. * The nodes in the specified string are added to the specified top node.
  141. * If no top node is provided, the XML string MUST be well-formed with a
  142. * single parent node like <?xml> for the entire string. The callback
  143. * function returns the value type that should be used for child nodes.
  144. * The constants @code MXML_INTEGER_CALLBACK@, @code MXML_OPAQUE_CALLBACK@,
  145. * @code MXML_REAL_CALLBACK@, and @code MXML_TEXT_CALLBACK@ are defined for
  146. * loading child (data) nodes of the specified type.
  147. *
  148. * Note: The most common programming error when using the Mini-XML library is
  149. * to load an XML file using the @code MXML_TEXT_CALLBACK@, which returns inline
  150. * text as a series of whitespace-delimited words, instead of using the
  151. * @code MXML_OPAQUE_CALLBACK@ which returns the inline text as a single string
  152. * (including whitespace).
  153. */
  154. mxml_node_t * /* O - First node or @code NULL@ if the string has errors. */
  155. mxmlLoadString(mxml_node_t *top, /* I - Top node */
  156. const char *s, /* I - String to load */
  157. mxml_load_cb_t cb) /* I - Callback function or constant */
  158. {
  159. /*
  160. * Read the XML data...
  161. */
  162. return (mxml_load_data(top, (void *)&s, cb, mxml_string_getc, MXML_NO_CALLBACK,
  163. NULL));
  164. }
  165. /*
  166. * 'mxmlLoadStream()' - Load a stream into an XML node tree.
  167. *
  168. * The nodes in the specified stream are added to the specified top node.
  169. * If no top node is provided, the XML file MUST be well-formed with a
  170. * single parent node like <?xml> for the entire file. The callback
  171. * function returns the value type that should be used for child nodes.
  172. * The constants @code MXML_INTEGER_CALLBACK@, @code MXML_OPAQUE_CALLBACK@,
  173. * @code MXML_REAL_CALLBACK@, and @code MXML_TEXT_CALLBACK@ are defined for
  174. * loading child (data) nodes of the specified type.
  175. *
  176. * Note: The most common programming error when using the Mini-XML library is
  177. * to load an XML file using the @code MXML_TEXT_CALLBACK@, which returns inline
  178. * text as a series of whitespace-delimited words, instead of using the
  179. * @code MXML_OPAQUE_CALLBACK@ which returns the inline text as a single string
  180. * (including whitespace).
  181. */
  182. mxml_node_t * /* O - First node or @code NULL@ if the file could not be read. */
  183. mxmlLoadStream(mxml_node_t *top, /* I - Top node */
  184. mxml_read_stream_cb_t read_stream_cb, /* I - Stream callback */
  185. void *read_stream_context, /* I - Stream context */
  186. mxml_load_cb_t cb) /* I - Callback function or constant */
  187. {
  188. _mxml_streambuf_t buf; /* stream buffer */
  189. /*
  190. * Initialize the stream buffer...
  191. */
  192. buf.ctxt = read_stream_context;
  193. buf.read = read_stream_cb;
  194. buf.current = buf.buffer;
  195. buf.end = buf.buffer;
  196. /*
  197. * Read the XML data...
  198. */
  199. return (mxml_load_data(top, &buf, cb, mxml_stream_getc, MXML_NO_CALLBACK, NULL));
  200. }
  201. /*
  202. * 'mxmlSaveAllocString()' - Save an XML tree to an allocated string.
  203. *
  204. * This function returns a pointer to a string containing the textual
  205. * representation of the XML node tree. The string should be freed
  206. * using `free()` when you are done with it. `NULL` is returned if the node
  207. * would produce an empty string or if the string cannot be allocated.
  208. *
  209. * The callback argument specifies a function that returns a whitespace
  210. * string or `NULL` before and after each element. If `MXML_NO_CALLBACK`
  211. * is specified, whitespace will only be added before `MXML_TEXT` nodes
  212. * with leading whitespace and before attribute names inside opening
  213. * element tags.
  214. */
  215. char * /* O - Allocated string or @code NULL@ */
  216. mxmlSaveAllocString(
  217. mxml_node_t *node, /* I - Node to write */
  218. mxml_save_cb_t cb, /* I - Whitespace callback or @code MXML_NO_CALLBACK@ */
  219. void *cb_ctx) /* I - Whitespace callback context or NULL */
  220. {
  221. int bytes; /* Required bytes */
  222. char buffer[8192]; /* Temporary buffer */
  223. char *s; /* Allocated string */
  224. /*
  225. * Write the node to the temporary buffer...
  226. */
  227. bytes = mxmlSaveString(node, buffer, sizeof(buffer), cb, cb_ctx);
  228. if (bytes <= 0)
  229. return (NULL);
  230. if (bytes < (int)(sizeof(buffer) - 1))
  231. {
  232. /*
  233. * Node fit inside the buffer, so just duplicate that string and
  234. * return...
  235. */
  236. return (strdup(buffer));
  237. }
  238. /*
  239. * Allocate a buffer of the required size and save the node to the
  240. * new buffer...
  241. */
  242. if ((s = malloc(bytes + 1)) == NULL)
  243. return (NULL);
  244. mxmlSaveString(node, s, bytes + 1, cb, cb_ctx);
  245. /*
  246. * Return the allocated string...
  247. */
  248. return (s);
  249. }
  250. /*
  251. * 'mxmlSaveFd()' - Save an XML tree to a file descriptor.
  252. *
  253. * The callback argument specifies a function that returns a whitespace
  254. * string or NULL before and after each element. If @code MXML_NO_CALLBACK@
  255. * is specified, whitespace will only be added before @code MXML_TEXT@ nodes
  256. * with leading whitespace and before attribute names inside opening
  257. * element tags.
  258. */
  259. int /* O - 0 on success, -1 on error. */
  260. mxmlSaveFd(mxml_node_t *node, /* I - Node to write */
  261. int fd, /* I - File descriptor to write to */
  262. mxml_save_cb_t cb, /* I - Whitespace callback or @code MXML_NO_CALLBACK@ */
  263. void *cb_ctx) /* I - Whitespace callback context or NULL */
  264. {
  265. int col; /* Final column */
  266. _mxml_fdbuf_t buf; /* File descriptor buffer */
  267. _mxml_global_t *global = _mxml_global();
  268. /* Global data */
  269. /*
  270. * Initialize the file descriptor buffer...
  271. */
  272. buf.fd = fd;
  273. buf.current = buf.buffer;
  274. buf.end = buf.buffer + sizeof(buf.buffer);
  275. /*
  276. * Write the node...
  277. */
  278. if ((col = mxml_write_node(node, &buf, cb, 0, mxml_fd_putc, global, cb_ctx)) < 0)
  279. return (-1);
  280. if (col > 0)
  281. if (mxml_fd_putc('\n', &buf) < 0)
  282. return (-1);
  283. /*
  284. * Flush and return...
  285. */
  286. return (mxml_fd_write(&buf));
  287. }
  288. /*
  289. * 'mxmlSaveFile()' - Save an XML tree to a file.
  290. *
  291. * The callback argument specifies a function that returns a whitespace
  292. * string or NULL before and after each element. If @code MXML_NO_CALLBACK@
  293. * is specified, whitespace will only be added before @code MXML_TEXT@ nodes
  294. * with leading whitespace and before attribute names inside opening
  295. * element tags.
  296. */
  297. int /* O - 0 on success, -1 on error. */
  298. mxmlSaveFile(mxml_node_t *node, /* I - Node to write */
  299. FILE *fp, /* I - File to write to */
  300. mxml_save_cb_t cb, /* I - Whitespace callback or @code MXML_NO_CALLBACK@ */
  301. void *cb_ctx) /* I - Whitespace callback context or NULL */
  302. {
  303. int col; /* Final column */
  304. _mxml_global_t *global = _mxml_global();
  305. /* Global data */
  306. /*
  307. * Write the node...
  308. */
  309. if ((col = mxml_write_node(node, fp, cb, 0, mxml_file_putc, global, cb_ctx)) < 0)
  310. return (-1);
  311. if (col > 0)
  312. if (putc('\n', fp) < 0)
  313. return (-1);
  314. /*
  315. * Return 0 (success)...
  316. */
  317. return (0);
  318. }
  319. /*
  320. * 'mxmlSaveStream()' - Save an XML tree to a stream.
  321. *
  322. * The callback argument specifies a function that returns a whitespace
  323. * string or NULL before and after each element. If @code MXML_NO_CALLBACK@
  324. * is specified, whitespace will only be added before @code MXML_TEXT@ nodes
  325. * with leading whitespace and before attribute names inside opening
  326. * element tags.
  327. */
  328. int /* O - 0 on success, -1 on error. */
  329. mxmlSaveStream(mxml_node_t *node, /* I - Node to write */
  330. mxml_write_stream_cb_t write_stream_cb, /* I - Stream callback */
  331. void *write_stream_context, /* I - Stream context */
  332. mxml_save_cb_t cb, /* I - Whitespace callback or @code MXML_NO_CALLBACK@ */
  333. void * cb_ctx) /* I - Whitespace callback context or NULL */
  334. {
  335. int col; /* Final column */
  336. _mxml_streambuf_t buf; /* Stream buffer */
  337. _mxml_global_t *global = _mxml_global();
  338. /* Global data */
  339. /*
  340. * Initialize the stream buffer...
  341. */
  342. buf.ctxt = write_stream_context;
  343. buf.write = write_stream_cb;
  344. buf.current = buf.buffer;
  345. buf.end = buf.buffer + sizeof(buf.buffer);
  346. /*
  347. * Write the node...
  348. */
  349. if ((col = mxml_write_node(node, &buf, cb, 0, mxml_stream_putc, global, cb_ctx)) < 0)
  350. return (-1);
  351. if (col > 0)
  352. if (mxml_stream_putc('\n', &buf) < 0)
  353. return (-1);
  354. /*
  355. * Flush and return...
  356. */
  357. return (mxml_stream_write(&buf));
  358. }
  359. /*
  360. * 'mxmlSaveString()' - Save an XML node tree to a string.
  361. *
  362. * This function returns the total number of bytes that would be
  363. * required for the string but only copies (bufsize - 1) characters
  364. * into the specified buffer.
  365. *
  366. * The callback argument specifies a function that returns a whitespace
  367. * string or NULL before and after each element. If @code MXML_NO_CALLBACK@
  368. * is specified, whitespace will only be added before @code MXML_TEXT@ nodes
  369. * with leading whitespace and before attribute names inside opening
  370. * element tags.
  371. */
  372. int /* O - Size of string */
  373. mxmlSaveString(mxml_node_t *node, /* I - Node to write */
  374. char *buffer, /* I - String buffer */
  375. int bufsize, /* I - Size of string buffer */
  376. mxml_save_cb_t cb, /* I - Whitespace callback or @code MXML_NO_CALLBACK@ */
  377. void *cb_ctx) /* I - Whitespace callback context or NULL */
  378. {
  379. int col; /* Final column */
  380. char *ptr[2]; /* Pointers for putc_cb */
  381. _mxml_global_t *global = _mxml_global();
  382. /* Global data */
  383. /*
  384. * Write the node...
  385. */
  386. ptr[0] = buffer;
  387. ptr[1] = buffer + bufsize;
  388. if ((col = mxml_write_node(node, ptr, cb, 0, mxml_string_putc, global, cb_ctx)) < 0)
  389. return (-1);
  390. if (col > 0)
  391. mxml_string_putc('\n', ptr);
  392. /*
  393. * Nul-terminate the buffer...
  394. */
  395. if (ptr[0] >= ptr[1])
  396. {
  397. if (bufsize > 0)
  398. buffer[bufsize - 1] = '\0';
  399. }
  400. else
  401. ptr[0][0] = '\0';
  402. /*
  403. * Return the number of characters...
  404. */
  405. return ((int)(ptr[0] - buffer));
  406. }
  407. /*
  408. * 'mxmlSAXLoadFd()' - Load a file descriptor into an XML node tree
  409. * using a SAX callback.
  410. *
  411. * The nodes in the specified file are added to the specified top node.
  412. * If no top node is provided, the XML file MUST be well-formed with a
  413. * single parent node like <?xml> for the entire file. The callback
  414. * function returns the value type that should be used for child nodes.
  415. * The constants @code MXML_INTEGER_CALLBACK@, @code MXML_OPAQUE_CALLBACK@,
  416. * @code MXML_REAL_CALLBACK@, and @code MXML_TEXT_CALLBACK@ are defined for
  417. * loading child nodes of the specified type.
  418. *
  419. * The SAX callback must call @link mxmlRetain@ for any nodes that need to
  420. * be kept for later use. Otherwise, nodes are deleted when the parent
  421. * node is closed or after each data, comment, CDATA, or directive node.
  422. *
  423. * @since Mini-XML 2.3@
  424. */
  425. mxml_node_t * /* O - First node or @code NULL@ if the file could not be read. */
  426. mxmlSAXLoadFd(mxml_node_t *top, /* I - Top node */
  427. int fd, /* I - File descriptor to read from */
  428. mxml_load_cb_t cb, /* I - Callback function or constant */
  429. mxml_sax_cb_t sax_cb, /* I - SAX callback or @code MXML_NO_CALLBACK@ */
  430. void *sax_data) /* I - SAX user data */
  431. {
  432. _mxml_fdbuf_t buf; /* File descriptor buffer */
  433. /*
  434. * Initialize the file descriptor buffer...
  435. */
  436. buf.fd = fd;
  437. buf.current = buf.buffer;
  438. buf.end = buf.buffer;
  439. /*
  440. * Read the XML data...
  441. */
  442. return (mxml_load_data(top, &buf, cb, mxml_fd_getc, sax_cb, sax_data));
  443. }
  444. /*
  445. * 'mxmlSAXLoadFile()' - Load a file into an XML node tree
  446. * using a SAX callback.
  447. *
  448. * The nodes in the specified file are added to the specified top node.
  449. * If no top node is provided, the XML file MUST be well-formed with a
  450. * single parent node like <?xml> for the entire file. The callback
  451. * function returns the value type that should be used for child nodes.
  452. * The constants @code MXML_INTEGER_CALLBACK@, @code MXML_OPAQUE_CALLBACK@,
  453. * @code MXML_REAL_CALLBACK@, and @code MXML_TEXT_CALLBACK@ are defined for
  454. * loading child nodes of the specified type.
  455. *
  456. * The SAX callback must call @link mxmlRetain@ for any nodes that need to
  457. * be kept for later use. Otherwise, nodes are deleted when the parent
  458. * node is closed or after each data, comment, CDATA, or directive node.
  459. *
  460. * @since Mini-XML 2.3@
  461. */
  462. mxml_node_t * /* O - First node or @code NULL@ if the file could not be read. */
  463. mxmlSAXLoadFile(
  464. mxml_node_t *top, /* I - Top node */
  465. FILE *fp, /* I - File to read from */
  466. mxml_load_cb_t cb, /* I - Callback function or constant */
  467. mxml_sax_cb_t sax_cb, /* I - SAX callback or @code MXML_NO_CALLBACK@ */
  468. void *sax_data) /* I - SAX user data */
  469. {
  470. /*
  471. * Read the XML data...
  472. */
  473. return (mxml_load_data(top, fp, cb, mxml_file_getc, sax_cb, sax_data));
  474. }
  475. /*
  476. * 'mxmlSAXLoadString()' - Load a string into an XML node tree
  477. * using a SAX callback.
  478. *
  479. * The nodes in the specified string are added to the specified top node.
  480. * If no top node is provided, the XML string MUST be well-formed with a
  481. * single parent node like <?xml> for the entire string. The callback
  482. * function returns the value type that should be used for child nodes.
  483. * The constants @code MXML_INTEGER_CALLBACK@, @code MXML_OPAQUE_CALLBACK@,
  484. * @code MXML_REAL_CALLBACK@, and @code MXML_TEXT_CALLBACK@ are defined for
  485. * loading child nodes of the specified type.
  486. *
  487. * The SAX callback must call @link mxmlRetain@ for any nodes that need to
  488. * be kept for later use. Otherwise, nodes are deleted when the parent
  489. * node is closed or after each data, comment, CDATA, or directive node.
  490. *
  491. * @since Mini-XML 2.3@
  492. */
  493. mxml_node_t * /* O - First node or @code NULL@ if the string has errors. */
  494. mxmlSAXLoadString(
  495. mxml_node_t *top, /* I - Top node */
  496. const char *s, /* I - String to load */
  497. mxml_load_cb_t cb, /* I - Callback function or constant */
  498. mxml_sax_cb_t sax_cb, /* I - SAX callback or @code MXML_NO_CALLBACK@ */
  499. void *sax_data) /* I - SAX user data */
  500. {
  501. /*
  502. * Read the XML data...
  503. */
  504. return (mxml_load_data(top, (void *)&s, cb, mxml_string_getc, sax_cb, sax_data));
  505. }
  506. /*
  507. * 'mxmlSetCustomHandlers()' - Set the handling functions for custom data.
  508. *
  509. * The load function accepts a node pointer and a data string and must
  510. * return 0 on success and non-zero on error.
  511. *
  512. * The save function accepts a node pointer and must return a malloc'd
  513. * string on success and @code NULL@ on error.
  514. *
  515. */
  516. void
  517. mxmlSetCustomHandlers(
  518. mxml_custom_load_cb_t load, /* I - Load function */
  519. mxml_custom_save_cb_t save) /* I - Save function */
  520. {
  521. _mxml_global_t *global = _mxml_global();
  522. /* Global data */
  523. global->custom_load_cb = load;
  524. global->custom_save_cb = save;
  525. }
  526. /*
  527. * 'mxmlSetErrorCallback()' - Set the error message callback.
  528. */
  529. void
  530. mxmlSetErrorCallback(mxml_error_cb_t cb)/* I - Error callback function */
  531. {
  532. _mxml_global_t *global = _mxml_global();
  533. /* Global data */
  534. global->error_cb = cb;
  535. }
  536. /*
  537. * 'mxmlSetWrapMargin()' - Set the wrap margin when saving XML data.
  538. *
  539. * Wrapping is disabled when "column" is 0.
  540. *
  541. * @since Mini-XML 2.3@
  542. */
  543. void
  544. mxmlSetWrapMargin(int column) /* I - Column for wrapping, 0 to disable wrapping */
  545. {
  546. _mxml_global_t *global = _mxml_global();
  547. /* Global data */
  548. global->wrap = column;
  549. }
  550. /*
  551. * 'mxml_add_char()' - Add a character to a buffer, expanding as needed.
  552. */
  553. static int /* O - 0 on success, -1 on error */
  554. mxml_add_char(int ch, /* I - Character to add */
  555. char **bufptr, /* IO - Current position in buffer */
  556. char **buffer, /* IO - Current buffer */
  557. int *bufsize) /* IO - Current buffer size */
  558. {
  559. char *newbuffer; /* New buffer value */
  560. if (*bufptr >= (*buffer + *bufsize - 4))
  561. {
  562. /*
  563. * Increase the size of the buffer...
  564. */
  565. if (*bufsize < 1024)
  566. (*bufsize) *= 2;
  567. else
  568. (*bufsize) += 1024;
  569. if ((newbuffer = realloc(*buffer, *bufsize)) == NULL)
  570. {
  571. mxml_error("Unable to expand string buffer to %d bytes.", *bufsize);
  572. return (-1);
  573. }
  574. *bufptr = newbuffer + (*bufptr - *buffer);
  575. *buffer = newbuffer;
  576. }
  577. if (ch < 0x80)
  578. {
  579. /*
  580. * Single byte ASCII...
  581. */
  582. *(*bufptr)++ = ch;
  583. }
  584. else if (ch < 0x800)
  585. {
  586. /*
  587. * Two-byte UTF-8...
  588. */
  589. *(*bufptr)++ = 0xc0 | (ch >> 6);
  590. *(*bufptr)++ = 0x80 | (ch & 0x3f);
  591. }
  592. else if (ch < 0x10000)
  593. {
  594. /*
  595. * Three-byte UTF-8...
  596. */
  597. *(*bufptr)++ = 0xe0 | (ch >> 12);
  598. *(*bufptr)++ = 0x80 | ((ch >> 6) & 0x3f);
  599. *(*bufptr)++ = 0x80 | (ch & 0x3f);
  600. }
  601. else
  602. {
  603. /*
  604. * Four-byte UTF-8...
  605. */
  606. *(*bufptr)++ = 0xf0 | (ch >> 18);
  607. *(*bufptr)++ = 0x80 | ((ch >> 12) & 0x3f);
  608. *(*bufptr)++ = 0x80 | ((ch >> 6) & 0x3f);
  609. *(*bufptr)++ = 0x80 | (ch & 0x3f);
  610. }
  611. return (0);
  612. }
  613. /*
  614. * 'mxml_fd_getc()' - Read a character from a file descriptor.
  615. */
  616. static int /* O - Character or EOF */
  617. mxml_fd_getc(void *p, /* I - File descriptor buffer */
  618. int *encoding) /* IO - Encoding */
  619. {
  620. _mxml_fdbuf_t *buf; /* File descriptor buffer */
  621. int ch, /* Current character */
  622. temp; /* Temporary character */
  623. /*
  624. * Grab the next character in the buffer...
  625. */
  626. buf = (_mxml_fdbuf_t *)p;
  627. if (buf->current >= buf->end)
  628. if (mxml_fd_read(buf) < 0)
  629. return (EOF);
  630. ch = *(buf->current)++;
  631. switch (*encoding)
  632. {
  633. case ENCODE_UTF8 :
  634. /*
  635. * Got a UTF-8 character; convert UTF-8 to Unicode and return...
  636. */
  637. if (!(ch & 0x80))
  638. {
  639. #if DEBUG > 1
  640. printf("mxml_fd_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
  641. #endif /* DEBUG > 1 */
  642. if (mxml_bad_char(ch))
  643. {
  644. mxml_error("Bad control character 0x%02x not allowed by XML standard.",
  645. ch);
  646. return (EOF);
  647. }
  648. return (ch);
  649. }
  650. else if (ch == 0xfe)
  651. {
  652. /*
  653. * UTF-16 big-endian BOM?
  654. */
  655. if (buf->current >= buf->end)
  656. if (mxml_fd_read(buf) < 0)
  657. return (EOF);
  658. ch = *(buf->current)++;
  659. if (ch != 0xff)
  660. return (EOF);
  661. *encoding = ENCODE_UTF16BE;
  662. return (mxml_fd_getc(p, encoding));
  663. }
  664. else if (ch == 0xff)
  665. {
  666. /*
  667. * UTF-16 little-endian BOM?
  668. */
  669. if (buf->current >= buf->end)
  670. if (mxml_fd_read(buf) < 0)
  671. return (EOF);
  672. ch = *(buf->current)++;
  673. if (ch != 0xfe)
  674. return (EOF);
  675. *encoding = ENCODE_UTF16LE;
  676. return (mxml_fd_getc(p, encoding));
  677. }
  678. else if ((ch & 0xe0) == 0xc0)
  679. {
  680. /*
  681. * Two-byte value...
  682. */
  683. if (buf->current >= buf->end)
  684. if (mxml_fd_read(buf) < 0)
  685. return (EOF);
  686. temp = *(buf->current)++;
  687. if ((temp & 0xc0) != 0x80)
  688. return (EOF);
  689. ch = ((ch & 0x1f) << 6) | (temp & 0x3f);
  690. if (ch < 0x80)
  691. {
  692. mxml_error("Invalid UTF-8 sequence for character 0x%04x.", ch);
  693. return (EOF);
  694. }
  695. }
  696. else if ((ch & 0xf0) == 0xe0)
  697. {
  698. /*
  699. * Three-byte value...
  700. */
  701. if (buf->current >= buf->end)
  702. if (mxml_fd_read(buf) < 0)
  703. return (EOF);
  704. temp = *(buf->current)++;
  705. if ((temp & 0xc0) != 0x80)
  706. return (EOF);
  707. ch = ((ch & 0x0f) << 6) | (temp & 0x3f);
  708. if (buf->current >= buf->end)
  709. if (mxml_fd_read(buf) < 0)
  710. return (EOF);
  711. temp = *(buf->current)++;
  712. if ((temp & 0xc0) != 0x80)
  713. return (EOF);
  714. ch = (ch << 6) | (temp & 0x3f);
  715. if (ch < 0x800)
  716. {
  717. mxml_error("Invalid UTF-8 sequence for character 0x%04x.", ch);
  718. return (EOF);
  719. }
  720. /*
  721. * Ignore (strip) Byte Order Mark (BOM)...
  722. */
  723. if (ch == 0xfeff)
  724. return (mxml_fd_getc(p, encoding));
  725. }
  726. else if ((ch & 0xf8) == 0xf0)
  727. {
  728. /*
  729. * Four-byte value...
  730. */
  731. if (buf->current >= buf->end)
  732. if (mxml_fd_read(buf) < 0)
  733. return (EOF);
  734. temp = *(buf->current)++;
  735. if ((temp & 0xc0) != 0x80)
  736. return (EOF);
  737. ch = ((ch & 0x07) << 6) | (temp & 0x3f);
  738. if (buf->current >= buf->end)
  739. if (mxml_fd_read(buf) < 0)
  740. return (EOF);
  741. temp = *(buf->current)++;
  742. if ((temp & 0xc0) != 0x80)
  743. return (EOF);
  744. ch = (ch << 6) | (temp & 0x3f);
  745. if (buf->current >= buf->end)
  746. if (mxml_fd_read(buf) < 0)
  747. return (EOF);
  748. temp = *(buf->current)++;
  749. if ((temp & 0xc0) != 0x80)
  750. return (EOF);
  751. ch = (ch << 6) | (temp & 0x3f);
  752. if (ch < 0x10000)
  753. {
  754. mxml_error("Invalid UTF-8 sequence for character 0x%04x.", ch);
  755. return (EOF);
  756. }
  757. }
  758. else
  759. return (EOF);
  760. break;
  761. case ENCODE_UTF16BE :
  762. /*
  763. * Read UTF-16 big-endian char...
  764. */
  765. if (buf->current >= buf->end)
  766. if (mxml_fd_read(buf) < 0)
  767. return (EOF);
  768. temp = *(buf->current)++;
  769. ch = (ch << 8) | temp;
  770. if (mxml_bad_char(ch))
  771. {
  772. mxml_error("Bad control character 0x%02x not allowed by XML standard.",
  773. ch);
  774. return (EOF);
  775. }
  776. else if (ch >= 0xd800 && ch <= 0xdbff)
  777. {
  778. /*
  779. * Multi-word UTF-16 char...
  780. */
  781. int lch;
  782. if (buf->current >= buf->end)
  783. if (mxml_fd_read(buf) < 0)
  784. return (EOF);
  785. lch = *(buf->current)++;
  786. if (buf->current >= buf->end)
  787. if (mxml_fd_read(buf) < 0)
  788. return (EOF);
  789. temp = *(buf->current)++;
  790. lch = (lch << 8) | temp;
  791. if (lch < 0xdc00 || lch >= 0xdfff)
  792. return (EOF);
  793. ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
  794. }
  795. break;
  796. case ENCODE_UTF16LE :
  797. /*
  798. * Read UTF-16 little-endian char...
  799. */
  800. if (buf->current >= buf->end)
  801. if (mxml_fd_read(buf) < 0)
  802. return (EOF);
  803. temp = *(buf->current)++;
  804. ch |= (temp << 8);
  805. if (mxml_bad_char(ch))
  806. {
  807. mxml_error("Bad control character 0x%02x not allowed by XML standard.",
  808. ch);
  809. return (EOF);
  810. }
  811. else if (ch >= 0xd800 && ch <= 0xdbff)
  812. {
  813. /*
  814. * Multi-word UTF-16 char...
  815. */
  816. int lch;
  817. if (buf->current >= buf->end)
  818. if (mxml_fd_read(buf) < 0)
  819. return (EOF);
  820. lch = *(buf->current)++;
  821. if (buf->current >= buf->end)
  822. if (mxml_fd_read(buf) < 0)
  823. return (EOF);
  824. temp = *(buf->current)++;
  825. lch |= (temp << 8);
  826. if (lch < 0xdc00 || lch >= 0xdfff)
  827. return (EOF);
  828. ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
  829. }
  830. break;
  831. }
  832. #if DEBUG > 1
  833. printf("mxml_fd_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
  834. #endif /* DEBUG > 1 */
  835. return (ch);
  836. }
  837. static int /* O - Character or EOF */
  838. mxml_stream_getc(void *p, /* I - File descriptor buffer */
  839. int *encoding) /* IO - Encoding */
  840. {
  841. _mxml_streambuf_t *buf; /* File descriptor buffer */
  842. int ch, /* Current character */
  843. temp; /* Temporary character */
  844. /*
  845. * Grab the next character in the buffer...
  846. */
  847. buf = (_mxml_streambuf_t *)p;
  848. if (buf->current >= buf->end)
  849. if (mxml_stream_read(buf) < 0)
  850. return (EOF);
  851. ch = *(buf->current)++;
  852. switch (*encoding)
  853. {
  854. case ENCODE_UTF8 :
  855. /*
  856. * Got a UTF-8 character; convert UTF-8 to Unicode and return...
  857. */
  858. if (!(ch & 0x80))
  859. {
  860. #if DEBUG > 1
  861. printf("mxml_fd_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
  862. #endif /* DEBUG > 1 */
  863. if (mxml_bad_char(ch))
  864. {
  865. mxml_error("Bad control character 0x%02x not allowed by XML standard!",
  866. ch);
  867. return (EOF);
  868. }
  869. return (ch);
  870. }
  871. else if (ch == 0xfe)
  872. {
  873. /*
  874. * UTF-16 big-endian BOM?
  875. */
  876. if (buf->current >= buf->end)
  877. if (mxml_stream_read(buf) < 0)
  878. return (EOF);
  879. ch = *(buf->current)++;
  880. if (ch != 0xff)
  881. return (EOF);
  882. *encoding = ENCODE_UTF16BE;
  883. return (mxml_stream_getc(p, encoding));
  884. }
  885. else if (ch == 0xff)
  886. {
  887. /*
  888. * UTF-16 little-endian BOM?
  889. */
  890. if (buf->current >= buf->end)
  891. if (mxml_stream_read(buf) < 0)
  892. return (EOF);
  893. ch = *(buf->current)++;
  894. if (ch != 0xfe)
  895. return (EOF);
  896. *encoding = ENCODE_UTF16LE;
  897. return (mxml_stream_getc(p, encoding));
  898. }
  899. else if ((ch & 0xe0) == 0xc0)
  900. {
  901. /*
  902. * Two-byte value...
  903. */
  904. if (buf->current >= buf->end)
  905. if (mxml_stream_read(buf) < 0)
  906. return (EOF);
  907. temp = *(buf->current)++;
  908. if ((temp & 0xc0) != 0x80)
  909. return (EOF);
  910. ch = ((ch & 0x1f) << 6) | (temp & 0x3f);
  911. if (ch < 0x80)
  912. {
  913. mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
  914. return (EOF);
  915. }
  916. }
  917. else if ((ch & 0xf0) == 0xe0)
  918. {
  919. /*
  920. * Three-byte value...
  921. */
  922. if (buf->current >= buf->end)
  923. if (mxml_stream_read(buf) < 0)
  924. return (EOF);
  925. temp = *(buf->current)++;
  926. if ((temp & 0xc0) != 0x80)
  927. return (EOF);
  928. ch = ((ch & 0x0f) << 6) | (temp & 0x3f);
  929. if (buf->current >= buf->end)
  930. if (mxml_stream_read(buf) < 0)
  931. return (EOF);
  932. temp = *(buf->current)++;
  933. if ((temp & 0xc0) != 0x80)
  934. return (EOF);
  935. ch = (ch << 6) | (temp & 0x3f);
  936. if (ch < 0x800)
  937. {
  938. mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
  939. return (EOF);
  940. }
  941. /*
  942. * Ignore (strip) Byte Order Mark (BOM)...
  943. */
  944. if (ch == 0xfeff)
  945. return (mxml_stream_getc(p, encoding));
  946. }
  947. else if ((ch & 0xf8) == 0xf0)
  948. {
  949. /*
  950. * Four-byte value...
  951. */
  952. if (buf->current >= buf->end)
  953. if (mxml_stream_read(buf) < 0)
  954. return (EOF);
  955. temp = *(buf->current)++;
  956. if ((temp & 0xc0) != 0x80)
  957. return (EOF);
  958. ch = ((ch & 0x07) << 6) | (temp & 0x3f);
  959. if (buf->current >= buf->end)
  960. if (mxml_stream_read(buf) < 0)
  961. return (EOF);
  962. temp = *(buf->current)++;
  963. if ((temp & 0xc0) != 0x80)
  964. return (EOF);
  965. ch = (ch << 6) | (temp & 0x3f);
  966. if (buf->current >= buf->end)
  967. if (mxml_stream_read(buf) < 0)
  968. return (EOF);
  969. temp = *(buf->current)++;
  970. if ((temp & 0xc0) != 0x80)
  971. return (EOF);
  972. ch = (ch << 6) | (temp & 0x3f);
  973. if (ch < 0x10000)
  974. {
  975. mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
  976. return (EOF);
  977. }
  978. }
  979. else
  980. return (EOF);
  981. break;
  982. case ENCODE_UTF16BE :
  983. /*
  984. * Read UTF-16 big-endian char...
  985. */
  986. if (buf->current >= buf->end)
  987. if (mxml_stream_read(buf) < 0)
  988. return (EOF);
  989. temp = *(buf->current)++;
  990. ch = (ch << 8) | temp;
  991. if (mxml_bad_char(ch))
  992. {
  993. mxml_error("Bad control character 0x%02x not allowed by XML standard!",
  994. ch);
  995. return (EOF);
  996. }
  997. else if (ch >= 0xd800 && ch <= 0xdbff)
  998. {
  999. /*
  1000. * Multi-word UTF-16 char...
  1001. */
  1002. int lch;
  1003. if (buf->current >= buf->end)
  1004. if (mxml_stream_read(buf) < 0)
  1005. return (EOF);
  1006. lch = *(buf->current)++;
  1007. if (buf->current >= buf->end)
  1008. if (mxml_stream_read(buf) < 0)
  1009. return (EOF);
  1010. temp = *(buf->current)++;
  1011. lch = (lch << 8) | temp;
  1012. if (lch < 0xdc00 || lch >= 0xdfff)
  1013. return (EOF);
  1014. ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
  1015. }
  1016. break;
  1017. case ENCODE_UTF16LE :
  1018. /*
  1019. * Read UTF-16 little-endian char...
  1020. */
  1021. if (buf->current >= buf->end)
  1022. if (mxml_stream_read(buf) < 0)
  1023. return (EOF);
  1024. temp = *(buf->current)++;
  1025. ch |= (temp << 8);
  1026. if (mxml_bad_char(ch))
  1027. {
  1028. mxml_error("Bad control character 0x%02x not allowed by XML standard!",
  1029. ch);
  1030. return (EOF);
  1031. }
  1032. else if (ch >= 0xd800 && ch <= 0xdbff)
  1033. {
  1034. /*
  1035. * Multi-word UTF-16 char...
  1036. */
  1037. int lch;
  1038. if (buf->current >= buf->end)
  1039. if (mxml_stream_read(buf) < 0)
  1040. return (EOF);
  1041. lch = *(buf->current)++;
  1042. if (buf->current >= buf->end)
  1043. if (mxml_stream_read(buf) < 0)
  1044. return (EOF);
  1045. temp = *(buf->current)++;
  1046. lch |= (temp << 8);
  1047. if (lch < 0xdc00 || lch >= 0xdfff)
  1048. return (EOF);
  1049. ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
  1050. }
  1051. break;
  1052. }
  1053. #if DEBUG > 1
  1054. printf("mxml_fd_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
  1055. #endif /* DEBUG > 1 */
  1056. return (ch);
  1057. }
  1058. /*
  1059. * 'mxml_fd_putc()' - Write a character to a file descriptor.
  1060. */
  1061. static int /* O - 0 on success, -1 on error */
  1062. mxml_fd_putc(int ch, /* I - Character */
  1063. void *p) /* I - File descriptor buffer */
  1064. {
  1065. _mxml_fdbuf_t *buf; /* File descriptor buffer */
  1066. /*
  1067. * Flush the write buffer as needed...
  1068. */
  1069. buf = (_mxml_fdbuf_t *)p;
  1070. if (buf->current >= buf->end)
  1071. if (mxml_fd_write(buf) < 0)
  1072. return (-1);
  1073. *(buf->current)++ = ch;
  1074. /*
  1075. * Return successfully...
  1076. */
  1077. return (0);
  1078. }
  1079. /*
  1080. * 'mxml_fd_read()' - Read a buffer of data from a file descriptor.
  1081. */
  1082. static int /* O - 0 on success, -1 on error */
  1083. mxml_fd_read(_mxml_fdbuf_t *buf) /* I - File descriptor buffer */
  1084. {
  1085. int bytes; /* Bytes read... */
  1086. /*
  1087. * Range check input...
  1088. */
  1089. if (!buf)
  1090. return (-1);
  1091. /*
  1092. * Read from the file descriptor...
  1093. */
  1094. while ((bytes = (int)read(buf->fd, buf->buffer, sizeof(buf->buffer))) < 0)
  1095. #ifdef EINTR
  1096. if (errno != EAGAIN && errno != EINTR)
  1097. #else
  1098. if (errno != EAGAIN)
  1099. #endif /* EINTR */
  1100. return (-1);
  1101. if (bytes == 0)
  1102. return (-1);
  1103. /*
  1104. * Update the pointers and return success...
  1105. */
  1106. buf->current = buf->buffer;
  1107. buf->end = buf->buffer + bytes;
  1108. return (0);
  1109. }
  1110. /*
  1111. * 'mxml_fd_write()' - Write a buffer of data to a file descriptor.
  1112. */
  1113. static int /* O - 0 on success, -1 on error */
  1114. mxml_fd_write(_mxml_fdbuf_t *buf) /* I - File descriptor buffer */
  1115. {
  1116. int bytes; /* Bytes written */
  1117. unsigned char *ptr; /* Pointer into buffer */
  1118. /*
  1119. * Range check...
  1120. */
  1121. if (!buf)
  1122. return (-1);
  1123. /*
  1124. * Return 0 if there is nothing to write...
  1125. */
  1126. if (buf->current == buf->buffer)
  1127. return (0);
  1128. /*
  1129. * Loop until we have written everything...
  1130. */
  1131. for (ptr = buf->buffer; ptr < buf->current; ptr += bytes)
  1132. if ((bytes = (int)write(buf->fd, ptr, buf->current - ptr)) < 0)
  1133. return (-1);
  1134. /*
  1135. * All done, reset pointers and return success...
  1136. */
  1137. buf->current = buf->buffer;
  1138. return (0);
  1139. }
  1140. static int /* O - 0 on success, -1 on error */
  1141. mxml_stream_putc(int ch, /* I - Character */
  1142. void *p) /* I - stream buffer */
  1143. {
  1144. _mxml_streambuf_t *buf; /* stream buffer */
  1145. /*
  1146. * Flush the write buffer as needed...
  1147. */
  1148. buf = (_mxml_streambuf_t *)p;
  1149. if (buf->current >= buf->end)
  1150. if (mxml_stream_write(buf) < 0)
  1151. return (-1);
  1152. *(buf->current)++ = ch;
  1153. /*
  1154. * Return successfully...
  1155. */
  1156. return (0);
  1157. }
  1158. static int /* O - 0 on success, -1 on error */
  1159. mxml_stream_read(_mxml_streambuf_t *buf) /* I - File descriptor buffer */
  1160. {
  1161. int bytes; /* Bytes read... */
  1162. /*
  1163. * Range check input...
  1164. */
  1165. if (!buf)
  1166. return (-1);
  1167. /*
  1168. * Read from the file descriptor...
  1169. */
  1170. bytes = (int)buf->read(buf->ctxt, buf->buffer, sizeof(buf->buffer));
  1171. if (bytes == 0)
  1172. return (-1);
  1173. /*
  1174. * Update the pointers and return success...
  1175. */
  1176. buf->current = buf->buffer;
  1177. buf->end = buf->buffer + bytes;
  1178. return (0);
  1179. }
  1180. static int /* O - 0 on success, -1 on error */
  1181. mxml_stream_write(_mxml_streambuf_t *buf) /* I - File descriptor buffer */
  1182. {
  1183. int bytes; /* Bytes written */
  1184. unsigned char *ptr; /* Pointer into buffer */
  1185. /*
  1186. * Range check...
  1187. */
  1188. if (!buf)
  1189. return (-1);
  1190. /*
  1191. * Return 0 if there is nothing to write...
  1192. */
  1193. if (buf->current == buf->buffer)
  1194. return (0);
  1195. /*
  1196. * Loop until we have written everything...
  1197. */
  1198. for (ptr = buf->buffer; ptr < buf->current; ptr += bytes)
  1199. if ((bytes = (int)buf->write(buf->ctxt, ptr, buf->current - ptr)) < 0)
  1200. return (-1);
  1201. /*
  1202. * All done, reset pointers and return success...
  1203. */
  1204. buf->current = buf->buffer;
  1205. return (0);
  1206. }
  1207. /*
  1208. * 'mxml_file_getc()' - Get a character from a file.
  1209. */
  1210. static int /* O - Character or EOF */
  1211. mxml_file_getc(void *p, /* I - Pointer to file */
  1212. int *encoding) /* IO - Encoding */
  1213. {
  1214. int ch, /* Character from file */
  1215. temp; /* Temporary character */
  1216. FILE *fp; /* Pointer to file */
  1217. /*
  1218. * Read a character from the file and see if it is EOF or ASCII...
  1219. */
  1220. fp = (FILE *)p;
  1221. ch = getc(fp);
  1222. if (ch == EOF)
  1223. return (EOF);
  1224. switch (*encoding)
  1225. {
  1226. case ENCODE_UTF8 :
  1227. /*
  1228. * Got a UTF-8 character; convert UTF-8 to Unicode and return...
  1229. */
  1230. if (!(ch & 0x80))
  1231. {
  1232. if (mxml_bad_char(ch))
  1233. {
  1234. mxml_error("Bad control character 0x%02x not allowed by XML standard.",
  1235. ch);
  1236. return (EOF);
  1237. }
  1238. #if DEBUG > 1
  1239. printf("mxml_file_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
  1240. #endif /* DEBUG > 1 */
  1241. return (ch);
  1242. }
  1243. else if (ch == 0xfe)
  1244. {
  1245. /*
  1246. * UTF-16 big-endian BOM?
  1247. */
  1248. ch = getc(fp);
  1249. if (ch != 0xff)
  1250. return (EOF);
  1251. *encoding = ENCODE_UTF16BE;
  1252. return (mxml_file_getc(p, encoding));
  1253. }
  1254. else if (ch == 0xff)
  1255. {
  1256. /*
  1257. * UTF-16 little-endian BOM?
  1258. */
  1259. ch = getc(fp);
  1260. if (ch != 0xfe)
  1261. return (EOF);
  1262. *encoding = ENCODE_UTF16LE;
  1263. return (mxml_file_getc(p, encoding));
  1264. }
  1265. else if ((ch & 0xe0) == 0xc0)
  1266. {
  1267. /*
  1268. * Two-byte value...
  1269. */
  1270. if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
  1271. return (EOF);
  1272. ch = ((ch & 0x1f) << 6) | (temp & 0x3f);
  1273. if (ch < 0x80)
  1274. {
  1275. mxml_error("Invalid UTF-8 sequence for character 0x%04x.", ch);
  1276. return (EOF);
  1277. }
  1278. }
  1279. else if ((ch & 0xf0) == 0xe0)
  1280. {
  1281. /*
  1282. * Three-byte value...
  1283. */
  1284. if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
  1285. return (EOF);
  1286. ch = ((ch & 0x0f) << 6) | (temp & 0x3f);
  1287. if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
  1288. return (EOF);
  1289. ch = (ch << 6) | (temp & 0x3f);
  1290. if (ch < 0x800)
  1291. {
  1292. mxml_error("Invalid UTF-8 sequence for character 0x%04x.", ch);
  1293. return (EOF);
  1294. }
  1295. /*
  1296. * Ignore (strip) Byte Order Mark (BOM)...
  1297. */
  1298. if (ch == 0xfeff)
  1299. return (mxml_file_getc(p, encoding));
  1300. }
  1301. else if ((ch & 0xf8) == 0xf0)
  1302. {
  1303. /*
  1304. * Four-byte value...
  1305. */
  1306. if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
  1307. return (EOF);
  1308. ch = ((ch & 0x07) << 6) | (temp & 0x3f);
  1309. if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
  1310. return (EOF);
  1311. ch = (ch << 6) | (temp & 0x3f);
  1312. if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
  1313. return (EOF);
  1314. ch = (ch << 6) | (temp & 0x3f);
  1315. if (ch < 0x10000)
  1316. {
  1317. mxml_error("Invalid UTF-8 sequence for character 0x%04x.", ch);
  1318. return (EOF);
  1319. }
  1320. }
  1321. else
  1322. return (EOF);
  1323. break;
  1324. case ENCODE_UTF16BE :
  1325. /*
  1326. * Read UTF-16 big-endian char...
  1327. */
  1328. ch = (ch << 8) | getc(fp);
  1329. if (mxml_bad_char(ch))
  1330. {
  1331. mxml_error("Bad control character 0x%02x not allowed by XML standard.",
  1332. ch);
  1333. return (EOF);
  1334. }
  1335. else if (ch >= 0xd800 && ch <= 0xdbff)
  1336. {
  1337. /*
  1338. * Multi-word UTF-16 char...
  1339. */
  1340. int lch = getc(fp);
  1341. lch = (lch << 8) | getc(fp);
  1342. if (lch < 0xdc00 || lch >= 0xdfff)
  1343. return (EOF);
  1344. ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
  1345. }
  1346. break;
  1347. case ENCODE_UTF16LE :
  1348. /*
  1349. * Read UTF-16 little-endian char...
  1350. */
  1351. ch |= (getc(fp) << 8);
  1352. if (mxml_bad_char(ch))
  1353. {
  1354. mxml_error("Bad control character 0x%02x not allowed by XML standard.",
  1355. ch);
  1356. return (EOF);
  1357. }
  1358. else if (ch >= 0xd800 && ch <= 0xdbff)
  1359. {
  1360. /*
  1361. * Multi-word UTF-16 char...
  1362. */
  1363. int lch = getc(fp);
  1364. lch |= (getc(fp) << 8);
  1365. if (lch < 0xdc00 || lch >= 0xdfff)
  1366. return (EOF);
  1367. ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
  1368. }
  1369. break;
  1370. }
  1371. #if DEBUG > 1
  1372. printf("mxml_file_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
  1373. #endif /* DEBUG > 1 */
  1374. return (ch);
  1375. }
  1376. /*
  1377. * 'mxml_file_putc()' - Write a character to a file.
  1378. */
  1379. static int /* O - 0 on success, -1 on failure */
  1380. mxml_file_putc(int ch, /* I - Character to write */
  1381. void *p) /* I - Pointer to file */
  1382. {
  1383. return (putc(ch, (FILE *)p) == EOF ? -1 : 0);
  1384. }
  1385. /*
  1386. * 'mxml_get_entity()' - Get the character corresponding to an entity...
  1387. */
  1388. static int /* O - Character value or EOF on error */
  1389. mxml_get_entity(mxml_node_t *parent, /* I - Parent node */
  1390. void *p, /* I - Pointer to source */
  1391. int *encoding, /* IO - Character encoding */
  1392. int (*getc_cb)(void *, int *),
  1393. /* I - Get character function */
  1394. int *line) /* IO - Current line number */
  1395. {
  1396. int ch; /* Current character */
  1397. char entity[64], /* Entity string */
  1398. *entptr; /* Pointer into entity */
  1399. entptr = entity;
  1400. while ((ch = (*getc_cb)(p, encoding)) != EOF)
  1401. {
  1402. if (ch > 126 || (!isalnum(ch) && ch != '#'))
  1403. break;
  1404. else if (entptr < (entity + sizeof(entity) - 1))
  1405. *entptr++ = ch;
  1406. else
  1407. {
  1408. mxml_error("Entity name too long under parent <%s> on line %d.", parent ? parent->value.element.name : "null", *line);
  1409. break;
  1410. }
  1411. }
  1412. *entptr = '\0';
  1413. if (ch != ';')
  1414. {
  1415. mxml_error("Character entity '%s' not terminated under parent <%s> on line %d.", entity, parent ? parent->value.element.name : "null", *line);
  1416. if (ch == '\n')
  1417. (*line)++;
  1418. return (EOF);
  1419. }
  1420. if (entity[0] == '#')
  1421. {
  1422. if (entity[1] == 'x')
  1423. ch = (int)strtol(entity + 2, NULL, 16);
  1424. else
  1425. ch = (int)strtol(entity + 1, NULL, 10);
  1426. }
  1427. else if ((ch = mxmlEntityGetValue(entity)) < 0)
  1428. mxml_error("Entity name '%s;' not supported under parent <%s> on line %d.", entity, parent ? parent->value.element.name : "null", *line);
  1429. if (mxml_bad_char(ch))
  1430. {
  1431. mxml_error("Bad control character 0x%02x under parent <%s> on line %d not allowed by XML standard.", ch, parent ? parent->value.element.name : "null", *line);
  1432. return (EOF);
  1433. }
  1434. return (ch);
  1435. }
  1436. /*
  1437. * 'mxml_load_data()' - Load data into an XML node tree.
  1438. */
  1439. static mxml_node_t * /* O - First node or NULL if the file could not be read. */
  1440. mxml_load_data(
  1441. mxml_node_t *top, /* I - Top node */
  1442. void *p, /* I - Pointer to data */
  1443. mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */
  1444. _mxml_getc_cb_t getc_cb, /* I - Read function */
  1445. mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */
  1446. void *sax_data) /* I - SAX user data */
  1447. {
  1448. mxml_node_t *node = NULL, /* Current node */
  1449. *first = NULL, /* First node added */
  1450. *parent = NULL; /* Current parent node */
  1451. int line = 1, /* Current line number */
  1452. ch, /* Character from file */
  1453. whitespace; /* Non-zero if whitespace seen */
  1454. char *buffer, /* String buffer */
  1455. *bufptr; /* Pointer into buffer */
  1456. int bufsize; /* Size of buffer */
  1457. mxml_type_t type; /* Current node type */
  1458. int encoding; /* Character encoding */
  1459. _mxml_global_t *global = _mxml_global();
  1460. /* Global data */
  1461. static const char * const types[] = /* Type strings... */
  1462. {
  1463. "MXML_ELEMENT", /* XML element with attributes */
  1464. "MXML_INTEGER", /* Integer value */
  1465. "MXML_OPAQUE", /* Opaque string */
  1466. "MXML_REAL", /* Real value */
  1467. "MXML_TEXT", /* Text fragment */
  1468. "MXML_CUSTOM" /* Custom data */
  1469. };
  1470. /*
  1471. * Read elements and other nodes from the file...
  1472. */
  1473. if ((buffer = malloc(64)) == NULL)
  1474. {
  1475. mxml_error("Unable to allocate string buffer.");
  1476. return (NULL);
  1477. }
  1478. bufsize = 64;
  1479. bufptr = buffer;
  1480. parent = top;
  1481. first = NULL;
  1482. whitespace = 0;
  1483. encoding = ENCODE_UTF8;
  1484. if (cb && parent)
  1485. type = (*cb)(parent);
  1486. else if (parent)
  1487. type = MXML_TEXT;
  1488. else
  1489. type = MXML_IGNORE;
  1490. if ((ch = (*getc_cb)(p, &encoding)) == EOF)
  1491. {
  1492. free(buffer);
  1493. return (NULL);
  1494. }
  1495. else if (ch != '<' && !top)
  1496. {
  1497. free(buffer);
  1498. mxml_error("XML does not start with '<' (saw '%c').", ch);
  1499. return (NULL);
  1500. }
  1501. do
  1502. {
  1503. if ((ch == '<' ||
  1504. (mxml_isspace(ch) && type != MXML_OPAQUE && type != MXML_CUSTOM)) &&
  1505. bufptr > buffer)
  1506. {
  1507. /*
  1508. * Add a new value node...
  1509. */
  1510. *bufptr = '\0';
  1511. switch (type)
  1512. {
  1513. case MXML_INTEGER :
  1514. node = mxmlNewInteger(parent, (int)strtol(buffer, &bufptr, 0));
  1515. break;
  1516. case MXML_OPAQUE :
  1517. node = mxmlNewOpaque(parent, buffer);
  1518. break;
  1519. case MXML_REAL :
  1520. node = mxmlNewReal(parent, strtod(buffer, &bufptr));
  1521. break;
  1522. case MXML_TEXT :
  1523. node = mxmlNewText(parent, whitespace, buffer);
  1524. break;
  1525. case MXML_CUSTOM :
  1526. if (global->custom_load_cb)
  1527. {
  1528. /*
  1529. * Use the callback to fill in the custom data...
  1530. */
  1531. node = mxmlNewCustom(parent, NULL, NULL);
  1532. if ((*global->custom_load_cb)(node, buffer))
  1533. {
  1534. mxml_error("Bad custom value '%s' in parent <%s> on line %d.", buffer, parent ? parent->value.element.name : "null", line);
  1535. mxmlDelete(node);
  1536. node = NULL;
  1537. }
  1538. break;
  1539. }
  1540. default : /* Ignore... */
  1541. node = NULL;
  1542. break;
  1543. }
  1544. if (*bufptr)
  1545. {
  1546. /*
  1547. * Bad integer/real number value...
  1548. */
  1549. mxml_error("Bad %s value '%s' in parent <%s> on line %d.", type == MXML_INTEGER ? "integer" : "real", buffer, parent ? parent->value.element.name : "null", line);
  1550. break;
  1551. }
  1552. bufptr = buffer;
  1553. whitespace = mxml_isspace(ch) && type == MXML_TEXT;
  1554. if (!node && type != MXML_IGNORE)
  1555. {
  1556. /*
  1557. * Print error and return...
  1558. */
  1559. mxml_error("Unable to add value node of type %s to parent <%s> on line %d.", types[type], parent ? parent->value.element.name : "null", line);
  1560. goto error;
  1561. }
  1562. if (sax_cb)
  1563. {
  1564. (*sax_cb)(node, MXML_SAX_DATA, sax_data);
  1565. if (!mxmlRelease(node))
  1566. node = NULL;
  1567. }
  1568. if (!first && node)
  1569. first = node;
  1570. }
  1571. else if (mxml_isspace(ch) && type == MXML_TEXT)
  1572. whitespace = 1;
  1573. if (ch == '\n')
  1574. line ++;
  1575. /*
  1576. * Add lone whitespace node if we have an element and existing
  1577. * whitespace...
  1578. */
  1579. if (ch == '<' && whitespace && type == MXML_TEXT)
  1580. {
  1581. if (parent)
  1582. {
  1583. node = mxmlNewText(parent, whitespace, "");
  1584. if (sax_cb)
  1585. {
  1586. (*sax_cb)(node, MXML_SAX_DATA, sax_data);
  1587. if (!mxmlRelease(node))
  1588. node = NULL;
  1589. }
  1590. if (!first && node)
  1591. first = node;
  1592. }
  1593. whitespace = 0;
  1594. }
  1595. if (ch == '<')
  1596. {
  1597. /*
  1598. * Start of open/close tag...
  1599. */
  1600. bufptr = buffer;
  1601. while ((ch = (*getc_cb)(p, &encoding)) != EOF)
  1602. {
  1603. if (mxml_isspace(ch) || ch == '>' || (ch == '/' && bufptr > buffer))
  1604. break;
  1605. else if (ch == '<')
  1606. {
  1607. mxml_error("Bare < in element.");
  1608. goto error;
  1609. }
  1610. else if (ch == '&')
  1611. {
  1612. if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb, &line)) == EOF)
  1613. goto error;
  1614. if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
  1615. goto error;
  1616. }
  1617. else if (ch < '0' && ch != '!' && ch != '-' && ch != '.' && ch != '/')
  1618. goto error;
  1619. else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
  1620. goto error;
  1621. else if (((bufptr - buffer) == 1 && buffer[0] == '?') ||
  1622. ((bufptr - buffer) == 3 && !strncmp(buffer, "!--", 3)) ||
  1623. ((bufptr - buffer) == 8 && !strncmp(buffer, "![CDATA[", 8)))
  1624. break;
  1625. if (ch == '\n')
  1626. line ++;
  1627. }
  1628. *bufptr = '\0';
  1629. if (!strcmp(buffer, "!--"))
  1630. {
  1631. /*
  1632. * Gather rest of comment...
  1633. */
  1634. while ((ch = (*getc_cb)(p, &encoding)) != EOF)
  1635. {
  1636. if (ch == '>' && bufptr > (buffer + 4) &&
  1637. bufptr[-3] != '-' && bufptr[-2] == '-' && bufptr[-1] == '-')
  1638. break;
  1639. else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
  1640. goto error;
  1641. if (ch == '\n')
  1642. line ++;
  1643. }
  1644. /*
  1645. * Error out if we didn't get the whole comment...
  1646. */
  1647. if (ch != '>')
  1648. {
  1649. /*
  1650. * Print error and return...
  1651. */
  1652. mxml_error("Early EOF in comment node on line %d.", line);
  1653. goto error;
  1654. }
  1655. /*
  1656. * Otherwise add this as an element under the current parent...
  1657. */
  1658. *bufptr = '\0';
  1659. if (!parent && first)
  1660. {
  1661. /*
  1662. * There can only be one root element!
  1663. */
  1664. mxml_error("<%s> cannot be a second root node after <%s> on line %d.", buffer, first->value.element.name, line);
  1665. goto error;
  1666. }
  1667. if ((node = mxmlNewComment(parent, buffer)) == NULL)
  1668. {
  1669. /*
  1670. * Just print error for now...
  1671. */
  1672. mxml_error("Unable to add comment node to parent <%s> on line %d.", parent ? parent->value.element.name : "null", line);
  1673. break;
  1674. }
  1675. if (sax_cb)
  1676. {
  1677. (*sax_cb)(node, MXML_SAX_COMMENT, sax_data);
  1678. if (!mxmlRelease(node))
  1679. node = NULL;
  1680. }
  1681. if (node && !first)
  1682. first = node;
  1683. }
  1684. else if (!strcmp(buffer, "![CDATA["))
  1685. {
  1686. /*
  1687. * Gather CDATA section...
  1688. */
  1689. while ((ch = (*getc_cb)(p, &encoding)) != EOF)
  1690. {
  1691. if (ch == '>' && !strncmp(bufptr - 2, "]]", 2))
  1692. {
  1693. /*
  1694. * Drop terminator from CDATA string...
  1695. */
  1696. bufptr[-2] = '\0';
  1697. break;
  1698. }
  1699. else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
  1700. goto error;
  1701. if (ch == '\n')
  1702. line ++;
  1703. }
  1704. /*
  1705. * Error out if we didn't get the whole comment...
  1706. */
  1707. if (ch != '>')
  1708. {
  1709. /*
  1710. * Print error and return...
  1711. */
  1712. mxml_error("Early EOF in CDATA node on line %d.", line);
  1713. goto error;
  1714. }
  1715. /*
  1716. * Otherwise add this as an element under the current parent...
  1717. */
  1718. *bufptr = '\0';
  1719. if (!parent && first)
  1720. {
  1721. /*
  1722. * There can only be one root element!
  1723. */
  1724. mxml_error("<%s> cannot be a second root node after <%s> on line %d.", buffer, first->value.element.name, line);
  1725. goto error;
  1726. }
  1727. if ((node = mxmlNewElement(parent, buffer)) == NULL)
  1728. {
  1729. /*
  1730. * Print error and return...
  1731. */
  1732. mxml_error("Unable to add CDATA node to parent <%s> on line %d.", parent ? parent->value.element.name : "null", line);
  1733. goto error;
  1734. }
  1735. if (sax_cb)
  1736. {
  1737. (*sax_cb)(node, MXML_SAX_CDATA, sax_data);
  1738. if (!mxmlRelease(node))
  1739. node = NULL;
  1740. }
  1741. if (node && !first)
  1742. first = node;
  1743. }
  1744. else if (buffer[0] == '?')
  1745. {
  1746. /*
  1747. * Gather rest of processing instruction...
  1748. */
  1749. while ((ch = (*getc_cb)(p, &encoding)) != EOF)
  1750. {
  1751. if (ch == '>' && bufptr > buffer && bufptr[-1] == '?')
  1752. break;
  1753. else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
  1754. goto error;
  1755. if (ch == '\n')
  1756. line ++;
  1757. }
  1758. /*
  1759. * Error out if we didn't get the whole processing instruction...
  1760. */
  1761. if (ch != '>')
  1762. {
  1763. /*
  1764. * Print error and return...
  1765. */
  1766. mxml_error("Early EOF in processing instruction node on line %d.", line);
  1767. goto error;
  1768. }
  1769. /*
  1770. * Otherwise add this as an element under the current parent...
  1771. */
  1772. *bufptr = '\0';
  1773. if (!parent && first)
  1774. {
  1775. /*
  1776. * There can only be one root element!
  1777. */
  1778. mxml_error("<%s> cannot be a second root node after <%s> on line %d.", buffer, first->value.element.name, line);
  1779. goto error;
  1780. }
  1781. if ((node = mxmlNewElement(parent, buffer)) == NULL)
  1782. {
  1783. /*
  1784. * Print error and return...
  1785. */
  1786. mxml_error("Unable to add processing instruction node to parent <%s> on line %d.", parent ? parent->value.element.name : "null", line);
  1787. goto error;
  1788. }
  1789. if (sax_cb)
  1790. {
  1791. (*sax_cb)(node, MXML_SAX_DIRECTIVE, sax_data);
  1792. if (strncmp(node->value.element.name, "?xml ", 5) && !mxmlRelease(node))
  1793. node = NULL;
  1794. }
  1795. if (node)
  1796. {
  1797. if (!first)
  1798. first = node;
  1799. if (!parent)
  1800. {
  1801. parent = node;
  1802. if (cb)
  1803. type = (*cb)(parent);
  1804. else
  1805. type = MXML_TEXT;
  1806. }
  1807. }
  1808. }
  1809. else if (buffer[0] == '!')
  1810. {
  1811. /*
  1812. * Gather rest of declaration...
  1813. */
  1814. do
  1815. {
  1816. if (ch == '>')
  1817. break;
  1818. else
  1819. {
  1820. if (ch == '&')
  1821. {
  1822. if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb, &line)) == EOF)
  1823. goto error;
  1824. }
  1825. if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
  1826. goto error;
  1827. }
  1828. if (ch == '\n')
  1829. line ++;
  1830. }
  1831. while ((ch = (*getc_cb)(p, &encoding)) != EOF);
  1832. /*
  1833. * Error out if we didn't get the whole declaration...
  1834. */
  1835. if (ch != '>')
  1836. {
  1837. /*
  1838. * Print error and return...
  1839. */
  1840. mxml_error("Early EOF in declaration node on line %d.", line);
  1841. goto error;
  1842. }
  1843. /*
  1844. * Otherwise add this as an element under the current parent...
  1845. */
  1846. *bufptr = '\0';
  1847. if (!parent && first)
  1848. {
  1849. /*
  1850. * There can only be one root element!
  1851. */
  1852. mxml_error("<%s> cannot be a second root node after <%s> on line %d.", buffer, first->value.element.name, line);
  1853. goto error;
  1854. }
  1855. if ((node = mxmlNewElement(parent, buffer)) == NULL)
  1856. {
  1857. /*
  1858. * Print error and return...
  1859. */
  1860. mxml_error("Unable to add declaration node to parent <%s> on line %d.", parent ? parent->value.element.name : "null", line);
  1861. goto error;
  1862. }
  1863. if (sax_cb)
  1864. {
  1865. (*sax_cb)(node, MXML_SAX_DIRECTIVE, sax_data);
  1866. if (!mxmlRelease(node))
  1867. node = NULL;
  1868. }
  1869. if (node)
  1870. {
  1871. if (!first)
  1872. first = node;
  1873. if (!parent)
  1874. {
  1875. parent = node;
  1876. if (cb)
  1877. type = (*cb)(parent);
  1878. else
  1879. type = MXML_TEXT;
  1880. }
  1881. }
  1882. }
  1883. else if (buffer[0] == '/')
  1884. {
  1885. /*
  1886. * Handle close tag...
  1887. */
  1888. if (!parent || strcmp(buffer + 1, parent->value.element.name))
  1889. {
  1890. /*
  1891. * Close tag doesn't match tree; print an error for now...
  1892. */
  1893. mxml_error("Mismatched close tag <%s> under parent <%s> on line %d.", buffer, parent ? parent->value.element.name : "(null)", line);
  1894. goto error;
  1895. }
  1896. /*
  1897. * Keep reading until we see >...
  1898. */
  1899. while (ch != '>' && ch != EOF)
  1900. ch = (*getc_cb)(p, &encoding);
  1901. node = parent;
  1902. parent = parent->parent;
  1903. if (sax_cb)
  1904. {
  1905. (*sax_cb)(node, MXML_SAX_ELEMENT_CLOSE, sax_data);
  1906. if (!mxmlRelease(node))
  1907. {
  1908. if (first == node)
  1909. first = NULL;
  1910. node = NULL;
  1911. }
  1912. }
  1913. /*
  1914. * Ascend into the parent and set the value type as needed...
  1915. */
  1916. if (cb && parent)
  1917. type = (*cb)(parent);
  1918. }
  1919. else
  1920. {
  1921. /*
  1922. * Handle open tag...
  1923. */
  1924. if (!parent && first)
  1925. {
  1926. /*
  1927. * There can only be one root element!
  1928. */
  1929. mxml_error("<%s> cannot be a second root node after <%s> on line %d.", buffer, first->value.element.name, line);
  1930. goto error;
  1931. }
  1932. if ((node = mxmlNewElement(parent, buffer)) == NULL)
  1933. {
  1934. /*
  1935. * Just print error for now...
  1936. */
  1937. mxml_error("Unable to add element node to parent <%s> on line %d.", parent ? parent->value.element.name : "null", line);
  1938. goto error;
  1939. }
  1940. if (mxml_isspace(ch))
  1941. {
  1942. if ((ch = mxml_parse_element(node, p, &encoding, getc_cb, &line)) == EOF)
  1943. goto error;
  1944. }
  1945. else if (ch == '/')
  1946. {
  1947. if ((ch = (*getc_cb)(p, &encoding)) != '>')
  1948. {
  1949. mxml_error("Expected > but got '%c' instead for element <%s/> on line %d.", ch, buffer, line);
  1950. mxmlDelete(node);
  1951. node = NULL;
  1952. goto error;
  1953. }
  1954. ch = '/';
  1955. }
  1956. if (sax_cb)
  1957. (*sax_cb)(node, MXML_SAX_ELEMENT_OPEN, sax_data);
  1958. if (!first)
  1959. first = node;
  1960. if (ch == EOF)
  1961. break;
  1962. if (ch != '/')
  1963. {
  1964. /*
  1965. * Descend into this node, setting the value type as needed...
  1966. */
  1967. parent = node;
  1968. if (cb && parent)
  1969. type = (*cb)(parent);
  1970. else
  1971. type = MXML_TEXT;
  1972. }
  1973. else if (sax_cb)
  1974. {
  1975. (*sax_cb)(node, MXML_SAX_ELEMENT_CLOSE, sax_data);
  1976. if (!mxmlRelease(node))
  1977. {
  1978. if (first == node)
  1979. first = NULL;
  1980. node = NULL;
  1981. }
  1982. }
  1983. }
  1984. bufptr = buffer;
  1985. }
  1986. else if (ch == '&')
  1987. {
  1988. /*
  1989. * Add character entity to current buffer...
  1990. */
  1991. if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb, &line)) == EOF)
  1992. goto error;
  1993. if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
  1994. goto error;
  1995. }
  1996. else if (type == MXML_OPAQUE || type == MXML_CUSTOM || !mxml_isspace(ch))
  1997. {
  1998. /*
  1999. * Add character to current buffer...
  2000. */
  2001. if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
  2002. goto error;
  2003. }
  2004. }
  2005. while ((ch = (*getc_cb)(p, &encoding)) != EOF);
  2006. /*
  2007. * Free the string buffer - we don't need it anymore...
  2008. */
  2009. free(buffer);
  2010. /*
  2011. * Find the top element and return it...
  2012. */
  2013. if (parent)
  2014. {
  2015. node = parent;
  2016. while (parent != top && parent->parent)
  2017. parent = parent->parent;
  2018. if (node != parent)
  2019. {
  2020. mxml_error("Missing close tag </%s> under parent <%s> on line %d.", node->value.element.name, node->parent ? node->parent->value.element.name : "(null)", line);
  2021. mxmlDelete(first);
  2022. return (NULL);
  2023. }
  2024. }
  2025. if (parent)
  2026. return (parent);
  2027. else
  2028. return (first);
  2029. /*
  2030. * Common error return...
  2031. */
  2032. error:
  2033. mxmlDelete(first);
  2034. free(buffer);
  2035. return (NULL);
  2036. }
  2037. /*
  2038. * 'mxml_parse_element()' - Parse an element for any attributes...
  2039. */
  2040. static int /* O - Terminating character */
  2041. mxml_parse_element(
  2042. mxml_node_t *node, /* I - Element node */
  2043. void *p, /* I - Data to read from */
  2044. int *encoding, /* IO - Encoding */
  2045. _mxml_getc_cb_t getc_cb, /* I - Data callback */
  2046. int *line) /* IO - Current line number */
  2047. {
  2048. int ch, /* Current character in file */
  2049. quote; /* Quoting character */
  2050. char *name, /* Attribute name */
  2051. *value, /* Attribute value */
  2052. *ptr; /* Pointer into name/value */
  2053. int namesize, /* Size of name string */
  2054. valsize; /* Size of value string */
  2055. /*
  2056. * Initialize the name and value buffers...
  2057. */
  2058. if ((name = malloc(64)) == NULL)
  2059. {
  2060. mxml_error("Unable to allocate memory for name.");
  2061. return (EOF);
  2062. }
  2063. namesize = 64;
  2064. if ((value = malloc(64)) == NULL)
  2065. {
  2066. free(name);
  2067. mxml_error("Unable to allocate memory for value.");
  2068. return (EOF);
  2069. }
  2070. valsize = 64;
  2071. /*
  2072. * Loop until we hit a >, /, ?, or EOF...
  2073. */
  2074. while ((ch = (*getc_cb)(p, encoding)) != EOF)
  2075. {
  2076. #if DEBUG > 1
  2077. fprintf(stderr, "parse_element: ch='%c'\n", ch);
  2078. #endif /* DEBUG > 1 */
  2079. /*
  2080. * Skip leading whitespace...
  2081. */
  2082. if (mxml_isspace(ch))
  2083. {
  2084. if (ch == '\n')
  2085. (*line)++;
  2086. continue;
  2087. }
  2088. /*
  2089. * Stop at /, ?, or >...
  2090. */
  2091. if (ch == '/' || ch == '?')
  2092. {
  2093. /*
  2094. * Grab the > character and print an error if it isn't there...
  2095. */
  2096. quote = (*getc_cb)(p, encoding);
  2097. if (quote != '>')
  2098. {
  2099. mxml_error("Expected '>' after '%c' for element %s, but got '%c' on line %d.", ch, node->value.element.name, quote, *line);
  2100. goto error;
  2101. }
  2102. break;
  2103. }
  2104. else if (ch == '<')
  2105. {
  2106. mxml_error("Bare < in element %s on line %d.", node->value.element.name, *line);
  2107. goto error;
  2108. }
  2109. else if (ch == '>')
  2110. break;
  2111. /*
  2112. * Read the attribute name...
  2113. */
  2114. ptr = name;
  2115. if (mxml_add_char(ch, &ptr, &name, &namesize))
  2116. goto error;
  2117. if (ch == '\"' || ch == '\'')
  2118. {
  2119. /*
  2120. * Name is in quotes, so get a quoted string...
  2121. */
  2122. quote = ch;
  2123. while ((ch = (*getc_cb)(p, encoding)) != EOF)
  2124. {
  2125. if (ch == '&')
  2126. {
  2127. if ((ch = mxml_get_entity(node, p, encoding, getc_cb, line)) == EOF)
  2128. goto error;
  2129. }
  2130. else if (ch == '\n')
  2131. (*line)++;
  2132. if (mxml_add_char(ch, &ptr, &name, &namesize))
  2133. goto error;
  2134. if (ch == quote)
  2135. break;
  2136. }
  2137. }
  2138. else
  2139. {
  2140. /*
  2141. * Grab an normal, non-quoted name...
  2142. */
  2143. while ((ch = (*getc_cb)(p, encoding)) != EOF)
  2144. {
  2145. if (mxml_isspace(ch) || ch == '=' || ch == '/' || ch == '>' ||
  2146. ch == '?')
  2147. {
  2148. if (ch == '\n')
  2149. (*line)++;
  2150. break;
  2151. }
  2152. else
  2153. {
  2154. if (ch == '&')
  2155. {
  2156. if ((ch = mxml_get_entity(node, p, encoding, getc_cb, line)) == EOF)
  2157. goto error;
  2158. }
  2159. if (mxml_add_char(ch, &ptr, &name, &namesize))
  2160. goto error;
  2161. }
  2162. }
  2163. }
  2164. *ptr = '\0';
  2165. if (mxmlElementGetAttr(node, name))
  2166. {
  2167. mxml_error("Duplicate attribute '%s' in element %s on line %d.", name, node->value.element.name, *line);
  2168. goto error;
  2169. }
  2170. while (ch != EOF && mxml_isspace(ch))
  2171. {
  2172. ch = (*getc_cb)(p, encoding);
  2173. if (ch == '\n')
  2174. (*line)++;
  2175. }
  2176. if (ch == '=')
  2177. {
  2178. /*
  2179. * Read the attribute value...
  2180. */
  2181. while ((ch = (*getc_cb)(p, encoding)) != EOF && mxml_isspace(ch))
  2182. {
  2183. if (ch == '\n')
  2184. (*line)++;
  2185. }
  2186. if (ch == EOF)
  2187. {
  2188. mxml_error("Missing value for attribute '%s' in element %s on line %d.", name, node->value.element.name, *line);
  2189. goto error;
  2190. }
  2191. if (ch == '\'' || ch == '\"')
  2192. {
  2193. /*
  2194. * Read quoted value...
  2195. */
  2196. quote = ch;
  2197. ptr = value;
  2198. while ((ch = (*getc_cb)(p, encoding)) != EOF)
  2199. {
  2200. if (ch == quote)
  2201. {
  2202. break;
  2203. }
  2204. else
  2205. {
  2206. if (ch == '&')
  2207. {
  2208. if ((ch = mxml_get_entity(node, p, encoding, getc_cb, line)) == EOF)
  2209. goto error;
  2210. }
  2211. else if (ch == '\n')
  2212. (*line)++;
  2213. if (mxml_add_char(ch, &ptr, &value, &valsize))
  2214. goto error;
  2215. }
  2216. }
  2217. *ptr = '\0';
  2218. }
  2219. else
  2220. {
  2221. /*
  2222. * Read unquoted value...
  2223. */
  2224. ptr = value;
  2225. if (mxml_add_char(ch, &ptr, &value, &valsize))
  2226. goto error;
  2227. while ((ch = (*getc_cb)(p, encoding)) != EOF)
  2228. {
  2229. if (mxml_isspace(ch) || ch == '=' || ch == '/' || ch == '>')
  2230. {
  2231. if (ch == '\n')
  2232. (*line)++;
  2233. break;
  2234. }
  2235. else
  2236. {
  2237. if (ch == '&')
  2238. {
  2239. if ((ch = mxml_get_entity(node, p, encoding, getc_cb, line)) == EOF)
  2240. goto error;
  2241. }
  2242. if (mxml_add_char(ch, &ptr, &value, &valsize))
  2243. goto error;
  2244. }
  2245. }
  2246. *ptr = '\0';
  2247. }
  2248. /*
  2249. * Set the attribute with the given string value...
  2250. */
  2251. mxmlElementSetAttr(node, name, value);
  2252. }
  2253. else
  2254. {
  2255. mxml_error("Missing value for attribute '%s' in element %s on line %d.", name, node->value.element.name, *line);
  2256. goto error;
  2257. }
  2258. /*
  2259. * Check the end character...
  2260. */
  2261. if (ch == '/' || ch == '?')
  2262. {
  2263. /*
  2264. * Grab the > character and print an error if it isn't there...
  2265. */
  2266. quote = (*getc_cb)(p, encoding);
  2267. if (quote != '>')
  2268. {
  2269. mxml_error("Expected '>' after '%c' for element %s, but got '%c' on line %d.", ch, node->value.element.name, quote, *line);
  2270. ch = EOF;
  2271. }
  2272. break;
  2273. }
  2274. else if (ch == '>')
  2275. break;
  2276. }
  2277. /*
  2278. * Free the name and value buffers and return...
  2279. */
  2280. free(name);
  2281. free(value);
  2282. return (ch);
  2283. /*
  2284. * Common error return point...
  2285. */
  2286. error:
  2287. free(name);
  2288. free(value);
  2289. return (EOF);
  2290. }
  2291. /*
  2292. * 'mxml_string_getc()' - Get a character from a string.
  2293. */
  2294. static int /* O - Character or EOF */
  2295. mxml_string_getc(void *p, /* I - Pointer to file */
  2296. int *encoding) /* IO - Encoding */
  2297. {
  2298. int ch; /* Character */
  2299. const char **s; /* Pointer to string pointer */
  2300. s = (const char **)p;
  2301. if ((ch = (*s)[0] & 255) != 0 || *encoding == ENCODE_UTF16LE)
  2302. {
  2303. /*
  2304. * Got character; convert UTF-8 to integer and return...
  2305. */
  2306. (*s)++;
  2307. switch (*encoding)
  2308. {
  2309. case ENCODE_UTF8 :
  2310. if (!(ch & 0x80))
  2311. {
  2312. #if DEBUG > 1
  2313. printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
  2314. #endif /* DEBUG > 1 */
  2315. if (mxml_bad_char(ch))
  2316. {
  2317. mxml_error("Bad control character 0x%02x not allowed by XML standard.",
  2318. ch);
  2319. return (EOF);
  2320. }
  2321. return (ch);
  2322. }
  2323. else if (ch == 0xfe)
  2324. {
  2325. /*
  2326. * UTF-16 big-endian BOM?
  2327. */
  2328. if (((*s)[0] & 255) != 0xff)
  2329. return (EOF);
  2330. *encoding = ENCODE_UTF16BE;
  2331. (*s)++;
  2332. return (mxml_string_getc(p, encoding));
  2333. }
  2334. else if (ch == 0xff)
  2335. {
  2336. /*
  2337. * UTF-16 little-endian BOM?
  2338. */
  2339. if (((*s)[0] & 255) != 0xfe)
  2340. return (EOF);
  2341. *encoding = ENCODE_UTF16LE;
  2342. (*s)++;
  2343. return (mxml_string_getc(p, encoding));
  2344. }
  2345. else if ((ch & 0xe0) == 0xc0)
  2346. {
  2347. /*
  2348. * Two-byte value...
  2349. */
  2350. if (((*s)[0] & 0xc0) != 0x80)
  2351. return (EOF);
  2352. ch = ((ch & 0x1f) << 6) | ((*s)[0] & 0x3f);
  2353. (*s)++;
  2354. if (ch < 0x80)
  2355. {
  2356. mxml_error("Invalid UTF-8 sequence for character 0x%04x.", ch);
  2357. return (EOF);
  2358. }
  2359. #if DEBUG > 1
  2360. printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
  2361. #endif /* DEBUG > 1 */
  2362. return (ch);
  2363. }
  2364. else if ((ch & 0xf0) == 0xe0)
  2365. {
  2366. /*
  2367. * Three-byte value...
  2368. */
  2369. if (((*s)[0] & 0xc0) != 0x80 ||
  2370. ((*s)[1] & 0xc0) != 0x80)
  2371. return (EOF);
  2372. ch = ((((ch & 0x0f) << 6) | ((*s)[0] & 0x3f)) << 6) | ((*s)[1] & 0x3f);
  2373. (*s) += 2;
  2374. if (ch < 0x800)
  2375. {
  2376. mxml_error("Invalid UTF-8 sequence for character 0x%04x.", ch);
  2377. return (EOF);
  2378. }
  2379. /*
  2380. * Ignore (strip) Byte Order Mark (BOM)...
  2381. */
  2382. if (ch == 0xfeff)
  2383. return (mxml_string_getc(p, encoding));
  2384. #if DEBUG > 1
  2385. printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
  2386. #endif /* DEBUG > 1 */
  2387. return (ch);
  2388. }
  2389. else if ((ch & 0xf8) == 0xf0)
  2390. {
  2391. /*
  2392. * Four-byte value...
  2393. */
  2394. if (((*s)[0] & 0xc0) != 0x80 ||
  2395. ((*s)[1] & 0xc0) != 0x80 ||
  2396. ((*s)[2] & 0xc0) != 0x80)
  2397. return (EOF);
  2398. ch = ((((((ch & 0x07) << 6) | ((*s)[0] & 0x3f)) << 6) |
  2399. ((*s)[1] & 0x3f)) << 6) | ((*s)[2] & 0x3f);
  2400. (*s) += 3;
  2401. if (ch < 0x10000)
  2402. {
  2403. mxml_error("Invalid UTF-8 sequence for character 0x%04x.", ch);
  2404. return (EOF);
  2405. }
  2406. #if DEBUG > 1
  2407. printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
  2408. #endif /* DEBUG > 1 */
  2409. return (ch);
  2410. }
  2411. else
  2412. return (EOF);
  2413. case ENCODE_UTF16BE :
  2414. /*
  2415. * Read UTF-16 big-endian char...
  2416. */
  2417. ch = (ch << 8) | ((*s)[0] & 255);
  2418. (*s) ++;
  2419. if (mxml_bad_char(ch))
  2420. {
  2421. mxml_error("Bad control character 0x%02x not allowed by XML standard.",
  2422. ch);
  2423. return (EOF);
  2424. }
  2425. else if (ch >= 0xd800 && ch <= 0xdbff)
  2426. {
  2427. /*
  2428. * Multi-word UTF-16 char...
  2429. */
  2430. int lch; /* Lower word */
  2431. if (!(*s)[0])
  2432. return (EOF);
  2433. lch = (((*s)[0] & 255) << 8) | ((*s)[1] & 255);
  2434. (*s) += 2;
  2435. if (lch < 0xdc00 || lch >= 0xdfff)
  2436. return (EOF);
  2437. ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
  2438. }
  2439. #if DEBUG > 1
  2440. printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
  2441. #endif /* DEBUG > 1 */
  2442. return (ch);
  2443. case ENCODE_UTF16LE :
  2444. /*
  2445. * Read UTF-16 little-endian char...
  2446. */
  2447. ch = ch | (((*s)[0] & 255) << 8);
  2448. if (!ch)
  2449. {
  2450. (*s) --;
  2451. return (EOF);
  2452. }
  2453. (*s) ++;
  2454. if (mxml_bad_char(ch))
  2455. {
  2456. mxml_error("Bad control character 0x%02x not allowed by XML standard.",
  2457. ch);
  2458. return (EOF);
  2459. }
  2460. else if (ch >= 0xd800 && ch <= 0xdbff)
  2461. {
  2462. /*
  2463. * Multi-word UTF-16 char...
  2464. */
  2465. int lch; /* Lower word */
  2466. if (!(*s)[1])
  2467. return (EOF);
  2468. lch = (((*s)[1] & 255) << 8) | ((*s)[0] & 255);
  2469. (*s) += 2;
  2470. if (lch < 0xdc00 || lch >= 0xdfff)
  2471. return (EOF);
  2472. ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
  2473. }
  2474. #if DEBUG > 1
  2475. printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
  2476. #endif /* DEBUG > 1 */
  2477. return (ch);
  2478. }
  2479. }
  2480. return (EOF);
  2481. }
  2482. /*
  2483. * 'mxml_string_putc()' - Write a character to a string.
  2484. */
  2485. static int /* O - 0 on success, -1 on failure */
  2486. mxml_string_putc(int ch, /* I - Character to write */
  2487. void *p) /* I - Pointer to string pointers */
  2488. {
  2489. char **pp; /* Pointer to string pointers */
  2490. pp = (char **)p;
  2491. if (pp[0] < pp[1])
  2492. pp[0][0] = ch;
  2493. pp[0] ++;
  2494. return (0);
  2495. }
  2496. /*
  2497. * 'mxml_write_name()' - Write a name string.
  2498. */
  2499. static int /* O - 0 on success, -1 on failure */
  2500. mxml_write_name(const char *s, /* I - Name to write */
  2501. void *p, /* I - Write pointer */
  2502. int (*putc_cb)(int, void *))
  2503. /* I - Write callback */
  2504. {
  2505. char quote; /* Quote character */
  2506. const char *name; /* Entity name */
  2507. if (*s == '\"' || *s == '\'')
  2508. {
  2509. /*
  2510. * Write a quoted name string...
  2511. */
  2512. if ((*putc_cb)(*s, p) < 0)
  2513. return (-1);
  2514. quote = *s++;
  2515. while (*s && *s != quote)
  2516. {
  2517. if ((name = mxmlEntityGetName(*s)) != NULL)
  2518. {
  2519. if ((*putc_cb)('&', p) < 0)
  2520. return (-1);
  2521. while (*name)
  2522. {
  2523. if ((*putc_cb)(*name, p) < 0)
  2524. return (-1);
  2525. name ++;
  2526. }
  2527. if ((*putc_cb)(';', p) < 0)
  2528. return (-1);
  2529. }
  2530. else if ((*putc_cb)(*s, p) < 0)
  2531. return (-1);
  2532. s ++;
  2533. }
  2534. /*
  2535. * Write the end quote...
  2536. */
  2537. if ((*putc_cb)(quote, p) < 0)
  2538. return (-1);
  2539. }
  2540. else
  2541. {
  2542. /*
  2543. * Write a non-quoted name string...
  2544. */
  2545. while (*s)
  2546. {
  2547. if ((*putc_cb)(*s, p) < 0)
  2548. return (-1);
  2549. s ++;
  2550. }
  2551. }
  2552. return (0);
  2553. }
  2554. /*
  2555. * 'mxml_write_node()' - Save an XML node to a file.
  2556. */
  2557. static int /* O - Column or -1 on error */
  2558. mxml_write_node(mxml_node_t *node, /* I - Node to write */
  2559. void *p, /* I - File to write to */
  2560. mxml_save_cb_t cb, /* I - Whitespace callback */
  2561. int col, /* I - Current column */
  2562. _mxml_putc_cb_t putc_cb,/* I - Output callback */
  2563. _mxml_global_t *global,/* I - Global data */
  2564. void * cb_ctx) /* I - Whitespace callback context */
  2565. {
  2566. mxml_node_t *current, /* Current node */
  2567. *next; /* Next node */
  2568. int i, /* Looping var */
  2569. width; /* Width of attr + value */
  2570. _mxml_attr_t *attr; /* Current attribute */
  2571. char s[255]; /* Temporary string */
  2572. /*
  2573. * Loop through this node and all of its children...
  2574. */
  2575. for (current = node; current; current = next)
  2576. {
  2577. /*
  2578. * Print the node value...
  2579. */
  2580. switch (current->type)
  2581. {
  2582. case MXML_ELEMENT :
  2583. case MXML_COMMENT :
  2584. col = mxml_write_ws(current, p, cb, MXML_WS_BEFORE_OPEN, col, putc_cb, cb_ctx);
  2585. if ((*putc_cb)('<', p) < 0)
  2586. return (-1);
  2587. if (current->value.element.name[0] == '?' ||
  2588. !strncmp(current->value.element.name, "!--", 3))
  2589. {
  2590. /*
  2591. * Comments and processing instructions do not use character
  2592. * entities.
  2593. */
  2594. const char *ptr; /* Pointer into name */
  2595. for (ptr = current->value.element.name; *ptr; ptr ++)
  2596. if ((*putc_cb)(*ptr, p) < 0)
  2597. return (-1);
  2598. }
  2599. else if (!strncmp(current->value.element.name, "![CDATA[", 8))
  2600. {
  2601. /*
  2602. * CDATA elements do not use character entities, but also need the
  2603. * "]]" terminator added at the end.
  2604. */
  2605. const char *ptr; /* Pointer into name */
  2606. for (ptr = current->value.element.name; *ptr; ptr ++)
  2607. if ((*putc_cb)(*ptr, p) < 0)
  2608. return (-1);
  2609. if ((*putc_cb)(']', p) < 0)
  2610. return (-1);
  2611. if ((*putc_cb)(']', p) < 0)
  2612. return (-1);
  2613. }
  2614. else if (mxml_write_name(current->value.element.name, p, putc_cb) < 0)
  2615. return (-1);
  2616. col += strlen(current->value.element.name) + 1;
  2617. for (i = current->value.element.num_attrs, attr = current->value.element.attrs;
  2618. i > 0;
  2619. i --, attr ++)
  2620. {
  2621. width = (int)strlen(attr->name);
  2622. if (attr->value)
  2623. width += strlen(attr->value) + 3;
  2624. if (global->wrap > 0 && (col + width) > global->wrap)
  2625. {
  2626. if ((*putc_cb)('\n', p) < 0)
  2627. return (-1);
  2628. col = 0;
  2629. }
  2630. else
  2631. {
  2632. if ((*putc_cb)(' ', p) < 0)
  2633. return (-1);
  2634. col ++;
  2635. }
  2636. if (mxml_write_name(attr->name, p, putc_cb) < 0)
  2637. return (-1);
  2638. if (attr->value)
  2639. {
  2640. if ((*putc_cb)('=', p) < 0)
  2641. return (-1);
  2642. if ((*putc_cb)('\"', p) < 0)
  2643. return (-1);
  2644. if (mxml_write_string(attr->value, p, putc_cb) < 0)
  2645. return (-1);
  2646. if ((*putc_cb)('\"', p) < 0)
  2647. return (-1);
  2648. }
  2649. col += width;
  2650. }
  2651. if (current->child)
  2652. {
  2653. /*
  2654. * Write children...
  2655. */
  2656. if ((*putc_cb)('>', p) < 0)
  2657. return (-1);
  2658. else
  2659. col ++;
  2660. col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb, cb_ctx);
  2661. }
  2662. else if (current->value.element.name[0] == '!' ||
  2663. current->value.element.name[0] == '?')
  2664. {
  2665. /*
  2666. * The ? and ! elements are special-cases...
  2667. */
  2668. if ((*putc_cb)('>', p) < 0)
  2669. return (-1);
  2670. else
  2671. col ++;
  2672. col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb, cb_ctx);
  2673. }
  2674. else
  2675. {
  2676. if ((*putc_cb)(' ', p) < 0)
  2677. return (-1);
  2678. if ((*putc_cb)('/', p) < 0)
  2679. return (-1);
  2680. if ((*putc_cb)('>', p) < 0)
  2681. return (-1);
  2682. col += 3;
  2683. col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb, cb_ctx);
  2684. }
  2685. break;
  2686. case MXML_INTEGER :
  2687. if (current->prev)
  2688. {
  2689. if (global->wrap > 0 && col > global->wrap)
  2690. {
  2691. if ((*putc_cb)('\n', p) < 0)
  2692. return (-1);
  2693. col = 0;
  2694. }
  2695. else if ((*putc_cb)(' ', p) < 0)
  2696. return (-1);
  2697. else
  2698. col ++;
  2699. }
  2700. snprintf(s, sizeof(s), "%d", current->value.integer);
  2701. if (mxml_write_string(s, p, putc_cb) < 0)
  2702. return (-1);
  2703. col += strlen(s);
  2704. break;
  2705. case MXML_OPAQUE :
  2706. if (mxml_write_string(current->value.opaque, p, putc_cb) < 0)
  2707. return (-1);
  2708. col += strlen(current->value.opaque);
  2709. break;
  2710. case MXML_REAL :
  2711. if (current->prev)
  2712. {
  2713. if (global->wrap > 0 && col > global->wrap)
  2714. {
  2715. if ((*putc_cb)('\n', p) < 0)
  2716. return (-1);
  2717. col = 0;
  2718. }
  2719. else if ((*putc_cb)(' ', p) < 0)
  2720. return (-1);
  2721. else
  2722. col ++;
  2723. }
  2724. snprintf(s, sizeof(s), "%f", current->value.real);
  2725. if (mxml_write_string(s, p, putc_cb) < 0)
  2726. return (-1);
  2727. col += strlen(s);
  2728. break;
  2729. case MXML_TEXT :
  2730. if (current->value.text.whitespace && col > 0)
  2731. {
  2732. if (global->wrap > 0 && col > global->wrap)
  2733. {
  2734. if ((*putc_cb)('\n', p) < 0)
  2735. return (-1);
  2736. col = 0;
  2737. }
  2738. else if ((*putc_cb)(' ', p) < 0)
  2739. return (-1);
  2740. else
  2741. col ++;
  2742. }
  2743. if (mxml_write_string(current->value.text.string, p, putc_cb) < 0)
  2744. return (-1);
  2745. col += strlen(current->value.text.string);
  2746. break;
  2747. case MXML_CUSTOM :
  2748. if (global->custom_save_cb)
  2749. {
  2750. char *data; /* Custom data string */
  2751. const char *newline; /* Last newline in string */
  2752. if ((data = (*global->custom_save_cb)(current)) == NULL)
  2753. return (-1);
  2754. if (mxml_write_string(data, p, putc_cb) < 0)
  2755. return (-1);
  2756. if ((newline = strrchr(data, '\n')) == NULL)
  2757. col += strlen(data);
  2758. else
  2759. col = (int)strlen(newline);
  2760. free(data);
  2761. break;
  2762. }
  2763. default : /* Should never happen */
  2764. return (-1);
  2765. }
  2766. /*
  2767. * Figure out the next node...
  2768. */
  2769. if ((next = current->child) == NULL)
  2770. {
  2771. if (current == node)
  2772. {
  2773. /*
  2774. * Don't traverse to sibling node if we are at the "root" node...
  2775. */
  2776. next = NULL;
  2777. }
  2778. else
  2779. {
  2780. /*
  2781. * Try the next sibling, and continue traversing upwards as needed...
  2782. */
  2783. while ((next = current->next) == NULL)
  2784. {
  2785. if (current == node || !current->parent)
  2786. break;
  2787. /*
  2788. * The ? and ! elements are special-cases and have no end tags...
  2789. */
  2790. current = current->parent;
  2791. if (current->value.element.name[0] != '!' &&
  2792. current->value.element.name[0] != '?')
  2793. {
  2794. col = mxml_write_ws(current, p, cb, MXML_WS_BEFORE_CLOSE, col, putc_cb, cb_ctx);
  2795. if ((*putc_cb)('<', p) < 0)
  2796. return (-1);
  2797. if ((*putc_cb)('/', p) < 0)
  2798. return (-1);
  2799. if (mxml_write_string(current->value.element.name, p, putc_cb) < 0)
  2800. return (-1);
  2801. if ((*putc_cb)('>', p) < 0)
  2802. return (-1);
  2803. col += strlen(current->value.element.name) + 3;
  2804. col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_CLOSE, col, putc_cb, cb_ctx);
  2805. }
  2806. if (current == node)
  2807. break;
  2808. }
  2809. }
  2810. }
  2811. }
  2812. return (col);
  2813. }
  2814. /*
  2815. * 'mxml_write_string()' - Write a string, escaping & and < as needed.
  2816. */
  2817. static int /* O - 0 on success, -1 on failure */
  2818. mxml_write_string(
  2819. const char *s, /* I - String to write */
  2820. void *p, /* I - Write pointer */
  2821. _mxml_putc_cb_t putc_cb) /* I - Write callback */
  2822. {
  2823. const char *name; /* Entity name, if any */
  2824. while (*s)
  2825. {
  2826. if ((name = mxmlEntityGetName(*s)) != NULL)
  2827. {
  2828. if ((*putc_cb)('&', p) < 0)
  2829. return (-1);
  2830. while (*name)
  2831. {
  2832. if ((*putc_cb)(*name, p) < 0)
  2833. return (-1);
  2834. name ++;
  2835. }
  2836. if ((*putc_cb)(';', p) < 0)
  2837. return (-1);
  2838. }
  2839. else if ((*putc_cb)(*s, p) < 0)
  2840. return (-1);
  2841. s ++;
  2842. }
  2843. return (0);
  2844. }
  2845. /*
  2846. * 'mxml_write_ws()' - Do whitespace callback...
  2847. */
  2848. static int /* O - New column */
  2849. mxml_write_ws(mxml_node_t *node, /* I - Current node */
  2850. void *p, /* I - Write pointer */
  2851. mxml_save_cb_t cb, /* I - Callback function */
  2852. int ws, /* I - Where value */
  2853. int col, /* I - Current column */
  2854. _mxml_putc_cb_t putc_cb, /* I - Write callback */
  2855. void * cb_ctx) /* I - Whitespace callback context */
  2856. {
  2857. const char *s; /* Whitespace string */
  2858. if (cb && (s = (*cb)(node, ws, cb_ctx)) != NULL)
  2859. {
  2860. while (*s)
  2861. {
  2862. if ((*putc_cb)(*s, p) < 0)
  2863. return (-1);
  2864. else if (*s == '\n')
  2865. col = 0;
  2866. else if (*s == '\t')
  2867. {
  2868. col += MXML_TAB;
  2869. col = col - (col % MXML_TAB);
  2870. }
  2871. else
  2872. col ++;
  2873. s ++;
  2874. }
  2875. }
  2876. return (col);
  2877. }