/* Return > 0 Total packet length.in bytes * = 0 Length unknown, need more data. * < 0 Error, invalid format. */ int packet_get_length(enum PacketParseType htype, const char* ptr, unsigned n, /* Bytes read so far */ unsigned max_plen, /* Max packet length, 0=no limit */ unsigned trunc_len, /* Truncate (lines) if longer, 0=no limit */ int* statep) /* Protocol specific state */ { unsigned hlen, plen; switch (htype) { case TCP_PB_RAW: if (n == 0) goto more; else { DEBUGF((" => nothing remain packet=%d\r\n", n)); return n; } case TCP_PB_1: /* TCP_PB_1: [L0 | Data] */ hlen = 1; if (n < hlen) goto more; plen = get_int8(ptr); goto remain; case TCP_PB_2: /* TCP_PB_2: [L1,L0 | Data] */ hlen = 2; if (n < hlen) goto more; plen = get_int16(ptr); goto remain; case TCP_PB_4: /* TCP_PB_4: [L3,L2,L1,L0 | Data] */ hlen = 4; if (n < hlen) goto more; plen = get_int32(ptr); goto remain; case TCP_PB_RM: /* TCP_PB_RM: [L3,L2,L1,L0 | Data] ** where MSB (bit) is used to signal end of record */ hlen = 4; if (n < hlen) goto more; plen = get_int32(ptr) & 0x7fffffff; goto remain; case TCP_PB_LINE_LF: { /* TCP_PB_LINE_LF: [Data ... \n] */ const char* ptr2; if ((ptr2 = memchr(ptr, '\n', n)) == NULL) { if (n > max_plen && max_plen != 0) { /* packet full */ DEBUGF((" => packet full (no NL)=%d\r\n", n)); goto error; } else if (n >= trunc_len && trunc_len!=0) { /* buffer full */ DEBUGF((" => line buffer full (no NL)=%d\r\n", n)); return trunc_len; } goto more; } else { int len = (ptr2 - ptr) + 1; /* including newline */ if (len > max_plen && max_plen!=0) { DEBUGF((" => packet_size %d exceeded\r\n", max_plen)); goto error; } if (len > trunc_len && trunc_len!=0) { DEBUGF((" => truncated line=%d\r\n", trunc_len)); return trunc_len; } DEBUGF((" => nothing remain packet=%d\r\n", len)); return len; } } case TCP_PB_ASN1: { /* TCP_PB_ASN1: handles long (4 bytes) or short length format */ const char* tptr = ptr; int length; int nn = n; if (n < 2) goto more; nn--; if ((*tptr++ & 0x1f) == 0x1f) { /* Long tag format */ while (nn && ((*tptr & 0x80) == 0x80)) { tptr++; nn--; } if (nn < 2) goto more; tptr++; nn--; } /* tptr now point to length field and nn characters remain */ length = *tptr & 0x7f; if ((*tptr & 0x80) == 0x80) { /* Long length format */ tptr++; nn--; if (nn < length) goto more; switch (length) { case 0: plen = 0; break; case 1: plen = get_int8(tptr); tptr += 1; break; case 2: plen = get_int16(tptr); tptr += 2; break; case 3: plen = get_int24(tptr); tptr += 3; break; case 4: plen = get_int32(tptr); tptr += 4; break; default: goto error; /* error */ } } else { tptr++; plen = length; } hlen = (tptr-ptr); goto remain; } case TCP_PB_CDR: { const struct cdr_head* hp; hlen = sizeof(struct cdr_head); if (n < hlen) goto more; hp = (struct cdr_head*) ptr; if (sys_memcmp(hp->magic, CDR_MAGIC, 4) != 0) goto error; if (hp->flags & 0x01) /* Byte ordering flag */ plen = get_little_int32(hp->message_size); else plen = get_int32(hp->message_size); goto remain; } case TCP_PB_FCGI: { const struct fcgi_head* hp; hlen = sizeof(struct fcgi_head); if (n < hlen) goto more; hp = (struct fcgi_head*) ptr; if (hp->version != FCGI_VERSION_1) goto error; plen = ((hp->contentLengthB1 << 8) | hp->contentLengthB0) + hp->paddingLength; goto remain; } case TCP_PB_HTTPH: case TCP_PB_HTTPH_BIN: *statep = !0; case TCP_PB_HTTP: case TCP_PB_HTTP_BIN: /* TCP_PB_HTTP: data \r\n(SP data\r\n)* */ plen = n; if (((plen == 1) && NL(ptr)) || ((plen == 2) && CRNL(ptr))) goto done; else { const char* ptr1 = ptr; int len = plen; if (!max_plen) { /* This is for backward compatibility with old user of decode_packet * that might use option 'line_length' to limit accepted length of * http lines. */ max_plen = trunc_len; } while (1) { const char* ptr2 = memchr(ptr1, '\n', len); if (ptr2 == NULL) { if (max_plen != 0) { if (n >= max_plen) /* packet full */ goto error; } goto more; } else { plen = (ptr2 - ptr) + 1; if (*statep == 0) { if (max_plen != 0 && plen > max_plen) goto error; goto done; } if (plen < n) { if (SP(ptr2+1) && plen>2) { /* header field value continue on next line */ ptr1 = ptr2+1; len = n - plen; } else { if (max_plen != 0 && plen > max_plen) goto error; goto done; } } else { if (max_plen != 0 && plen > max_plen) goto error; goto more; } } } } case TCP_PB_TPKT: { const struct tpkt_head* hp; hlen = sizeof(struct tpkt_head); if (n < hlen) goto more; hp = (struct tpkt_head*) ptr; if (hp->vrsn == TPKT_VRSN) { plen = get_int16(hp->packet_length) - hlen; } else { goto error; } goto remain; } case TCP_PB_SSL_TLS: hlen = 5; if (n < hlen) goto more; if ((ptr[0] & 0x80) && ptr[2] == 1) { /* Ssl-v2 Client hello <<1:1, Len:15, 1:8, Version:16>> */ plen = (get_int16(&ptr[0]) & 0x7fff) - 3; } else { /* <<ContentType:8, Version:16, Length:16>> */ plen = get_int16(&ptr[3]); } goto remain; default: DEBUGF((" => case error\r\n")); return -1; } more: return 0; remain: { int tlen = hlen + plen; if ((max_plen != 0 && plen > max_plen) || tlen < (int)hlen) { /* wrap-around protection */ return -1; } return tlen; } done: return plen; error: return -1; }
static int decode_data(double **data, const xmlChar * input, dataFormat data_format, codingTypes coding, byteOrder byte_order, int max_input_len) { GArray *data_stream, *debase64_buf, *decoded_data; char *p, *end_ptr; unsigned int i; double val; int data_count = 0; gwy_debug("start."); if (input == NULL) { g_warning("SPML: decode_data(): NULL input"); *data = NULL; return 0; } switch (coding) { case ZLIB_COMPR_BASE64: /*/ XXX: strlen() may not be nice there */ if (decode_b64((char *)input, &debase64_buf, strlen(input)) != 0) { if (debase64_buf != NULL) { g_array_free(debase64_buf, TRUE); } g_warning("Cannot decode data in BASE64 code."); *data = NULL; return 0; } if (inflate_dynamic_array(debase64_buf, &data_stream) != 0) { g_warning("Cannot inflate compressed data."); g_array_free(debase64_buf, TRUE); if (data_stream != NULL) { g_array_free(data_stream, TRUE); } *data = NULL; return 0; } g_array_free(debase64_buf, TRUE); break; case BASE64: /*/ XXX: strlen() may not be nice there */ if (decode_b64((char *)input, &data_stream, strlen(input)) != 0) { g_warning("Cannot decode data in BASE64 code."); if (data_stream != NULL) { g_array_free(data_stream, TRUE); } *data = NULL; return 0; } break; case ASCII: p = (char *)input; data_stream = g_array_new(FALSE, FALSE, sizeof(double)); while (p != NULL) { double num; if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') { p++; continue; } num = g_ascii_strtod(p, &end_ptr); if (num == 0 && end_ptr == p) { g_warning("SPML: decode_data(): No conversion performed " "from ASCII string."); break; } g_array_append_val(data_stream, num); p = end_ptr; data_count++; } break; /*/ TODO: */ case HEX: case BINARY: g_warning("SPML: decode_data(): Data coding 'HEX' and 'BINARY' " "not supported."); break; case UNKNOWN_CODING: break; } if (coding == ASCII) { /* we have already decoded data */ if (max_input_len != -1 && data_count != max_input_len) { /* not enough input data to fill array defined by length * max_input_len */ g_warning("SPML: decode_data():\n" "Input has not the same length as declared in " "dimensions\n" "(max:%d vs read:%d). Has the channel attribute\n" "'channelReadMethodName'? The channel may be one\n" "dimensional data used for axis values but not as\n" "a source of data for Gwyddion.", max_input_len, data_count); g_array_free(data_stream, TRUE); *data = NULL; return 0; } else { *data = (double *)data_stream->data; /* we can free dynamic array, but not */ g_array_free(data_stream, FALSE); /* containing data. */ gwy_debug("Datacount: %d", data_count); return data_count; } } decoded_data = g_array_new(FALSE, FALSE, sizeof(double)); p = data_stream->data; i = 0; switch (data_format) { case FLOAT32: while (i < data_stream->len) { val = get_float32(&p, byte_order); g_array_append_val(decoded_data, val); data_count++; i += sizeof(float); } break; case FLOAT64: while (i < data_stream->len) { val = get_float64(&p, byte_order); g_array_append_val(decoded_data, val); i += sizeof(double); } break; case INT8: while (i < data_stream->len) { val = get_int8(&p); g_array_append_val(decoded_data, val); i += sizeof(gint8); } break; case INT16: while (i < data_stream->len) { val = get_int16(&p, byte_order); g_array_append_val(decoded_data, val); i += sizeof(gint16); } break; case INT32: while (i < data_stream->len) { val = get_int32(&p, byte_order); g_array_append_val(decoded_data, val); i += sizeof(gint32); } break; case UINT32: while (i < data_stream->len) { val = get_uint32(&p, byte_order); g_array_append_val(decoded_data, val); i += sizeof(guint32); } break; case UINT8: while (i < data_stream->len) { val = get_uint8(&p); g_array_append_val(decoded_data, val); i += sizeof(guint8); } break; case UINT16: while (i < data_stream->len) { val = get_uint16(&p, byte_order); g_array_append_val(decoded_data, val); i += sizeof(guint16); } break; case STRING: g_warning ("SPML: decode_data(): Data format 'String' not supported."); break; case UNKNOWN_DATAFORMAT: g_warning("SPML: decode_data(): Unknown dataformat."); break; } g_array_free(data_stream, TRUE); data_count = decoded_data->len; if (max_input_len != -1 && data_count != max_input_len) { g_warning("SPML: decode_data():\n" "Input has not the same length as declared in dimensions\n" "(max:%d vs read:%d). Has the channel attribute\n" "'channelReadMethodName'? The channel may be one\n" "dimensional data used for axis values but not as\n" "a source of data for Gwyddion.", max_input_len, data_count); g_array_free(decoded_data, TRUE); *data = NULL; return 0; } *data = (double *)decoded_data->data; g_array_free(decoded_data, FALSE); /* we can free dynamic array, but not */ /* containing data. */ gwy_debug("Datacount: %d", data_count); return data_count; }