PageRenderTime 57ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/src/utils/xml_parser.c

https://github.com/svettom/gpac
C | 2037 lines | 1926 code | 66 blank | 45 comment | 102 complexity | fca6bb30d4994cb55bcd47c6aaa6cba1 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * GPAC - Multimedia Framework C SDK
  3. *
  4. * Authors: Jean Le Feuvre
  5. * Copyright (c) Telecom ParisTech 2005-2012
  6. * All rights reserved
  7. *
  8. * This file is part of GPAC / common tools sub-project
  9. *
  10. * GPAC is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU Lesser General Public License as published by
  12. * the Free Software Foundation; either version 2, or (at your option)
  13. * any later version.
  14. *
  15. * GPAC is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU Lesser General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public
  21. * License along with this library; see the file COPYING. If not, write to
  22. * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  23. *
  24. */
  25. #include "../../include/gpac/xml.h"
  26. #include "../../include/gpac/utf.h"
  27. #ifndef GPAC_DISABLE_ZLIB
  28. /*since 0.2.2, we use zlib for xmt/x3d reading to handle gz files*/
  29. #include <zlib.h>
  30. #if (defined(WIN32) || defined(_WIN32_WCE)) && !defined(__GNUC__)
  31. #pragma comment(lib, "zlib")
  32. #endif
  33. #else
  34. #define NO_GZIP
  35. #endif
  36. static GF_Err gf_xml_sax_parse_intern(GF_SAXParser *parser, char *current);
  37. static char *xml_translate_xml_string(char *str)
  38. {
  39. char *value;
  40. u32 size, i, j;
  41. if (!str || !strlen(str)) return NULL;
  42. value = (char *)gf_malloc(sizeof(char) * 500);
  43. size = 500;
  44. i = j = 0;
  45. while (str[i]) {
  46. if (j+20 >= size) {
  47. size += 500;
  48. value = (char *)gf_realloc(value, sizeof(char)*size);
  49. }
  50. if (str[i] == '&') {
  51. if (str[i+1]=='#') {
  52. char szChar[20], *end;
  53. u16 wchar[2];
  54. u32 val;
  55. const unsigned short *srcp;
  56. strncpy(szChar, str+i, 10);
  57. end = strchr(szChar, ';');
  58. if (!end) break;
  59. end[1] = 0;
  60. i += (u32) strlen(szChar);
  61. wchar[1] = 0;
  62. if (szChar[2]=='x')
  63. sscanf(szChar, "&#x%x;", &val);
  64. else
  65. sscanf(szChar, "&#%u;", &val);
  66. wchar[0] = val;
  67. srcp = wchar;
  68. j += (u32) gf_utf8_wcstombs(&value[j], 20, &srcp);
  69. }
  70. else if (!strnicmp(&str[i], "&amp;", sizeof(char)*5)) {
  71. value[j] = '&';
  72. j++;
  73. i+= 5;
  74. }
  75. else if (!strnicmp(&str[i], "&lt;", sizeof(char)*4)) {
  76. value[j] = '<';
  77. j++;
  78. i+= 4;
  79. }
  80. else if (!strnicmp(&str[i], "&gt;", sizeof(char)*4)) {
  81. value[j] = '>';
  82. j++;
  83. i+= 4;
  84. }
  85. else if (!strnicmp(&str[i], "&apos;", sizeof(char)*6)) {
  86. value[j] = '\'';
  87. j++;
  88. i+= 6;
  89. }
  90. else if (!strnicmp(&str[i], "&quot;", sizeof(char)*6)) {
  91. value[j] = '\"';
  92. j++;
  93. i+= 6;
  94. } else {
  95. value[j] = str[i];
  96. j++; i++;
  97. }
  98. } else {
  99. value[j] = str[i];
  100. j++; i++;
  101. }
  102. }
  103. value[j] = 0;
  104. return value;
  105. }
  106. enum
  107. {
  108. SAX_STATE_ATT_NAME,
  109. SAX_STATE_ATT_VALUE,
  110. SAX_STATE_ELEMENT,
  111. SAX_STATE_COMMENT,
  112. SAX_STATE_TEXT_CONTENT,
  113. SAX_STATE_ENTITY,
  114. SAX_STATE_SKIP_DOCTYPE,
  115. SAX_STATE_CDATA,
  116. SAX_STATE_DONE,
  117. SAX_STATE_XML_PROC,
  118. SAX_STATE_SYNTAX_ERROR
  119. };
  120. typedef struct
  121. {
  122. u32 name_start, name_end;
  123. u32 val_start, val_end;
  124. Bool has_entities;
  125. } GF_XMLSaxAttribute;
  126. /* #define NO_GZIP */
  127. struct _tag_sax_parser
  128. {
  129. /*0: UTF-8, 1: UTF-16 BE, 2: UTF-16 LE. String input is always converted back to utf8*/
  130. s32 unicode_type;
  131. char *buffer;
  132. /*alloc size, line size and current position*/
  133. u32 alloc_size, line_size, current_pos;
  134. /*current node depth*/
  135. u32 node_depth;
  136. /*gz input file*/
  137. #ifdef NO_GZIP
  138. FILE *f_in;
  139. #else
  140. gzFile gz_in;
  141. #endif
  142. /*current line , file size and pos for user notif*/
  143. u32 line, file_size, file_pos;
  144. /*SAX callbacks*/
  145. gf_xml_sax_node_start sax_node_start;
  146. gf_xml_sax_node_end sax_node_end;
  147. gf_xml_sax_text_content sax_text_content;
  148. void *sax_cbck;
  149. gf_xml_sax_progress on_progress;
  150. u32 sax_state;
  151. u32 init_state;
  152. GF_List *entities;
  153. char att_sep;
  154. Bool in_entity, suspended;
  155. u32 in_quote;
  156. u32 elt_start_pos, elt_end_pos;
  157. /*last error found*/
  158. char err_msg[1000];
  159. u32 att_name_start, elt_name_start, elt_name_end, text_start, text_end;
  160. GF_XMLAttribute *attrs;
  161. GF_XMLSaxAttribute *sax_attrs;
  162. u32 nb_attrs, nb_alloc_attrs;
  163. };
  164. static GF_XMLSaxAttribute *xml_get_sax_attribute(GF_SAXParser *parser)
  165. {
  166. if (parser->nb_attrs==parser->nb_alloc_attrs) {
  167. parser->nb_alloc_attrs++;
  168. parser->sax_attrs = (GF_XMLSaxAttribute *)gf_realloc(parser->sax_attrs, sizeof(GF_XMLSaxAttribute)*parser->nb_alloc_attrs);
  169. parser->attrs = (GF_XMLAttribute *)gf_realloc(parser->attrs, sizeof(GF_XMLAttribute)*parser->nb_alloc_attrs);
  170. }
  171. return &parser->sax_attrs[parser->nb_attrs++];
  172. }
  173. static void xml_sax_swap(GF_SAXParser *parser)
  174. {
  175. if (parser->current_pos && ((parser->sax_state==SAX_STATE_TEXT_CONTENT) || (parser->sax_state==SAX_STATE_COMMENT) ) ) {
  176. assert(parser->line_size >= parser->current_pos);
  177. parser->line_size -= parser->current_pos;
  178. parser->file_pos += parser->current_pos;
  179. if (parser->line_size) memmove(parser->buffer, parser->buffer + parser->current_pos, sizeof(char)*parser->line_size);
  180. parser->buffer[parser->line_size] = 0;
  181. parser->current_pos = 0;
  182. }
  183. }
  184. static void format_sax_error(GF_SAXParser *parser, u32 linepos, const char* fmt, ...)
  185. {
  186. va_list args;
  187. u32 len;
  188. char szM[20];
  189. va_start(args, fmt);
  190. vsprintf(parser->err_msg, fmt, args);
  191. va_end(args);
  192. sprintf(szM, " - Line %d: ", parser->line + 1);
  193. strcat(parser->err_msg, szM);
  194. len = (u32) strlen(parser->err_msg);
  195. strncpy(parser->err_msg + len, parser->buffer+ (linepos ? linepos : parser->current_pos), 10);
  196. parser->err_msg[len + 10] = 0;
  197. parser->sax_state = SAX_STATE_SYNTAX_ERROR;
  198. }
  199. static void xml_sax_node_end(GF_SAXParser *parser, Bool had_children)
  200. {
  201. char *name, *sep, c;
  202. assert(parser->elt_name_start);
  203. assert(parser->elt_name_end);
  204. if (!parser->node_depth) {
  205. format_sax_error(parser, 0, "Markup error");
  206. return;
  207. }
  208. c = parser->buffer[parser->elt_name_end - 1];
  209. parser->buffer[parser->elt_name_end - 1] = 0;
  210. name = parser->buffer + parser->elt_name_start - 1;
  211. if (parser->sax_node_end) {
  212. sep = strchr(name, ':');
  213. if (sep) {
  214. sep[0] = 0;
  215. parser->sax_node_end(parser->sax_cbck, sep+1, name);
  216. sep[0] = ':';
  217. } else {
  218. parser->sax_node_end(parser->sax_cbck, name, NULL);
  219. }
  220. }
  221. parser->buffer[parser->elt_name_end - 1] = c;
  222. parser->node_depth--;
  223. if (!parser->init_state && !parser->node_depth) parser->sax_state = SAX_STATE_DONE;
  224. xml_sax_swap(parser);
  225. parser->text_start = parser->text_end = 0;
  226. }
  227. static void xml_sax_node_start(GF_SAXParser *parser)
  228. {
  229. Bool has_entities = 0;
  230. u32 i;
  231. char *sep, c, *name;
  232. assert(parser->elt_name_start && parser->elt_name_end);
  233. c = parser->buffer[parser->elt_name_end - 1];
  234. parser->buffer[parser->elt_name_end - 1] = 0;
  235. name = parser->buffer + parser->elt_name_start - 1;
  236. for (i=0;i<parser->nb_attrs; i++) {
  237. parser->attrs[i].name = parser->buffer + parser->sax_attrs[i].name_start - 1;
  238. parser->buffer[parser->sax_attrs[i].name_end-1] = 0;
  239. parser->attrs[i].value = parser->buffer + parser->sax_attrs[i].val_start - 1;
  240. parser->buffer[parser->sax_attrs[i].val_end-1] = 0;
  241. if (strchr(parser->attrs[i].value, '&')) {
  242. parser->sax_attrs[i].has_entities = 1;
  243. has_entities = 1;
  244. parser->attrs[i].value = xml_translate_xml_string(parser->attrs[i].value);
  245. }
  246. /*store first char pos after current attrib for node peeking*/
  247. parser->att_name_start = parser->sax_attrs[i].val_end;
  248. }
  249. if (parser->sax_node_start) {
  250. sep = strchr(name, ':');
  251. if (sep) {
  252. sep[0] = 0;
  253. parser->sax_node_start(parser->sax_cbck, sep+1, name, parser->attrs, parser->nb_attrs);
  254. sep[0] = ':';
  255. } else {
  256. parser->sax_node_start(parser->sax_cbck, name, NULL, parser->attrs, parser->nb_attrs);
  257. }
  258. }
  259. parser->att_name_start = 0;
  260. parser->buffer[parser->elt_name_end - 1] = c;
  261. parser->node_depth++;
  262. if (has_entities) {
  263. for (i=0;i<parser->nb_attrs; i++) {
  264. if (parser->sax_attrs[i].has_entities) {
  265. parser->sax_attrs[i].has_entities = 0;
  266. gf_free(parser->attrs[i].value);
  267. }
  268. }
  269. }
  270. parser->nb_attrs = 0;
  271. xml_sax_swap(parser);
  272. parser->text_start = parser->text_end = 0;
  273. }
  274. static Bool xml_sax_parse_attribute(GF_SAXParser *parser)
  275. {
  276. char *sep;
  277. GF_XMLSaxAttribute *att = NULL;
  278. /*looking for attribute name*/
  279. if (parser->sax_state==SAX_STATE_ATT_NAME) {
  280. /*looking for start*/
  281. if (!parser->att_name_start) {
  282. while (parser->current_pos < parser->line_size) {
  283. u8 c = parser->buffer[parser->current_pos];
  284. switch (c) {
  285. case '\n':
  286. parser->line++;
  287. case ' ':
  288. case '\r':
  289. case '\t':
  290. parser->current_pos++;
  291. continue;
  292. /*end of element*/
  293. case '?':
  294. if (parser->init_state!=1) break;
  295. case '/':
  296. /*not enough data*/
  297. if (parser->current_pos+1 == parser->line_size) return 1;
  298. if (parser->buffer[parser->current_pos+1]=='>') {
  299. parser->current_pos+=2;
  300. parser->elt_end_pos = parser->file_pos + parser->current_pos - 1;
  301. /*done parsing attr AND elements*/
  302. if (!parser->init_state) {
  303. xml_sax_node_start(parser);
  304. /*move to SAX_STATE_TEXT_CONTENT to force text flush*/
  305. parser->sax_state = SAX_STATE_TEXT_CONTENT;
  306. xml_sax_node_end(parser, 0);
  307. } else {
  308. parser->nb_attrs = 0;
  309. }
  310. parser->sax_state = (parser->init_state) ? SAX_STATE_ELEMENT : SAX_STATE_TEXT_CONTENT;
  311. parser->text_start = parser->text_end = 0;
  312. return 0;
  313. }
  314. if (!parser->in_quote && (c=='/')) {
  315. if (!parser->init_state) {
  316. format_sax_error(parser, 0, "Markup error");
  317. return 1;
  318. }
  319. }
  320. break;
  321. case '"':
  322. if (parser->sax_state==SAX_STATE_ATT_VALUE) break;
  323. if (parser->in_quote && (parser->in_quote!=c) ) {
  324. format_sax_error(parser, 0, "Markup error");
  325. return 1;
  326. }
  327. if (parser->in_quote) parser->in_quote = 0;
  328. else parser->in_quote = c;
  329. break;
  330. case '>':
  331. parser->current_pos+=1;
  332. /*end of <!DOCTYPE>*/
  333. if (parser->init_state) {
  334. if (parser->init_state==1) {
  335. format_sax_error(parser, 0, "Invalid DOCTYPE");
  336. return 1;
  337. }
  338. parser->sax_state = SAX_STATE_ELEMENT;
  339. return 0;
  340. }
  341. /*done parsing attr*/
  342. parser->sax_state = SAX_STATE_TEXT_CONTENT;
  343. xml_sax_node_start(parser);
  344. return 0;
  345. case '[':
  346. if (parser->init_state) {
  347. parser->current_pos+=1;
  348. if (parser->init_state==1) {
  349. format_sax_error(parser, 0, "Invalid DOCTYPE");
  350. return 1;
  351. }
  352. parser->sax_state = SAX_STATE_ELEMENT;
  353. return 0;
  354. }
  355. break;
  356. case '<':
  357. format_sax_error(parser, 0, "Invalid character '<'");
  358. return 0;
  359. /*first char of attr name*/
  360. default:
  361. parser->att_name_start = parser->current_pos + 1;
  362. break;
  363. }
  364. parser->current_pos++;
  365. if (parser->att_name_start) break;
  366. }
  367. if (parser->current_pos == parser->line_size) return 1;
  368. }
  369. if (parser->init_state==2) {
  370. sep = strchr(parser->buffer + parser->att_name_start - 1, parser->in_quote ? parser->in_quote : ' ');
  371. /*not enough data*/
  372. if (!sep) return 1;
  373. parser->current_pos = (u32) (sep - parser->buffer);
  374. parser->att_name_start = 0;
  375. if (parser->in_quote) {
  376. parser->current_pos++;
  377. parser->in_quote = 0;
  378. }
  379. return 0;
  380. }
  381. /*looking for '"'*/
  382. if (parser->att_name_start) {
  383. u32 i, first=1;
  384. sep = strchr(parser->buffer + parser->att_name_start - 1, '=');
  385. /*not enough data*/
  386. if (!sep) return 1;
  387. parser->current_pos = (u32) (sep - parser->buffer);
  388. att = xml_get_sax_attribute(parser);
  389. att->name_start = parser->att_name_start;
  390. att->name_end = parser->current_pos + 1;
  391. while (strchr(" \n\t", parser->buffer[att->name_end - 2])) {
  392. assert(att->name_end);
  393. att->name_end --;
  394. }
  395. att->has_entities = 0;
  396. for (i=att->name_start; i<att->name_end; i++) {
  397. char c = parser->buffer[i-1];
  398. if ((c>='a') && (c<='z')) {}
  399. else if ((c>='A') && (c<='Z')) {}
  400. else if ((c==':') || (c=='_')) {}
  401. else if (!first && ((c=='-') || (c=='.') || ((c>='0') && (c<='9')) )) {}
  402. else {
  403. format_sax_error(parser, att->name_start-1, "Invalid character \'%c\' for attribute name", c);
  404. return 1;
  405. }
  406. first=0;
  407. }
  408. parser->att_name_start = 0;
  409. parser->current_pos++;
  410. parser->sax_state = SAX_STATE_ATT_VALUE;
  411. }
  412. }
  413. if (parser->sax_state == SAX_STATE_ATT_VALUE) {
  414. att = &parser->sax_attrs[parser->nb_attrs-1];
  415. /*looking for first delimiter*/
  416. if (!parser->att_sep) {
  417. while (parser->current_pos < parser->line_size) {
  418. u8 c = parser->buffer[parser->current_pos];
  419. switch (c) {
  420. case '\n':
  421. parser->line++;
  422. case ' ':
  423. case '\r':
  424. case '\t':
  425. parser->current_pos++;
  426. continue;
  427. case '\'':
  428. case '"':
  429. parser->att_sep = c;
  430. att->val_start = parser->current_pos + 2;
  431. break;
  432. default:
  433. break;
  434. }
  435. parser->current_pos++;
  436. if (parser->att_sep) break;
  437. }
  438. if (parser->current_pos == parser->line_size) return 1;
  439. }
  440. att_retry:
  441. assert(parser->att_sep);
  442. sep = strchr(parser->buffer + parser->current_pos, parser->att_sep);
  443. if (!sep || !sep[1]) return 1;
  444. if (sep[1]==parser->att_sep) {
  445. format_sax_error(parser, (u32) (sep - parser->buffer), "Invalid character %c after attribute value separator %c ", sep[1], parser->att_sep);
  446. return 1;
  447. }
  448. if (!parser->init_state && (strchr(" />\n\t\r", sep[1])==NULL)) {
  449. parser->current_pos = (u32) (sep - parser->buffer + 1);
  450. goto att_retry;
  451. }
  452. parser->current_pos = (u32) (sep - parser->buffer);
  453. att->val_end = parser->current_pos + 1;
  454. parser->current_pos++;
  455. /*"style" always at the begining of the attributes for ease of parsing*/
  456. if (!strncmp(parser->buffer + att->name_start-1, "style", 5)) {
  457. GF_XMLSaxAttribute prev = parser->sax_attrs[0];
  458. parser->sax_attrs[0] = *att;
  459. *att = prev;
  460. }
  461. parser->att_sep = 0;
  462. parser->sax_state = SAX_STATE_ATT_NAME;
  463. parser->att_name_start = 0;
  464. return 0;
  465. }
  466. return 1;
  467. }
  468. typedef struct
  469. {
  470. char *name;
  471. char *value;
  472. u32 namelen;
  473. u8 sep;
  474. } XML_Entity;
  475. static void xml_sax_flush_text(GF_SAXParser *parser)
  476. {
  477. char *text, c;
  478. if (!parser->text_start || parser->init_state || !parser->sax_text_content) return;
  479. assert(parser->text_start < parser->text_end);
  480. c = parser->buffer[parser->text_end-1];
  481. parser->buffer[parser->text_end-1] = 0;
  482. text = parser->buffer + parser->text_start-1;
  483. /*solve XML built-in entities*/
  484. if (strchr(text, '&') && strchr(text, ';')) {
  485. char *xml_text = xml_translate_xml_string(text);
  486. if (xml_text) {
  487. parser->sax_text_content(parser->sax_cbck, xml_text, (parser->sax_state==SAX_STATE_CDATA) ? 1 : 0);
  488. gf_free(xml_text);
  489. }
  490. } else {
  491. parser->sax_text_content(parser->sax_cbck, text, (parser->sax_state==SAX_STATE_CDATA) ? 1 : 0);
  492. }
  493. parser->buffer[parser->text_end-1] = c;
  494. parser->text_start = parser->text_end = 0;
  495. }
  496. static void xml_sax_store_text(GF_SAXParser *parser, u32 txt_len)
  497. {
  498. if (!txt_len) return;
  499. if (!parser->text_start) {
  500. parser->text_start = parser->current_pos + 1;
  501. parser->text_end = parser->text_start + txt_len;
  502. parser->current_pos += txt_len;
  503. assert(parser->current_pos <= parser->line_size);
  504. return;
  505. }
  506. /*contiguous text*/
  507. if (parser->text_end && (parser->text_end-1 == parser->current_pos)) {
  508. parser->text_end += txt_len;
  509. parser->current_pos += txt_len;
  510. assert(parser->current_pos <= parser->line_size);
  511. return;
  512. }
  513. /*need to flush*/
  514. xml_sax_flush_text(parser);
  515. parser->text_start = parser->current_pos + 1;
  516. parser->text_end = parser->text_start + txt_len;
  517. parser->current_pos += txt_len;
  518. assert(parser->current_pos <= parser->line_size);
  519. }
  520. static char *xml_get_current_text(GF_SAXParser *parser)
  521. {
  522. char *text, c;
  523. if (!parser->text_start) return NULL;
  524. c = parser->buffer[parser->text_end-1];
  525. parser->buffer[parser->text_end-1] = 0;
  526. text = gf_strdup(parser->buffer + parser->text_start-1);
  527. parser->buffer[parser->text_end-1] = c;
  528. parser->text_start = parser->text_end = 0;
  529. return text;
  530. }
  531. static void xml_sax_skip_doctype(GF_SAXParser *parser)
  532. {
  533. while (parser->current_pos < parser->line_size) {
  534. if (parser->buffer[parser->current_pos]=='>') {
  535. parser->sax_state = SAX_STATE_ELEMENT;
  536. parser->current_pos++;
  537. xml_sax_swap(parser);
  538. return;
  539. }
  540. parser->current_pos++;
  541. }
  542. }
  543. static void xml_sax_skip_xml_proc(GF_SAXParser *parser)
  544. {
  545. while (parser->current_pos + 1 < parser->line_size) {
  546. if ((parser->buffer[parser->current_pos]=='?') && (parser->buffer[parser->current_pos+1]=='>')) {
  547. parser->sax_state = SAX_STATE_ELEMENT;
  548. parser->current_pos++;
  549. xml_sax_swap(parser);
  550. return;
  551. }
  552. parser->current_pos++;
  553. }
  554. }
  555. static void xml_sax_parse_entity(GF_SAXParser *parser)
  556. {
  557. char szName[1024];
  558. u32 i = 0;
  559. XML_Entity *ent = (XML_Entity *)gf_list_last(parser->entities);
  560. char *skip_chars = " \t\n\r";
  561. i=0;
  562. if (ent && ent->value) ent = NULL;
  563. if (ent) skip_chars = NULL;
  564. while (parser->current_pos+i < parser->line_size) {
  565. u8 c = parser->buffer[parser->current_pos+i];
  566. if (skip_chars && strchr(skip_chars, c)) {
  567. if (c=='\n') parser->line++;
  568. parser->current_pos++;
  569. continue;
  570. }
  571. if (!ent && (c=='%')) {
  572. parser->current_pos+=i+1;
  573. parser->sax_state = SAX_STATE_SKIP_DOCTYPE;
  574. return;
  575. }
  576. else if (!ent && ((c=='\"') || (c=='\'')) ) {
  577. szName[i] = 0;
  578. GF_SAFEALLOC(ent, XML_Entity);
  579. ent->name = gf_strdup(szName);
  580. ent->namelen = (u32) strlen(ent->name);
  581. ent->sep = c;
  582. parser->current_pos += 1+i;
  583. assert(parser->current_pos < parser->line_size);
  584. xml_sax_swap(parser);
  585. i=0;
  586. gf_list_add(parser->entities, ent);
  587. skip_chars = NULL;
  588. } else if (ent && c==ent->sep) {
  589. xml_sax_store_text(parser, i);
  590. ent->value = xml_get_current_text(parser);
  591. if (!ent->value) ent->value = gf_strdup("");
  592. parser->current_pos += 1;
  593. assert(parser->current_pos < parser->line_size);
  594. xml_sax_swap(parser);
  595. parser->sax_state = SAX_STATE_SKIP_DOCTYPE;
  596. return;
  597. } else if (!ent) {
  598. szName[i] = c;
  599. i++;
  600. } else {
  601. i++;
  602. }
  603. }
  604. xml_sax_store_text(parser, i);
  605. }
  606. static void xml_sax_cdata(GF_SAXParser *parser)
  607. {
  608. char *cd_end = strstr(parser->buffer + parser->current_pos, "]]>");
  609. if (!cd_end) {
  610. xml_sax_store_text(parser, parser->line_size - parser->current_pos);
  611. } else {
  612. u32 size = (u32) (cd_end - (parser->buffer + parser->current_pos));
  613. xml_sax_store_text(parser, size);
  614. xml_sax_flush_text(parser);
  615. parser->current_pos += 3;
  616. assert(parser->current_pos <= parser->line_size);
  617. parser->sax_state = SAX_STATE_TEXT_CONTENT;
  618. }
  619. }
  620. static Bool xml_sax_parse_comments(GF_SAXParser *parser)
  621. {
  622. char *end = strstr(parser->buffer + parser->current_pos, "-->");
  623. if (!end) {
  624. if (parser->line_size>3)
  625. parser->current_pos = parser->line_size-3;
  626. xml_sax_swap(parser);
  627. return 0;
  628. }
  629. parser->current_pos += 3 + (u32) (end - (parser->buffer + parser->current_pos) );
  630. assert(parser->current_pos <= parser->line_size);
  631. parser->sax_state = SAX_STATE_TEXT_CONTENT;
  632. parser->text_start = parser->text_end = 0;
  633. xml_sax_swap(parser);
  634. return 1;
  635. }
  636. static GF_Err xml_sax_parse(GF_SAXParser *parser, Bool force_parse)
  637. {
  638. u32 i = 0;
  639. Bool is_text, is_end;
  640. u8 c;
  641. char *elt, sep;
  642. u32 cdata_sep;
  643. is_text = 0;
  644. while (parser->current_pos<parser->line_size) {
  645. if (!force_parse && parser->suspended) goto exit;
  646. restart:
  647. is_text = 0;
  648. switch (parser->sax_state) {
  649. /*load an XML element*/
  650. case SAX_STATE_TEXT_CONTENT:
  651. is_text = 1;
  652. case SAX_STATE_ELEMENT:
  653. elt = NULL;
  654. i=0;
  655. while ((c = parser->buffer[parser->current_pos+i]) !='<') {
  656. if ((parser->init_state==2) && (c ==']')) {
  657. parser->sax_state = SAX_STATE_ATT_NAME;
  658. parser->current_pos+=i+1;
  659. goto restart;
  660. }
  661. i++;
  662. if (c=='\n') parser->line++;
  663. if (parser->current_pos+i==parser->line_size) goto exit;
  664. }
  665. if (is_text && i) {
  666. xml_sax_store_text(parser, i);
  667. is_text = 0;
  668. parser->sax_state = SAX_STATE_ELEMENT;
  669. } else if (i) {
  670. parser->current_pos += i;
  671. assert(parser->current_pos < parser->line_size);
  672. }
  673. is_end = 0;
  674. i = 0;
  675. cdata_sep = 0;
  676. while (1) {
  677. char c = parser->buffer[parser->current_pos+1+i];
  678. if (!strncmp(parser->buffer+parser->current_pos+1+i, "!--", 3)) {
  679. parser->sax_state = SAX_STATE_COMMENT;
  680. i += 3;
  681. break;
  682. }
  683. if (!c) {
  684. i = 0;
  685. goto exit;
  686. }
  687. if ((c=='\t') || (c=='\r') || (c==' ') ) {
  688. if (i) break;
  689. else parser->current_pos++;
  690. }
  691. else if (c=='\n') {
  692. parser->line++;
  693. if (i) break;
  694. else parser->current_pos++;
  695. }
  696. else if (c=='>') break;
  697. else if (c=='=') break;
  698. else if (c=='[') {
  699. i++;
  700. if (!cdata_sep) cdata_sep = 1;
  701. else {
  702. break;
  703. }
  704. }
  705. else if (c=='/') {
  706. is_end = !i ? 1 : 2;
  707. i++;
  708. } else if (c=='<') {
  709. if (parser->sax_state != SAX_STATE_COMMENT) {
  710. parser->sax_state = SAX_STATE_SYNTAX_ERROR;
  711. return GF_CORRUPTED_DATA;
  712. }
  713. } else {
  714. i++;
  715. }
  716. /* if ((c=='[') && (parser->buffer[parser->elt_name_start-1 + i-2]=='A') ) break; */
  717. if (parser->current_pos+1+i==parser->line_size) {
  718. i=0;
  719. goto exit;
  720. }
  721. }
  722. if (i) {
  723. parser->elt_name_start = parser->current_pos+1 + 1;
  724. if (is_end==1) parser->elt_name_start ++;
  725. if (is_end==2) parser->elt_name_end = parser->current_pos+1+i;
  726. else parser->elt_name_end = parser->current_pos+1+i + 1;
  727. }
  728. if (is_end) {
  729. xml_sax_flush_text(parser);
  730. parser->elt_end_pos = parser->file_pos + parser->current_pos + i;
  731. if (is_end==2) {
  732. parser->sax_state = SAX_STATE_ELEMENT;
  733. xml_sax_node_start(parser);
  734. xml_sax_node_end(parser, 0);
  735. } else {
  736. parser->elt_end_pos += parser->elt_name_end - parser->elt_name_start;
  737. xml_sax_node_end(parser, 1);
  738. }
  739. if (parser->sax_state == SAX_STATE_SYNTAX_ERROR) break;
  740. parser->current_pos+=2+i;
  741. parser->sax_state = SAX_STATE_TEXT_CONTENT;
  742. break;
  743. }
  744. sep = parser->buffer[parser->elt_name_end-1];
  745. parser->buffer[parser->elt_name_end-1] = 0;
  746. elt = parser->buffer + parser->elt_name_start-1;
  747. parser->sax_state = SAX_STATE_ATT_NAME;
  748. assert(parser->elt_start_pos <= parser->file_pos + parser->current_pos);
  749. parser->elt_start_pos = parser->file_pos + parser->current_pos;
  750. if (!strncmp(elt, "!--", 3)) {
  751. xml_sax_flush_text(parser);
  752. parser->sax_state = SAX_STATE_COMMENT;
  753. if (i>3) parser->current_pos -= (i-3);
  754. }
  755. else if (!strcmp(elt, "?xml")) parser->init_state = 1;
  756. else if (!strcmp(elt, "!DOCTYPE")) parser->init_state = 2;
  757. else if (!strcmp(elt, "!ENTITY")) parser->sax_state = SAX_STATE_ENTITY;
  758. else if (!strcmp(elt, "!ATTLIST") || !strcmp(elt, "!ELEMENT")) parser->sax_state = SAX_STATE_SKIP_DOCTYPE;
  759. else if (!strcmp(elt, "![CDATA["))
  760. parser->sax_state = SAX_STATE_CDATA;
  761. else if (elt[0]=='?') parser->sax_state = SAX_STATE_XML_PROC;
  762. /*node found*/
  763. else {
  764. xml_sax_flush_text(parser);
  765. if (parser->init_state) {
  766. parser->init_state = 0;
  767. /*that's a bit ugly: since we solve entities when appending text, we need to
  768. reparse the current buffer*/
  769. if (gf_list_count(parser->entities)) {
  770. char *orig_buf;
  771. GF_Err e;
  772. parser->buffer[parser->elt_name_end-1] = sep;
  773. orig_buf = gf_strdup(parser->buffer + parser->current_pos);
  774. parser->current_pos = 0;
  775. parser->line_size = 0;
  776. parser->elt_start_pos = 0;
  777. parser->sax_state = SAX_STATE_TEXT_CONTENT;
  778. e = gf_xml_sax_parse_intern(parser, orig_buf);
  779. gf_free(orig_buf);
  780. return e;
  781. }
  782. }
  783. }
  784. parser->current_pos+=1+i;
  785. parser->buffer[parser->elt_name_end-1] = sep;
  786. break;
  787. case SAX_STATE_COMMENT:
  788. if (!xml_sax_parse_comments(parser)) {
  789. xml_sax_swap(parser);
  790. goto exit;
  791. }
  792. break;
  793. case SAX_STATE_ATT_NAME:
  794. case SAX_STATE_ATT_VALUE:
  795. if (xml_sax_parse_attribute(parser))
  796. goto exit;
  797. break;
  798. case SAX_STATE_ENTITY:
  799. xml_sax_parse_entity(parser);
  800. break;
  801. case SAX_STATE_SKIP_DOCTYPE:
  802. xml_sax_skip_doctype(parser);
  803. break;
  804. case SAX_STATE_XML_PROC:
  805. xml_sax_skip_xml_proc(parser);
  806. break;
  807. case SAX_STATE_CDATA:
  808. xml_sax_cdata(parser);
  809. break;
  810. case SAX_STATE_SYNTAX_ERROR:
  811. return GF_CORRUPTED_DATA;
  812. case SAX_STATE_DONE:
  813. return GF_EOS;
  814. }
  815. }
  816. exit:
  817. #if 0
  818. if (is_text) {
  819. if (i) xml_sax_store_text(parser, i);
  820. /*DON'T FLUSH TEXT YET, wait for next '<' to do so otherwise we may corrupt xml base entities (&apos;, ...)*/
  821. }
  822. #endif
  823. xml_sax_swap(parser);
  824. if (parser->sax_state==SAX_STATE_SYNTAX_ERROR)
  825. return GF_CORRUPTED_DATA;
  826. else
  827. return GF_OK;
  828. }
  829. static GF_Err xml_sax_append_string(GF_SAXParser *parser, char *string)
  830. {
  831. u32 size = parser->line_size;
  832. u32 nl_size = (u32) strlen(string);
  833. if (!nl_size) return GF_OK;
  834. if ( (parser->alloc_size < size+nl_size+1)
  835. /* || (parser->alloc_size / 2 ) > size+nl_size+1 */
  836. )
  837. {
  838. parser->alloc_size = size+nl_size+1;
  839. parser->alloc_size = 3 * parser->alloc_size / 2;
  840. parser->buffer = gf_realloc(parser->buffer, sizeof(char) * parser->alloc_size);
  841. if (!parser->buffer ) return GF_OUT_OF_MEM;
  842. }
  843. memcpy(parser->buffer+size, string, sizeof(char)*nl_size);
  844. parser->buffer[size+nl_size] = 0;
  845. parser->line_size = size+nl_size;
  846. return GF_OK;
  847. }
  848. static XML_Entity *gf_xml_locate_entity(GF_SAXParser *parser, char *ent_start, Bool *needs_text)
  849. {
  850. u32 i, count;
  851. u32 len = (u32) strlen(ent_start);
  852. *needs_text = 0;
  853. count = gf_list_count(parser->entities);
  854. for (i=0; i<count; i++) {
  855. XML_Entity *ent = (XML_Entity *)gf_list_get(parser->entities, i);
  856. if (len < ent->namelen + 1) {
  857. *needs_text = 1;
  858. return NULL;
  859. }
  860. if (!strncmp(ent->name, ent_start, ent->namelen) && (ent_start[ent->namelen]==';')) {
  861. return ent;
  862. }
  863. }
  864. return NULL;
  865. }
  866. static GF_Err gf_xml_sax_parse_intern(GF_SAXParser *parser, char *current)
  867. {
  868. u32 count;
  869. /*solve entities*/
  870. count = gf_list_count(parser->entities);
  871. while (count) {
  872. char *entityEnd;
  873. XML_Entity *ent;
  874. char *entityStart = strstr(current, "&");
  875. Bool needs_text;
  876. u32 line_num;
  877. /*if in entity, the start of the entity is in the buffer !!*/
  878. if (parser->in_entity) {
  879. u32 len;
  880. char *name;
  881. entityEnd = strstr(current, ";");
  882. if (!entityEnd) return xml_sax_append_string(parser, current);
  883. entityStart = strrchr(parser->buffer, '&');
  884. entityEnd[0] = 0;
  885. len = (u32) strlen(entityStart) + (u32) strlen(current) + 1;
  886. name = gf_malloc(sizeof(char)*len);
  887. sprintf(name, "%s%s;", entityStart+1, current);
  888. ent = gf_xml_locate_entity(parser, name, &needs_text);
  889. gf_free(name);
  890. if (!ent && !needs_text) {
  891. xml_sax_append_string(parser, current);
  892. xml_sax_parse(parser, 1);
  893. entityEnd[0] = ';';
  894. current = entityEnd;
  895. continue;
  896. }
  897. assert(ent);
  898. /*truncate input buffer*/
  899. parser->line_size -= (u32) strlen(entityStart);
  900. entityStart[0] = 0;
  901. parser->in_entity = 0;
  902. entityEnd[0] = ';';
  903. current = entityEnd+1;
  904. } else {
  905. if (!entityStart) break;
  906. ent = gf_xml_locate_entity(parser, entityStart+1, &needs_text);
  907. /*store current string before entity start*/
  908. entityStart[0] = 0;
  909. xml_sax_append_string(parser, current);
  910. xml_sax_parse(parser, 1);
  911. entityStart[0] = '&';
  912. /*this is not an entitiy*/
  913. if (!ent && !needs_text) {
  914. xml_sax_append_string(parser, "&");
  915. current = entityStart+1;
  916. continue;
  917. }
  918. if (!ent) {
  919. parser->in_entity = 1;
  920. /*store entity start*/
  921. return xml_sax_append_string(parser, entityStart);
  922. }
  923. current = entityStart + ent->namelen + 2;
  924. }
  925. /*append entity*/
  926. line_num = parser->line;
  927. xml_sax_append_string(parser, ent->value);
  928. xml_sax_parse(parser, 1);
  929. parser->line = line_num;
  930. }
  931. xml_sax_append_string(parser, current);
  932. return xml_sax_parse(parser, 0);
  933. }
  934. GF_EXPORT
  935. GF_Err gf_xml_sax_parse(GF_SAXParser *parser, const void *string)
  936. {
  937. GF_Err e;
  938. char *current;
  939. char *utf_conv = NULL;
  940. if (parser->unicode_type < 0) return GF_BAD_PARAM;
  941. if (parser->unicode_type>1) {
  942. const u16 *sptr = (const u16 *)string;
  943. u32 len = 2 * (u32) gf_utf8_wcslen(sptr);
  944. utf_conv = (char *)gf_malloc(sizeof(char)*(len+1));
  945. len = (u32) gf_utf8_wcstombs(utf_conv, len, &sptr);
  946. if (len==(u32) -1) {
  947. parser->sax_state = SAX_STATE_SYNTAX_ERROR;
  948. gf_free(utf_conv);
  949. return GF_CORRUPTED_DATA;
  950. }
  951. utf_conv[len] = 0;
  952. current = utf_conv;
  953. } else {
  954. current = (char *)string;
  955. }
  956. e = gf_xml_sax_parse_intern(parser, current);
  957. if (utf_conv) gf_free(utf_conv);
  958. return e;
  959. }
  960. GF_EXPORT
  961. GF_Err gf_xml_sax_init(GF_SAXParser *parser, unsigned char *BOM)
  962. {
  963. u32 offset;
  964. if (!BOM) {
  965. parser->unicode_type = 0;
  966. parser->sax_state = SAX_STATE_ELEMENT;
  967. return GF_OK;
  968. }
  969. if (parser->unicode_type >= 0) return gf_xml_sax_parse(parser, BOM);
  970. offset = 0;
  971. if ((BOM[0]==0xFF) && (BOM[1]==0xFE)) {
  972. if (!BOM[2] && !BOM[3]) return GF_NOT_SUPPORTED;
  973. parser->unicode_type = 2;
  974. offset = 2;
  975. } else if ((BOM[0]==0xFE) && (BOM[1]==0xFF)) {
  976. if (!BOM[2] && !BOM[3]) return GF_NOT_SUPPORTED;
  977. parser->unicode_type = 1;
  978. offset = 2;
  979. } else if ((BOM[0]==0xEF) && (BOM[1]==0xBB) && (BOM[2]==0xBF)) {
  980. /*we handle UTF8 as asci*/
  981. parser->unicode_type = 0;
  982. offset = 3;
  983. } else {
  984. parser->unicode_type = 0;
  985. offset = 0;
  986. }
  987. parser->sax_state = SAX_STATE_ELEMENT;
  988. return gf_xml_sax_parse(parser, BOM + offset);
  989. }
  990. static void xml_sax_reset(GF_SAXParser *parser)
  991. {
  992. while (1) {
  993. XML_Entity *ent = (XML_Entity *)gf_list_last(parser->entities);
  994. if (!ent) break;
  995. gf_list_rem_last(parser->entities);
  996. if (ent->name) gf_free(ent->name);
  997. if (ent->value) gf_free(ent->value);
  998. gf_free(ent);
  999. }
  1000. if (parser->buffer) gf_free(parser->buffer);
  1001. parser->buffer = NULL;
  1002. parser->current_pos = 0;
  1003. gf_free(parser->attrs);
  1004. parser->attrs = NULL;
  1005. gf_free(parser->sax_attrs);
  1006. parser->sax_attrs = NULL;
  1007. parser->nb_alloc_attrs = parser->nb_attrs = 0;
  1008. }
  1009. #define XML_INPUT_SIZE 4096
  1010. static GF_Err xml_sax_read_file(GF_SAXParser *parser)
  1011. {
  1012. GF_Err e = GF_EOS;
  1013. unsigned char szLine[XML_INPUT_SIZE+2];
  1014. #ifdef NO_GZIP
  1015. if (!parser->f_in) return GF_BAD_PARAM;
  1016. #else
  1017. if (!parser->gz_in) return GF_BAD_PARAM;
  1018. #endif
  1019. while (!parser->suspended) {
  1020. #ifdef NO_GZIP
  1021. s32 read = fread(szLine, 1, XML_INPUT_SIZE, parser->f_in);
  1022. #else
  1023. s32 read = gzread(parser->gz_in, szLine, XML_INPUT_SIZE);
  1024. #endif
  1025. if ((read<=0) /*&& !parser->node_depth*/) break;
  1026. szLine[read] = 0;
  1027. szLine[read+1] = 0;
  1028. e = gf_xml_sax_parse(parser, szLine);
  1029. if (e) break;
  1030. if (parser->file_pos > parser->file_size) parser->file_size = parser->file_pos + 1;
  1031. if (parser->on_progress) parser->on_progress(parser->sax_cbck, parser->file_pos, parser->file_size);
  1032. }
  1033. #ifdef NO_GZIP
  1034. if (feof(parser->f_in)) {
  1035. #else
  1036. if (gzeof(parser->gz_in)) {
  1037. #endif
  1038. if (!e) e = GF_EOS;
  1039. if (parser->on_progress) parser->on_progress(parser->sax_cbck, parser->file_size, parser->file_size);
  1040. #ifdef NO_GZIP
  1041. fclose(parser->f_in);
  1042. parser->f_in = NULL;
  1043. #else
  1044. gzclose(parser->gz_in);
  1045. parser->gz_in = 0;
  1046. #endif
  1047. parser->elt_start_pos = parser->elt_end_pos = 0;
  1048. parser->elt_name_start = parser->elt_name_end = 0;
  1049. parser->att_name_start = 0;
  1050. parser->current_pos = 0;
  1051. parser->line_size = 0;
  1052. parser->att_sep = 0;
  1053. parser->file_pos = 0;
  1054. parser->file_size = 0;
  1055. parser->line_size = 0;
  1056. }
  1057. return e;
  1058. }
  1059. GF_EXPORT
  1060. GF_Err gf_xml_sax_parse_file(GF_SAXParser *parser, const char *fileName, gf_xml_sax_progress OnProgress)
  1061. {
  1062. FILE *test;
  1063. GF_Err e;
  1064. #ifndef NO_GZIP
  1065. gzFile gzInput;
  1066. #endif
  1067. unsigned char szLine[6];
  1068. parser->on_progress = OnProgress;
  1069. if (!strncmp(fileName, "gmem://", 7)) {
  1070. u32 size;
  1071. u8 *xml_mem_address;
  1072. if (sscanf(fileName, "gmem://%d@%p", &size, &xml_mem_address) != 2) {
  1073. return GF_URL_ERROR;
  1074. }
  1075. parser->file_size = size;
  1076. memcpy(szLine, xml_mem_address, 3);
  1077. szLine[4] = szLine[5] = 0;
  1078. e = gf_xml_sax_init(parser, szLine);
  1079. if (e) return e;
  1080. parser->file_pos = 4;
  1081. parser->elt_start_pos = 0;
  1082. parser->current_pos = 0;
  1083. e = gf_xml_sax_parse(parser, xml_mem_address+3);
  1084. if (parser->on_progress) parser->on_progress(parser->sax_cbck, parser->file_pos, parser->file_size);
  1085. parser->elt_start_pos = parser->elt_end_pos = 0;
  1086. parser->elt_name_start = parser->elt_name_end = 0;
  1087. parser->att_name_start = 0;
  1088. parser->current_pos = 0;
  1089. parser->line_size = 0;
  1090. parser->att_sep = 0;
  1091. parser->file_pos = 0;
  1092. parser->file_size = 0;
  1093. parser->line_size = 0;
  1094. return e;
  1095. }
  1096. /*check file exists and gets its size (zlib doesn't support SEEK_END)*/
  1097. test = gf_f64_open(fileName, "rb");
  1098. if (!test) return GF_URL_ERROR;
  1099. gf_f64_seek(test, 0, SEEK_END);
  1100. assert(gf_f64_tell(test) < 1<<31);
  1101. parser->file_size = (u32) gf_f64_tell(test);
  1102. fclose(test);
  1103. #ifdef NO_GZIP
  1104. parser->f_in = gf_f64_open(fileName, "rt");
  1105. fread(szLine, 1, 4, parser->f_in);
  1106. #else
  1107. gzInput = gzopen(fileName, "rb");
  1108. if (!gzInput) return GF_IO_ERR;
  1109. parser->gz_in = gzInput;
  1110. /*init SAX parser (unicode setup)*/
  1111. gzread(gzInput, szLine, 4);
  1112. #endif
  1113. szLine[4] = szLine[5] = 0;
  1114. e = gf_xml_sax_init(parser, szLine);
  1115. if (e) return e;
  1116. parser->file_pos = 4;
  1117. /* souchay : not sure for next 2 lines, but it works better it seems */
  1118. parser->elt_start_pos = 0;
  1119. parser->current_pos = 0;
  1120. return xml_sax_read_file(parser);
  1121. }
  1122. GF_EXPORT
  1123. Bool gf_xml_sax_binary_file(GF_SAXParser *parser)
  1124. {
  1125. if (!parser) return 0;
  1126. #ifdef NO_GZIP
  1127. return 0;
  1128. #else
  1129. if (!parser->gz_in) return 0;
  1130. return (((z_stream*)parser->gz_in)->data_type==Z_BINARY) ? 1 : 0;
  1131. #endif
  1132. }
  1133. GF_EXPORT
  1134. GF_SAXParser *gf_xml_sax_new(gf_xml_sax_node_start on_node_start,
  1135. gf_xml_sax_node_end on_node_end,
  1136. gf_xml_sax_text_content on_text_content,
  1137. void *cbck)
  1138. {
  1139. GF_SAXParser *parser;
  1140. GF_SAFEALLOC(parser, GF_SAXParser);
  1141. parser->entities = gf_list_new();
  1142. parser->unicode_type = -1;
  1143. parser->sax_node_start = on_node_start;
  1144. parser->sax_node_end = on_node_end;
  1145. parser->sax_text_content = on_text_content;
  1146. parser->sax_cbck = cbck;
  1147. return parser;
  1148. }
  1149. GF_EXPORT
  1150. void gf_xml_sax_del(GF_SAXParser *parser)
  1151. {
  1152. xml_sax_reset(parser);
  1153. gf_list_del(parser->entities);
  1154. #ifdef NO_GZIP
  1155. if (parser->f_in) fclose(parser->f_in);
  1156. #else
  1157. if (parser->gz_in) gzclose(parser->gz_in);
  1158. #endif
  1159. gf_free(parser);
  1160. }
  1161. GF_EXPORT
  1162. GF_Err gf_xml_sax_suspend(GF_SAXParser *parser, Bool do_suspend)
  1163. {
  1164. parser->suspended = do_suspend;
  1165. if (!do_suspend) {
  1166. #ifdef NO_GZIP
  1167. if (parser->f_in) return xml_sax_read_file(parser);
  1168. #else
  1169. if (parser->gz_in) return xml_sax_read_file(parser);
  1170. #endif
  1171. return xml_sax_parse(parser, 0);
  1172. }
  1173. return GF_OK;
  1174. }
  1175. GF_EXPORT
  1176. u32 gf_xml_sax_get_line(GF_SAXParser *parser) { return parser->line + 1 ; }
  1177. GF_EXPORT
  1178. u32 gf_xml_sax_get_file_size(GF_SAXParser *parser)
  1179. {
  1180. #ifdef NO_GZIP
  1181. return parser->f_in ? parser->file_size : 0;
  1182. #else
  1183. return parser->gz_in ? parser->file_size : 0;
  1184. #endif
  1185. }
  1186. GF_EXPORT
  1187. u32 gf_xml_sax_get_file_pos(GF_SAXParser *parser)
  1188. {
  1189. #ifdef NO_GZIP
  1190. return parser->f_in ? parser->file_pos : 0;
  1191. #else
  1192. return parser->gz_in ? parser->file_pos : 0;
  1193. #endif
  1194. }
  1195. GF_EXPORT
  1196. char *gf_xml_sax_peek_node(GF_SAXParser *parser, char *att_name, char *att_value, char *substitute, char *get_attr, char *end_pattern, Bool *is_substitute)
  1197. {
  1198. u32 state, att_len, alloc_size;
  1199. #ifdef NO_GZIP
  1200. u64 pos;
  1201. #else
  1202. z_off_t pos;
  1203. #endif
  1204. Bool from_buffer;
  1205. Bool dobreak=0;
  1206. char szLine1[XML_INPUT_SIZE+2], szLine2[XML_INPUT_SIZE+2], *szLine, *cur_line, *sep, *start, first_c, *result;
  1207. #define CPYCAT_ALLOC(__str, __is_copy) if ( strlen(__str) + (__is_copy ? 0 : strlen(szLine))>=alloc_size) {\
  1208. alloc_size = 1 + (u32) strlen(__str); \
  1209. if (!__is_copy) alloc_size += (u32) strlen(szLine); \
  1210. szLine = gf_realloc(szLine, alloc_size); \
  1211. }\
  1212. if (__is_copy) strcpy(szLine, __str); \
  1213. else strcat(szLine, __str); \
  1214. from_buffer=0;
  1215. #ifdef NO_GZIP
  1216. if (!parser->f_in) from_buffer=1;
  1217. #else
  1218. if (!parser->gz_in) from_buffer=1;
  1219. #endif
  1220. result = NULL;
  1221. szLine1[0] = szLine2[0] = 0;
  1222. pos=0;
  1223. if (!from_buffer) {
  1224. #ifdef NO_GZIP
  1225. pos = gf_f64_tell(parser->f_in);
  1226. #else
  1227. pos = gztell(parser->gz_in);
  1228. #endif
  1229. }
  1230. att_len = (u32) strlen(parser->buffer + parser->att_name_start);
  1231. if (att_len<2*XML_INPUT_SIZE) att_len = 2*XML_INPUT_SIZE;
  1232. alloc_size = att_len;
  1233. szLine = (char *) gf_malloc(sizeof(char)*alloc_size);
  1234. strcpy(szLine, parser->buffer + parser->att_name_start);
  1235. parser->buffer[parser->elt_name_end - 1] = '"';
  1236. cur_line = szLine;
  1237. att_len = (u32) strlen(att_value);
  1238. state = 0;
  1239. goto retry;
  1240. while (1) {
  1241. u32 read;
  1242. u8 sep_char;
  1243. if (!from_buffer) {
  1244. #ifdef NO_GZIP
  1245. if (feof(parser->f_in)) break;
  1246. #else
  1247. if (gzeof(parser->gz_in)) break;
  1248. #endif
  1249. }
  1250. if (dobreak) break;
  1251. if (cur_line == szLine2) {
  1252. cur_line = szLine1;
  1253. } else {
  1254. cur_line = szLine2;
  1255. }
  1256. if (from_buffer) {
  1257. dobreak=1;
  1258. } else {
  1259. #ifdef NO_GZIP
  1260. read = fread(cur_line, 1, XML_INPUT_SIZE, parser->f_in);
  1261. #else
  1262. read = gzread(parser->gz_in, cur_line, XML_INPUT_SIZE);
  1263. #endif
  1264. cur_line[read] = cur_line[read+1] = 0;
  1265. CPYCAT_ALLOC(cur_line, 0);
  1266. }
  1267. if (end_pattern) {
  1268. start = strstr(szLine, end_pattern);
  1269. if (start) {
  1270. start[0] = 0;
  1271. dobreak = 1;
  1272. }
  1273. }
  1274. retry:
  1275. if (state == 2) goto fetch_attr;
  1276. sep = strstr(szLine, att_name);
  1277. if (!sep && !state) {
  1278. state = 0;
  1279. start = strrchr(szLine, '<');
  1280. if (start) {
  1281. CPYCAT_ALLOC(start, 1);
  1282. } else {
  1283. CPYCAT_ALLOC(cur_line, 1);
  1284. }
  1285. continue;
  1286. }
  1287. if (!state) {
  1288. state = 1;
  1289. /*load next line*/
  1290. first_c = sep[0];
  1291. sep[0] = 0;
  1292. start = strrchr(szLine, '<');
  1293. if (!start)
  1294. goto exit;
  1295. sep[0] = first_c;
  1296. CPYCAT_ALLOC(start, 1);
  1297. sep = strstr(szLine, att_name);
  1298. }
  1299. sep = strchr(sep, '=');
  1300. if (!sep) {
  1301. state = 0;
  1302. CPYCAT_ALLOC(cur_line, 1);
  1303. continue;
  1304. }
  1305. while (sep[0] && (sep[0] != '\"') && (sep[0] != '\'') ) sep++;
  1306. if (!sep[0]) continue;
  1307. sep_char = sep[0];
  1308. sep++;
  1309. while (sep[0] && strchr(" \n\r\t", sep[0]) ) sep++;
  1310. if (!sep[0]) continue;
  1311. if (!strchr(sep, sep_char))
  1312. continue;
  1313. /*found*/
  1314. if (!strncmp(sep, att_value, att_len)) {
  1315. u32 pos;
  1316. sep = szLine + 1;
  1317. while (strchr(" \t\r\n", sep[0])) sep++;
  1318. pos = 0;
  1319. while (!strchr(" \t\r\n", sep[pos])) pos++;
  1320. first_c = sep[pos];
  1321. sep[pos] = 0;
  1322. state = 2;
  1323. if (!substitute || !get_attr || strcmp(sep, substitute) ) {
  1324. if (is_substitute) *is_substitute = 0;
  1325. result = gf_strdup(sep);
  1326. goto exit;
  1327. }
  1328. sep[pos] = first_c;
  1329. fetch_attr:
  1330. sep = strstr(szLine + 1, get_attr);
  1331. if (!sep) {
  1332. CPYCAT_ALLOC(cur_line, 1);
  1333. continue;
  1334. }
  1335. sep += strlen(get_attr);
  1336. while (strchr("= \t\r\n", sep[0])) sep++;
  1337. sep++;
  1338. pos = 0;
  1339. while (!strchr(" \t\r\n/>", sep[pos])) pos++;
  1340. sep[pos-1] = 0;
  1341. result = gf_strdup(sep);
  1342. if (is_substitute) *is_substitute = 1;
  1343. goto exit;
  1344. }
  1345. state = 0;
  1346. CPYCAT_ALLOC(sep, 1);
  1347. goto retry;
  1348. }
  1349. exit:
  1350. gf_free(szLine);
  1351. if (!from_buffer) {
  1352. #ifdef NO_GZIP
  1353. gf_f64_seek(parser->f_in, pos, SEEK_SET);
  1354. #else
  1355. gzrewind(parser->gz_in);
  1356. gzseek(parser->gz_in, pos, SEEK_SET);
  1357. #endif
  1358. }
  1359. return result;
  1360. }
  1361. GF_EXPORT
  1362. const char *gf_xml_sax_get_error(GF_SAXParser *parser)
  1363. {
  1364. return parser->err_msg;
  1365. }
  1366. struct _peek_type
  1367. {
  1368. GF_SAXParser *parser;
  1369. char *res;
  1370. };
  1371. static void on_peek_node_start(void *cbk, const char *name, const char *ns, const GF_XMLAttribute *attributes, u32 nb_attributes)
  1372. {
  1373. struct _peek_type *pt = (struct _peek_type*)cbk;
  1374. pt->res = gf_strdup(name);
  1375. pt->parser->suspended = 1;
  1376. }
  1377. GF_EXPORT
  1378. char *gf_xml_get_root_type(const char *file, GF_Err *ret)
  1379. {
  1380. GF_Err e;
  1381. struct _peek_type pt;
  1382. pt.res = NULL;
  1383. pt.parser = gf_xml_sax_new(on_peek_node_start, NULL, NULL, &pt);
  1384. e = gf_xml_sax_parse_file(pt.parser, file, NULL);
  1385. if (ret) *ret = e;
  1386. gf_xml_sax_del(pt.parser);
  1387. return pt.res;
  1388. }
  1389. GF_EXPORT
  1390. u32 gf_xml_sax_get_node_start_pos(GF_SAXParser *parser)
  1391. {
  1392. return parser->elt_start_pos;
  1393. }
  1394. GF_EXPORT
  1395. u32 gf_xml_sax_get_node_end_pos(GF_SAXParser *parser)
  1396. {
  1397. return parser->elt_end_pos;
  1398. }
  1399. struct _tag_dom_parser
  1400. {
  1401. GF_SAXParser *parser;
  1402. GF_List *stack;
  1403. GF_XMLNode *root;
  1404. u32 depth;
  1405. void (*OnProgress)(void *cbck, u64 done, u64 tot);
  1406. void *cbk;
  1407. };
  1408. GF_EXPORT
  1409. void gf_xml_dom_node_del(GF_XMLNode *node)
  1410. {
  1411. if (!node) return;
  1412. if (node->attributes) {
  1413. while (gf_list_count(node->attributes)) {
  1414. GF_XMLAttribute *att = (GF_XMLAttribute *)gf_list_last(node->attributes);
  1415. gf_list_rem_last(node->attributes);
  1416. if (att->name) gf_free(att->name);
  1417. if (att->value) gf_free(att->value);
  1418. gf_free(att);
  1419. }
  1420. gf_list_del(node->attributes);
  1421. }
  1422. if (node->content) {
  1423. while (gf_list_count(node->content)) {
  1424. GF_XMLNode *child = (GF_XMLNode *)gf_list_last(node->content);
  1425. gf_list_rem_last(node->content);
  1426. gf_xml_dom_node_del(child);
  1427. }
  1428. gf_list_del(node->content);
  1429. }
  1430. if (node->ns) gf_free(node->ns);
  1431. if (node->name) gf_free(node->name);
  1432. gf_free(node);
  1433. }
  1434. static void on_dom_node_start(void *cbk, const char *name, const char *ns, const GF_XMLAttribute *attributes, u32 nb_attributes)
  1435. {
  1436. u32 i;
  1437. GF_DOMParser *par = (GF_DOMParser *) cbk;
  1438. GF_XMLNode *node;
  1439. if (par->root && !gf_list_count(par->stack)) {
  1440. par->parser->suspended = 1;
  1441. return;
  1442. }
  1443. GF_SAFEALLOC(node, GF_XMLNode);
  1444. node->attributes = gf_list_new();
  1445. for (i=0; i<nb_attributes; i++) {
  1446. GF_XMLAttribute *att;
  1447. GF_SAFEALLOC(att, GF_XMLAttribute);
  1448. att->name = gf_strdup(attributes[i].name);
  1449. att->value = gf_strdup(attributes[i].value);
  1450. gf_list_add(node->attributes, att);
  1451. }
  1452. node->content = gf_list_new();
  1453. node->name = gf_strdup(name);
  1454. if (ns) node->ns = gf_strdup(ns);
  1455. gf_list_add(par->stack, node);
  1456. if (!par->root) par->root = node;
  1457. }
  1458. static void on_dom_node_end(void *cbk, const char *name, const char *ns)
  1459. {
  1460. GF_DOMParser *par = (GF_DOMParser *)cbk;
  1461. GF_XMLNode *last = (GF_XMLNode *)gf_list_last(par->stack);
  1462. gf_list_rem_last(par->stack);
  1463. if (!last || strcmp(last->name, name) || (!ns && last->ns) || (ns && !last->ns) || (ns && strcmp(last->ns, ns) ) ) {
  1464. format_sax_error(par->parser, 0, "Invalid node stack: closing node is %s but %s was expected", name, last->name);
  1465. par->parser->suspended = 1;
  1466. gf_xml_dom_node_del(last);
  1467. if (last==par->root) par->root=NULL;
  1468. return;
  1469. }
  1470. if (last != par->root) {
  1471. GF_XMLNode *node = (GF_XMLNode *)gf_list_last(par->stack);
  1472. assert(node->content);
  1473. assert(gf_list_find(node->content, last) == -1);
  1474. gf_list_add(node->content, last);
  1475. }
  1476. }
  1477. static void on_dom_text_content(void *cbk, const char *content, Bool is_cdata)
  1478. {
  1479. GF_DOMParser *par = (GF_DOMParser *)cbk;
  1480. GF_XMLNode *node;
  1481. GF_XMLNode *last = (GF_XMLNode *)gf_list_last(par->stack);
  1482. if (!last) return;
  1483. assert(last->content);
  1484. GF_SAFEALLOC(node, GF_XMLNode);
  1485. node->type = is_cdata ? GF_XML_CDATA_TYPE : GF_XML_TEXT_TYPE;
  1486. node->name = gf_strdup(content);
  1487. gf_list_add(last->content, node);
  1488. }
  1489. GF_EXPORT
  1490. GF_DOMParser *gf_xml_dom_new()
  1491. {
  1492. GF_DOMParser *dom;
  1493. GF_SAFEALLOC(dom, GF_DOMParser);
  1494. return dom;
  1495. }
  1496. static void gf_xml_dom_reset(GF_DOMParser *dom, Bool full_reset)
  1497. {
  1498. if (full_reset && dom->parser) {
  1499. gf_xml_sax_del(dom->parser);
  1500. dom->parser = NULL;
  1501. }
  1502. if (dom->stack) {
  1503. while (gf_list_count(dom->stack)) {
  1504. GF_XMLNode *n = (GF_XMLNode *)gf_list_last(dom->stack);
  1505. gf_list_rem_last(dom->stack);
  1506. if (dom->root==n) dom->root = NULL;
  1507. gf_xml_dom_node_del(n);
  1508. }
  1509. gf_list_del(dom->stack);
  1510. dom->stack = NULL;
  1511. }
  1512. if (full_reset && dom->root) {
  1513. gf_xml_dom_node_del(dom->root);
  1514. dom->root = NULL;
  1515. }
  1516. }
  1517. GF_EXPORT
  1518. void gf_xml_dom_del(GF_DOMParser *parser)
  1519. {
  1520. gf_xml_dom_reset(parser, 1);
  1521. gf_free(parser);
  1522. }
  1523. GF_EXPORT
  1524. GF_XMLNode *gf_xml_dom_detach_root(GF_DOMParser *parser)
  1525. {
  1526. GF_XMLNode *root = parser->root;
  1527. parser->root = NULL;
  1528. return root;
  1529. }
  1530. static void dom_on_progress(void *cbck, u64 done, u64 tot)
  1531. {
  1532. GF_DOMParser *dom = (GF_DOMParser *)cbck;
  1533. dom->OnProgress(dom->cbk, done, tot);
  1534. }
  1535. GF_EXPORT
  1536. GF_Err gf_xml_dom_parse(GF_DOMParser *dom, const char *file, gf_xml_sax_progress OnProgress, void *cbk)
  1537. {
  1538. GF_Err e;
  1539. gf_xml_dom_reset(dom, 1);
  1540. dom->stack = gf_list_new();
  1541. dom->parser = gf_xml_sax_new(on_dom_node_start, on_dom_node_end, on_dom_text_content, dom);
  1542. dom->OnProgress = OnProgress;
  1543. dom->cbk = cbk;
  1544. e = gf_xml_sax_parse_file(dom->parser, file, OnProgress ? dom_on_progress : NULL);
  1545. gf_xml_dom_reset(dom, 0);
  1546. return e<0 ? e : GF_OK;
  1547. }
  1548. GF_EXPORT
  1549. GF_Err gf_xml_dom_parse_string(GF_DOMParser *dom, char *string)
  1550. {
  1551. GF_Err e;
  1552. gf_xml_dom_reset(dom, 1);
  1553. dom->stack = gf_list_new();
  1554. dom->parser = gf_xml_sax_new(on_dom_node_start, on_dom_node_end, on_dom_text_content, dom);
  1555. e = gf_xml_sax_init(dom->parser, (unsigned char *) string);
  1556. gf_xml_dom_reset(dom, 0);
  1557. return e<0 ? e : GF_OK;
  1558. }
  1559. GF_EXPORT
  1560. GF_XMLNode *gf_xml_dom_create_root(GF_DOMParser *parser, const char* name){
  1561. GF_XMLNode * root;
  1562. if (!parser) return NULL;
  1563. GF_SAFEALLOC(root, GF_XMLNode);
  1564. if (!root) return NULL;
  1565. root->name = gf_strdup(name);
  1566. return root;
  1567. }
  1568. GF_EXPORT
  1569. GF_XMLNode *gf_xml_dom_get_root(GF_DOMParser *parser)
  1570. {
  1571. return parser? parser->root : NULL;
  1572. }
  1573. GF_EXPORT
  1574. const char *gf_xml_dom_get_error(GF_DOMParser *parser)
  1575. {
  1576. return gf_xml_sax_get_error(parser->parser);
  1577. }
  1578. GF_EXPORT
  1579. u32 gf_xml_dom_get_line(GF_DOMParser *parser)
  1580. {
  1581. return gf_xml_sax_get_line(parser->parser);
  1582. }
  1583. static void gf_xml_dom_node_serialize(GF_XMLNode *node, Bool content_only, char **str, u32 *alloc_size, u32 *size)
  1584. {
  1585. u32 i, count, vlen;
  1586. char *name;
  1587. #define SET_STRING(v) \
  1588. vlen = (u32) strlen(v); \
  1589. if (vlen+ (*size) >= (*alloc_size)) { \
  1590. (*alloc_size) += 1024; \
  1591. (*str) = gf_realloc((*str), (*alloc_size)); \
  1592. (*str)[(*size)] = 0; \
  1593. } \
  1594. strcat((*str), v); \
  1595. *size += vlen; \
  1596. switch (node->type) {
  1597. case GF_XML_CDATA_TYPE:
  1598. SET_STRING("![CDATA[");
  1599. SET_STRING(node->name);
  1600. SET_STRING("]]>");
  1601. return;
  1602. case GF_XML_TEXT_TYPE:
  1603. name = node->name;
  1604. if ((name[0]=='\r') && (name[1]=='\n'))
  1605. name++;
  1606. SET_STRING(name);
  1607. return;
  1608. }
  1609. if (!content_only) {
  1610. SET_STRING("<");
  1611. if (node->ns) {
  1612. SET_STRING(node->ns);
  1613. SET_STRING(":");
  1614. }
  1615. SET_STRING(node->name);
  1616. SET_STRING(" ");
  1617. count = gf_list_count(node->attributes);
  1618. for (i=0; i<count; i++) {
  1619. GF_XMLAttribute *att = gf_list_get(node->attributes, i);
  1620. SET_STRING(att->name);
  1621. SET_STRING("=\"");
  1622. SET_STRING(att->value);
  1623. SET_STRING("\" ");
  1624. }
  1625. if (!gf_list_count(node->content)) {
  1626. SET_STRING("/>");
  1627. return;
  1628. }
  1629. SET_STRING(">");
  1630. }
  1631. count = gf_list_count(node->content);
  1632. for (i=0; i<count; i++) {
  1633. GF_XMLNode *child = gf_list_get(node->content, i);
  1634. gf_xml_dom_node_serialize(child, 0, str, alloc_size, size);
  1635. }
  1636. if (!content_only) {
  1637. SET_STRING("</");
  1638. if (node->ns) {
  1639. SET_STRING(node->ns);
  1640. SET_STRING(":");
  1641. }
  1642. SET_STRING(node->name);
  1643. SET_STRING(">");
  1644. }
  1645. }
  1646. GF_EXPORT
  1647. char *gf_xml_dom_serialize(GF_XMLNode *node, Bool content_only)
  1648. {
  1649. u32 alloc_size = 0;
  1650. u32 size = 0;
  1651. char *str = NULL;
  1652. gf_xml_dom_node_serialize(node, content_only, &str, &alloc_size, &size);
  1653. return str;
  1654. }
  1655. GF_EXPORT
  1656. GF_XMLAttribute *gf_xml_dom_set_attribute(GF_XMLNode *node, const char* name, const char* value){
  1657. GF_XMLAttribute *att;
  1658. if (!name || !value) return NULL;
  1659. if (!node->attributes) {
  1660. node->attributes = gf_list_new();
  1661. if (!node->attributes) return NULL;
  1662. }
  1663. GF_SAFEALLOC(att, GF_XMLAttribute);
  1664. if (!att) return NULL;
  1665. att->name = gf_strdup(name);
  1666. att->value = gf_strdup(value);
  1667. gf_list_add(node->attributes, att);
  1668. return att;
  1669. }
  1670. GF_EXPORT
  1671. GF_XMLAttribute *gf_xml_dom_get_attribute(GF_XMLNode *node, const char* name){
  1672. u32 i = 0;
  1673. GF_XMLAttribute *att;
  1674. if (!node | !name) return NULL;
  1675. while ( (att = (GF_XMLAttribute*)gf_list_enum(node->attributes, &i))) {
  1676. if (!strcmp(att->name, name)){
  1677. return att;
  1678. }
  1679. }
  1680. return NULL;
  1681. }
  1682. GF_EXPORT
  1683. GF_Err gf_xml_dom_append_child(GF_XMLNode *node, GF_XMLNode *child){
  1684. if (!node | !child) return GF_BAD_PARAM;
  1685. if (!node->content){
  1686. node->content = gf_list_new();
  1687. if (!node->content) return GF_OUT_OF_MEM;
  1688. }
  1689. return gf_list_add(node->content, child);
  1690. }
  1691. GF_EXPORT
  1692. GF_XMLNode* gf_xml_dom_node_new(const char* ns, const char* name){
  1693. GF_XMLNode* node;
  1694. GF_SAFEALLOC(node, GF_XMLNode);
  1695. if (!node) return NULL;
  1696. if (ns){
  1697. node->ns = gf_strdup(ns);
  1698. if (!node->ns){
  1699. gf_free(node);
  1700. return NULL;
  1701. }
  1702. }
  1703. if (name){
  1704. node->name = gf_strdup(name);
  1705. if (!node->name){
  1706. gf_free(node->ns);
  1707. gf_free(node);
  1708. return NULL;
  1709. }
  1710. }
  1711. return node;
  1712. }
  1713. #include "../../include/gpac/bitstream.h"
  1714. #include "../../include/gpac/base_coding.h"
  1715. #define XML_SCAN_INT(_fmt, _value) \
  1716. {\
  1717. if (strstr(att->value, "0x")) { u32 __i; sscanf(att->value+2, "%x", &__i); _value = __i; }\
  1718. else if (strstr(att->value, "0X")) { u32 __i; sscanf(att->value+2, "%X", &__i); _value = __i; }\
  1719. else sscanf(att->value, _fmt, &_value); \
  1720. }\
  1721. GF_EXPORT
  1722. GF_Err gf_xml_parse_bit_sequence(GF_XMLNode *bsroot, char **specInfo, u32 *specInfoSize)
  1723. {
  1724. u32 i, j;
  1725. GF_XMLNode *node;
  1726. GF_XMLAttribute *att;
  1727. GF_BitStream *bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
  1728. if (!bs) return GF_OUT_OF_MEM;
  1729. i=0;
  1730. while ((node = (GF_XMLNode *) gf_list_enum(bsroot->content, &i))) {
  1731. u32 nb_bits = 0;
  1732. u32 size = 0;
  1733. u64 offset = 0;
  1734. s64 value = 0;
  1735. bin128 word128;
  1736. Bool use_word128 = GF_FALSE;
  1737. const char *szFile = NULL;
  1738. const char *szString = NULL;
  1739. const char *szBase64 = NULL;
  1740. const char *szData = NULL;
  1741. if (node->type) continue;
  1742. if (stricmp(node->name, "BS") ) continue;
  1743. j=0;
  1744. while ( (att = (GF_XMLAttribute *)gf_list_enum(node->attributes, &j))) {
  1745. if (!stricmp(att->name, "bits")) {
  1746. XML_SCAN_INT("%d", nb_bits);
  1747. } else if (!stricmp(att->name, "value")) {
  1748. XML_SCAN_INT(LLD, value);
  1749. } else if (!stricmp(att->name, "mediaOffset") || !stricmp(att->name, "dataOffset")) {
  1750. XML_SCAN_INT(LLU, offset);
  1751. } else if (!stricmp(att->name, "dataLength")) {
  1752. XML_SCAN_INT("%u", size);
  1753. } else if (!stricmp(att->name, "mediaFile") || !stricmp(att->name, "dataFile")) {
  1754. szFile = att->value;
  1755. } else if (!stricmp(att->name, "text") || !stricmp(att->name, "string")) {
  1756. szString = att->value;
  1757. } else if (!stricmp(att->name, "fcc")) {
  1758. value = GF_4CC(att->value[0], att->value[1], att->value[2], att->value[3]);
  1759. nb_bits = 32;

Large files files are truncated, but you can click here to view the full file