Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * This file is part of LibParserUtils.
  3.  * Licensed under the MIT License,
  4.  *                http://www.opensource.org/licenses/mit-license.php
  5.  * Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
  6.  */
  7.  
  8. #include <assert.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11.  
  12. #include <parserutils/charset/mibenum.h>
  13. #include <parserutils/charset/utf8.h>
  14. #include <parserutils/input/inputstream.h>
  15.  
  16. #include "input/filter.h"
  17. #include "utils/utils.h"
  18.  
  19. /**
  20.  * Private input stream definition
  21.  */
  22. typedef struct parserutils_inputstream_private {
  23.         parserutils_inputstream public; /**< Public part. Must be first */
  24.  
  25.         parserutils_buffer *raw;        /**< Buffer containing raw data */
  26.  
  27.         bool done_first_chunk;          /**< Whether the first chunk has
  28.                                          * been processed */
  29.  
  30.         uint16_t mibenum;               /**< MIB enum for charset, or 0 */
  31.         uint32_t encsrc;                /**< Charset source */
  32.  
  33.         parserutils_filter *input;      /**< Charset conversion filter */
  34.  
  35.         parserutils_charset_detect_func csdetect; /**< Charset detection func.*/
  36.  
  37.         parserutils_alloc alloc;        /**< Memory (de)allocation function */
  38.         void *pw;                       /**< Client private data */
  39. } parserutils_inputstream_private;
  40.  
  41. static inline parserutils_error parserutils_inputstream_refill_buffer(
  42.                 parserutils_inputstream_private *stream);
  43. static inline parserutils_error parserutils_inputstream_strip_bom(
  44.                 uint16_t *mibenum, parserutils_buffer *buffer);
  45.  
  46. /**
  47.  * Create an input stream
  48.  *
  49.  * \param enc       Document charset, or NULL to autodetect
  50.  * \param encsrc    Value for encoding source, if specified, or 0
  51.  * \param csdetect  Charset detection function, or NULL
  52.  * \param alloc     Memory (de)allocation function
  53.  * \param pw        Pointer to client-specific private data (may be NULL)
  54.  * \param stream    Pointer to location to receive stream instance
  55.  * \return PARSERUTILS_OK on success,
  56.  *         PARSERUTILS_BADPARM on bad parameters,
  57.  *         PARSERUTILS_NOMEM on memory exhaustion,
  58.  *         PARSERUTILS_BADENCODING on unsupported encoding
  59.  *
  60.  * The value 0 is defined as being the lowest priority encoding source
  61.  * (i.e. the default fallback encoding). Beyond this, no further
  62.  * interpretation is made upon the encoding source.
  63.  */
  64. parserutils_error parserutils_inputstream_create(const char *enc,
  65.                 uint32_t encsrc, parserutils_charset_detect_func csdetect,
  66.                 parserutils_alloc alloc, void *pw,
  67.                 parserutils_inputstream **stream)
  68. {
  69.         parserutils_inputstream_private *s;
  70.         parserutils_error error;
  71.  
  72.         if (alloc == NULL || stream == NULL)
  73.                 return PARSERUTILS_BADPARM;
  74.  
  75.         s = alloc(NULL, sizeof(parserutils_inputstream_private), pw);
  76.         if (s == NULL)
  77.                 return PARSERUTILS_NOMEM;
  78.  
  79.         error = parserutils_buffer_create(alloc, pw, &s->raw);
  80.         if (error != PARSERUTILS_OK) {
  81.                 alloc(s, 0, pw);
  82.                 return error;
  83.         }
  84.  
  85.         error = parserutils_buffer_create(alloc, pw, &s->public.utf8);
  86.         if (error != PARSERUTILS_OK) {
  87.                 parserutils_buffer_destroy(s->raw);
  88.                 alloc(s, 0, pw);
  89.                 return error;
  90.         }
  91.  
  92.         s->public.cursor = 0;
  93.         s->public.had_eof = false;
  94.         s->done_first_chunk = false;
  95.  
  96.         error = parserutils__filter_create("UTF-8", alloc, pw, &s->input);
  97.         if (error != PARSERUTILS_OK) {
  98.                 parserutils_buffer_destroy(s->public.utf8);
  99.                 parserutils_buffer_destroy(s->raw);
  100.                 alloc(s, 0, pw);
  101.                 return error;
  102.         }
  103.  
  104.         if (enc != NULL) {
  105.                 parserutils_filter_optparams params;
  106.  
  107.                 s->mibenum =
  108.                         parserutils_charset_mibenum_from_name(enc, strlen(enc));
  109.  
  110.                 if (s->mibenum == 0)
  111.                         return PARSERUTILS_BADENCODING;
  112.  
  113.                 params.encoding.name = enc;
  114.  
  115.                 error = parserutils__filter_setopt(s->input,
  116.                                 PARSERUTILS_FILTER_SET_ENCODING,
  117.                                 &params);
  118.                 if (error != PARSERUTILS_OK) {
  119.                         parserutils__filter_destroy(s->input);
  120.                         parserutils_buffer_destroy(s->public.utf8);
  121.                         parserutils_buffer_destroy(s->raw);
  122.                         alloc(s, 0, pw);
  123.                         return error;
  124.                 }
  125.  
  126.                 s->encsrc = encsrc;
  127.         } else {
  128.                 s->mibenum = 0;
  129.                 s->encsrc = 0;
  130.         }
  131.  
  132.         s->csdetect = csdetect;
  133.  
  134.         s->alloc = alloc;
  135.         s->pw = pw;
  136.  
  137.         *stream = (parserutils_inputstream *) s;
  138.  
  139.         return PARSERUTILS_OK;
  140. }
  141.  
  142. /**
  143.  * Destroy an input stream
  144.  *
  145.  * \param stream  Input stream to destroy
  146.  * \return PARSERUTILS_OK on success, appropriate error otherwise
  147.  */
  148. parserutils_error parserutils_inputstream_destroy(
  149.                 parserutils_inputstream *stream)
  150. {
  151.         parserutils_inputstream_private *s =
  152.                         (parserutils_inputstream_private *) stream;
  153.  
  154.         if (stream == NULL)
  155.                 return PARSERUTILS_BADPARM;
  156.  
  157.         parserutils__filter_destroy(s->input);
  158.         parserutils_buffer_destroy(s->public.utf8);
  159.         parserutils_buffer_destroy(s->raw);
  160.         s->alloc(s, 0, s->pw);
  161.  
  162.         return PARSERUTILS_OK;
  163. }
  164.  
  165. /**
  166.  * Append data to an input stream
  167.  *
  168.  * \param stream  Input stream to append data to
  169.  * \param data    Data to append (in document charset), or NULL to flag EOF
  170.  * \param len     Length, in bytes, of data
  171.  * \return PARSERUTILS_OK on success, appropriate error otherwise
  172.  */
  173. parserutils_error parserutils_inputstream_append(
  174.                 parserutils_inputstream *stream,
  175.                 const uint8_t *data, size_t len)
  176. {
  177.         parserutils_inputstream_private *s =
  178.                         (parserutils_inputstream_private *) stream;
  179.  
  180.         if (stream == NULL)
  181.                 return PARSERUTILS_BADPARM;
  182.  
  183.         if (data == NULL) {
  184.                 s->public.had_eof = true;
  185.                 return PARSERUTILS_OK;
  186.         }
  187.  
  188.         return parserutils_buffer_append(s->raw, data, len);
  189. }
  190.  
  191. /**
  192.  * Insert data into stream at current location
  193.  *
  194.  * \param stream  Input stream to insert into
  195.  * \param data    Data to insert (UTF-8 encoded)
  196.  * \param len     Length, in bytes, of data
  197.  * \return PARSERUTILS_OK on success, appropriate error otherwise
  198.  */
  199. parserutils_error parserutils_inputstream_insert(
  200.                 parserutils_inputstream *stream,
  201.                 const uint8_t *data, size_t len)
  202. {
  203.         parserutils_inputstream_private *s =
  204.                         (parserutils_inputstream_private *) stream;
  205.  
  206.         if (stream == NULL || data == NULL)
  207.                 return PARSERUTILS_BADPARM;
  208.  
  209.         return parserutils_buffer_insert(s->public.utf8, s->public.cursor,
  210.                         data, len);
  211. }
  212.  
  213. #define IS_ASCII(x) (((x) & 0x80) == 0)
  214.  
  215. /**
  216.  * Look at the character in the stream that starts at
  217.  * offset bytes from the cursor (slow version)
  218.  *
  219.  * \param stream  Stream to look in
  220.  * \param offset  Byte offset of start of character
  221.  * \param ptr     Pointer to location to receive pointer to character data
  222.  * \param length  Pointer to location to receive character length (in bytes)
  223.  * \return PARSERUTILS_OK on success,
  224.  *                    _NEEDDATA on reaching the end of available input,
  225.  *                    _EOF on reaching the end of all input,
  226.  *                    _BADENCODING if the input cannot be decoded,
  227.  *                    _NOMEM on memory exhaustion,
  228.  *                    _BADPARM if bad parameters are passed.
  229.  *
  230.  * Once the character pointed to by the result of this call has been advanced
  231.  * past (i.e. parserutils_inputstream_advance has caused the stream cursor to
  232.  * pass over the character), then no guarantee is made as to the validity of
  233.  * the data pointed to. Thus, any attempt to dereference the pointer after
  234.  * advancing past the data it points to is a bug.
  235.  */
  236. parserutils_error parserutils_inputstream_peek_slow(
  237.                 parserutils_inputstream *stream,
  238.                 size_t offset, const uint8_t **ptr, size_t *length)
  239. {
  240.         parserutils_inputstream_private *s =
  241.                         (parserutils_inputstream_private *) stream;
  242.         parserutils_error error = PARSERUTILS_OK;
  243.         size_t len;
  244.  
  245.         if (stream == NULL || ptr == NULL || length == NULL)
  246.                 return PARSERUTILS_BADPARM;
  247.  
  248.         /* There's insufficient data in the buffer, so read some more */
  249.         if (s->raw->length == 0) {
  250.                 /* No more data to be had */
  251.                 return s->public.had_eof ? PARSERUTILS_EOF
  252.                                          : PARSERUTILS_NEEDDATA;
  253.         }
  254.  
  255.         /* Refill utf8 buffer from raw buffer */
  256.         error = parserutils_inputstream_refill_buffer(s);
  257.         if (error != PARSERUTILS_OK)
  258.                 return error;
  259.  
  260.         /* Refill may have succeeded, but not actually produced any new data */
  261.         if (s->public.cursor + offset == s->public.utf8->length)
  262.                 return PARSERUTILS_NEEDDATA;
  263.  
  264.         /* Now try the read */
  265.         if (IS_ASCII(s->public.utf8->data[s->public.cursor + offset])) {
  266.                 len = 1;
  267.         } else {
  268.                 error = parserutils_charset_utf8_char_byte_length(
  269.                         s->public.utf8->data + s->public.cursor + offset,
  270.                         &len);
  271.  
  272.                 if (error != PARSERUTILS_OK && error != PARSERUTILS_NEEDDATA)
  273.                         return error;
  274.  
  275.                 if (error == PARSERUTILS_NEEDDATA) {
  276.                         return s->public.had_eof ? PARSERUTILS_EOF
  277.                                                  : PARSERUTILS_NEEDDATA;
  278.                 }
  279.         }
  280.  
  281.         (*length) = len;
  282.         (*ptr) = (s->public.utf8->data + s->public.cursor + offset);
  283.  
  284.         return PARSERUTILS_OK;
  285. }
  286.  
  287. #undef IS_ASCII
  288.  
  289. /**
  290.  * Read the source charset of the input stream
  291.  *
  292.  * \param stream  Input stream to query
  293.  * \param source  Pointer to location to receive charset source identifier
  294.  * \return Pointer to charset name (constant; do not free)
  295.  */
  296. const char *parserutils_inputstream_read_charset(
  297.                 parserutils_inputstream *stream, uint32_t *source)
  298. {
  299.         parserutils_inputstream_private *s =
  300.                         (parserutils_inputstream_private *) stream;
  301.  
  302.         if (stream == NULL || source == NULL)
  303.                 return NULL;
  304.  
  305.         *source = s->encsrc;
  306.  
  307.         if (s->encsrc == 0)
  308.                 return "UTF-8";
  309.  
  310.         return parserutils_charset_mibenum_to_name(s->mibenum);
  311. }
  312.  
  313. /**
  314.  * Change the source charset of the input stream
  315.  *
  316.  * \param stream   Input stream to modify
  317.  * \param enc      Charset name
  318.  * \param source   Charset source identifier
  319.  * \return PARSERUTILS_OK on success,
  320.  *         PARSERUTILS_BADPARM on invalid parameters,
  321.  *         PARSERUTILS_INVALID if called after data has been read from stream,
  322.  *         PARSERUTILS_BADENCODING if the encoding is unsupported,
  323.  *         PARSERUTILS_NOMEM on memory exhaustion.
  324.  */
  325. parserutils_error parserutils_inputstream_change_charset(
  326.                 parserutils_inputstream *stream,
  327.                 const char *enc, uint32_t source)
  328. {
  329.         parserutils_inputstream_private *s =
  330.                         (parserutils_inputstream_private *) stream;
  331.         parserutils_filter_optparams params;
  332.         uint16_t temp;
  333.         parserutils_error error;
  334.  
  335.         if (stream == NULL || enc == NULL)
  336.                 return PARSERUTILS_BADPARM;
  337.  
  338.         if (s->done_first_chunk)
  339.                 return PARSERUTILS_INVALID;
  340.  
  341.         temp = parserutils_charset_mibenum_from_name(enc, strlen(enc));
  342.         if (temp == 0)
  343.                 return PARSERUTILS_BADENCODING;
  344.  
  345.         /* Ensure filter is using the correct encoding */
  346.         params.encoding.name = enc;
  347.         error = parserutils__filter_setopt(s->input,
  348.                         PARSERUTILS_FILTER_SET_ENCODING,
  349.                         &params);
  350.         if (error != PARSERUTILS_OK)
  351.                 return error;
  352.  
  353.         /* Finally, replace the current settings */
  354.         s->mibenum = temp;
  355.         s->encsrc = source;
  356.  
  357.         return PARSERUTILS_OK;
  358. }
  359.  
  360. /******************************************************************************
  361.  ******************************************************************************/
  362.  
  363. /**
  364.  * Refill the UTF-8 buffer from the raw buffer
  365.  *
  366.  * \param stream  The inputstream to operate on
  367.  * \return PARSERUTILS_OK on success
  368.  */
  369. parserutils_error parserutils_inputstream_refill_buffer(
  370.                 parserutils_inputstream_private *stream)
  371. {
  372.         const uint8_t *raw;
  373.         uint8_t *utf8;
  374.         size_t raw_length, utf8_space;
  375.         parserutils_error error;
  376.  
  377.         /* If this is the first chunk of data, we must detect the charset and
  378.          * strip the BOM, if one exists */
  379.         if (stream->done_first_chunk == false) {
  380.                 parserutils_filter_optparams params;
  381.  
  382.                 /* If there is a charset detection routine, give it an
  383.                  * opportunity to override any charset specified when the
  384.                  * inputstream was created */
  385.                 if (stream->csdetect != NULL) {
  386.                         error = stream->csdetect(stream->raw->data,
  387.                                 stream->raw->length,
  388.                                 &stream->mibenum, &stream->encsrc);
  389.                         if (error != PARSERUTILS_OK) {
  390.                                 if (error != PARSERUTILS_NEEDDATA ||
  391.                                                 stream->public.had_eof == false)
  392.                                         return error;
  393.  
  394.                                 /* We don't have enough data to detect the
  395.                                  * input encoding, but we're not going to get
  396.                                  * any more as we've been notified of EOF.
  397.                                  * Therefore, leave the encoding alone
  398.                                  * so that any charset specified when the
  399.                                  * inputstream was created will be preserved.
  400.                                  * If there was no charset specified, then
  401.                                  * we'll default to UTF-8, below */
  402.                         }
  403.                 }
  404.  
  405.                 /* Default to UTF-8 if there is still no encoding information
  406.                  * We'll do this if there was no encoding specified up-front
  407.                  * and:
  408.                  *    1) there was no charset detection routine
  409.                  * or 2) there was insufficient data for the charset
  410.                  *       detection routine to detect an encoding
  411.                  */
  412.                 if (stream->mibenum == 0) {
  413.                         stream->mibenum =
  414.                                 parserutils_charset_mibenum_from_name("UTF-8",
  415.                                         SLEN("UTF-8"));
  416.                         stream->encsrc = 0;
  417.                 }
  418.  
  419.                 if (stream->mibenum == 0)
  420.                         abort();
  421.  
  422.                 /* Strip any BOM, and update encoding as appropriate */
  423.                 error = parserutils_inputstream_strip_bom(&stream->mibenum,
  424.                                 stream->raw);
  425.                 if (error != PARSERUTILS_OK)
  426.                         return error;
  427.  
  428.                 /* Ensure filter is using the correct encoding */
  429.                 params.encoding.name =
  430.                         parserutils_charset_mibenum_to_name(stream->mibenum);
  431.  
  432.                 error = parserutils__filter_setopt(stream->input,
  433.                                 PARSERUTILS_FILTER_SET_ENCODING,
  434.                                 &params);
  435.                 if (error != PARSERUTILS_OK)
  436.                         return error;
  437.  
  438.                 stream->done_first_chunk = true;
  439.         }
  440.  
  441.         /* Work out how to perform the buffer fill */
  442.         if (stream->public.cursor == stream->public.utf8->length) {
  443.                 /* Cursor's at the end, so simply reuse the entire buffer */
  444.                 utf8 = stream->public.utf8->data;
  445.                 utf8_space = stream->public.utf8->allocated;
  446.         } else {
  447.                 /* Cursor's not at the end, so shift data after cursor to the
  448.                  * bottom of the buffer. If the buffer's still over half full,
  449.                  * extend it. */
  450.                 memmove(stream->public.utf8->data,
  451.                         stream->public.utf8->data + stream->public.cursor,
  452.                         stream->public.utf8->length - stream->public.cursor);
  453.  
  454.                 stream->public.utf8->length -= stream->public.cursor;
  455.  
  456.                 if (stream->public.utf8->length >
  457.                                 stream->public.utf8->allocated / 2) {
  458.                         error = parserutils_buffer_grow(stream->public.utf8);
  459.                         if (error != PARSERUTILS_OK)
  460.                                 return error;
  461.                 }
  462.  
  463.                 utf8 = stream->public.utf8->data + stream->public.utf8->length;
  464.                 utf8_space = stream->public.utf8->allocated -
  465.                                 stream->public.utf8->length;
  466.         }
  467.  
  468.         raw = stream->raw->data;
  469.         raw_length = stream->raw->length;
  470.  
  471.         /* Try to fill utf8 buffer from the raw data */
  472.         error = parserutils__filter_process_chunk(stream->input,
  473.                         &raw, &raw_length, &utf8, &utf8_space);
  474.         /* _NOMEM implies that there's more input to read than available space
  475.          * in the utf8 buffer. That's fine, so we'll ignore that error. */
  476.         if (error != PARSERUTILS_OK && error != PARSERUTILS_NOMEM)
  477.                 return error;
  478.  
  479.         /* Remove the raw data we've processed from the raw buffer */
  480.         error = parserutils_buffer_discard(stream->raw, 0,
  481.                         stream->raw->length - raw_length);
  482.         if (error != PARSERUTILS_OK)
  483.                 return error;
  484.  
  485.         /* Fix up the utf8 buffer information */
  486.         stream->public.utf8->length =
  487.                         stream->public.utf8->allocated - utf8_space;
  488.  
  489.         /* Finally, fix up the cursor */
  490.         stream->public.cursor = 0;
  491.  
  492.         return PARSERUTILS_OK;
  493. }
  494.  
  495. /**
  496.  * Strip a BOM from a buffer in the given encoding
  497.  *
  498.  * \param mibenum  Pointer to the character set of the buffer, updated on exit
  499.  * \param buffer   The buffer to process
  500.  */
  501. parserutils_error parserutils_inputstream_strip_bom(uint16_t *mibenum,
  502.                 parserutils_buffer *buffer)
  503. {
  504.         static uint16_t utf8;
  505.         static uint16_t utf16;
  506.         static uint16_t utf16be;
  507.         static uint16_t utf16le;
  508.         static uint16_t utf32;
  509.         static uint16_t utf32be;
  510.         static uint16_t utf32le;
  511.  
  512.         if (utf8 == 0) {
  513.                 utf8 = parserutils_charset_mibenum_from_name("UTF-8",
  514.                                 SLEN("UTF-8"));
  515.                 utf16 = parserutils_charset_mibenum_from_name("UTF-16",
  516.                                 SLEN("UTF-16"));
  517.                 utf16be = parserutils_charset_mibenum_from_name("UTF-16BE",
  518.                                 SLEN("UTF-16BE"));
  519.                 utf16le = parserutils_charset_mibenum_from_name("UTF-16LE",
  520.                                 SLEN("UTF-16LE"));
  521.                 utf32 = parserutils_charset_mibenum_from_name("UTF-32",
  522.                                 SLEN("UTF-32"));
  523.                 utf32be = parserutils_charset_mibenum_from_name("UTF-32BE",
  524.                                 SLEN("UTF-32BE"));
  525.                 utf32le = parserutils_charset_mibenum_from_name("UTF-32LE",
  526.                                 SLEN("UTF-32LE"));
  527.         }
  528.  
  529. #define UTF32_BOM_LEN (4)
  530. #define UTF16_BOM_LEN (2)
  531. #define UTF8_BOM_LEN  (3)
  532.  
  533.         if (*mibenum == utf8) {
  534.                 if (buffer->length >= UTF8_BOM_LEN &&
  535.                                 buffer->data[0] == 0xEF &&
  536.                                 buffer->data[1] == 0xBB &&
  537.                                 buffer->data[2] == 0xBF) {
  538.                         return parserutils_buffer_discard(
  539.                                         buffer, 0, UTF8_BOM_LEN);
  540.                 }
  541.         } else if (*mibenum == utf16be) {
  542.                 if (buffer->length >= UTF16_BOM_LEN &&
  543.                                 buffer->data[0] == 0xFE &&
  544.                                 buffer->data[1] == 0xFF) {
  545.                         return parserutils_buffer_discard(
  546.                                         buffer, 0, UTF16_BOM_LEN);
  547.                 }
  548.         } else if (*mibenum == utf16le) {
  549.                 if (buffer->length >= UTF16_BOM_LEN &&
  550.                                 buffer->data[0] == 0xFF &&
  551.                                 buffer->data[1] == 0xFE) {
  552.                         return parserutils_buffer_discard(
  553.                                         buffer, 0, UTF16_BOM_LEN);
  554.                 }
  555.         } else if (*mibenum == utf16) {
  556.                 *mibenum = utf16be;
  557.  
  558.                 if (buffer->length >= UTF16_BOM_LEN) {
  559.                         if (buffer->data[0] == 0xFE &&
  560.                                         buffer->data[1] == 0xFF) {
  561.                                 return parserutils_buffer_discard(
  562.                                                 buffer, 0, UTF16_BOM_LEN);
  563.                         } else if (buffer->data[0] == 0xFF &&
  564.                                         buffer->data[1] == 0xFE) {
  565.                                 *mibenum = utf16le;
  566.                                 return parserutils_buffer_discard(
  567.                                                 buffer, 0, UTF16_BOM_LEN);
  568.                         }
  569.                 }
  570.         } else if (*mibenum == utf32be) {
  571.                 if (buffer->length >= UTF32_BOM_LEN &&
  572.                                 buffer->data[0] == 0x00 &&
  573.                                 buffer->data[1] == 0x00 &&
  574.                                 buffer->data[2] == 0xFE &&
  575.                                 buffer->data[3] == 0xFF) {
  576.                         return parserutils_buffer_discard(
  577.                                         buffer, 0, UTF32_BOM_LEN);
  578.                 }
  579.         } else if (*mibenum == utf32le) {
  580.                 if (buffer->length >= UTF32_BOM_LEN &&
  581.                                 buffer->data[0] == 0xFF &&
  582.                                 buffer->data[1] == 0xFE &&
  583.                                 buffer->data[2] == 0x00 &&
  584.                                 buffer->data[3] == 0x00) {
  585.                         return parserutils_buffer_discard(
  586.                                         buffer, 0, UTF32_BOM_LEN);
  587.                 }
  588.         } else if (*mibenum == utf32) {
  589.                 *mibenum = utf32be;
  590.  
  591.                 if (buffer->length >= UTF32_BOM_LEN) {
  592.                         if (buffer->data[0] == 0x00 &&
  593.                                         buffer->data[1] == 0x00 &&
  594.                                         buffer->data[2] == 0xFE &&
  595.                                         buffer->data[3] == 0xFF) {
  596.                                 return parserutils_buffer_discard(
  597.                                                 buffer, 0, UTF32_BOM_LEN);
  598.                         } else if (buffer->data[0] == 0xFF &&
  599.                                         buffer->data[1] == 0xFE &&
  600.                                         buffer->data[2] == 0x00 &&
  601.                                         buffer->data[3] == 0x00) {
  602.                                 *mibenum = utf32le;
  603.                                 return parserutils_buffer_discard(
  604.                                                 buffer, 0, UTF32_BOM_LEN);
  605.                         }
  606.                 }
  607.         }
  608.  
  609. #undef UTF8_BOM_LEN
  610. #undef UTF16_BOM_LEN
  611. #undef UTF32_BOM_LEN
  612.  
  613.         return PARSERUTILS_OK;
  614. }
  615.  
  616.