/* ** OSSP xds - Extensible Data Serialization ** Copyright (c) 2001-2005 Ralf S. Engelschall ** Copyright (c) 2001-2005 The OSSP Project ** Copyright (c) 2001-2005 Cable & Wireless ** ** This file is part of OSSP xds, an extensible data serialization ** library which can be found at http://www.ossp.org/pkg/lib/xds/. ** ** Permission to use, copy, modify, and distribute this software for ** any purpose with or without fee is hereby granted, provided that ** the above copyright notice and this permission notice appear in all ** copies. ** ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ** SUCH DAMAGE. ** ** xds_engine_xml.c: XML encoding/decoding engine */ #include #include #include #include "xds.h" /* * Encode/decode XML document framework */ static const char xds_xml_begin_text[] = "\n" "\n" "\n"; static const char xds_xml_end_text[] = "\n"; int xml_encode_begin(xds_t *xds, void *engine_context, void *buffer, size_t buffer_size, size_t *used_buffer_size, va_list *args) { xds_init_encoding_engine(strlen(xds_xml_begin_text)); memmove(buffer, xds_xml_begin_text, strlen(xds_xml_begin_text)); return XDS_OK; } int xml_decode_begin(xds_t *xds, void *engine_context, void *buffer, size_t buffer_size, size_t *used_buffer_size, va_list *args) { xds_init_encoding_engine(strlen(xds_xml_begin_text)); if (strncasecmp(buffer, xds_xml_begin_text, strlen(xds_xml_begin_text)) != 0) return XDS_ERR_TYPE_MISMATCH; return XDS_OK; } int xml_encode_end(xds_t *xds, void *engine_context, void *buffer, size_t buffer_size, size_t *used_buffer_size, va_list *args) { xds_init_encoding_engine(strlen(xds_xml_end_text)); memmove(buffer, xds_xml_end_text, strlen(xds_xml_end_text)); return XDS_OK; } int xml_decode_end(xds_t *xds, void *engine_context, void *buffer, size_t buffer_size, size_t *used_buffer_size, va_list *args) { xds_init_decoding_engine(strlen(xds_xml_end_text)); if (strncasecmp(buffer, xds_xml_end_text, strlen(xds_xml_end_text)) != 0) return XDS_ERR_TYPE_MISMATCH; return XDS_OK; } /* * Encode/decode signed 32-bit integer values. */ int xml_encode_int32(xds_t *xds, void *engine_context, void *buffer, size_t buffer_size, size_t *used_buffer_size, va_list *args) { xds_int32_t value; char buf[32]; size_t i, j; char *p; int negative; xds_init_encoding_engine(7 + 8 + 11); /* Get the value and format it into our buffer. Keep track of the length of the formatted result. */ value = va_arg(*args, xds_int32_t); if (value < 0) { negative = XDS_TRUE; value = 0 - value; } else negative = XDS_FALSE; i = 0; do { unsigned char remainder = value % 10; value = value / 10; buf[i++] = '0' + remainder; } while (value != 0); if (negative) buf[i++] = '-'; /* Now that we know the correct size of our data's representation, write it into the buffer. */ *used_buffer_size = 7 + 8 + i; p = buffer; memmove(p, "", 7); p += 7; for (j = i; j > 0;) *p++ = buf[--j]; memmove(p, "", 8); return XDS_OK; } int xml_decode_int32(xds_t *xds, void *engine_context, void *buffer, size_t buffer_size, size_t *used_buffer_size, va_list *args) { xds_int32_t *value; char *p; int negative; xds_init_decoding_engine(7 + 8 + 1); /* Does the opening XML tag match? */ if (strncasecmp(buffer, "", 7) != 0) return XDS_ERR_TYPE_MISMATCH; /* Decode the representation of the value. */ value = va_arg(*args, xds_int32_t *); *value = 0; p = (char *)buffer + 7; if (*p == '-') { negative = XDS_TRUE; p++; } else negative = XDS_FALSE; while (isdigit((int)*p)) { if (p >= (char *)buffer + buffer_size) return XDS_ERR_UNDERFLOW; *value *= 10; *value += *p++ - '0'; } if (negative) *value = 0 - *value; /* Does the closing XML tag match? */ if (p + 8 > (char *)buffer + buffer_size) return XDS_ERR_UNDERFLOW; else if (strncasecmp(p, "", 8) != 0) return XDS_ERR_TYPE_MISMATCH; *used_buffer_size = p + 8 - (char *)buffer; return XDS_OK; } /* * Encode/decode unsigned 32-bit integer values. */ int xml_encode_uint32(xds_t *xds, void *engine_context, void *buffer, size_t buffer_size, size_t *used_buffer_size, va_list *args) { xds_uint32_t value; char buf[32]; size_t i, j; char *p; xds_init_encoding_engine(8 + 9 + 10); /* Format value into our buffer. */ value = va_arg(*args, xds_uint32_t); i = 0; do { unsigned char remainder = value % 10; value = value / 10; buf[i++] = '0' + remainder; } while (value != 0); /* Store the correct buffer size. */ *used_buffer_size = 8 + 9 + i; /* Write result into the buffer. */ p = buffer; memmove(p, "", 8); p += 8; for (j = i; j > 0;) *p++ = buf[--j]; memmove(p, "", 9); return XDS_OK; } int xml_decode_uint32(xds_t *xds, void *engine_context, void *buffer, size_t buffer_size, size_t *used_buffer_size, va_list *args) { xds_uint32_t *value; char *p; xds_init_decoding_engine(8 + 9 + 1); /* Does the opening XML tag match? */ if (strncasecmp(buffer, "", 8) != 0) return XDS_ERR_TYPE_MISMATCH; /* Decode the representation of the value. */ value = va_arg(*args, xds_uint32_t *); *value = 0; p = (char *)buffer + 8; while (isdigit((int)*p)) { if (p >= (char *)buffer + buffer_size) return XDS_ERR_UNDERFLOW; *value *= 10; *value += *p++ - '0'; } /* Does the closing XML tag match? */ if (p + 9 > (char *)buffer + buffer_size) return XDS_ERR_UNDERFLOW; else if (strncasecmp(p, "", 9) != 0) return XDS_ERR_TYPE_MISMATCH; *used_buffer_size = p + 9 - (char *)buffer; return XDS_OK; } #ifdef XDS_HAVE_64_BIT_SUPPORT /* * Encode/decode signed 64-bit integer values. */ int xml_encode_int64(xds_t *xds, void *engine_context, void *buffer, size_t buffer_size, size_t *used_buffer_size, va_list *args) { xds_int64_t value; char buf[64]; size_t i, j; char *p; int negative; xds_init_encoding_engine(7 + 8 + 21); /* Format value into our buffer. */ value = va_arg(*args, xds_int64_t); if (value < 0) { negative = XDS_TRUE; value = 0 - value; } else negative = XDS_FALSE; i = 0; do { unsigned char remainder = value % 10; value = value / 10; buf[i++] = '0' + remainder; } while (value != 0); if (negative) buf[i++] = '-'; /* Store the correct buffer size. */ *used_buffer_size = 7 + 8 + i; /* Write result into the buffer. */ p = buffer; memmove(p, "", 7); p += 7; for (j = i; j > 0;) *p++ = buf[--j]; memmove(p, "", 8); return XDS_OK; } int xml_decode_int64(xds_t *xds, void *engine_context, void *buffer, size_t buffer_size, size_t *used_buffer_size, va_list *args) { xds_int64_t *value; char *p; int negative; xds_init_decoding_engine(7 + 8 + 1); /* Does the opening XML tag match? */ if (strncasecmp(buffer, "", 7) != 0) return XDS_ERR_TYPE_MISMATCH; /* Decode the representation of the value. */ value = va_arg(*args, xds_int64_t *); *value = 0; p = (char *)buffer + 7; if (*p == '-') { negative = XDS_TRUE; p++; } else negative = XDS_FALSE; while (isdigit((int)*p)) { if (p >= (char *)buffer + buffer_size) return XDS_ERR_UNDERFLOW; *value *= 10; *value += *p++ - '0'; } if (negative) *value = 0 - *value; /* Does the closing XML tag match? */ if (p + 8 > (char *)buffer + buffer_size) return XDS_ERR_UNDERFLOW; else if (strncasecmp(p, "", 8) != 0) return XDS_ERR_TYPE_MISMATCH; *used_buffer_size = p + 8 - (char *)buffer; return XDS_OK; } /* * Encode/decode unsigned 64-bit integer values. */ int xml_encode_uint64(xds_t *xds, void *engine_context, void *buffer, size_t buffer_size, size_t *used_buffer_size, va_list *args) { xds_uint64_t value; char buf[64]; size_t i, j; char *p; xds_init_encoding_engine(8 + 9 + 20); /* Format value into our buffer. */ value = va_arg(*args, xds_uint64_t); i = 0; do { unsigned char remainder = value % 10; value = value / 10; buf[i++] = '0' + remainder; } while (value != 0); /* Store the correct buffer size. */ *used_buffer_size = 8 + 9 + i; /* Write result into the buffer. */ p = buffer; memmove(p, "", 8); p += 8; for (j = i; j > 0;) *p++ = buf[--j]; memmove(p, "", 9); return XDS_OK; } int xml_decode_uint64(xds_t *xds, void *engine_context, void *buffer, size_t buffer_size, size_t *used_buffer_size, va_list *args) { xds_uint64_t *value; char *p; xds_init_decoding_engine(8 + 9 + 1); /* Does the opening XML tag match? */ if (strncasecmp(buffer, "", 8) != 0) return XDS_ERR_TYPE_MISMATCH; /* Decode the representation of the value. */ value = va_arg(*args, xds_uint64_t *); *value = 0; p = (char *)buffer + 8; while (isdigit((int)*p)) { if (p >= (char *)buffer + buffer_size) return XDS_ERR_UNDERFLOW; *value *= 10; *value += *p++ - '0'; } /* Does the closing XML tag match? */ if (p + 9 > (char *)buffer + buffer_size) return XDS_ERR_UNDERFLOW; else if (strncasecmp(p, "", 9) != 0) return XDS_ERR_TYPE_MISMATCH; *used_buffer_size = p + 9 - (char *)buffer; return XDS_OK; } #endif /* XDS_HAVE_64_BIT_SUPPORT */ /* * Encode/decode floating point values. */ int xml_encode_float(xds_t *xds, void *engine_context, void *buffer, size_t buffer_size, size_t *used_buffer_size, va_list *args) { xds_init_encoding_engine(7 + 8 + 1); *used_buffer_size = snprintf(buffer, buffer_size, "%f", va_arg(*args, double)); if (*used_buffer_size >= buffer_size) return XDS_ERR_OVERFLOW; else return XDS_OK; } int xml_decode_float(xds_t *xds, void *engine_context, void *buffer, size_t buffer_size, size_t *used_buffer_size, va_list *args) { int size; xds_init_decoding_engine(7 + 8 + 1); if (sscanf(buffer, "%f%n", va_arg(*args, float*), &size) != 1) return XDS_ERR_TYPE_MISMATCH; else { *used_buffer_size = size; return XDS_OK; } } /* * Encode/decode double-precision floating point values. */ int xml_encode_double(xds_t *xds, void *engine_context, void *buffer, size_t buffer_size, size_t *used_buffer_size, va_list *args) { xds_init_encoding_engine(8 + 9 + 1); *used_buffer_size = snprintf(buffer, buffer_size, "%f", va_arg(*args, double)); if (*used_buffer_size >= buffer_size) return XDS_ERR_OVERFLOW; else return XDS_OK; } int xml_decode_double(xds_t *xds, void *engine_context, void *buffer, size_t buffer_size, size_t *used_buffer_size, va_list *args) { int size; xds_init_decoding_engine(8 + 9 + 1); if (sscanf(buffer, "%lf%n", va_arg(*args, double*), &size) != 1) return XDS_ERR_TYPE_MISMATCH; else { *used_buffer_size = size; return XDS_OK; } } /* * Encode/decode NUL-terminated character strings. */ #define bits(c) (0x80 | ((c) & 0x3F)) #define put(c) *strptr++ = (c); #define putbits(c) put(bits(c)) #define finish() *strptr = '\0' static char *sputu8(xds_uint32_t c, char *strptr) { if (strptr == NULL) return NULL; if (c < 0x80) { put(c); finish(); } else if (c < 0x800) { put(0xC0 | (c >> 6)); putbits(c); finish(); } else if (c < 0x10000) { put(0xE0 | (c >> 12)); putbits(c >> 6); putbits(c); finish(); } else if (c < 0x200000) { put(0xF0 | (c >> 18)); putbits(c >> 12); putbits(c >> 6); putbits(c); finish(); } else if (c < 0x400000) { put(0xF8 | (c >> 24)); putbits(c >> 18); putbits(c >> 12); putbits(c >> 6); putbits(c); finish(); } else if (c < 0x80000000) { put(0xFC | (c >> 30)); putbits(c >> 24); putbits(c >> 18); putbits(c >> 12); putbits(c >> 6); putbits(c); finish(); } else finish(); /* Not a valid Unicode "character" */ return strptr; } static const char TAG_OPEN[] = ""; static const char TAG_CLOSE[] = ""; static const size_t TAG_OPEN_LEN = sizeof (TAG_OPEN) - 1; static const size_t TAG_CLOSE_LEN = sizeof (TAG_CLOSE) - 1; int xml_encode_string(xds_t *xds, void *engine_context, void *buffer, size_t buffer_size, size_t *used_buffer_size, va_list *args) { char *src; size_t src_len; char *dst; size_t dst_size; char *tmp; /* Setup the engine. We need at least space for our tags; how long the actual content is going to be will be seen soon. */ xds_init_encoding_engine(TAG_OPEN_LEN + TAG_CLOSE_LEN); /* Get the data from the stack. */ src = va_arg(*args, char *); xds_check_parameter(src != NULL); src_len = strlen(src); /* Set up the target buffer. */ dst = buffer; dst_size = buffer_size; /* Write the opening tag. */ memmove(dst, TAG_OPEN, TAG_OPEN_LEN); dst += TAG_OPEN_LEN; dst_size -= TAG_OPEN_LEN; /* Format the data into the buffer. */ while (src_len > 0 && dst_size > 0) { if (*((xds_uint8_t *) src) >= 0x80) { /* UTF-8ify it. */ if (dst_size >= 7) { tmp = sputu8((xds_uint32_t) * ((xds_uint8_t *) src), dst); src++; src_len--; dst_size -= tmp - dst; dst = tmp; } else dst_size = 0; } else if (*src == '<') { /* Turn into "<". */ if (dst_size >= 4) { *dst++ = '&'; dst_size--; *dst++ = 'l'; dst_size--; *dst++ = 't'; dst_size--; *dst++ = ';'; dst_size--; src++; src_len--; } else dst_size = 0; } else if (*src == '&') { /* Turn into "&". */ if (dst_size >= 5) { *dst++ = '&'; dst_size--; *dst++ = 'a'; dst_size--; *dst++ = 'm'; dst_size--; *dst++ = 'p'; dst_size--; *dst++ = ';'; dst_size--; src++; src_len--; } else dst_size = 0; } else if (*src == '>') { /* Turn into ">". */ if (dst_size >= 4) { *dst++ = '&'; dst_size--; *dst++ = 'g'; dst_size--; *dst++ = 't'; dst_size--; *dst++ = ';'; dst_size--; src++; src_len--; } else dst_size = 0; } else { /* No special character; just copy it. */ *dst++ = *src++; src_len--; dst_size--; } } if (src_len > 0) { /* Target buffer was too small. */ *used_buffer_size = buffer_size + 1; return XDS_ERR_OVERFLOW; } /* Write the closing tag. */ memmove(dst, TAG_CLOSE, TAG_CLOSE_LEN); dst += TAG_CLOSE_LEN; dst_size -= TAG_CLOSE_LEN; *used_buffer_size = dst - (char *)buffer; return XDS_OK; } #define INVALID \ 0x80000000 #define get(c) \ c = *strptr++; \ if (chars) \ (*chars)++; \ if ((c) == 0) \ return (unsigned int)EOF static unsigned int sgetu8(unsigned char *strptr, int *chars) { unsigned int c; int i, iterations; unsigned char ch; if (chars) *chars = 0; if (strptr == NULL) return (unsigned int)EOF; get(c); if ((c & 0xFE) == 0xFC) { c &= 0x01; iterations = 5; } else if ((c & 0xFC) == 0xF8) { c &= 0x03; iterations = 4; } else if ((c & 0xF8) == 0xF0) { c &= 0x07; iterations = 3; } else if ((c & 0xF0) == 0xE0) { c &= 0x0F; iterations = 2; } else if ((c & 0xE0) == 0xC0) { c &= 0x1F; iterations = 1; } else if ((c & 0x80) == 0x80) return INVALID; else return c; for (i = 0; i < iterations; i++) { get(ch); if ((ch & 0xC0) != 0x80) return INVALID; c <<= 6; c |= ch & 0x3F; } return c; } int xml_decode_string(xds_t *xds, void *engine_context, void *buffer, size_t buffer_size, size_t *used_buffer_size, va_list *args) { char **target_buffer; char *src; size_t src_len; char *dst; int utf8_len; unsigned int rc; /* Setup the engine. We need at least space for our tags; how long the actual content is going to be will be seen soon. */ xds_init_encoding_engine(TAG_OPEN_LEN + TAG_CLOSE_LEN); /* Is the opening tag there? */ if (strncasecmp(buffer, TAG_OPEN, TAG_OPEN_LEN) != 0) return XDS_ERR_TYPE_MISMATCH; /* Determine the length of the encoded data. */ src = (char *)buffer + TAG_OPEN_LEN; for (src_len = 0; src[src_len] != '<'; ++src_len) if (src[src_len] == '\0') return XDS_ERR_TYPE_MISMATCH; /* Check the closing tag. */ if (strncasecmp(src + src_len, TAG_CLOSE, TAG_CLOSE_LEN) != 0) return XDS_ERR_TYPE_MISMATCH; *used_buffer_size = TAG_OPEN_LEN + src_len + TAG_CLOSE_LEN; /* Allocate target buffer. */ target_buffer = va_arg(*args, char **); xds_check_parameter(target_buffer != NULL); *target_buffer = dst = malloc(src_len + 1); if (dst == NULL) return XDS_ERR_NO_MEM; /* Decode the data into the target buffer. */ while (src_len > 0) { if (*src == '&') { if (src_len >= 4 && strncmp(src, "<", 4) == 0) { *dst++ = '<'; src += 4; src_len -= 4; } else if (src_len >= 4 && strncmp(src, ">", 4) == 0) { *dst++ = '>'; src += 4; src_len -= 4; } else if (src_len >= 5 && strncmp(src, "&", 5) == 0) { *dst++ = '&'; src += 5; src_len -= 5; } else { free(dst); return XDS_ERR_TYPE_MISMATCH; } } else if (*((xds_uint8_t *) src) >= 0x80) { rc = sgetu8((xds_uint8_t *)src, &utf8_len); if (rc == (unsigned int)EOF) return XDS_ERR_UNDERFLOW; else if (rc == INVALID || rc > 255) return XDS_ERR_TYPE_MISMATCH; *dst++ = (xds_uint8_t)rc; src += utf8_len; src_len -= utf8_len; } else { *dst++ = *src++; src_len--; } } *dst = '\0'; return XDS_OK; } /* * Encode/decode octet streams. */ static const char xds_base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char xds_pad64 = '='; static int base64_encode(char *dst, size_t dstlen, unsigned char const *src, size_t srclen) { size_t dstpos; unsigned char input[3]; unsigned char output[4]; int ocnt; size_t i; if (srclen == 0) return 0; if (dst == NULL) { /* just calculate required length of dst */ dstlen = (((srclen + 2) / 3) * 4); return dstlen; } /* bulk encoding */ dstpos = 0; ocnt = 0; while (srclen >= 3) { input[0] = *src++; input[1] = *src++; input[2] = *src++; srclen -= 3; output[0] = ( input[0] >> 2); output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); output[3] = ( input[2] & 0x3f); if (dstpos + 4 > dstlen) return -1; dst[dstpos++] = xds_base64[output[0]]; dst[dstpos++] = xds_base64[output[1]]; dst[dstpos++] = xds_base64[output[2]]; dst[dstpos++] = xds_base64[output[3]]; } /* now worry about padding with remaining 1 or 2 bytes */ if (srclen != 0) { input[0] = input[1] = input[2] = '\0'; for (i = 0; i < srclen; i++) input[i] = *src++; output[0] = ( input[0] >> 2); output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); if (dstpos + 4 > dstlen) return -1; dst[dstpos++] = xds_base64[output[0]]; dst[dstpos++] = xds_base64[output[1]]; if (srclen == 1) dst[dstpos++] = xds_pad64; else dst[dstpos++] = xds_base64[output[2]]; dst[dstpos++] = xds_pad64; } if (dstpos >= dstlen) return -1; dst[dstpos] = '\0'; return dstpos; } int xml_encode_octetstream(xds_t *xds, void *engine_context, void *buffer, size_t buffer_size, size_t *used_buffer_size, va_list *args) { xds_uint8_t *src; size_t src_len; /* We need at least 27 byte for the starting and ending tag. */ xds_init_encoding_engine(13 + 14); /* Get parameters from stack. */ src = (xds_uint8_t *)va_arg(*args, void *); xds_check_parameter(src != NULL); src_len = va_arg(*args, size_t); /* Calculate how many bytes we'll need in buffer and make sure we have them. */ *used_buffer_size = base64_encode(NULL, 0, src, src_len); if (*used_buffer_size == (size_t) - 1) return XDS_ERR_UNKNOWN; else *used_buffer_size += 13 + 14; if (buffer_size < *used_buffer_size) return XDS_ERR_OVERFLOW; /* Format the data into the buffer. */ memmove(buffer, "", 13); if (base64_encode((char *)buffer + 13, buffer_size - 13, src, src_len) < 0) return XDS_ERR_UNKNOWN; memmove((char *)buffer + *used_buffer_size - 14, "", 14); /* Done. */ return XDS_OK; } static int base64_decode(unsigned char *dst, size_t dstlen, char const *src, size_t srclen) { int dstidx, state, ch = 0; unsigned char res; char *pos; if (srclen == 0) return 0; state = 0; dstidx = 0; res = 0; while (srclen-- > 0) { ch = *src++; if (isascii(ch) && isspace(ch)) /* Skip whitespace anywhere */ continue; if (ch == xds_pad64) break; pos = strchr(xds_base64, ch); if (pos == 0) /* A non-base64 character */ return -1; switch (state) { case 0: if (dst != NULL) { if ((size_t) dstidx >= dstlen) return -1; dst[dstidx] = ((pos - xds_base64) << 2); } state = 1; break; case 1: if (dst != NULL) { if ((size_t) dstidx >= dstlen) return -1; dst[dstidx] |= ((pos - xds_base64) >> 4); res = (((pos - xds_base64) & 0x0f) << 4); } dstidx++; state = 2; break; case 2: if (dst != NULL) { if ((size_t) dstidx >= dstlen) return -1; dst[dstidx] = res | ((pos - xds_base64) >> 2); res = ((pos - xds_base64) & 0x03) << 6; } dstidx++; state = 3; break; case 3: if (dst != NULL) { if ((size_t) dstidx >= dstlen) return -1; dst[dstidx] = res | (pos - xds_base64); } dstidx++; state = 0; break; default: break; } } /* * We are done decoding Base-64 chars. Let's see if we ended * on a byte boundary, and/or with erroneous trailing characters. */ if (ch == xds_pad64) { /* We got a pad char. */ switch (state) { case 0: /* Invalid = in first position */ case 1: /* Invalid = in second position */ return -1; case 2: /* Valid, means one byte of info */ /* Skip any number of spaces. */ while (srclen > 0) { ch = *src++; --srclen; if (!(isascii(ch) && isspace(ch))) break; } /* Make sure there is another trailing = sign. */ if (ch != xds_pad64) return -1; /* FALLTHROUGH */ case 3: /* Valid, means two bytes of info */ /* * We know this char is an =. Is there anything but * whitespace after it? */ while (srclen > 0) { ch = *src++; --srclen; if (!(isascii(ch) && isspace(ch))) return -1; } /* * Now make sure for cases 2 and 3 that the "extra" * bits that slopped past the last full byte were * zeros. If we don't check them, they become a * subliminal channel. */ if (dst != NULL && res != 0) return -1; default: break; } } else { /* * We ended by seeing the end of the string. Make sure we * have no partial bytes lying around. */ if (state != 0) return -1; } return dstidx; } int xml_decode_octetstream(xds_t *xds, void *engine_context, void *buffer, size_t buffer_size, size_t *used_buffer_size, va_list *args) { char *p; size_t p_len; xds_uint8_t **data; size_t *data_len; /* We need at least 27 byte for the starting and ending tag. */ xds_init_encoding_engine(13 + 14); /* Get parameters from stack. */ data = va_arg(*args, xds_uint8_t **); xds_check_parameter(data != NULL); data_len = va_arg(*args, size_t *); /* Check for the opening tag. */ if (memcmp("", buffer, 13) != 0) return XDS_ERR_TYPE_MISMATCH; /* Find the end of the data and calculate the length of the base64-encoded stuff. */ p = (char *)buffer + 13; while (p < ((char *)buffer + buffer_size) && *p != '<') ++p; if (p == ((char *)buffer + buffer_size)) return XDS_ERR_TYPE_MISMATCH; else { p_len = p - ((char *)buffer + 13); p = (char *)buffer + 13; } /* Now find out how long the decoded data is going to be, allocate a buffer for it, and decode away. */ *data_len = base64_decode(NULL, 0, p, p_len); if (*data_len == (size_t) - 1) return XDS_ERR_UNKNOWN; *data = malloc(*data_len); if (*data == NULL) return XDS_ERR_NO_MEM; base64_decode(*data, *data_len, p, p_len); /* Check that we have a closing tag. */ if (memcmp(p + p_len, "", 14) != 0) { free(*data); return XDS_ERR_TYPE_MISMATCH; } *used_buffer_size = 13 + p_len + 14; return XDS_OK; }