diff --git a/Source/ThirdParty/tfsxml/tfsxml.c b/Source/ThirdParty/tfsxml/tfsxml.c index ff31dbcf..450c48a1 100644 --- a/Source/ThirdParty/tfsxml/tfsxml.c +++ b/Source/ThirdParty/tfsxml/tfsxml.c @@ -1,22 +1,24 @@ -/* Copyright (c) MediaArea.net SARL. All Rights Reserved. +/* Copyright (c) MediaArea.net SARL -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. -(zlib license) +(MIT License) */ @@ -35,7 +37,7 @@ freely, subject to the following restrictions: /* * priv flags : * 0: is inside an element header - * 1: previous element is closed + * 1: previous element is open (potentially with sub elements) */ /* @@ -43,68 +45,68 @@ freely, subject to the following restrictions: * 0: must be decoded */ -static inline void set_flag(tfsxml_string* priv, int offset) -{ +static inline void set_flag(tfsxml_string* priv, int offset) { priv->flags |= (1 << offset); } -static inline int get_flag(tfsxml_string* priv, int offset) -{ +static inline int get_flag(tfsxml_string* priv, int offset) { return priv->flags & (1 << offset); } -static inline void unset_flag(tfsxml_string* priv, int offset) -{ +static inline void unset_flag(tfsxml_string* priv, int offset) { priv->flags &= ~(1 << offset); } -static inline void next_char(tfsxml_string* priv) +#define set_is_in_element_header() set_flag(priv, 0) +#define get_is_in_element_header() get_flag(priv, 0) +#define unset_is_in_element_header() unset_flag(priv, 0) +#define set_previous_element_is_open() set_flag(priv, 1) +#define get_previous_element_is_open() get_flag(priv, 1) +#define unset_previous_element_is_open() unset_flag(priv, 1) + +#define set_must_be_decoded() set_flag(v, 0) + +static inline void set_level(tfsxml_string* priv, int level) { - priv->buf++; - priv->len--; + const int offset = (sizeof(priv->flags) - 1) * 8; + priv->flags <<= 8; + priv->flags >>= 8; + priv->flags |= level << offset; } -static inline int tfsxml_leave_element_header(tfsxml_string* priv) +static inline void get_level(tfsxml_string* priv, unsigned* level) { - /* Skip attributes */ - tfsxml_string n, v; - while (!tfsxml_attr(priv, &n, &v)); - - return 0; + const int offset = (sizeof(priv->flags) - 1) * 8; + *level = priv->flags >> offset; } +static inline void next_char(tfsxml_string* priv) { + priv->buf++; + priv->len--; +} -static inline int tfsxml_has_value(tfsxml_string* v) -{ - int is_end = 0; - const char* buf = v->buf; - int len = v->len; - while (len && !is_end) - { - switch (*buf) - { - case '\n': - case '\t': - case '\r': - case ' ': - buf++; - len--; - break; - default: - is_end = 1; +static int tfsxml_leave_element_header(tfsxml_string* priv) { + /* Skip attributes */ + tfsxml_string n, v; + for (;;) { + int result = tfsxml_attr(priv, &n, &v); + switch (result) { + case -1: { + return 0; + } + case 1: { + return 1; + } + default: { + } } } - if (is_end) - return 0; - return -1; } -int tfsxml_strcmp_charp(tfsxml_string a, const char* b) -{ - /* Compare char per charand return the difference if chars are no equal */ - for (; a.len && *b; a.buf++, a.len--, b++) - { - char c = *a.buf - *b; +int tfsxml_strcmp_charp(tfsxml_string a, const char* b) { + /* Compare char per char and return the difference if chars are no equal */ + for (; a.len && *b; a.buf++, a.len--, b++) { + int c = *a.buf - *b; if (c) return c; } @@ -117,23 +119,26 @@ int tfsxml_strcmp_charp(tfsxml_string a, const char* b) return *a.buf; /* a is longer than b */ } -tfsxml_string tfsxml_strstr_charp(tfsxml_string a, const char* b) -{ +int tfsxml_strncmp_charp(tfsxml_string a, const char* b, unsigned n) { + tfsxml_string a2 = a; + if (a2.len > n) + a2.len = n; + return tfsxml_strcmp_charp(a2, b); +} + +tfsxml_string tfsxml_strstr_charp(tfsxml_string a, const char* b) { /* Iterate string to be scanned */ - for (; a.len; a.buf++, a.len--) - { + for (; a.len; a.buf++, a.len--) { const char* buf = a.buf; int len = a.len; const char* bb = b; /* Compare char per char */ - for (; len && *bb; buf++, len--, bb++) - { + for (; len && *bb; buf++, len--, bb++) { char c = *buf - *bb; if (c) break; } - if (!len || *bb) - { + if (!len || *bb) { return a; } } @@ -142,16 +147,18 @@ tfsxml_string tfsxml_strstr_charp(tfsxml_string a, const char* b) return a; } -int tfsxml_init(tfsxml_string* priv, const void* buf, int len) -{ +int tfsxml_init(tfsxml_string* priv, const void* buf, unsigned len, unsigned version) { const char* buf_8 = (const char*)buf; + if (version != 0) { + return -1; + } + /* BOM detection */ if (len > 3 && (unsigned char)buf_8[0] == 0xEF && (unsigned char)buf_8[1] == 0xBB - && (unsigned char)buf_8[2] == 0xBF) - { + && (unsigned char)buf_8[2] == 0xBF) { buf_8 += 3; len -= 3; } @@ -166,518 +173,578 @@ int tfsxml_init(tfsxml_string* priv, const void* buf, int len) priv->buf = (const char*)buf; priv->len = len; priv->flags = 0; - set_flag(priv, 1); return 0; } -int tfsxml_next(tfsxml_string* priv, tfsxml_string* n) -{ - int level; +int tfsxml_next(tfsxml_string* priv, tfsxml_string* n) { + tfsxml_string priv_bak; + unsigned level; + + get_level(priv, &level); /* Exiting previous element header analysis if needed */ - if (get_flag(priv, 0) && tfsxml_leave_element_header(priv)) - return -1; + if (!level && get_is_in_element_header()) { + int result = tfsxml_leave_element_header(priv); + if (result) { + return result; + } + } /* Leaving previous element content if needed */ - if (!get_flag(priv, 1) && tfsxml_leave(priv)) - return -1; + if (level || get_previous_element_is_open()) { + if (!level && get_previous_element_is_open()) { + level++; + } + level--; + set_level(priv, level); + int result = tfsxml_leave(priv); + if (result) { + return result; + } + get_level(priv, &level); + } - level = 0; - while (priv->len) - { - switch (*priv->buf) - { - case '<': - next_char(priv); - if (priv->len && *priv->buf == '?') - { - n->buf = priv->buf; - while (priv->len && *priv->buf != '>') - { - next_char(priv); - } - n->len = priv->buf - n->buf; - if (priv->len) - next_char(priv); - set_flag(priv, 1); - return 0; - } - if (priv->len && *priv->buf == '!') - { - unsigned long long probe = 0; - int i; - for (i = 1; i < 8; i++) - { - probe <<= 8; - probe |= priv->buf[i]; + priv_bak = *priv; + while (priv->len) { + switch (*priv->buf) { + case '<': { + if (priv->len == 1) { + *priv = priv_bak; + set_level(priv, level); + return 1; } - if (probe == 0x5B43444154415BULL) /* "[CDATA[" */ - { - probe = 0; - priv->buf += 9; - priv->len -= 9; - while (priv->len) - { - probe &= 0xFFFF; - probe <<= 8; - probe |= *priv->buf; - if (probe == 0x5D5D3EULL) /* "]]>" */ - break; - priv->buf++; - priv->len--; + if (priv->buf[1] == '/') { + while (priv->len && *priv->buf != '>') { + next_char(priv); } - break; - } - n->buf = priv->buf; - if (priv->len >= 3 && priv->buf[1] == '-' && priv->buf[2] == '-') - { - int len_sav = priv->len; - const char* buf = priv->buf + 3; - int len = priv->len - 3; - probe = 0; - while (len) - { - probe &= 0xFFFF; - probe <<= 8; - probe |= *buf; - if (probe == 0x2D2D3EULL) /* "-->" */ - break; - buf++; - len--; + if (!priv->len) { + *priv = priv_bak; + set_level(priv, level); + return 1; } - n->buf = priv->buf; - n->len = len_sav - len; - priv->buf += n->len; - priv->len -= n->len; - if (priv->len) + if (!level) { next_char(priv); - return 0; + unset_previous_element_is_open(); + set_level(priv, level); + return -1; + } + level--; + break; } - while (priv->len && *priv->buf != '>') + if (priv->buf[1] == '?') { next_char(priv); - n->len = priv->buf - n->buf; - if (priv->len) - next_char(priv); - set_flag(priv, 1); - return 0; - } - if (*priv->buf == '/') - { - while (priv->len && *priv->buf != '>') + n->buf = priv->buf; + while (priv->len && *priv->buf != '>') { + next_char(priv); + } + if (!priv->len) { + *priv = priv_bak; + set_level(priv, level); + return 1; + } + n->len = priv->buf - n->buf; next_char(priv); - next_char(priv); - if (!level) - { - n->buf = NULL; - n->len = 0; - set_flag(priv, 1); - return -1; + unset_previous_element_is_open(); + set_level(priv, 0); + return 0; } - level--; - break; - } - if (!level) - { - n->buf = priv->buf; - for (;;) - { - if (!priv->len) - return -1; - - switch (*priv->buf) - { - case '\n': - case '\t': - case '\r': - case ' ': - case '/': - case '>': + if (priv->buf[1] == '!') { + unsigned long long probe = 0; + int i; + if (priv->len <= 8) { + *priv = priv_bak; + set_level(priv, level); + return 1; + } + for (i = 2; i <= 8; i++) { + probe <<= 8; + probe |= priv->buf[i]; + } + if (probe == 0x5B43444154415BULL) { /* "buf += 9; + priv->len -= 9; + while (priv->len) { + probe &= 0xFFFF; + probe <<= 8; + probe |= *priv->buf; + if (probe == 0x5D5D3EULL) { /* "]]>" */ + break; + } + next_char(priv); + } + if (!priv->len) { + *priv = priv_bak; + set_level(priv, level); + return 1; + } + break; + } + if ((probe >> 40) == 0x2D2D) { /* "" */ + break; + next_char(priv); + } + if (!priv->len) { + *priv = priv_bak; + set_level(priv, level); + return 1; + } n->len = priv->buf - n->buf; - set_flag(priv, 0); - unset_flag(priv, 1); + next_char(priv); + unset_previous_element_is_open(); + set_level(priv, 0); return 0; - default:; } + while (priv->len && *priv->buf != '>') { + next_char(priv); + } + if (!priv->len) { + *priv = priv_bak; + set_level(priv, level); + return 1; + } + n->buf = priv_bak.buf; + n->len = priv->buf - n->buf; next_char(priv); + unset_previous_element_is_open(); + set_level(priv, 0); + return 0; } + if (!level) { + next_char(priv); + n->buf = priv->buf; + for (;;) { + if (!priv->len) { + *priv = priv_bak; + set_level(priv, level); + return 1; + } + + switch (*priv->buf) { + case '\n': + case '\t': + case '\r': + case ' ': + case '/': + case '>': + n->len = priv->buf - n->buf; + set_is_in_element_header(); + set_previous_element_is_open(); + set_level(priv, 0); + return 0; + default: { + } + } + next_char(priv); + } + } + level++; + break; + } + default: { } - level++; - break; - default:; } next_char(priv); } - n->buf = NULL; - n->len = 0; - unset_flag(priv, 0); - unset_flag(priv, 1); - return -1; + set_level(priv, level); + return 1; } -int tfsxml_attr(tfsxml_string* priv, tfsxml_string* n, tfsxml_string* v) -{ - if (!get_flag(priv, 0)) +int tfsxml_attr(tfsxml_string* priv, tfsxml_string* n, tfsxml_string* v) { + if (!get_is_in_element_header()) { return -1; + } v->flags = 0; - while (priv->len) - { - switch (*priv->buf) - { - case '\n': - case '\t': - case '\r': - case ' ': - break; - case '/': - set_flag(priv, 1); - break; - case '>': - next_char(priv); - n->buf = NULL; - n->len = 0; - v->buf = NULL; - v->len = 0; - v->flags = 0; - unset_flag(priv, 0); - return -1; - default: - { - /* Attribute */ - n->buf = priv->buf; - while (priv->len && *priv->buf != '=') - { - next_char(priv); + tfsxml_string priv_bak = *priv; + while (priv->len) { + switch (*priv->buf) { + case '/': { + unset_previous_element_is_open(); + //fall through + } + case '\n': + case '\t': + case '\r': + case ' ': { + break; } - n->len = priv->buf - n->buf; - if (!priv->len) + case '>': { + next_char(priv); + unset_is_in_element_header(); return -1; - next_char(priv); - } - { - /* Value */ - const char quote = *priv->buf; - next_char(priv); - v->buf = priv->buf; - while (priv->len && *priv->buf != quote) - { - if (*priv->buf == '&') - set_flag(v, 0); + } + default: { + if (!get_previous_element_is_open()) { + break; // Junk after "/", ignoring + } + + /* Attribute */ + n->buf = priv->buf; + while (priv->len && *priv->buf != '=') { + next_char(priv); + } + if (!priv->len) { + *priv = priv_bak; + return 1; + } + n->len = priv->buf - n->buf; next_char(priv); + + /* Value */ + const char quote = *priv->buf; + if (!priv->len) { + *priv = priv_bak; + return 1; + } + next_char(priv); + v->buf = priv->buf; + while (priv->len && *priv->buf != quote) { + if (*priv->buf == '&') { + set_flag(v, 0); + } + next_char(priv); + } + v->len = priv->buf - v->buf; + if (!priv->len) { + *priv = priv_bak; + return 1; + } + next_char(priv); + return 0; } - v->len = priv->buf - v->buf; - if (!priv->len) - return -1; - next_char(priv); - return 0; - } } next_char(priv); } - n->buf = NULL; - n->len = 0; - n->flags = 0; - v->buf = NULL; - v->len = 0; - v->flags = 0; - unset_flag(priv, 0); - return -1; + *priv = priv_bak; + return 1; } - -int tfsxml_value(tfsxml_string* priv, tfsxml_string* v) -{ - tfsxml_string priv_bak = *priv; - int len_sav; +int tfsxml_value(tfsxml_string* priv, tfsxml_string* v) { + tfsxml_string priv_bak; + unsigned len_sav; /* Exiting previous element header analysis if needed */ - int is_first = 0; - if (get_flag(priv, 0)) - { - if (tfsxml_leave_element_header(priv)) - return -1; - is_first = 1; - - /* Previous element must not be finished */ - if (get_flag(priv, 1)) - return -1; + if (get_is_in_element_header()) { + int result = tfsxml_leave_element_header(priv); + if (result) { + return result; + } } + /* Previous element must not be finished */ + if (!get_previous_element_is_open()) { + return -1; + } + + priv_bak = *priv; len_sav = priv->len; v->flags = 0; - while (priv->len) - { - switch (*priv->buf) - { - case '&': - set_flag(v, 0); - break; - case '<': - if (priv->len == len_sav && priv->len > 8) - { - unsigned long long probe = 0; - int i; - for (i = 1; i <= 8; i++) - { - probe <<= 8; - probe |= priv->buf[i]; + while (priv->len) { + switch (*priv->buf) { + case '&': { + set_must_be_decoded(); + break; + } + case '<': { + if (priv->len == 1) { + *priv = priv_bak; + return 1; } - if (probe == 0x215B43444154415BULL) /* "![CDATA[" */ - { - const char* buf = priv->buf + 9; - int len = priv->len - 9; - probe = 0; - while (len) - { - probe &= 0xFFFF; + if (priv->buf[1] == '!') { + if (priv->len <= 8) { + *priv = priv_bak; + return 1; + } + unsigned long long probe = 0; + int i; + for (i = 2; i <= 8; i++) { probe <<= 8; - probe |= *buf; - if (probe == 0x5D5D3EULL) /* "]]>" */ - break; - buf++; - len--; - } - v->buf = priv->buf; - v->len = len_sav - len; - if (v->len < priv->len) - v->len++; - priv->buf += v->len; - priv->len -= v->len; - v->buf += 9; - v->len -= 12; - return 0; + probe |= priv->buf[i]; + } + if (probe == 0x5B43444154415BULL) { /* "buf += 9; + priv->len -= 9; + while (priv->len) { + probe &= 0xFFFF; + probe <<= 8; + probe |= *priv->buf; + if (probe == 0x5D5D3EULL) { /* "]]>" */ + break; + } + next_char(priv); + } + if (!priv->len) { + *priv = priv_bak; + return 1; + } + break; + } } + v->len = len_sav - priv->len; + v->buf = priv->buf - v->len; + set_previous_element_is_open(); + set_level(priv, 0); + int result = tfsxml_leave(priv); + if (result) { + *priv = priv_bak; + return result; + } + return 0; } - v->len = len_sav - priv->len; - v->buf = priv->buf - v->len; - if (tfsxml_has_value(v)) - { - *priv = priv_bak; - return -1; - } - if (is_first) - { - unset_flag(priv, 1); - tfsxml_leave(priv); + default: { } - return 0; - default:; } next_char(priv); } - - v->len = len_sav; - v->buf = priv->buf - v->len; - v->flags = 0; - if (tfsxml_has_value(v)) - { - *priv = priv_bak; - return -1; - } - return 0; + *priv = priv_bak; + return 1; } -int tfsxml_enter(tfsxml_string* priv) -{ - /* Exiting previous element header analysis if needed */ - if (get_flag(priv, 0) && tfsxml_leave_element_header(priv)) - return -1; +int tfsxml_enter(tfsxml_string* priv) { + /* Exiting previous element header if needed */ + if (get_is_in_element_header()) { + int result = tfsxml_leave_element_header(priv); + if (result) { + return result; + } + } /* Previous element must not be finished */ - if (get_flag(priv, 1)) + if (!get_previous_element_is_open()) { return -1; + } - set_flag(priv, 1); + unset_previous_element_is_open(); return 0; } -int tfsxml_leave(tfsxml_string* priv) -{ - int level; +int tfsxml_leave(tfsxml_string* priv) { + tfsxml_string priv_bak; + unsigned level; + + get_level(priv, &level); + level++; /* Exiting previous element header analysis if needed */ - if (get_flag(priv, 0) && tfsxml_leave_element_header(priv)) - return -1; + if (get_is_in_element_header()) { + int result = tfsxml_leave_element_header(priv); + if (result) { + get_level(priv, &level); + set_level(priv, level - 1); + return result; + } + if (get_previous_element_is_open()) { + level++; + } + } - level = get_flag(priv, 1) ? 1 : 0; - while (priv->len) - { - switch (*priv->buf) - { - case '<': - next_char(priv); - if (priv->len && *priv->buf == '/') - { - if (!level) - { - while (priv->len && *priv->buf != '>') - next_char(priv); - next_char(priv); - set_flag(priv, 1); - return 0; - } - level--; - if (priv->len) - next_char(priv); - break; - } - if (priv->len && *priv->buf == '?') - { - while (priv->len && *priv->buf != '>') - { - next_char(priv); + set_previous_element_is_open(); + priv_bak = *priv; + while (priv->len) { + switch (*priv->buf) { + case '<': { + priv_bak = *priv; + if (priv->len == 1) { + *priv = priv_bak; + set_level(priv, level - 1); + return 1; } - if (priv->len) - next_char(priv); - set_flag(priv, 1); - break; - } - if (priv->len && *priv->buf == '!') - { - unsigned long long probe = 0; - int i; - for (i = 1; i < 8; i++) - { - probe <<= 8; - probe |= priv->buf[i]; + if (priv->buf[1] == '/') { + while (priv->len && *priv->buf != '>') { + next_char(priv); + } + if (!priv->len) { + *priv = priv_bak; + set_level(priv, level - 1); + return 1; + } + level--; + if (!level) { + next_char(priv); + unset_previous_element_is_open(); + set_level(priv, 0); + return 0; + } + priv_bak = *priv; + break; } - if (probe == 0x5B43444154415BULL) /* "[CDATA[" */ - { - probe = 0; - priv->buf += 9; - priv->len -= 9; - while (priv->len) - { - probe &= 0xFFFF; - probe <<= 8; - probe |= *priv->buf; - if (probe == 0x5D5D3EULL) /* "]]>" */ - break; - priv->buf++; - priv->len--; + if (priv->buf[1] == '?') { + while (priv->len && *priv->buf != '>') { + next_char(priv); + } + if (!priv->len) { + *priv = priv_bak; + set_level(priv, level - 1); + return 1; } + unset_previous_element_is_open(); break; } - if (priv->len >= 3 && priv->buf[1] == '-' && priv->buf[2] == '-') - { - const char* buf = priv->buf + 3; - int len_sav = priv->len; - int len = priv->len - 3; - probe = 0; - while (len) - { - probe &= 0xFFFF; + if (priv->buf[1] == '!') { + unsigned long long probe = 0; + int i; + if (priv->len <= 8) { + *priv = priv_bak; + set_level(priv, level - 1); + return 1; + } + for (i = 2; i <= 8; i++) { probe <<= 8; - probe |= *buf; - if (probe == 0x2D2D3EULL) /* "-->" */ - break; - buf++; - len--; + probe |= priv->buf[i]; + } + if (probe == 0x5B43444154415BULL) { /* "buf += 9; + priv->len -= 9; + while (priv->len) { + probe &= 0xFFFF; + probe <<= 8; + probe |= *priv->buf; + if (probe == 0x5D5D3EULL) { /* "]]>" */ + break; + } + next_char(priv); + } + if (!priv->len) { + *priv = priv_bak; + set_level(priv, level - 1); + return 1; + } + break; } - len = len_sav - len; - priv->buf += len; - priv->len -= len; - if (priv->len) + if ((probe >> 40) == 0x2D2D) { /* "" */ + break; + next_char(priv); + } + if (!priv->len) { + *priv = priv_bak; + set_level(priv, level - 1); + return 1; + } + break; + } + while (priv->len && *priv->buf != '>') { next_char(priv); + } + if (!priv->len) { + *priv = priv_bak; + set_level(priv, level - 1); + return 1; + } + next_char(priv); break; } - while (priv->len && *priv->buf != '>') + for (;;) { + int split; + + if (!priv->len) { + *priv = priv_bak; + set_level(priv, level - 1); + return 1; + } + + split = 0; + switch (*priv->buf) { + case '\n': + case '\t': + case '\r': + case ' ': + case '/': + case '>': { + set_is_in_element_header(); + set_previous_element_is_open(); + split = 1; + break; + } + default: { + } + } + if (split) + break; next_char(priv); - next_char(priv); - break; - } - for (;;) - { - int split; - - if (!priv->len) - return -1; - - split = 0; - switch (*priv->buf) - { - case '\n': - case '\t': - case '\r': - case ' ': - case '/': - case '>': - set_flag(priv, 0); - unset_flag(priv, 1); - split = 1; - break; - default:; } - if (split) - break; - next_char(priv); + int result = tfsxml_leave_element_header(priv); + if (result) { + set_is_in_element_header(); + set_previous_element_is_open(); + set_level(priv, level - 1); + return result; + } + if (get_previous_element_is_open()) { + level++; + set_previous_element_is_open(); + } + continue; + } + default: { } - if (tfsxml_leave_element_header(priv)) - return -1; - if (!get_flag(priv, 1)) - level++; - break; - default:; - next_char(priv); } + next_char(priv); } - - set_flag(priv, 1); - set_flag(priv, 3); - return 0; + set_level(priv, level - 1); + return 1; } -static const char* const tfsxml_decode_markup[2] = -{ +static const char* const tfsxml_decode_markup[2] = { "amp\0apos\0gt\0lt\0quot", "&'><\"", }; -void tfsxml_decode(void* s, const tfsxml_string* v, void (*func)(void*, const char*, int)) -{ +void tfsxml_decode(void* s, const tfsxml_string* v, void (*func)(void*, const char*, unsigned)) { const char* buf_begin; const char* buf = v->buf; - int len = v->len; + unsigned len = v->len; - if (!(v->flags & 1)) - { + if (!(v->flags & 1)) { func(s, buf, len); return; } buf_begin = buf; - while (len) - { - if (*buf == '&') - { + while (len) { + if (*buf == '&') { const char* buf_end = buf; int len_end = len; - while (len_end && *buf_end != ';') - { + while (len_end && *buf_end != ';') { buf_end++; len_end--; } - if (len_end) - { + if (len_end) { const char* buf_beg = buf + 1; - int len_beg = buf_end - buf_beg; - if (len_beg && *buf_beg == '#') - { + unsigned len_beg = buf_end - buf_beg; + if (len_beg && *buf_beg == '#') { unsigned long value = 0; buf_beg++; len_beg--; - if (*buf_beg == 'x' || *buf_beg == 'X') - { + if (*buf_beg == 'x' || *buf_beg == 'X') { buf_beg++; len_beg--; - while (len_beg) - { + while (len_beg) { char c = *buf_beg++; len_beg--; value <<= 4; - if (value >= 0x110000) - { + if (value >= 0x110000) { value = -1; break; } @@ -687,58 +754,48 @@ void tfsxml_decode(void* s, const tfsxml_string* v, void (*func)(void*, const ch value |= c - ('A' - 10); else if (c >= 'a' && c <= 'f') value |= c - ('a' - 10); - else - { + else { value = -1; break; } } } - else - { - while (len_beg) - { + else { + while (len_beg) { char c = *buf_beg++; len_beg--; - if (c < '0' || c > '9') - { + if (c < '0' || c > '9') { value = -1; break; } value *= 10; value += c - '0'; - if (value >= 0x110000) - { + if (value >= 0x110000) { value = -1; break; } } } - if (value != (unsigned long)-1) - { + if (value != (unsigned long)-1) { char utf8[4]; func(s, buf_begin, buf - buf_begin); - if (value < 0x0080) - { + if (value < 0x0080) { utf8[0] = (char)value; func(s, utf8, 1); } - else if (value < 0x0800) - { + else if (value < 0x0800) { utf8[0] = 0xC0 | (char)(value >> 6); utf8[1] = 0x80 | (char)(value & 0x3F); func(s, utf8, 2); } - else if (value < 0x10000) - { + else if (value < 0x10000) { utf8[0] = 0xE0 | (char)((value >> 12)); utf8[1] = 0x80 | (char)((value >> 6) & 0x3F); utf8[2] = 0x80 | (char)((value & 0x3F)); func(s, utf8, 3); } - else if (value < 0x110000) - { + else if (value < 0x110000) { utf8[0] = 0xF0 | (char)((value >> 18)); utf8[1] = 0x80 | (char)((value >> 12) & 0x3F); utf8[2] = 0x80 | (char)((value >> 6) & 0x3F); @@ -751,26 +808,23 @@ void tfsxml_decode(void* s, const tfsxml_string* v, void (*func)(void*, const ch buf_begin = buf_end + 1; } } - else - { + else { const char* const buf_beg_sav = buf_beg; const char* replaced = tfsxml_decode_markup[0]; const char* replace_bys = tfsxml_decode_markup[1]; - for (;;) - { + for (;;) { char replace_by = *replace_bys++; - if (!replace_by) + if (!replace_by) { break; + } - while (*replaced) - { + while (*replaced) { if (buf_beg == buf_end || !*replaced || *replaced != *buf_beg) break; replaced++; buf_beg++; } - if (buf_beg == buf_end && !*replaced) - { + if (buf_beg == buf_end && !*replaced) { func(s, buf_begin, buf - buf_begin); func(s, &replace_by, 1); len -= buf_end - buf; @@ -779,13 +833,41 @@ void tfsxml_decode(void* s, const tfsxml_string* v, void (*func)(void*, const ch break; } buf_beg = buf_beg_sav; - while (*replaced) + while (*replaced) { replaced++; + } replaced++; } } } } + if (*buf == '<' && len > 8) { + unsigned long long probe = 0; + int i; + for (i = 1; i <= 8; i++) { + probe <<= 8; + probe |= buf[i]; + } + if (probe == 0x215B43444154415BULL) { /* "" */ + break; + } + buf++; + len--; + } + func(s, buf_begin, buf - 2 - buf_begin); + buf_begin = buf + 1; + } + } buf++; len--; } diff --git a/Source/ThirdParty/tfsxml/tfsxml.h b/Source/ThirdParty/tfsxml/tfsxml.h index 0ca54f3b..321f804d 100644 --- a/Source/ThirdParty/tfsxml/tfsxml.h +++ b/Source/ThirdParty/tfsxml/tfsxml.h @@ -1,3 +1,27 @@ +/* Copyright (c) MediaArea.net SARL + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +(MIT License) + +*/ + /* * Tiny Fast Streamable XML parser */ @@ -28,22 +52,22 @@ extern "C" * * @note after init, priv should not be directly used (data may be something else than a buf/len pair) */ - typedef struct tfsxml_string -{ +typedef struct tfsxml_string { const char* buf; - int len; - int flags; + unsigned len; + unsigned flags; } tfsxml_string; /** Initialize the parser * - * @param priv pointer to a tfsxml_string dedicated instance, private use by the parser - * @param buf pointer to start of the buffer - * @param len length of the buffer + * @param priv pointer to a tfsxml_string dedicated instance, private use by the parser + * @param buf pointer to start of the buffer + * @param len length of the buffer + * @param version API version supported by the client * * @note after init, priv should not be directly used (data may be something else than a buf/len pair) */ -int tfsxml_init(tfsxml_string* priv, const void* buf, int len); +int tfsxml_init(tfsxml_string* priv, const void* buf, unsigned len, unsigned version); /** Get next element or other content except an element value * @@ -52,6 +76,7 @@ int tfsxml_init(tfsxml_string* priv, const void* buf, int len); * * @return 0 if an element is available at the current level * -1 if no element is available at the current level + * 1 if need of more data */ int tfsxml_next(tfsxml_string* priv, tfsxml_string* n); @@ -63,6 +88,7 @@ int tfsxml_next(tfsxml_string* priv, tfsxml_string* n); * * @return 0 if an attribute is available for the current element * -1 if no more attribute is available for the current element + * 1 if need of more data */ int tfsxml_attr(tfsxml_string* priv, tfsxml_string* n, tfsxml_string* v); @@ -73,6 +99,7 @@ int tfsxml_attr(tfsxml_string* priv, tfsxml_string* n, tfsxml_string* v); * * @return 0 if a value is available for the current element * -1 if no value is available for the current element + * 1 if need of more data * * @note if this element has sub-elements, the whole content (all sub-elements) are provided */ @@ -84,6 +111,7 @@ int tfsxml_value(tfsxml_string* priv, tfsxml_string* v); * * @return 0 if it is possible to enter in an element * -1 if it is not possible to enter in an element + * 1 if need of more data */ int tfsxml_enter(tfsxml_string* priv); @@ -93,6 +121,7 @@ int tfsxml_enter(tfsxml_string* priv); * * @return 0 if it is possible to leave an element * -1 if it is not possible to leave an element + * 1 if need of more data */ int tfsxml_leave(tfsxml_string* priv); @@ -102,17 +131,17 @@ int tfsxml_leave(tfsxml_string* priv); /** Convert encoded XML block (attribute or value) to real content (encoded in UTF-8) * - * @param s opaque data transmitted to func - * @param b XML content to decode - * @param func function that will receive blocks of decoded content + * @param s opaque data transmitted to func + * @param v XML content to decode + * @param func append function that will receive blocks of decoded content * - * @param func_s s - * @param buf decoded content - * @param len length of the decoded content + * @param func_s string to append to + * @param func_buf decoded content + * @param func_len length of the decoded content * * @note see tfsxml_decode_string C++ function for an example of usage */ -void tfsxml_decode(void* s, const tfsxml_string* v, void (*func)(void* func_s, const char* func_buf, int func_len)); +void tfsxml_decode(void* s, const tfsxml_string* v, void (*func)(void* func_s, const char* func_buf, unsigned func_len)); /** ------------------------------------------------------------------------- Helper functions related to tfsxml_string @@ -127,6 +156,16 @@ void tfsxml_decode(void* s, const tfsxml_string* v, void (*func)(void* func_s, c */ int tfsxml_strcmp_charp(tfsxml_string a, const char* b); +/** Compare two strings + * + * @param a string to compare + * @param b string to compare + * @param n maximum number of characters to compare + * + * @note similar to C strncmp function + */ +int tfsxml_strncmp_charp(tfsxml_string a, const char* b, unsigned n); + /** Locate substring * * @param a string to be scanned @@ -141,7 +180,7 @@ tfsxml_string tfsxml_strstr_charp(tfsxml_string a, const char* b); #endif /* defined(__cplusplus) && !defined(TFSXML_NAMESPACE) */ #ifdef __cplusplus -static void tfsxml_decode_string(void* d, const char* buf, int len) { ((std::string*)d)->append(buf, len); } +static void tfsxml_decode_string(void* d, const char* buf, unsigned len) { ((std::string*)d)->append(buf, len); } /** Convert encoded XML block (attribute or value) to real content (encoded in UTF-8) *