home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / modules / xml / expat / xmltok / xmltok.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  18.4 KB  |  760 lines

  1. /*
  2. The contents of this file are subject to the Mozilla Public License
  3. Version 1.0 (the "License"); you may not use this file except in
  4. compliance with the License. You may obtain a copy of the License at
  5. http://www.mozilla.org/MPL/
  6.  
  7. Software distributed under the License is distributed on an "AS IS"
  8. basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
  9. License for the specific language governing rights and limitations
  10. under the License.
  11.  
  12. The Original Code is expat.
  13.  
  14. The Initial Developer of the Original Code is James Clark.
  15. Portions created by James Clark are Copyright (C) 1998
  16. James Clark. All Rights Reserved.
  17.  
  18. Contributor(s):
  19. */
  20.  
  21. #include "xmldef.h"
  22. #include "xmltok.h"
  23. #include "nametab.h"
  24.  
  25. #define VTABLE1 \
  26.   { PREFIX(prologTok), PREFIX(contentTok) }, \
  27.   { PREFIX(attributeValueTok), PREFIX(entityValueTok) }, \
  28.   PREFIX(sameName), \
  29.   PREFIX(nameMatchesAscii), \
  30.   PREFIX(nameLength), \
  31.   PREFIX(skipS), \
  32.   PREFIX(getAtts), \
  33.   PREFIX(charRefNumber), \
  34.   PREFIX(updatePosition), \
  35.   PREFIX(isPublicId)
  36.  
  37. #define VTABLE2 \
  38.   PREFIX(encode), \
  39.   { PREFIX(toUtf8) }
  40.  
  41. #define VTABLE VTABLE1, VTABLE2
  42.  
  43. #define UCS2_GET_NAMING(pages, hi, lo) \
  44.    (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1 << ((lo) & 0x1F)))
  45.  
  46. /* A 2 byte UTF-8 representation splits the characters 11 bits
  47. between the bottom 5 and 6 bits of the bytes.
  48. We need 8 bits to index into pages, 3 bits to add to that index and
  49. 5 bits to generate the mask. */
  50. #define UTF8_GET_NAMING2(pages, byte) \
  51.     (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \
  52.                       + ((((byte)[0]) & 3) << 1) \
  53.                       + ((((byte)[1]) >> 5) & 1)] \
  54.          & (1 << (((byte)[1]) & 0x1F)))
  55.  
  56. /* A 3 byte UTF-8 representation splits the characters 16 bits
  57. between the bottom 4, 6 and 6 bits of the bytes.
  58. We need 8 bits to index into pages, 3 bits to add to that index and
  59. 5 bits to generate the mask. */
  60. #define UTF8_GET_NAMING3(pages, byte) \
  61.   (namingBitmap[((pages)[((((byte)[0]) & 0xF) << 4) \
  62.                              + ((((byte)[1]) >> 2) & 0xF)] \
  63.                << 3) \
  64.                       + ((((byte)[1]) & 3) << 1) \
  65.                       + ((((byte)[2]) >> 5) & 1)] \
  66.          & (1 << (((byte)[2]) & 0x1F)))
  67.  
  68. #define UTF8_GET_NAMING(pages, p, n) \
  69.   ((n) == 2 \
  70.   ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \
  71.   : ((n) == 3 \
  72.      ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) \
  73.      : 0))
  74.  
  75. #define UTF8_INVALID3(p) \
  76.   ((*p) == 0xED \
  77.   ? (((p)[1] & 0x20) != 0) \
  78.   : ((*p) == 0xEF \
  79.      ? ((p)[1] == 0xBF && ((p)[2] == 0xBF || (p)[2] == 0xBE)) \
  80.      : 0))
  81.  
  82. #define UTF8_INVALID4(p) ((*p) == 0xF4 && ((p)[1] & 0x30) != 0)
  83.  
  84. struct normal_encoding {
  85.   ENCODING enc;
  86.   unsigned char type[256];
  87. };
  88.  
  89. static int checkCharRefNumber(int);
  90.  
  91. #include "xmltok_impl.h"
  92.  
  93. /* minimum bytes per character */
  94. #define MINBPC 1
  95. #define BYTE_TYPE(enc, p) \
  96.   (((struct normal_encoding *)(enc))->type[(unsigned char)*(p)])
  97. #define BYTE_TO_ASCII(enc, p) (*p)
  98. #define IS_NAME_CHAR(enc, p, n) UTF8_GET_NAMING(namePages, p, n)
  99. #define IS_NMSTRT_CHAR(enc, p, n) UTF8_GET_NAMING(nmstrtPages, p, n)
  100. #define IS_INVALID_CHAR(enc, p, n) \
  101. ((n) == 3 \
  102.   ? UTF8_INVALID3((const unsigned char *)(p)) \
  103.   : ((n) == 4 ? UTF8_INVALID4((const unsigned char *)(p)) : 0))
  104.  
  105. /* c is an ASCII character */
  106. #define CHAR_MATCHES(enc, p, c) (*(p) == c)
  107.  
  108. #define PREFIX(ident) normal_ ## ident
  109. #include "xmltok_impl.c"
  110.  
  111. #undef MINBPC
  112. #undef BYTE_TYPE
  113. #undef BYTE_TO_ASCII
  114. #undef CHAR_MATCHES
  115. #undef IS_NAME_CHAR
  116. #undef IS_NMSTRT_CHAR
  117. #undef IS_INVALID_CHAR
  118.  
  119. enum {
  120.   /* cvalN is value of masked first byte of N byte sequence */
  121.   cval1 = 0x00,
  122.   cval2 = 0xc0,
  123.   cval3 = 0xe0,
  124.   cval4 = 0xf0,
  125.   /* minN is minimum legal resulting value for N byte sequence */
  126.   min2 = 0x80,
  127.   min3 = 0x800,
  128.   min4 = 0x10000
  129. };
  130.  
  131. static
  132. int utf8_encode(const ENCODING *enc, int c, char *buf)
  133. {
  134.   if (c < 0)
  135.     return 0;
  136.   if (c < min2) {
  137.     buf[0] = (c | cval1);
  138.     return 1;
  139.   }
  140.   if (c < min3) {
  141.     buf[0] = ((c >> 6) | cval2);
  142.     buf[1] = ((c & 0x3f) | 0x80);
  143.     return 2;
  144.   }
  145.   if (c < min4) {
  146.     buf[0] = ((c >> 12) | cval3);
  147.     buf[1] = (((c >> 6) & 0x3f) | 0x80);
  148.     buf[2] = ((c & 0x3f) | 0x80);
  149.     return 3;
  150.   }
  151.   if (c < 0x110000) {
  152.     buf[0] = ((c >> 18) | cval4);
  153.     buf[1] = (((c >> 12) & 0x3f) | 0x80);
  154.     buf[2] = (((c >> 6) & 0x3f) | 0x80);
  155.     buf[3] = ((c & 0x3f) | 0x80);
  156.     return 4;
  157.   }
  158.   return 0;
  159. }
  160.  
  161. static
  162. void utf8_toUtf8(const ENCODING *enc,
  163.          const char **fromP, const char *fromLim,
  164.          char **toP, const char *toLim)
  165. {
  166.   char *to;
  167.   const char *from;
  168.   if (fromLim - *fromP > toLim - *toP) {
  169.     /* Avoid copying partial characters. */
  170.     for (fromLim = *fromP + (toLim - *toP); fromLim > *fromP; fromLim--)
  171.       if (((unsigned char)fromLim[-1] & 0xc0) != 0x80)
  172.     break;
  173.   }
  174.   for (to = *toP, from = *fromP; from != fromLim; from++, to++)
  175.     *to = *from;
  176.   *fromP = from;
  177.   *toP = to;
  178. }
  179.  
  180. static const struct normal_encoding utf8_encoding = {
  181.   { VTABLE1, utf8_encode, { utf8_toUtf8 }, 1 },
  182.   {
  183. #include "asciitab.h"
  184. #include "utf8tab.h"
  185.   }
  186. };
  187.  
  188. static const struct normal_encoding internal_utf8_encoding = {
  189.   { VTABLE1, utf8_encode, { utf8_toUtf8 }, 1 },
  190.   {
  191. #include "iasciitab.h"
  192. #include "utf8tab.h"
  193.   }
  194. };
  195.  
  196. static
  197. int latin1_encode(const ENCODING *enc, int c, char *buf)
  198. {
  199.   if (c < 0)
  200.     return 0;
  201.   if (c <= 0xFF) {
  202.     buf[0] = (char)c;
  203.     return 1;
  204.   }
  205.   return 0;
  206. }
  207.  
  208. static
  209. void latin1_toUtf8(const ENCODING *enc,
  210.            const char **fromP, const char *fromLim,
  211.            char **toP, const char *toLim)
  212. {
  213.   for (;;) {
  214.     unsigned char c;
  215.     if (*fromP == fromLim)
  216.       break;
  217.     c = (unsigned char)**fromP;
  218.     if (c & 0x80) {
  219.       if (toLim - *toP < 2)
  220.     break;
  221.       *(*toP)++ = ((c >> 6) | cval2);
  222.       *(*toP)++ = ((c & 0x3f) | 0x80);
  223.       (*fromP)++;
  224.     }
  225.     else {
  226.       if (*toP == toLim)
  227.     break;
  228.       *(*toP)++ = *(*fromP)++;
  229.     }
  230.   }
  231. }
  232.  
  233. static const struct normal_encoding latin1_encoding = {
  234.   { VTABLE1, latin1_encode, { latin1_toUtf8 }, 1 },
  235.   {
  236. #include "asciitab.h"
  237. #include "latin1tab.h"
  238.   }
  239. };
  240.  
  241. #define latin1tab (latin1_encoding.type)
  242.  
  243. #undef PREFIX
  244.  
  245. static int unicode_byte_type(char hi, char lo)
  246. {
  247.   switch ((unsigned char)hi) {
  248.   case 0xD8: case 0xD9: case 0xDA: case 0xDB:
  249.     return BT_LEAD4;
  250.   case 0xDC: case 0xDD: case 0xDE: case 0xDF:
  251.     return BT_TRAIL;
  252.   case 0xFF:
  253.     switch ((unsigned char)lo) {
  254.     case 0xFF:
  255.     case 0xFE:
  256.       return BT_NONXML;
  257.     }
  258.     break;
  259.   }
  260.   return BT_NONASCII;
  261. }
  262.  
  263. #define DEFINE_UTF16_ENCODE \
  264. static \
  265. int PREFIX(encode)(const ENCODING *enc, int charNum, char *buf) \
  266. { \
  267.   if (charNum < 0) \
  268.     return 0; \
  269.   if (charNum < 0x10000) { \
  270.     SET2(buf, charNum); \
  271.     return 2; \
  272.   } \
  273.   if (charNum < 0x110000) { \
  274.     charNum -= 0x10000; \
  275.     SET2(buf, (charNum >> 10) + 0xD800); \
  276.     SET2(buf + 2, (charNum & 0x3FF) + 0xDC00); \
  277.     return 4; \
  278.   } \
  279.   return 0; \
  280. }
  281.  
  282. #define DEFINE_UTF16_TO_UTF8 \
  283. static \
  284. void PREFIX(toUtf8)(const ENCODING *enc, \
  285.             const char **fromP, const char *fromLim, \
  286.             char **toP, const char *toLim) \
  287. { \
  288.   const char *from; \
  289.   for (from = *fromP; from != fromLim; from += 2) { \
  290.     int plane; \
  291.     unsigned char lo2; \
  292.     unsigned char lo = GET_LO(from); \
  293.     unsigned char hi = GET_HI(from); \
  294.     switch (hi) { \
  295.     case 0: \
  296.       if (lo < 0x80) { \
  297.         if (*toP == toLim) { \
  298.           *fromP = from; \
  299.       return; \
  300.         } \
  301.         *(*toP)++ = lo; \
  302.         break; \
  303.       } \
  304.       /* fall through */ \
  305.     case 0x1: case 0x2: case 0x3: \
  306.     case 0x4: case 0x5: case 0x6: case 0x7: \
  307.       if (toLim -  *toP < 2) { \
  308.         *fromP = from; \
  309.     return; \
  310.       } \
  311.       *(*toP)++ = ((lo >> 6) | (hi << 2) |  cval2); \
  312.       *(*toP)++ = ((lo & 0x3f) | 0x80); \
  313.       break; \
  314.     default: \
  315.       if (toLim -  *toP < 3)  { \
  316.         *fromP = from; \
  317.     return; \
  318.       } \
  319.       /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \
  320.       *(*toP)++ = ((hi >> 4) | cval3); \
  321.       *(*toP)++ = (((hi & 0xf) << 2) | (lo >> 6) | 0x80); \
  322.       *(*toP)++ = ((lo & 0x3f) | 0x80); \
  323.       break; \
  324.     case 0xD8: case 0xD9: case 0xDA: case 0xDB: \
  325.       if (toLim -  *toP < 4) { \
  326.     *fromP = from; \
  327.     return; \
  328.       } \
  329.       plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \
  330.       *(*toP)++ = ((plane >> 2) | cval4); \
  331.       *(*toP)++ = (((lo >> 2) & 0xF) | ((plane & 0x3) << 4) | 0x80); \
  332.       from += 2; \
  333.       lo2 = GET_LO(from); \
  334.       *(*toP)++ = (((lo & 0x3) << 4) \
  335.                | ((GET_HI(from) & 0x3) << 2) \
  336.            | (lo2 >> 6) \
  337.            | 0x80); \
  338.       *(*toP)++ = ((lo2 & 0x3f) | 0x80); \
  339.       break; \
  340.     } \
  341.   } \
  342.   *fromP = from; \
  343. }
  344.  
  345. #define PREFIX(ident) little2_ ## ident
  346. #define MINBPC 2
  347. #define BYTE_TYPE(enc, p) \
  348.  ((p)[1] == 0 ? latin1tab[(unsigned char)*(p)] : unicode_byte_type((p)[1], (p)[0]))
  349. #define BYTE_TO_ASCII(enc, p) ((p)[1] == 0 ? (p)[0] : -1)
  350. #define CHAR_MATCHES(enc, p, c) ((p)[1] == 0 && (p)[0] == c)
  351. #define IS_NAME_CHAR(enc, p, n) \
  352.   UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0])
  353. #define IS_NMSTRT_CHAR(enc, p, n) \
  354.   UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[1], (unsigned char)p[0])
  355.  
  356. #include "xmltok_impl.c"
  357.  
  358. #define SET2(ptr, ch) \
  359.   (((ptr)[0] = ((ch) & 0xff)), ((ptr)[1] = ((ch) >> 8)))
  360. #define GET_LO(ptr) ((unsigned char)(ptr)[0])
  361. #define GET_HI(ptr) ((unsigned char)(ptr)[1])
  362.  
  363. DEFINE_UTF16_ENCODE
  364. DEFINE_UTF16_TO_UTF8
  365.  
  366. #undef SET2
  367. #undef GET_LO
  368. #undef GET_HI
  369. #undef MINBPC
  370. #undef BYTE_TYPE
  371. #undef BYTE_TO_ASCII
  372. #undef CHAR_MATCHES
  373. #undef IS_NAME_CHAR
  374. #undef IS_NMSTRT_CHAR
  375. #undef IS_INVALID_CHAR
  376.  
  377. static const struct encoding little2_encoding = { VTABLE, 2 };
  378.  
  379. #undef PREFIX
  380.  
  381. #define PREFIX(ident) big2_ ## ident
  382. #define MINBPC 2
  383. /* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */
  384. #define BYTE_TYPE(enc, p) \
  385.  ((p)[0] == 0 ? latin1tab[(unsigned char)(p)[1]] : unicode_byte_type((p)[0], (p)[1]))
  386. #define BYTE_TO_ASCII(enc, p) ((p)[0] == 0 ? (p)[1] : -1)
  387. #define CHAR_MATCHES(enc, p, c) ((p)[0] == 0 && (p)[1] == c)
  388. #define IS_NAME_CHAR(enc, p, n) \
  389.   UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1])
  390. #define IS_NMSTRT_CHAR(enc, p, n) \
  391.   UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[0], (unsigned char)p[1])
  392.  
  393. #include "xmltok_impl.c"
  394.  
  395. #define SET2(ptr, ch) \
  396.   (((ptr)[0] = ((ch) >> 8)), ((ptr)[1] = ((ch) & 0xFF)))
  397. #define GET_LO(ptr) ((unsigned char)(ptr)[1])
  398. #define GET_HI(ptr) ((unsigned char)(ptr)[0])
  399.  
  400. DEFINE_UTF16_ENCODE
  401. DEFINE_UTF16_TO_UTF8
  402.  
  403. #undef SET2
  404. #undef GET_LO
  405. #undef GET_HI
  406. #undef MINBPC
  407. #undef BYTE_TYPE
  408. #undef BYTE_TO_ASCII
  409. #undef CHAR_MATCHES
  410. #undef IS_NAME_CHAR
  411. #undef IS_NMSTRT_CHAR
  412. #undef IS_INVALID_CHAR
  413.  
  414. static const struct encoding big2_encoding = { VTABLE, 2 };
  415.  
  416. #undef PREFIX
  417.  
  418. static
  419. int streqci(const char *s1, const char *s2)
  420. {
  421.   for (;;) {
  422.     char c1 = *s1++;
  423.     char c2 = *s2++;
  424.     if ('a' <= c1 && c1 <= 'z')
  425.       c1 += 'A' - 'a';
  426.     if ('a' <= c2 && c2 <= 'z')
  427.       c2 += 'A' - 'a';
  428.     if (c1 != c2)
  429.       return 0;
  430.     if (!c1)
  431.       break;
  432.   }
  433.   return 1;
  434. }
  435.  
  436. static
  437. int initScan(const ENCODING *enc, int state, const char *ptr, const char *end,
  438.          const char **nextTokPtr)
  439. {
  440.   const ENCODING **encPtr;
  441.  
  442.   if (ptr == end)
  443.     return XML_TOK_NONE;
  444.   encPtr = ((const INIT_ENCODING *)enc)->encPtr;
  445.   if (ptr + 1 == end) {
  446.     switch ((unsigned char)*ptr) {
  447.     case 0xFE:
  448.     case 0xFF:
  449.     case 0x00:
  450.     case 0x3C:
  451.       return XML_TOK_PARTIAL;
  452.     }
  453.   }
  454.   else {
  455.     switch (((unsigned char)ptr[0] << 8) | (unsigned char)ptr[1]) {
  456.     case 0x003C:
  457.       *encPtr = &big2_encoding;
  458.       return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
  459.     case 0xFEFF:
  460.       *nextTokPtr = ptr + 2;
  461.       *encPtr = &big2_encoding;
  462.       return XML_TOK_BOM;
  463.     case 0x3C00:
  464.       *encPtr = &little2_encoding;
  465.       return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
  466.     case 0xFFFE:
  467.       *nextTokPtr = ptr + 2;
  468.       *encPtr = &little2_encoding;
  469.       return XML_TOK_BOM;
  470.     }
  471.   }
  472.   *encPtr = &utf8_encoding.enc;
  473.   return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
  474. }
  475.  
  476. static
  477. int initScanProlog(const ENCODING *enc, const char *ptr, const char *end,
  478.            const char **nextTokPtr)
  479. {
  480.   return initScan(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr);
  481. }
  482.  
  483. static
  484. int initScanContent(const ENCODING *enc, const char *ptr, const char *end,
  485.             const char **nextTokPtr)
  486. {
  487.   return initScan(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr);
  488. }
  489.  
  490. static
  491. void initUpdatePosition(const ENCODING *enc, const char *ptr,
  492.             const char *end, POSITION *pos)
  493. {
  494.   normal_updatePosition(&utf8_encoding.enc, ptr, end, pos);
  495. }
  496.  
  497. const ENCODING *XmlGetInternalEncoding(int e)
  498. {
  499.   switch (e) {
  500.   case XML_UTF8_ENCODING:
  501.     return &internal_utf8_encoding.enc;
  502.   }
  503.   return 0;
  504. }
  505.  
  506. int XmlInitEncoding(INIT_ENCODING *p, const ENCODING **encPtr, const char *name)
  507. {
  508.   if (name) {
  509.     if (streqci(name, "ISO-8859-1")) {
  510.       *encPtr = &latin1_encoding.enc;
  511.       return 1;
  512.     }
  513.     if (streqci(name, "UTF-8")) {
  514.       *encPtr = &utf8_encoding.enc;
  515.       return 1;
  516.     }
  517.     if (!streqci(name, "UTF-16"))
  518.       return 0;
  519.   }
  520.   p->initEnc.scanners[XML_PROLOG_STATE] = initScanProlog;
  521.   p->initEnc.scanners[XML_CONTENT_STATE] = initScanContent;
  522.   p->initEnc.updatePosition = initUpdatePosition;
  523.   p->initEnc.minBytesPerChar = 1;
  524.   p->encPtr = encPtr;
  525.   *encPtr = &(p->initEnc);
  526.   return 1;
  527. }
  528.  
  529. static
  530. int toAscii(const ENCODING *enc, const char *ptr, const char *end)
  531. {
  532.   char buf[1];
  533.   char *p = buf;
  534.   XmlConvert(enc, XML_UTF8_ENCODING, &ptr, end, &p, p + 1);
  535.   if (p == buf)
  536.     return -1;
  537.   else
  538.     return buf[0];
  539. }
  540.  
  541. static
  542. int isSpace(int c)
  543. {
  544.   switch (c) {
  545.   case ' ':
  546.   case '\r':
  547.   case '\n':
  548.   case '\t':
  549.     return 1;
  550.   }
  551.   return 0;
  552. }
  553.  
  554. /* Return 1 if there's just optional white space
  555. or there's an S followed by name=val. */
  556. static
  557. int parsePseudoAttribute(const ENCODING *enc,
  558.              const char *ptr,
  559.              const char *end,
  560.              const char **namePtr,
  561.              const char **valPtr,
  562.              const char **nextTokPtr)
  563. {
  564.   int c;
  565.   char open;
  566.   if (ptr == end) {
  567.     *namePtr = 0;
  568.     return 1;
  569.   }
  570.   if (!isSpace(toAscii(enc, ptr, end))) {
  571.     *nextTokPtr = ptr;
  572.     return 0;
  573.   }
  574.   do {
  575.     ptr += enc->minBytesPerChar;
  576.   } while (isSpace(toAscii(enc, ptr, end)));
  577.   if (ptr == end) {
  578.     *namePtr = 0;
  579.     return 1;
  580.   }
  581.   *namePtr = ptr;
  582.   for (;;) {
  583.     c = toAscii(enc, ptr, end);
  584.     if (c == -1) {
  585.       *nextTokPtr = ptr;
  586.       return 0;
  587.     }
  588.     if (c == '=')
  589.       break;
  590.     if (isSpace(c)) {
  591.       do {
  592.     ptr += enc->minBytesPerChar;
  593.       } while (isSpace(c = toAscii(enc, ptr, end)));
  594.       if (c != '=') {
  595.     *nextTokPtr = ptr;
  596.     return 0;
  597.       }
  598.       break;
  599.     }
  600.     ptr += enc->minBytesPerChar;
  601.   }
  602.   if (ptr == *namePtr) {
  603.     *nextTokPtr = ptr;
  604.     return 0;
  605.   }
  606.   ptr += enc->minBytesPerChar;
  607.   c = toAscii(enc, ptr, end);
  608.   while (isSpace(c)) {
  609.     ptr += enc->minBytesPerChar;
  610.     c = toAscii(enc, ptr, end);
  611.   }
  612.   if (c != '"' && c != '\'') {
  613.     *nextTokPtr = ptr;
  614.     return 0;
  615.   }
  616.   open = c;
  617.   ptr += enc->minBytesPerChar;
  618.   *valPtr = ptr;
  619.   for (;; ptr += enc->minBytesPerChar) {
  620.     c = toAscii(enc, ptr, end);
  621.     if (c == open)
  622.       break;
  623.     if (!('a' <= c && c <= 'z')
  624.     && !('A' <= c && c <= 'Z')
  625.     && !('0' <= c && c <= '9')
  626.     && c != '.'
  627.     && c != '-'
  628.     && c != '_') {
  629.       *nextTokPtr = ptr;
  630.       return 0;
  631.     }
  632.   }
  633.   *nextTokPtr = ptr + enc->minBytesPerChar;
  634.   return 1;
  635. }
  636.  
  637. static
  638. const ENCODING *findEncoding(const ENCODING *enc, const char *ptr, const char *end)
  639. {
  640. #define ENCODING_MAX 128
  641.   char buf[ENCODING_MAX];
  642.   char *p = buf;
  643.   int i;
  644.   XmlConvert(enc, XML_UTF8_ENCODING, &ptr, end, &p, p + ENCODING_MAX - 1);
  645.   if (ptr != end)
  646.     return 0;
  647.   *p = 0;
  648.   for (i = 0; buf[i]; i++) {
  649.     if ('a' <= buf[i] && buf[i] <= 'z')
  650.       buf[i] +=  'A' - 'a';
  651.   }
  652.   if (streqci(buf, "UTF-8"))
  653.     return &utf8_encoding.enc;
  654.   if (streqci(buf, "ISO-8859-1"))
  655.     return &latin1_encoding.enc;
  656.   if (streqci(buf, "UTF-16")) {
  657.     static const unsigned short n = 1;
  658.     if (enc->minBytesPerChar == 2)
  659.       return enc;
  660.     return &big2_encoding;
  661.   }
  662.   return 0;  
  663. }
  664.  
  665. int XmlParseXmlDecl(int isGeneralTextEntity,
  666.             const ENCODING *enc,
  667.             const char *ptr,
  668.             const char *end,
  669.             const char **badPtr,
  670.             const char **versionPtr,
  671.             const char **encodingName,
  672.             const ENCODING **encoding,
  673.             int *standalone)
  674. {
  675.   const char *val = 0;
  676.   const char *name = 0;
  677.   ptr += 5 * enc->minBytesPerChar;
  678.   end -= 2 * enc->minBytesPerChar;
  679.   if (!parsePseudoAttribute(enc, ptr, end, &name, &val, &ptr) || !name) {
  680.     *badPtr = ptr;
  681.     return 0;
  682.   }
  683.   if (!XmlNameMatchesAscii(enc, name, "version")) {
  684.     if (!isGeneralTextEntity) {
  685.       *badPtr = name;
  686.       return 0;
  687.     }
  688.   }
  689.   else {
  690.     if (versionPtr)
  691.       *versionPtr = val;
  692.     if (!parsePseudoAttribute(enc, ptr, end, &name, &val, &ptr)) {
  693.       *badPtr = ptr;
  694.       return 0;
  695.     }
  696.     if (!name)
  697.       return 1;
  698.   }
  699.   if (XmlNameMatchesAscii(enc, name, "encoding")) {
  700.     int c = toAscii(enc, val, end);
  701.     if (!('a' <= c && c <= 'z') && !('A' <= c && c <= 'Z')) {
  702.       *badPtr = val;
  703.       return 0;
  704.     }
  705.     if (encodingName)
  706.       *encodingName = val;
  707.     if (encoding)
  708.       *encoding = findEncoding(enc, val, ptr - enc->minBytesPerChar);
  709.     if (!parsePseudoAttribute(enc, ptr, end, &name, &val, &ptr)) {
  710.       *badPtr = ptr;
  711.       return 0;
  712.     }
  713.     if (!name)
  714.       return 1;
  715.   }
  716.   if (!XmlNameMatchesAscii(enc, name, "standalone") || isGeneralTextEntity) {
  717.     *badPtr = name;
  718.     return 0;
  719.   }
  720.   if (XmlNameMatchesAscii(enc, val, "yes")) {
  721.     if (standalone)
  722.       *standalone = 1;
  723.   }
  724.   else if (XmlNameMatchesAscii(enc, val, "no")) {
  725.     if (standalone)
  726.       *standalone = 0;
  727.   }
  728.   else {
  729.     *badPtr = val;
  730.     return 0;
  731.   }
  732.   while (isSpace(toAscii(enc, ptr, end)))
  733.     ptr += enc->minBytesPerChar;
  734.   if (ptr != end) {
  735.     *badPtr = ptr;
  736.     return 0;
  737.   }
  738.   return 1;
  739. }
  740.  
  741. static
  742. int checkCharRefNumber(int result)
  743. {
  744.   switch (result >> 8) {
  745.   case 0xD8: case 0xD9: case 0xDA: case 0xDB:
  746.   case 0xDC: case 0xDD: case 0xDE: case 0xDF:
  747.     return -1;
  748.   case 0:
  749.     if (latin1_encoding.type[result] == BT_NONXML)
  750.       return -1;
  751.     break;
  752.   case 0xFF:
  753.     if (result == 0xFFFE || result == 0xFFFF)
  754.       return -1;
  755.     break;
  756.   }
  757.   return result;
  758. }
  759.  
  760.