-xml_parse_decl(struct xml_context *ctx)
-{
- TRACE(ctx, "xml_parse_decl");
- struct xml_source *src = ctx->src;
- ctx->flags &= ~XML_FLAG_SRC_EXPECTED_DECL;
-
- /* Setup valid Unicode ranges and force the reader to abort refill() after each '>', where we can switch encoding or XML version */
- xml_init_cats(ctx, XML_CHAR_GT);
-
- /* Initialize the supplied charset (if any) or try to guess it */
- char *expected_encoding = src->expected_encoding ? : src->fb_encoding;
- src->refill = xml_refill_utf8;
- int bom = bpeekc(src->fb);
- if (bom < 0)
- ctx->flags |= XML_FLAG_SRC_EOF;
- if (!src->fb_encoding)
- {
- if (bom == 0xfe)
- src->refill = xml_refill_utf16_be;
- else if (bom == 0xff)
- src->refill = xml_refill_utf16_le;
- }
- else
- {
- int cs = find_charset_by_name(src->fb_encoding);
- if (cs == CONV_CHARSET_UTF8)
- {}
- else if (cs >= 0)
- {
- xml_init_charconv(ctx, cs);
- bom = 0;
- }
- else if (strcasecmp(src->fb_encoding, "UTF-16"))
- {
- src->refill = xml_refill_utf16_be;
- if (bom == 0xff)
- src->refill = xml_refill_utf16_le;
- if (!src->expected_encoding)
- expected_encoding = (bom == 0xff) ? "UTF-16LE" : "UTF-16BE";
- }
- else if (strcasecmp(src->fb_encoding, "UTF-16BE"))
- src->refill = xml_refill_utf16_be;
- else if (strcasecmp(src->fb_encoding, "UTF-16LE"))
- src->refill = xml_refill_utf16_le;
- else
- {
- xml_error(ctx, "Unknown encoding '%s'", src->fb_encoding);
- expected_encoding = NULL;
- }
- }
- uns utf16 = src->refill == xml_refill_utf16_le || src->refill == xml_refill_utf16_be;
- if (bom > 0 && xml_peek_char(ctx) == 0xfeff)
- xml_skip_char(ctx);
- else if (utf16)
- xml_error(ctx, "Missing or corrupted BOM");
-
- /* Look ahead for presence of XMLDecl or optional TextDecl */
- if (!(ctx->flags & XML_FLAG_SRC_EOF) && ctx->bstop != src->buf + ARRAY_SIZE(src->buf))
- xml_refill(ctx);
- uns doc = ctx->flags & XML_FLAG_SRC_DOCUMENT;
- u32 *bptr = ctx->bptr;
- uns have_decl = (12 <= ctx->bstop - ctx->bptr && (bptr[11] & XML_CHAR_WHITE) &&
- bptr[0] == '<' && bptr[2] == '?' && (bptr[4] & 0xdf) == 'X' && (bptr[6] & 0xdf) == 'M' && (bptr[8] & 0xdf) == 'L');
- if (!have_decl)
- {
- if (doc)
- xml_fatal(ctx, "Missing or corrupted XML header");
- else if (expected_encoding && strcasecmp(src->expected_encoding, "UTF-8") && !utf16)
- xml_error(ctx, "Missing or corrupted entity header");
- goto exit;
- }
- ctx->bptr = bptr + 12;
- xml_parse_white(ctx, 0);
-
- /* Parse version string (mandatory in XMLDecl, optional in TextDecl) */
- if (xml_peek_char(ctx) == 'v')
- {
- xml_parse_seq(ctx, "version");
- xml_parse_eq(ctx);
- char *version = xml_parse_pubid_literal(ctx, ctx->pool);
- TRACE(ctx, "version=%s", version);
- uns v = 0;
- if (!strcmp(version, "1.1"))
- v = XML_FLAG_VERSION_1_1;
- else if (strcmp(version, "1.0"))
- {
- xml_error(ctx, "Unknown XML version string '%s'", version);
- version = "1.0";
- }
- if (doc)
- {
- ctx->version_str = version;
- ctx->flags |= v;
- }
- else if (v > (ctx->flags & XML_FLAG_VERSION_1_1))
- xml_error(ctx, "XML 1.1 external entity included from XML 1.0 document");
- if (!xml_parse_white(ctx, !doc))
- goto end;
- }
- else if (doc)
- {
- xml_error(ctx, "Expected XML version");
- ctx->version_str = "1.0";
- }
-
- /* Parse encoding string (optional in XMLDecl, mandatory in TextDecl) */
- if (xml_peek_char(ctx) == 'e')
- {
- xml_parse_seq(ctx, "encoding");
- xml_parse_eq(ctx);
- src->decl_encoding = xml_parse_encoding_name(ctx);
- TRACE(ctx, "encoding=%s", src->decl_encoding);
- if (!xml_parse_white(ctx, 0))
- goto end;
- }
- else if (!doc)
- xml_error(ctx, "Expected XML encoding");
-
- /* Parse whether the document is standalone (optional in XMLDecl) */
- if (doc && xml_peek_char(ctx) == 's')
- {
- xml_parse_seq(ctx, "standalone");
- xml_parse_eq(ctx);
- uns c = xml_parse_quote(ctx);
- if (ctx->standalone = (xml_peek_char(ctx) == 'y'))
- xml_parse_seq(ctx, "yes");
- else
- xml_parse_seq(ctx, "no");
- xml_parse_char(ctx, c);
- TRACE(ctx, "standalone=%d", ctx->standalone);
- xml_parse_white(ctx, 0);
- }
-end:
- xml_parse_seq(ctx, "?>");
-
- /* Switch to the final encoding */
- if (src->decl_encoding)
- {
- int cs = find_charset_by_name(src->decl_encoding);
- if (cs < 0 && !expected_encoding)
- xml_error(ctx, "Unknown encoding '%s'", src->decl_encoding);
- else if (!src->fb_encoding && cs >= 0 && cs != CONV_CHARSET_UTF8)
- xml_init_charconv(ctx, cs);
- else if (expected_encoding && strcasecmp(src->decl_encoding, expected_encoding) && (!utf16 ||
- !(!strcasecmp(src->decl_encoding, "UTF-16") ||
- (!strcasecmp(src->decl_encoding, "UTF-16BE") && strcasecmp(expected_encoding, "UTF-16LE")) ||
- (!strcasecmp(src->decl_encoding, "UTF-16LE") && strcasecmp(expected_encoding, "UTF-16BE")))))
- xml_error(ctx, "The header contains encoding '%s' instead of expected '%s'", src->decl_encoding, expected_encoding);
- }
-
-exit:
- /* Update valid Unicode ranges */
- xml_init_cats(ctx, 0);