/*
* ndpi_serializer.c
*
* Copyright (C) 2011-23 - ntop.org and contributors
*
* nDPI is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* nDPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with nDPI. If not, see .
*
*/
#include
#include
#include
#include
#include "ndpi_api.h"
#include "ndpi_config.h"
#include
#ifndef WIN32
#include
#endif
#if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__
#include
#endif
#ifdef WIN32
#define NDPI_I64_FORMAT "%I64d"
#define NDPI_U64_FORMAT "%I64u"
#else
#define NDPI_I64_FORMAT "%lld"
#define NDPI_U64_FORMAT "%llu"
#endif
#define OPTIMIZE_NUMERIC_KEYS /* Convert numeric string keys into int keys */
#define OPTIMIZE_CSV_SERIALIZATION /* Optimize serialization speed in case of CSV */
/* ********************************** */
u_int64_t ndpi_htonll(u_int64_t v) {
union { u_int32_t lv[2]; u_int64_t llv; } u;
u.lv[0] = htonl(v >> 32);
u.lv[1] = htonl(v & 0xFFFFFFFFULL);
return(u.llv);
}
/* ********************************** */
u_int64_t ndpi_ntohll(u_int64_t v) {
union { u_int32_t lv[2]; u_int64_t llv; } u;
u.llv = v;
return((u_int64_t)ntohl(u.lv[0]) << 32) | (u_int64_t)ntohl(u.lv[1]);
}
/* ********************************** */
#ifdef OPTIMIZE_NUMERIC_KEYS
static int ndpi_is_number(const char *str, u_int32_t str_len) {
unsigned int i;
for(i = 0; i < str_len; i++)
if(!ndpi_isdigit(str[i])) return(0);
return(1);
}
#endif
/* ********************************** */
/*
* Escapes a string to be suitable for a JSON value, adding double quotes, and terminating the string with a null byte.
* It is recommended to provide a destination buffer (dst) which is as large as double the source buffer (src) at least.
* Upon successful return, these functions return the number of characters printed (excluding the null byte used to terminate the string).
*/
int ndpi_json_string_escape(const char *src, int src_len, char *dst, int dst_max_len) {
char c = 0;
int i, j = 0;
dst[j++] = '"';
for(i = 0; i < src_len && j < dst_max_len; i++) {
c = src[i];
switch (c) {
case '\\':
case '"':
case '/':
dst[j++] = '\\';
dst[j++] = c;
break;
case '\b':
dst[j++] = '\\';
dst[j++] = 'b';
break;
case '\t':
dst[j++] = '\\';
dst[j++] = 't';
break;
case '\n':
dst[j++] = '\\';
dst[j++] = 'n';
break;
case '\f':
dst[j++] = '\\';
dst[j++] = 'f';
break;
case '\r':
dst[j++] = '\\';
dst[j++] = 'r';
break;
default:
if(c < ' ')
; /* non printable */
else
dst[j++] = c;
}
}
dst[j++] = '"';
dst[j+1] = '\0';
return(j);
}
/* ********************************** */
void ndpi_reset_serializer(ndpi_serializer *_serializer) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
serializer->status.flags = 0;
if(serializer->fmt == ndpi_serialization_format_json) {
u_int32_t buff_diff;
serializer->status.buffer.size_used = 0;
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
if (!serializer->multiline_json_array) {
/* Note: please keep a space at the beginning as it is used for arrays when an end-of-record is used */
serializer->buffer.data[serializer->status.buffer.size_used++] = ' ';
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if (!serializer->inner_json) {
serializer->status.buffer.size_used += ndpi_snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, "{}");
}
} else if(serializer->fmt == ndpi_serialization_format_csv) {
serializer->status.header.size_used = 0;
serializer->status.buffer.size_used = 0;
} else { /* ndpi_serialization_format_tlv */
serializer->status.buffer.size_used = 2 * sizeof(u_int8_t);
}
}
/* ********************************** */
void ndpi_serializer_skip_header(ndpi_serializer *_serializer) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
serializer->status.flags |= NDPI_SERIALIZER_STATUS_HDR_DONE;
}
/* ********************************** */
static int ndpi_init_serializer_buffer(ndpi_private_serializer_buffer *buffer, u_int32_t buffer_size) {
buffer->initial_size = buffer->size = buffer_size;
buffer->data = (u_int8_t *)ndpi_calloc(buffer->size, sizeof(u_int8_t));
if(buffer->data == NULL)
return(-1);
return(0);
}
/* ********************************** */
int ndpi_init_serializer_ll(ndpi_serializer *_serializer,
ndpi_serialization_format fmt,
u_int32_t buffer_size) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
memset(serializer, 0, sizeof(ndpi_private_serializer));
if (fmt == ndpi_serialization_format_multiline_json) {
fmt = ndpi_serialization_format_json;
serializer->multiline_json_array = 1;
} else if (fmt == ndpi_serialization_format_inner_json) {
fmt = ndpi_serialization_format_json;
serializer->inner_json = 1;
}
serializer->fmt = fmt;
if (buffer_size < 3 ||
ndpi_init_serializer_buffer(&serializer->buffer, buffer_size) != 0)
return(-1);
if(serializer->fmt == ndpi_serialization_format_json) {
/* nothing to do */
} else if (fmt == ndpi_serialization_format_csv) {
if (ndpi_init_serializer_buffer(&serializer->header, NDPI_SERIALIZER_DEFAULT_HEADER_SIZE) != 0) {
ndpi_term_serializer(_serializer);
return(-1);
}
} else /* ndpi_serialization_format_tlv */ {
serializer->buffer.data[0] = 1; /* version */
serializer->buffer.data[1] = (u_int8_t) fmt;
}
serializer->csv_separator[0] = ',';
serializer->csv_separator[1] = '\0';
ndpi_reset_serializer(_serializer);
return(0);
}
/* ********************************** */
int ndpi_init_serializer(ndpi_serializer *_serializer,
ndpi_serialization_format fmt) {
return(ndpi_init_serializer_ll(_serializer, fmt, NDPI_SERIALIZER_DEFAULT_BUFFER_SIZE));
}
/* ********************************** */
static inline int ndpi_extend_serializer_buffer(ndpi_private_serializer_buffer *buffer, u_int32_t min_len) {
u_int32_t new_size;
void *r;
if(min_len < NDPI_SERIALIZER_DEFAULT_BUFFER_INCR) {
if(buffer->initial_size < NDPI_SERIALIZER_DEFAULT_BUFFER_INCR) {
if(min_len < buffer->initial_size)
min_len = buffer->initial_size;
} else {
min_len = NDPI_SERIALIZER_DEFAULT_BUFFER_INCR;
}
}
new_size = buffer->size + min_len;
new_size = ((new_size / 4) + 1) * 4; /* required by zmq encryption */
r = ndpi_realloc((void *) buffer->data, buffer->size, new_size);
if(r == NULL)
return(-1);
buffer->data = r;
buffer->size = new_size;
return(0);
}
/* ********************************** */
static inline int ndpi_serializer_check_header_room(ndpi_private_serializer *serializer, u_int32_t needed) {
u_int32_t buff_diff = serializer->header.size - serializer->status.header.size_used;
if (buff_diff < needed)
if (ndpi_extend_serializer_buffer(&serializer->header, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->header.size - serializer->status.header.size_used;
return(buff_diff);
}
/* ********************************** */
static inline int ndpi_serializer_header_uint32(ndpi_private_serializer *serializer, u_int32_t key) {
int room;
if (serializer->status.flags & NDPI_SERIALIZER_STATUS_HDR_DONE)
return(0);
room = ndpi_serializer_check_header_room(serializer, 12);
if (room < 0)
return(-1);
serializer->status.header.size_used += ndpi_snprintf((char *) &serializer->header.data[serializer->status.header.size_used],
room, "%s%u", (serializer->status.header.size_used > 0) ? serializer->csv_separator : "", key);
return(0);
}
/* ********************************** */
static inline int ndpi_serializer_header_string(ndpi_private_serializer *serializer, const char *key, u_int16_t klen) {
int room;
if (serializer->status.flags & NDPI_SERIALIZER_STATUS_HDR_DONE)
return(0);
room = ndpi_serializer_check_header_room(serializer, klen + 4);
if (room < 0)
return(-1);
if (serializer->status.header.size_used > 0) {
int slen = strlen(serializer->csv_separator);
memcpy(&serializer->header.data[serializer->status.header.size_used], serializer->csv_separator, slen);
serializer->status.header.size_used += slen;
}
if (klen > 0) {
memcpy(&serializer->header.data[serializer->status.header.size_used], key, klen);
serializer->status.header.size_used += klen;
}
serializer->header.data[serializer->status.header.size_used] = '\0';
return(0);
}
/* ********************************** */
char* ndpi_serializer_get_buffer(ndpi_serializer *_serializer, u_int32_t *buffer_len) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
char *buf = (char*)serializer->buffer.data;
/* NULL terminate the buffer */
if(serializer->buffer.size > serializer->status.buffer.size_used) /* safety check */
serializer->buffer.data[serializer->status.buffer.size_used] = '\0';
*buffer_len = serializer->status.buffer.size_used;
if(serializer->fmt == ndpi_serialization_format_json) {
while((buf[0] == '\0') || (buf[0] == ' '))
buf++, *buffer_len = *buffer_len - 1;
}
return(buf);
}
/* ********************************** */
u_int32_t ndpi_serializer_get_buffer_len(ndpi_serializer *_serializer) {
return(((ndpi_private_serializer*)_serializer)->status.buffer.size_used);
}
/* ********************************** */
u_int32_t ndpi_serializer_get_internal_buffer_size(ndpi_serializer *_serializer) {
return(((ndpi_private_serializer*)_serializer)->buffer.size);
}
/* ********************************** */
int ndpi_serializer_set_buffer_len(ndpi_serializer *_serializer, u_int32_t l) {
ndpi_private_serializer *p = (ndpi_private_serializer*)_serializer;
if(p) {
if(p->buffer.size <= l)
return(-1); /* Invalid size */
p->status.buffer.size_used = l;
return(0);
}
return(-2);
}
/* ********************************** */
/* Return the header automatically built from keys (CSV only) */
char* ndpi_serializer_get_header(ndpi_serializer *_serializer, u_int32_t *buffer_len) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
char *buf = (char*)serializer->header.data;
if(buf == NULL) {
*buffer_len = 0;
return("");
}
/* NULL terminate the buffer */
if(serializer->header.size > serializer->status.header.size_used) /* safety check */
serializer->header.data[serializer->status.header.size_used] = '\0';
*buffer_len = serializer->status.header.size_used;
return(buf);
}
/* ********************************** */
ndpi_serialization_format ndpi_serializer_get_format(ndpi_serializer *_serializer) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
return(serializer->fmt);
}
/* ********************************** */
void ndpi_serializer_set_csv_separator(ndpi_serializer *_serializer, char separator) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
serializer->csv_separator[0] = separator;
}
/* ********************************** */
void ndpi_term_serializer(ndpi_serializer *_serializer) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
if(serializer->buffer.data) {
ndpi_free(serializer->buffer.data);
serializer->buffer.size = 0;
serializer->buffer.data = NULL;
}
if(serializer->header.data) {
ndpi_free(serializer->header.data);
serializer->header.size = 0;
serializer->header.data = NULL;
}
}
/* ********************************** */
static inline void ndpi_serialize_single_uint8(ndpi_private_serializer *serializer,
u_int8_t s) {
u_int8_t v = s;
memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], &v, sizeof(u_int8_t));
serializer->status.buffer.size_used += sizeof(u_int8_t);
}
/* ********************************** */
static inline void ndpi_serialize_single_uint16(ndpi_private_serializer *serializer,
u_int16_t s) {
u_int16_t v = htons(s);
memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], &v, sizeof(u_int16_t));
serializer->status.buffer.size_used += sizeof(u_int16_t);
}
/* ********************************** */
static inline void ndpi_serialize_single_uint32(ndpi_private_serializer *serializer,
u_int32_t s) {
u_int32_t v = htonl(s);
memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], &v, sizeof(u_int32_t));
serializer->status.buffer.size_used += sizeof(u_int32_t);
}
/* ********************************** */
static inline void ndpi_serialize_single_uint64(ndpi_private_serializer *serializer,
u_int64_t s) {
u_int64_t v = ndpi_htonll(s);
memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], &v, sizeof(u_int64_t));
serializer->status.buffer.size_used += sizeof(u_int64_t);
}
/* ********************************** */
/* TODO: fix portability across platforms */
static inline void ndpi_serialize_single_float(ndpi_private_serializer *serializer,
float s) {
memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], &s, sizeof(s));
serializer->status.buffer.size_used += sizeof(float);
}
/* ********************************** */
/* TODO: fix portability across platforms */
#if 0
static inline void ndpi_serialize_single_double(ndpi_private_serializer *serializer,
double s) {
memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], &s, sizeof(s));
serializer->status.buffer.size_used += sizeof(double);
}
#endif
/* ********************************** */
static inline void ndpi_serialize_single_string(ndpi_private_serializer *serializer,
const char *s, u_int16_t slen) {
u_int16_t l = htons(slen);
memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], &l, sizeof(u_int16_t));
serializer->status.buffer.size_used += sizeof(u_int16_t);
if(slen > 0)
memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], s, slen);
serializer->status.buffer.size_used += slen;
}
/* ********************************** */
static inline void ndpi_deserialize_single_uint8(ndpi_private_deserializer *deserializer,
u_int32_t offset, u_int8_t *s) {
*s = (*((u_int8_t *) &deserializer->buffer.data[offset]));
}
/* ********************************** */
static inline void ndpi_deserialize_single_uint16(ndpi_private_deserializer *deserializer,
u_int32_t offset, u_int16_t *s) {
*s = ntohs(*((u_int16_t *) &deserializer->buffer.data[offset]));
}
/* ********************************** */
static inline void ndpi_deserialize_single_uint32(ndpi_private_deserializer *deserializer,
u_int32_t offset, u_int32_t *s) {
*s = ntohl(*((u_int32_t *) &deserializer->buffer.data[offset]));
}
/* ********************************** */
static inline void ndpi_deserialize_single_int8(ndpi_private_deserializer *deserializer,
u_int32_t offset, int8_t *s) {
*s = (*((int8_t *) &deserializer->buffer.data[offset]));
}
/* ********************************** */
static inline void ndpi_deserialize_single_int16(ndpi_private_deserializer *deserializer,
u_int32_t offset, int16_t *s) {
*s = ntohs(*((int16_t *) &deserializer->buffer.data[offset]));
}
/* ********************************** */
static inline void ndpi_deserialize_single_int32(ndpi_private_deserializer *deserializer,
u_int32_t offset, int32_t *s) {
*s = ntohl(*((int32_t *) &deserializer->buffer.data[offset]));
}
/* ********************************** */
static inline void ndpi_deserialize_single_uint64(ndpi_private_deserializer *deserializer,
u_int32_t offset, u_int64_t *s) {
*s = ndpi_ntohll(*(u_int64_t*)&deserializer->buffer.data[offset]);
}
/* ********************************** */
static inline void ndpi_deserialize_single_int64(ndpi_private_deserializer *deserializer,
u_int32_t offset, int64_t *s) {
*s = ndpi_ntohll(*(int64_t*)&deserializer->buffer.data[offset]);
}
/* ********************************** */
/* TODO: fix portability across platforms */
static inline void ndpi_deserialize_single_float(ndpi_private_deserializer *deserializer,
u_int32_t offset, float *s) {
*s = *(float*)&deserializer->buffer.data[offset];
}
/* ********************************** */
/* TODO: fix portability across platforms */
static inline void ndpi_deserialize_single_double(ndpi_private_deserializer *deserializer,
u_int32_t offset, double *s) {
*s = *(double*)&deserializer->buffer.data[offset];
}
/* ********************************** */
static inline void ndpi_deserialize_single_string(ndpi_private_deserializer *deserializer,
u_int32_t offset, ndpi_string *v) {
v->str_len = ntohs(*((u_int16_t *) &deserializer->buffer.data[offset]));
v->str = (char *) &deserializer->buffer.data[offset + sizeof(u_int16_t)];
}
/* ********************************** */
/*
This function helps extending the existing serializer by adding a new
element in the array. This element is handled as raw without any
further check whatsoever
*/
int ndpi_serialize_raw_record(ndpi_serializer *_serializer,
u_char *record, u_int32_t record_len) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int16_t needed = record_len;
u_int8_t add_comma = 0;
if(serializer->fmt == ndpi_serialization_format_json) {
needed += 1;
if (serializer->multiline_json_array) {
if(serializer->status.buffer.size_used == 2) /* Empty buffer {} */
serializer->status.buffer.size_used = 0; /* Remove {} */
else
needed += 2;
} else {
if(serializer->status.buffer.size_used == 3) /* Empty buffer [{} */
serializer->status.buffer.size_used = 2; /* Remove {} */
else
needed += 2, add_comma = 1;
}
}
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if(serializer->fmt == ndpi_serialization_format_json) {
if (!serializer->multiline_json_array) {
if (add_comma)
serializer->buffer.data[serializer->status.buffer.size_used-1] = ',';
else
serializer->status.buffer.size_used--;
}
}
memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], record, record_len);
serializer->status.buffer.size_used += record_len;
if(serializer->fmt == ndpi_serialization_format_json) {
if (!serializer->multiline_json_array) {
serializer->buffer.data[serializer->status.buffer.size_used] = ']';
if(add_comma) serializer->status.buffer.size_used++;
}
}
ndpi_serialize_end_of_record(_serializer);
return(0);
}
/* ********************************** */
int ndpi_serialize_end_of_record(ndpi_serializer *_serializer) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int16_t needed = sizeof(u_int8_t) /* type */;
if(serializer->fmt == ndpi_serialization_format_json ||
serializer->fmt == ndpi_serialization_format_csv)
needed += 1;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if(serializer->fmt == ndpi_serialization_format_csv) {
serializer->buffer.data[serializer->status.buffer.size_used++] = '\n';
serializer->buffer.data[serializer->status.buffer.size_used] = '\0';
serializer->status.flags |= NDPI_SERIALIZER_STATUS_HDR_DONE;
serializer->status.flags |= NDPI_SERIALIZER_STATUS_EOR;
} else if(serializer->fmt == ndpi_serialization_format_json) {
if(serializer->multiline_json_array) {
serializer->buffer.data[serializer->status.buffer.size_used++] = '\n';
serializer->buffer.data[serializer->status.buffer.size_used] = '\0';
} else {
if(!(serializer->status.flags & NDPI_SERIALIZER_STATUS_ARRAY)) {
serializer->buffer.data[0] = '[';
serializer->status.buffer.size_used += ndpi_snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, "]");
}
}
serializer->status.flags |= NDPI_SERIALIZER_STATUS_ARRAY | NDPI_SERIALIZER_STATUS_EOR;
serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_COMMA;
} else /* ndpi_serialization_format_tlv */ {
serializer->buffer.data[serializer->status.buffer.size_used++] = ndpi_serialization_end_of_record;
}
serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_NOT_EMPTY;
return(0);
}
/* ********************************** */
static inline void ndpi_serialize_csv_pre(ndpi_private_serializer *serializer) {
if(serializer->status.flags & NDPI_SERIALIZER_STATUS_EOR) {
serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_EOR;
} else if (serializer->status.buffer.size_used == 0) {
/* nothing to do */
} else {
if(serializer->buffer.size > serializer->status.buffer.size_used) {
serializer->buffer.data[serializer->status.buffer.size_used] = serializer->csv_separator[0];
serializer->status.buffer.size_used++;
}
}
}
/* ********************************** */
static inline void ndpi_serialize_json_pre(ndpi_serializer *_serializer) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
if(serializer->status.flags & NDPI_SERIALIZER_STATUS_EOR) {
serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_EOR;
if(serializer->multiline_json_array) {
serializer->buffer.data[serializer->status.buffer.size_used++] = '\n';
} else {
serializer->status.buffer.size_used--; /* Remove ']' */
serializer->buffer.data[serializer->status.buffer.size_used++] = ',';
}
if (!serializer->inner_json)
serializer->buffer.data[serializer->status.buffer.size_used++] = '{';
} else {
if(!serializer->multiline_json_array) {
if(serializer->status.flags & NDPI_SERIALIZER_STATUS_ARRAY)
serializer->status.buffer.size_used--; /* Remove ']' */
}
if (!serializer->inner_json)
serializer->status.buffer.size_used--; /* Remove '}' */
if(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST) {
if(!serializer->multiline_json_array)
serializer->status.buffer.size_used--; /* Remove ']' */
if(serializer->status.flags & NDPI_SERIALIZER_STATUS_SOL)
serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_SOL;
else
serializer->buffer.data[serializer->status.buffer.size_used++] = ',';
} else {
if(serializer->status.flags & NDPI_SERIALIZER_STATUS_SOB)
serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_SOB;
else if(serializer->status.flags & NDPI_SERIALIZER_STATUS_COMMA)
serializer->buffer.data[serializer->status.buffer.size_used++] = ',';
}
}
}
/* ********************************** */
static inline int ndpi_serialize_json_post(ndpi_serializer *_serializer) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
if (!serializer->multiline_json_array) {
if(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST) {
if(serializer->status.buffer.size_used >= serializer->buffer.size)
return -1;
serializer->buffer.data[serializer->status.buffer.size_used++] = ']';
}
}
if(serializer->status.buffer.size_used >= serializer->buffer.size)
return -1;
if (!serializer->inner_json || serializer->status.flags & NDPI_SERIALIZER_STATUS_CEOB) {
serializer->buffer.data[serializer->status.buffer.size_used++] = '}';
serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_CEOB;
}
if (!serializer->multiline_json_array) {
if(serializer->status.flags & NDPI_SERIALIZER_STATUS_ARRAY) {
if(serializer->status.buffer.size_used >= serializer->buffer.size)
return -1;
serializer->buffer.data[serializer->status.buffer.size_used++] = ']';
}
}
serializer->status.flags |= NDPI_SERIALIZER_STATUS_COMMA;
return 0;
}
/* ********************************** */
static inline ndpi_serialization_type ndpi_serialize_key_uint32(ndpi_private_serializer *serializer, u_int32_t key) {
ndpi_serialization_type kt;
if(key <= 0xff) {
ndpi_serialize_single_uint8(serializer, key);
kt = ndpi_serialization_uint8;
} else if(key <= 0xffff) {
ndpi_serialize_single_uint16(serializer, key);
kt = ndpi_serialization_uint16;
} else {
ndpi_serialize_single_uint32(serializer, key);
kt = ndpi_serialization_uint32;
}
return(kt);
}
/* ********************************** */
int ndpi_serialize_uint32_uint32(ndpi_serializer *_serializer,
u_int32_t key, u_int32_t value) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
int rc;
u_int16_t needed =
sizeof(u_int8_t) /* type */ +
sizeof(u_int32_t) /* key */ +
sizeof(u_int32_t);
if(serializer->fmt == ndpi_serialization_format_json)
needed += 24;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if(serializer->fmt == ndpi_serialization_format_json) {
ndpi_serialize_json_pre(_serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) {
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used],
buff_diff, "\"%u\":", key);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used],
buff_diff, "%u", value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
if(ndpi_serialize_json_post(_serializer) != 0)
return(-1);
} else if(serializer->fmt == ndpi_serialization_format_csv) {
if (ndpi_serializer_header_uint32(serializer, key) < 0) return(-1);
ndpi_serialize_csv_pre(serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used], buff_diff,
"%u", value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
} else {
ndpi_serialization_type kt;
u_int8_t type = 0;
u_int32_t type_offset = serializer->status.buffer.size_used++;
kt = ndpi_serialize_key_uint32(serializer, key);
type = (kt << 4);
if(value <= 0xff) {
ndpi_serialize_single_uint8(serializer, value);
type |= ndpi_serialization_uint8;
} else if(value <= 0xffff) {
ndpi_serialize_single_uint16(serializer, value);
type |= ndpi_serialization_uint16;
} else {
ndpi_serialize_single_uint32(serializer, value);
type |= ndpi_serialization_uint32;
}
serializer->buffer.data[type_offset] = type;
}
serializer->status.flags |= NDPI_SERIALIZER_STATUS_NOT_EMPTY;
return(0);
}
/* ********************************** */
int ndpi_serialize_uint32_uint64(ndpi_serializer *_serializer,
u_int32_t key, u_int64_t value) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int16_t needed =
sizeof(u_int8_t) /* type */ +
sizeof(u_int32_t) /* key */ +
sizeof(u_int64_t);
int rc;
if(serializer->fmt == ndpi_serialization_format_json)
needed += 32;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if(serializer->fmt == ndpi_serialization_format_json) {
ndpi_serialize_json_pre(_serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) {
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used], buff_diff,
"\"%u\":", key);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used], buff_diff,
NDPI_U64_FORMAT, (unsigned long long)value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
if(ndpi_serialize_json_post(_serializer) != 0)
return(-1);
} else if(serializer->fmt == ndpi_serialization_format_csv) {
if (ndpi_serializer_header_uint32(serializer, key) < 0) return(-1);
ndpi_serialize_csv_pre(serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used], buff_diff,
NDPI_U64_FORMAT, (unsigned long long)value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
} else {
if(value <= 0xffffffff) {
return(ndpi_serialize_uint32_uint32(_serializer, key, value));
} else {
ndpi_serialization_type kt;
u_int8_t type = 0;
u_int32_t type_offset = serializer->status.buffer.size_used++;
kt = ndpi_serialize_key_uint32(serializer, key);
type = (kt << 4);
ndpi_serialize_single_uint64(serializer, value);
type |= ndpi_serialization_uint64;
serializer->buffer.data[type_offset] = type;
}
}
serializer->status.flags |= NDPI_SERIALIZER_STATUS_NOT_EMPTY;
return(0);
}
/* ********************************** */
int ndpi_serialize_uint32_int32(ndpi_serializer *_serializer,
u_int32_t key, int32_t value) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int16_t needed =
sizeof(u_int8_t) /* type */ +
sizeof(u_int32_t) /* key */ +
sizeof(int32_t);
int rc;
if(serializer->fmt == ndpi_serialization_format_json)
needed += 24;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if(serializer->fmt == ndpi_serialization_format_json) {
ndpi_serialize_json_pre(_serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) {
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used],
buff_diff, "\"%u\":", key);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used],
buff_diff, "%d", value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
if(ndpi_serialize_json_post(_serializer) != 0)
return(-1);
} else if(serializer->fmt == ndpi_serialization_format_csv) {
if (ndpi_serializer_header_uint32(serializer, key) < 0) return(-1);
ndpi_serialize_csv_pre(serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used], buff_diff,
"%d", value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
} else {
ndpi_serialization_type kt;
u_int8_t type = 0;
u_int32_t type_offset = serializer->status.buffer.size_used++;
kt = ndpi_serialize_key_uint32(serializer, key);
type = (kt << 4);
if(value <= 127 && value >= -128) {
ndpi_serialize_single_uint8(serializer, value);
type |= ndpi_serialization_int8;
} else if(value <= 32767 && value >= -32768) {
ndpi_serialize_single_uint16(serializer, value);
type |= ndpi_serialization_int16;
} else {
ndpi_serialize_single_uint32(serializer, value);
type |= ndpi_serialization_int32;
}
serializer->buffer.data[type_offset] = type;
}
serializer->status.flags |= NDPI_SERIALIZER_STATUS_NOT_EMPTY;
return(0);
}
/* ********************************** */
int ndpi_serialize_uint32_int64(ndpi_serializer *_serializer,
u_int32_t key, int64_t value) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int16_t needed =
sizeof(u_int8_t) /* type */ +
sizeof(u_int32_t) /* key */ +
sizeof(int64_t);
int rc;
if(serializer->fmt == ndpi_serialization_format_json)
needed += 32;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if(serializer->fmt == ndpi_serialization_format_json) {
ndpi_serialize_json_pre(_serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) {
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used],
buff_diff, "\"%u\":", key);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used],
buff_diff, NDPI_I64_FORMAT, (long long int)value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
if(ndpi_serialize_json_post(_serializer) != 0)
return(-1);
} else if(serializer->fmt == ndpi_serialization_format_csv) {
if (ndpi_serializer_header_uint32(serializer, key) < 0) return(-1);
ndpi_serialize_csv_pre(serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used], buff_diff,
NDPI_I64_FORMAT, (long long int)value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
}
else {
if((value & 0xFFFFFFFF) == value) {
return(ndpi_serialize_uint32_int32(_serializer, key, value));
} else {
ndpi_serialization_type kt;
u_int8_t type = 0;
u_int32_t type_offset = serializer->status.buffer.size_used++;
kt = ndpi_serialize_key_uint32(serializer, key);
type = (kt << 4);
ndpi_serialize_single_uint64(serializer, value);
type |= ndpi_serialization_int64;
serializer->buffer.data[type_offset] = type;
}
}
serializer->status.flags |= NDPI_SERIALIZER_STATUS_NOT_EMPTY;
return(0);
}
/* ********************************** */
int ndpi_serialize_uint32_float(ndpi_serializer *_serializer,
u_int32_t key, float value,
const char *format /* e.f. "%.2f" */) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int16_t needed =
sizeof(u_int8_t) /* type */ +
sizeof(u_int32_t) /* key */ +
sizeof(float) +
32; /* Safety, because printing float might lead to LONG string */
int rc;
if(serializer->fmt == ndpi_serialization_format_json)
needed += 32;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if(serializer->fmt == ndpi_serialization_format_json) {
ndpi_serialize_json_pre(_serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) {
rc = ndpi_snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, "\"%u\":", key);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
rc = ndpi_snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, format, value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
if(ndpi_serialize_json_post(_serializer) != 0)
return(-1);
} else if(serializer->fmt == ndpi_serialization_format_csv) {
if (ndpi_serializer_header_uint32(serializer, key) < 0) return(-1);
ndpi_serialize_csv_pre(serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
rc = ndpi_snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, format, value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
} else {
ndpi_serialization_type kt;
u_int8_t type = 0;
u_int32_t type_offset = serializer->status.buffer.size_used++;
kt = ndpi_serialize_key_uint32(serializer, key);
type = (kt << 4);
ndpi_serialize_single_float(serializer, value);
type |= ndpi_serialization_float;
serializer->buffer.data[type_offset] = type;
}
serializer->status.flags |= NDPI_SERIALIZER_STATUS_NOT_EMPTY;
return(0);
}
/* ********************************** */
int ndpi_serialize_uint32_double(ndpi_serializer *_serializer,
u_int32_t key, double value,
const char *format /* e.f. "%.2f" */) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int16_t needed =
sizeof(u_int8_t) /* type */ +
sizeof(u_int32_t) /* key */ +
sizeof(double) +
32; /* Safety, because printing double might lead to LONG string */
int rc;
if(serializer->fmt == ndpi_serialization_format_json)
needed += 32;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if(serializer->fmt == ndpi_serialization_format_json) {
ndpi_serialize_json_pre(_serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) {
rc = ndpi_snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, "\"%u\":", key);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
rc = ndpi_snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, format, value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
if(ndpi_serialize_json_post(_serializer) != 0)
return(-1);
} else if(serializer->fmt == ndpi_serialization_format_csv) {
if (ndpi_serializer_header_uint32(serializer, key) < 0) return(-1);
ndpi_serialize_csv_pre(serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
rc = ndpi_snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, format, value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
} else {
#if 1
return(-1);
#else
ndpi_serialization_type kt;
u_int8_t type = 0;
u_int32_t type_offset = serializer->status.buffer.size_used++;
kt = ndpi_serialize_key_uint32(serializer, key);
type = (kt << 4);
ndpi_serialize_single_float(serializer, value);
type |= ndpi_serialization_double;
serializer->buffer.data[type_offset] = type;
#endif
}
serializer->status.flags |= NDPI_SERIALIZER_STATUS_NOT_EMPTY;
return(0);
}
/* ********************************** */
int ndpi_serialize_uint32_binary(ndpi_serializer *_serializer,
u_int32_t key, const char *value, u_int16_t slen) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int32_t needed =
sizeof(u_int8_t) /* type */ +
sizeof(u_int32_t) /* key */ +
sizeof(u_int16_t) /* len */ +
slen;
int rc;
if(serializer->fmt == ndpi_serialization_format_json)
needed += 24 + slen;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if(serializer->fmt == ndpi_serialization_format_json) {
ndpi_serialize_json_pre(_serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) {
rc = ndpi_snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used],
buff_diff, "\"%u\":", key);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
serializer->status.buffer.size_used += ndpi_json_string_escape(value, slen,
(char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
if(ndpi_serialize_json_post(_serializer) != 0)
return(-1);
} else if(serializer->fmt == ndpi_serialization_format_csv) {
if (ndpi_serializer_header_uint32(serializer, key) < 0) return(-1);
ndpi_serialize_csv_pre(serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used], buff_diff,
"%.*s", slen, value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
} else {
ndpi_serialization_type kt;
u_int8_t type = 0;
u_int32_t type_offset = serializer->status.buffer.size_used++;
kt = ndpi_serialize_key_uint32(serializer, key);
type = (kt << 4);
ndpi_serialize_single_string(serializer, value, slen);
type |= ndpi_serialization_string;
serializer->buffer.data[type_offset] = type;
}
serializer->status.flags |= NDPI_SERIALIZER_STATUS_NOT_EMPTY;
return(0);
}
/* ********************************** */
int ndpi_serialize_uint32_string(ndpi_serializer *_serializer,
u_int32_t key, const char *_value) {
const char *value = _value ? _value : "";
return(ndpi_serialize_uint32_binary(_serializer, key, value, strlen(value)));
}
/* ********************************** */
int ndpi_serialize_uint32_boolean(ndpi_serializer *_serializer,
u_int32_t key, u_int8_t value) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int32_t needed = 24;
int rc;
if(serializer->fmt != ndpi_serialization_format_json &&
serializer->fmt != ndpi_serialization_format_csv)
return(-1);
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if(serializer->fmt == ndpi_serialization_format_json) {
ndpi_serialize_json_pre(_serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) {
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used],
buff_diff, "\"%u\":", key);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used],
buff_diff, "%s", value ? "true" : "false");
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
if(ndpi_serialize_json_post(_serializer) != 0)
return(-1);
} else if(serializer->fmt == ndpi_serialization_format_csv) {
if (ndpi_serializer_header_uint32(serializer, key) < 0) return(-1);
ndpi_serialize_csv_pre(serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used], buff_diff,
"%s", value ? "true" : "false");
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
}
serializer->status.flags |= NDPI_SERIALIZER_STATUS_NOT_EMPTY;
return(0);
}
/* ********************************** */
int ndpi_serialize_binary_int32(ndpi_serializer *_serializer,
const char *key, u_int16_t klen,
int32_t value) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int32_t needed;
int rc;
#ifdef OPTIMIZE_NUMERIC_KEYS
if(ndpi_is_number(key, klen))
return(ndpi_serialize_uint32_int32(_serializer, atoi(key), value));
#endif
needed =
sizeof(u_int8_t) /* type */ +
sizeof(u_int16_t) /* key len */ +
klen /* key */ +
sizeof(u_int32_t);
if(serializer->fmt == ndpi_serialization_format_json)
needed += 16 + klen;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if(serializer->fmt == ndpi_serialization_format_json) {
ndpi_serialize_json_pre(_serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) {
serializer->status.buffer.size_used += ndpi_json_string_escape(key, klen,
(char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff);
serializer->buffer.data[serializer->status.buffer.size_used] = ':';
serializer->status.buffer.size_used++;
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, "%d", value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
if(ndpi_serialize_json_post(_serializer) != 0)
return(-1);
} else if(serializer->fmt == ndpi_serialization_format_csv) {
if (ndpi_serializer_header_string(serializer, key, klen) < 0) return(-1);
ndpi_serialize_csv_pre(serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used], buff_diff,
"%d", value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
} else {
if(value <= 127 && value >= -128) {
serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_int8;
ndpi_serialize_single_string(serializer, key, klen);
ndpi_serialize_single_uint8(serializer, value);
} else if(value <= 32767 && value >= -32768) {
serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_int16;
ndpi_serialize_single_string(serializer, key, klen);
ndpi_serialize_single_uint16(serializer, value);
} else {
serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_int32;
ndpi_serialize_single_string(serializer, key, klen);
ndpi_serialize_single_uint32(serializer, value);
}
}
serializer->status.flags |= NDPI_SERIALIZER_STATUS_NOT_EMPTY;
return(0);
}
/* ********************************** */
int ndpi_serialize_string_int32(ndpi_serializer *_serializer,
const char *key, int32_t value) {
#ifdef OPTIMIZE_CSV_SERIALIZATION
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
if(serializer->fmt == ndpi_serialization_format_csv) {
/* Key is ignored */
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int16_t needed = 12 /* 10 (billion) + CVS separator + \0 */;
int rc;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
}
if(!(serializer->status.flags & NDPI_SERIALIZER_STATUS_HDR_DONE)) {
if(ndpi_serializer_header_string(serializer, key, strlen(key)) < 0)
return(-1);
}
ndpi_serialize_csv_pre(serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
rc = ndpi_snprintf((char*)&serializer->buffer.data[serializer->status.buffer.size_used],
buff_diff, "%u", value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
return(0);
} else
#endif
return(ndpi_serialize_binary_int32(_serializer, key, strlen(key), value));
}
/* ********************************** */
int ndpi_serialize_binary_int64(ndpi_serializer *_serializer,
const char *key, u_int16_t klen,
int64_t value) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int32_t needed;
int rc;
#ifdef OPTIMIZE_NUMERIC_KEYS
if(ndpi_is_number(key, klen))
return(ndpi_serialize_uint32_int64(_serializer, atoi(key), value));
#endif
needed =
sizeof(u_int8_t) /* type */ +
sizeof(u_int16_t) /* key len */ +
klen /* key */ +
sizeof(u_int64_t);
if(serializer->fmt == ndpi_serialization_format_json)
needed += 16 + klen;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if(serializer->fmt == ndpi_serialization_format_json) {
ndpi_serialize_json_pre(_serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) {
serializer->status.buffer.size_used += ndpi_json_string_escape(key, klen,
(char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
serializer->buffer.data[serializer->status.buffer.size_used] = ':';
serializer->status.buffer.size_used++;
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used], buff_diff,
NDPI_I64_FORMAT, (long long int)value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
if(ndpi_serialize_json_post(_serializer) != 0)
return(-1);
} else if(serializer->fmt == ndpi_serialization_format_csv) {
if (ndpi_serializer_header_string(serializer, key, klen) < 0) return(-1);
ndpi_serialize_csv_pre(serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
rc = ndpi_snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff,
NDPI_I64_FORMAT, (long long int)value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
} else {
if ((value & 0xFFFFFFFF) == value) {
return(ndpi_serialize_string_int32(_serializer, key, value));
} else {
serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_int64;
ndpi_serialize_single_string(serializer, key, klen);
ndpi_serialize_single_uint64(serializer, value);
}
}
serializer->status.flags |= NDPI_SERIALIZER_STATUS_NOT_EMPTY;
return(0);
}
/* ********************************** */
int ndpi_serialize_string_int64(ndpi_serializer *_serializer,
const char *key, int64_t value) {
return(ndpi_serialize_binary_int64(_serializer, key, strlen(key), value));
}
/* ********************************** */
int ndpi_serialize_binary_uint32(ndpi_serializer *_serializer,
const char *key, u_int16_t klen, u_int32_t value) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int32_t needed;
int rc;
#ifdef OPTIMIZE_CSV_SERIALIZATION
if(serializer->fmt == ndpi_serialization_format_csv) {
/* Key is ignored */
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int16_t needed;
char _value[16];
ndpi_snprintf(_value, sizeof(_value), "%u", value);
needed = strlen(_value) + 1 /* CVS separator */;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
else
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if(!(serializer->status.flags & NDPI_SERIALIZER_STATUS_HDR_DONE)) {
if(ndpi_serializer_header_string(serializer, key, klen) < 0)
return(-1);
}
ndpi_serialize_csv_pre(serializer);
needed--;
memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], _value, needed);
serializer->status.buffer.size_used += needed;
return(0);
}
#endif
#ifdef OPTIMIZE_NUMERIC_KEYS
if(ndpi_is_number(key, klen))
return(ndpi_serialize_uint32_uint32(_serializer, atoi(key), value));
#endif
needed =
sizeof(u_int8_t) /* type */ +
sizeof(u_int16_t) /* key len */ +
klen /* key */ +
sizeof(u_int32_t) + /* value (as int) */
20 /* value (as string, in case of CSV) */ +
16 /* extra overhead for JSON */;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if(serializer->fmt == ndpi_serialization_format_json) {
ndpi_serialize_json_pre(_serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) {
serializer->status.buffer.size_used += ndpi_json_string_escape(key, klen,
(char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
serializer->buffer.data[serializer->status.buffer.size_used] = ':';
serializer->status.buffer.size_used++;
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used],
buff_diff, "%u", value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
if(ndpi_serialize_json_post(_serializer) != 0)
return(-1);
} else if(serializer->fmt == ndpi_serialization_format_csv) {
#ifndef OPTIMIZE_CSV_SERIALIZATION
if (ndpi_serializer_header_string(serializer, key, klen) < 0) return(-1);
ndpi_serialize_csv_pre(serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used], buff_diff,
"%u", value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
#endif
} else {
if(value <= 0xff) {
serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_uint8;
ndpi_serialize_single_string(serializer, key, klen);
ndpi_serialize_single_uint8(serializer, value);
} else if(value <= 0xffff) {
serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_uint16;
ndpi_serialize_single_string(serializer, key, klen);
ndpi_serialize_single_uint16(serializer, value);
} else {
serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_uint32;
ndpi_serialize_single_string(serializer, key, klen);
ndpi_serialize_single_uint32(serializer, value);
}
}
serializer->status.flags |= NDPI_SERIALIZER_STATUS_NOT_EMPTY;
return(0);
}
/* ********************************** */
int ndpi_serialize_string_uint32(ndpi_serializer *_serializer,
const char *key, u_int32_t value) {
return(ndpi_serialize_binary_uint32(_serializer, key, strlen(key), value));
}
/* ********************************** */
int ndpi_serialize_string_uint32_format(ndpi_serializer *_serializer,
const char *key, u_int32_t value,
const char *format) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
if(serializer->fmt == ndpi_serialization_format_json) {
/*
JSON supports base 10 numbers only
http://cjihrig.com/blog/json-overview/
*/
return(ndpi_serialize_string_uint32(_serializer, key, value));
} else {
char buf[16];
ndpi_snprintf(buf, sizeof(buf), format, value);
return(ndpi_serialize_string_string(_serializer, key, buf));
}
}
/* ********************************** */
int ndpi_serialize_binary_uint64(ndpi_serializer *_serializer,
const char *key, u_int16_t klen,
u_int64_t value) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int32_t needed;
int rc;
#ifdef OPTIMIZE_NUMERIC_KEYS
if(ndpi_is_number(key, klen))
return(ndpi_serialize_uint32_uint64(_serializer, atoi(key), value));
#endif
needed =
sizeof(u_int8_t) /* type */ +
sizeof(u_int16_t) /* key len */ +
klen /* key */ +
sizeof(u_int64_t);
if(serializer->fmt == ndpi_serialization_format_json)
needed += 16 + klen;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if(serializer->fmt == ndpi_serialization_format_json) {
ndpi_serialize_json_pre(_serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) {
serializer->status.buffer.size_used += ndpi_json_string_escape(key, klen,
(char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
serializer->buffer.data[serializer->status.buffer.size_used] = ':';
serializer->status.buffer.size_used++;
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used], buff_diff,
NDPI_U64_FORMAT, (unsigned long long)value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
if(ndpi_serialize_json_post(_serializer) != 0)
return(-1);
} else if(serializer->fmt == ndpi_serialization_format_csv) {
if (ndpi_serializer_header_string(serializer, key, klen) < 0) return(-1);
ndpi_serialize_csv_pre(serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used], buff_diff,
NDPI_U64_FORMAT, (unsigned long long)value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
} else {
if(value <= 0xffffffff) {
return(ndpi_serialize_string_uint32(_serializer, key, value));
} else {
serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_uint64;
ndpi_serialize_single_string(serializer, key, klen);
ndpi_serialize_single_uint64(serializer, value);
}
}
serializer->status.flags |= NDPI_SERIALIZER_STATUS_NOT_EMPTY;
return(0);
}
/* ********************************** */
int ndpi_serialize_string_uint64(ndpi_serializer *_serializer,
const char *key, u_int64_t value) {
return(ndpi_serialize_binary_uint64(_serializer, key, strlen(key), value));
}
/* ********************************** */
int ndpi_serialize_binary_float(ndpi_serializer *_serializer,
const char *key,
u_int16_t klen,
float value,
const char *format /* e.f. "%.2f" */) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int32_t needed;
int rc;
#ifdef OPTIMIZE_NUMERIC_KEYS
if(ndpi_is_number(key, klen))
return(ndpi_serialize_uint32_float(_serializer, atoi(key), value, format));
#endif
needed =
sizeof(u_int8_t) /* type */ +
sizeof(u_int16_t) /* key len */ +
klen /* key */ +
sizeof(float) +
32; /* Safety, because printing float might lead to LONG string */
if(serializer->fmt == ndpi_serialization_format_json)
needed += 32 + klen;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if(serializer->fmt == ndpi_serialization_format_json) {
ndpi_serialize_json_pre(_serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) {
serializer->status.buffer.size_used += ndpi_json_string_escape(key, klen,
(char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff);
serializer->buffer.data[serializer->status.buffer.size_used] = ':';
serializer->status.buffer.size_used++;
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
rc = ndpi_snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, format, value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
if(ndpi_serialize_json_post(_serializer) != 0)
return(-1);
} else if(serializer->fmt == ndpi_serialization_format_csv) {
if (ndpi_serializer_header_string(serializer, key, klen) < 0) return(-1);
ndpi_serialize_csv_pre(serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
rc = ndpi_snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, format, value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
} else {
serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_float;
ndpi_serialize_single_string(serializer, key, klen);
ndpi_serialize_single_float(serializer, value);
}
serializer->status.flags |= NDPI_SERIALIZER_STATUS_NOT_EMPTY;
return(0);
}
/* ********************************** */
/* JSON/CSV only (TLV not yet supported due to a type field limit) */
int ndpi_serialize_binary_double(ndpi_serializer *_serializer,
const char *key,
u_int16_t klen,
double value,
const char *format /* e.f. "%.2f" */) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int32_t needed;
int rc;
needed =
sizeof(u_int8_t) /* type */ +
sizeof(u_int16_t) /* key len */ +
klen /* key */ +
sizeof(double) +
32; /* Safety, because printing double might lead to LONG string */
if(serializer->fmt == ndpi_serialization_format_json)
needed += 32 + klen;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if(serializer->fmt == ndpi_serialization_format_json) {
ndpi_serialize_json_pre(_serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) {
serializer->status.buffer.size_used += ndpi_json_string_escape(key, klen,
(char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff);
serializer->buffer.data[serializer->status.buffer.size_used] = ':';
serializer->status.buffer.size_used++;
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
rc = ndpi_snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, format, value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
if(ndpi_serialize_json_post(_serializer) != 0)
return(-1);
} else if(serializer->fmt == ndpi_serialization_format_csv) {
if (ndpi_serializer_header_string(serializer, key, klen) < 0) return(-1);
ndpi_serialize_csv_pre(serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
rc = ndpi_snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, format, value);
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
} else {
#if 1
return(-1);
#else
serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_double;
ndpi_serialize_single_string(serializer, key, klen);
ndpi_serialize_single_double(serializer, value);
#endif
}
serializer->status.flags |= NDPI_SERIALIZER_STATUS_NOT_EMPTY;
return(0);
}
/* ********************************** */
int ndpi_serialize_string_float(ndpi_serializer *_serializer,
const char *key,
float value,
const char *format /* e.f. "%.2f" */) {
return(ndpi_serialize_binary_float(_serializer, key, strlen(key), value, format));
}
/* ********************************** */
int ndpi_serialize_string_double(ndpi_serializer *_serializer,
const char *key,
double value,
const char *format /* e.f. "%.2f" */)
{
return(ndpi_serialize_binary_double(_serializer, key, strlen(key), value, format));
}
/* ********************************** */
/* Key is a pair, value is a raw value */
static int ndpi_serialize_binary_raw(ndpi_serializer *_serializer,
const char *key,
u_int16_t klen,
const char *value,
u_int16_t vlen,
u_int8_t escape) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int32_t needed;
needed =
sizeof(u_int8_t) /* type */ +
sizeof(u_int16_t) /* key len */ +
klen +
sizeof(u_int16_t) /* len */ +
vlen;
if(serializer->fmt == ndpi_serialization_format_json)
needed += 16 + klen + vlen;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if(serializer->fmt == ndpi_serialization_format_json) {
ndpi_serialize_json_pre(_serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) {
serializer->status.buffer.size_used += ndpi_json_string_escape(key, klen,
(char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff);
serializer->buffer.data[serializer->status.buffer.size_used] = ':';
serializer->status.buffer.size_used++;
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if (escape)
serializer->status.buffer.size_used += ndpi_json_string_escape(value, vlen,
(char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff);
else {
memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], value, vlen);
serializer->status.buffer.size_used += vlen;
}
if(ndpi_serialize_json_post(_serializer) != 0)
return(-1);
} else if(serializer->fmt == ndpi_serialization_format_csv) {
if (ndpi_serializer_header_string(serializer, key, klen) < 0) return(-1);
ndpi_serialize_csv_pre(serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], value, vlen);
serializer->status.buffer.size_used += vlen;
} else {
serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_string;
ndpi_serialize_single_string(serializer, key, klen);
ndpi_serialize_single_string(serializer, value, vlen);
}
serializer->status.flags |= NDPI_SERIALIZER_STATUS_NOT_EMPTY;
return(0);
}
/* ********************************** */
/* Key is a pair, value is a pair */
int ndpi_serialize_binary_binary(ndpi_serializer *_serializer,
const char *key,
u_int16_t klen,
const char *_value,
u_int16_t vlen) {
const char *value = _value ? _value : "";
#ifdef OPTIMIZE_NUMERIC_KEYS
if(ndpi_is_number(key, klen))
return(ndpi_serialize_uint32_binary(_serializer, atoi(key), value, vlen));
#endif
return(ndpi_serialize_binary_raw(_serializer, key, klen, value, vlen, 1 /* escape */));
}
/* ********************************** */
/* Key is a string, value is a pair */
int ndpi_serialize_string_binary(ndpi_serializer *_serializer,
const char *key, const char *_value,
u_int16_t vlen) {
return(ndpi_serialize_binary_binary(_serializer, key, strlen(key), _value, vlen));
}
/* ********************************** */
/* Key is a string, value is a string (strlen is used to compute the len) */
int ndpi_serialize_string_string_len(ndpi_serializer *_serializer,
const char *key,
const char *value, u_int16_t value_len) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
#ifdef OPTIMIZE_CSV_SERIALIZATION
if(serializer->fmt == ndpi_serialization_format_csv) {
/* Key is ignored */
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int16_t needed = value_len + 1 /* CVS separator */;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
else
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if(!(serializer->status.flags & NDPI_SERIALIZER_STATUS_HDR_DONE)) {
if(ndpi_serializer_header_string(serializer, key, strlen(key)) < 0)
return(-1);
}
ndpi_serialize_csv_pre(serializer);
needed--;
memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], value, needed);
serializer->status.buffer.size_used += needed;
return(0);
} else
#endif
return(ndpi_serialize_binary_binary(_serializer, key, strlen(key),
value, value_len));
}
/* ********************************** */
/* Key is a string, value is a string (strlen is used to compute the len) */
int ndpi_serialize_string_string(ndpi_serializer *_serializer,
const char *key, const char *_value) {
const char *value = _value ? _value : "";
return(ndpi_serialize_string_string_len(_serializer, key, value, strlen(value)));
}
/* ********************************** */
/* Key is a string, value is a raw json value (it can be a number, an escaped/quoted string, an array, ..) */
int ndpi_serialize_string_raw(ndpi_serializer *_serializer,
const char *key, const char *_value, u_int16_t vlen) {
return(ndpi_serialize_binary_raw(_serializer, key, strlen(key), _value, vlen, 0 /* do not escape */));
}
/* ********************************** */
int ndpi_serialize_binary_boolean(ndpi_serializer *_serializer,
const char *key, u_int16_t klen, u_int8_t value) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int32_t needed;
int rc;
if(serializer->fmt != ndpi_serialization_format_json &&
serializer->fmt != ndpi_serialization_format_csv)
return(-1);
#ifdef OPTIMIZE_NUMERIC_KEYS
if(ndpi_is_number(key, klen))
return(ndpi_serialize_uint32_boolean(_serializer, atoi(key), value));
#endif
needed = klen + 16;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if(serializer->fmt == ndpi_serialization_format_json) {
ndpi_serialize_json_pre(_serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) {
serializer->status.buffer.size_used += ndpi_json_string_escape(key, klen,
(char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff);
serializer->buffer.data[serializer->status.buffer.size_used] = ':';
serializer->status.buffer.size_used++;
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
rc = ndpi_snprintf((char *)
&serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, "%s",
value ? "true" : "false");
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
if(ndpi_serialize_json_post(_serializer) != 0)
return(-1);
} else if(serializer->fmt == ndpi_serialization_format_csv) {
if (ndpi_serializer_header_string(serializer, key, strlen(key)) < 0) return(-1);
ndpi_serialize_csv_pre(serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
rc = ndpi_snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff,
"%s", value ? "true" : "false");
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
}
serializer->status.flags |= NDPI_SERIALIZER_STATUS_NOT_EMPTY;
return(0);
}
/* ********************************** */
int ndpi_serialize_string_boolean(ndpi_serializer *_serializer,
const char *key, u_int8_t value) {
return(ndpi_serialize_binary_boolean(_serializer, key, strlen(key), value));
}
/* ********************************** */
int ndpi_serialize_start_of_list_binary(ndpi_serializer *_serializer,
const char *key, u_int16_t klen) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int32_t needed;
int rc;
if(serializer->fmt != ndpi_serialization_format_json &&
serializer->fmt != ndpi_serialization_format_tlv)
return(-1);
needed = 16 + klen;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if (serializer->fmt == ndpi_serialization_format_json) {
ndpi_serialize_json_pre(_serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
serializer->status.buffer.size_used += ndpi_json_string_escape(key, klen,
(char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
rc = ndpi_snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, ": [");
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
serializer->status.flags |= NDPI_SERIALIZER_STATUS_LIST | NDPI_SERIALIZER_STATUS_SOL;
if(ndpi_serialize_json_post(_serializer) != 0)
return(-1);
} else {
serializer->buffer.data[serializer->status.buffer.size_used++] = ndpi_serialization_start_of_list;
ndpi_serialize_single_string(serializer, key, klen);
}
return(0);
}
/* ********************************** */
/* Serialize start of simple values list */
int ndpi_serialize_start_of_list(ndpi_serializer *_serializer,
const char *_key) {
const char *key = _key ? _key : "";
u_int16_t klen = strlen(key);
return(ndpi_serialize_start_of_list_binary(_serializer, key, klen));
}
/* ********************************** */
/* Serialize end of simple values list */
int ndpi_serialize_end_of_list(ndpi_serializer *_serializer) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
if(serializer->fmt != ndpi_serialization_format_json &&
serializer->fmt != ndpi_serialization_format_tlv)
return(-1);
if (serializer->fmt == ndpi_serialization_format_json) {
if(serializer->status.flags & NDPI_SERIALIZER_STATUS_SOL) /* Empty list */
serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_SOL;
serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_LIST;
} else {
if(serializer->status.buffer.size_used == serializer->buffer.size)
return(-1);
serializer->buffer.data[serializer->status.buffer.size_used++] = ndpi_serialization_end_of_list;
}
return(0);
}
/* ********************************** */
/* Serialize start of nested block */
int ndpi_serialize_start_of_block_binary(ndpi_serializer *_serializer,
const char *key, u_int16_t klen) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int32_t needed;
int rc;
if(serializer->fmt != ndpi_serialization_format_json &&
serializer->fmt != ndpi_serialization_format_tlv)
return(-1);
needed = 16 + klen;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if (serializer->fmt == ndpi_serialization_format_json) {
ndpi_serialize_json_pre(_serializer);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
serializer->status.buffer.size_used += ndpi_json_string_escape(key, klen,
(char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
rc = ndpi_snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, ": {");
if(rc < 0 || (u_int)rc >= buff_diff)
return(-1);
serializer->status.buffer.size_used += rc;
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
if(ndpi_serialize_json_post(_serializer) != 0)
return(-1);
serializer->status.flags |= NDPI_SERIALIZER_STATUS_SOB;
} else /* ndpi_serialization_format_tlv */ {
serializer->buffer.data[serializer->status.buffer.size_used++] = ndpi_serialization_start_of_block;
ndpi_serialize_single_string(serializer, key, klen);
}
return(0);
}
/* ********************************** */
/* Serialize start of nested block */
int ndpi_serialize_start_of_block(ndpi_serializer *_serializer,
const char *_key) {
const char *key = _key ? _key : "";
u_int16_t klen = strlen(key);
return(ndpi_serialize_start_of_block_binary(_serializer, key, klen));
}
/* ********************************** */
/* Serialize start of nested block with a numeric key */
int ndpi_serialize_start_of_block_uint32(ndpi_serializer *_serializer, u_int32_t key) {
char buf[11];
int written = ndpi_snprintf(buf, sizeof(buf), "%u", key);
if (written <= 0 || written == sizeof(buf))
{
return(-1);
}
return(ndpi_serialize_start_of_block_binary(_serializer, buf, written));
}
/* ********************************** */
/* Serialize end of nested block (JSON only)*/
int ndpi_serialize_end_of_block(ndpi_serializer *_serializer) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
u_int32_t needed;
if(serializer->fmt != ndpi_serialization_format_json &&
serializer->fmt != ndpi_serialization_format_tlv)
return(-1);
needed = 4;
if(buff_diff < needed) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
return(-1);
buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
if (serializer->fmt == ndpi_serialization_format_json) {
if(serializer->status.flags & NDPI_SERIALIZER_STATUS_SOB) /* Empty block */
serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_SOB;
// buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
serializer->status.flags |= NDPI_SERIALIZER_STATUS_CEOB;
if(ndpi_serialize_json_post(_serializer) != 0)
return(-1);
} else {
serializer->buffer.data[serializer->status.buffer.size_used++] = ndpi_serialization_end_of_block;
}
return(0);
}
/* ********************************** */
void ndpi_serializer_create_snapshot(ndpi_serializer *_serializer) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
memcpy(&serializer->snapshot, &serializer->status, sizeof(ndpi_private_serializer_status));
serializer->has_snapshot = 1;
}
/* ********************************** */
void ndpi_serializer_rollback_snapshot(ndpi_serializer *_serializer) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
if(serializer->has_snapshot) {
memcpy(&serializer->status, &serializer->snapshot, sizeof(ndpi_private_serializer_status));
serializer->has_snapshot = 0;
if(serializer->fmt == ndpi_serialization_format_json) {
if(serializer->status.flags & NDPI_SERIALIZER_STATUS_ARRAY) {
if (!serializer->multiline_json_array)
serializer->buffer.data[serializer->status.buffer.size_used-1] = ']';
} else {
if (!serializer->multiline_json_array)
serializer->buffer.data[0] = ' ';
if (!serializer->inner_json)
serializer->buffer.data[serializer->status.buffer.size_used-1] = '}';
}
}
}
}
/* ********************************** */
/* ********************************** */
int ndpi_init_deserializer_buf(ndpi_deserializer *_deserializer,
u_int8_t *serialized_buffer,
u_int32_t serialized_buffer_len) {
ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer;
if(serialized_buffer_len < (2 * sizeof(u_int8_t)))
return(-1);
deserializer->buffer.data = serialized_buffer;
if(deserializer->buffer.data[0] != 1)
return(-2); /* Invalid version */
deserializer->buffer.size = serialized_buffer_len;
deserializer->fmt = deserializer->buffer.data[1];
ndpi_reset_serializer(_deserializer);
return(0);
}
/* ********************************** */
int ndpi_init_deserializer(ndpi_deserializer *deserializer,
ndpi_serializer *_serializer) {
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
return(ndpi_init_deserializer_buf(deserializer,
serializer->buffer.data,
serializer->status.buffer.size_used));
}
/* ********************************** */
ndpi_serialization_format ndpi_deserialize_get_format(ndpi_deserializer *_deserializer) {
ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer;
return(deserializer->fmt);
}
/* ********************************** */
static inline ndpi_serialization_type ndpi_deserialize_get_key_subtype(ndpi_private_deserializer *deserializer) {
u_int8_t type;
if(deserializer->status.buffer.size_used >= deserializer->buffer.size)
return(ndpi_serialization_unknown);
type = deserializer->buffer.data[deserializer->status.buffer.size_used];
return((ndpi_serialization_type) (type >> 4));
}
/* ********************************** */
static inline ndpi_serialization_type ndpi_deserialize_get_value_subtype(ndpi_private_deserializer *deserializer) {
u_int8_t type;
if(deserializer->status.buffer.size_used >= deserializer->buffer.size)
return(ndpi_serialization_unknown);
type = deserializer->buffer.data[deserializer->status.buffer.size_used];
return(ndpi_serialization_type) (type & 0xf);
}
/* ********************************** */
ndpi_serialization_type ndpi_deserialize_get_item_type(ndpi_deserializer *_deserializer, ndpi_serialization_type *key_type) {
ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer;
ndpi_serialization_type kt, et;
/* Note: 32/64 bit types are automatically encoded/decoded as 8/16 bit */
kt = ndpi_deserialize_get_key_subtype(deserializer);
switch(kt) {
case ndpi_serialization_uint8:
case ndpi_serialization_uint16:
kt = ndpi_serialization_uint32;
break;
default:
break;
}
et = ndpi_deserialize_get_value_subtype(deserializer);
switch(et) {
case ndpi_serialization_uint8:
case ndpi_serialization_uint16:
et = ndpi_serialization_uint32;
break;
case ndpi_serialization_int8:
case ndpi_serialization_int16:
et = ndpi_serialization_int32;
break;
default:
break;
}
*key_type = kt;
return(et);
}
/* ********************************** */
static inline int ndpi_deserialize_get_single_string_size(ndpi_private_deserializer *deserializer, u_int32_t offset) {
u_int32_t buff_diff = deserializer->buffer.size - offset;
u_int16_t expected, str_len;
expected = sizeof(u_int16_t) /* len */;
if(buff_diff < expected) return(-2);
str_len = ntohs(*((u_int16_t *) &deserializer->buffer.data[offset]));
expected += str_len;
if(buff_diff < expected) return(-2);
return(expected);
}
/* ********************************** */
static inline int ndpi_deserialize_get_single_size(ndpi_private_deserializer *deserializer, ndpi_serialization_type type, u_int32_t offset) {
u_int16_t size;
switch(type) {
case ndpi_serialization_uint8:
case ndpi_serialization_int8:
size = sizeof(u_int8_t);
break;
case ndpi_serialization_uint16:
case ndpi_serialization_int16:
size = sizeof(u_int16_t);
break;
case ndpi_serialization_uint32:
case ndpi_serialization_int32:
size = sizeof(u_int32_t);
break;
case ndpi_serialization_uint64:
case ndpi_serialization_int64:
size = sizeof(u_int64_t);
break;
case ndpi_serialization_float:
size = sizeof(float);
break;
case ndpi_serialization_double:
size = sizeof(double);
break;
case ndpi_serialization_string:
case ndpi_serialization_start_of_block:
case ndpi_serialization_start_of_list:
size = ndpi_deserialize_get_single_string_size(deserializer, offset);
break;
case ndpi_serialization_end_of_record:
case ndpi_serialization_end_of_block:
case ndpi_serialization_end_of_list:
case ndpi_serialization_unknown:
size = 0;
break;
default:
return(-2);
break;
}
return(size);
}
/* ********************************** */
/* Move the current offset (status.buffer.size_used) to point
* to the next element */
int ndpi_deserialize_next(ndpi_deserializer *_deserializer) {
ndpi_private_deserializer *deserializer = (ndpi_private_deserializer *) _deserializer;
u_int32_t buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used;
ndpi_serialization_type kt, et;
u_int16_t expected;
int size;
expected = sizeof(u_int8_t) /* type */;
if(buff_diff < expected) return(-2);
kt = ndpi_deserialize_get_key_subtype(deserializer);
size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected);
if(size < 0) return(-2);
expected += size;
et = ndpi_deserialize_get_value_subtype(deserializer);
size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.buffer.size_used + expected);
if(size < 0) return(-2);
expected += size;
deserializer->status.buffer.size_used += expected;
return(0);
}
/* ********************************** */
int ndpi_deserialize_key_uint32(ndpi_deserializer *_deserializer,
u_int32_t *key) {
ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer;
u_int32_t offset, buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used;
ndpi_serialization_type kt;
u_int16_t expected;
u_int16_t v16;
u_int8_t v8;
int size;
expected = sizeof(u_int8_t) /* type */;
if(buff_diff < expected) return(-2);
kt = ndpi_deserialize_get_key_subtype(deserializer);
size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected);
if(size < 0) return(-2);
offset = deserializer->status.buffer.size_used + expected;
switch(kt) {
case ndpi_serialization_uint32:
ndpi_deserialize_single_uint32(deserializer, offset, key);
break;
case ndpi_serialization_uint16:
ndpi_deserialize_single_uint16(deserializer, offset, &v16);
*key = v16;
break;
case ndpi_serialization_uint8:
ndpi_deserialize_single_uint8(deserializer, offset, &v8);
*key = v8;
break;
default:
return(-1);
break;
}
return(0);
}
/* ********************************** */
/* Return the string key for the current element */
int ndpi_deserialize_key_string(ndpi_deserializer *_deserializer,
ndpi_string *key) {
ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer;
ndpi_serialization_type kt;
u_int32_t buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used;
u_int16_t expected;
int size;
expected = sizeof(u_int8_t) /* type */;
key->str = NULL;
key->str_len = 0;
if(buff_diff < expected) return(-2);
kt = ndpi_deserialize_get_key_subtype(deserializer);
size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected);
if(size < 0) return(-2);
ndpi_deserialize_single_string(deserializer, deserializer->status.buffer.size_used + expected, key);
return(0);
}
/* ********************************** */
int ndpi_deserialize_value_uint32(ndpi_deserializer *_deserializer,
u_int32_t *value) {
ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer;
ndpi_serialization_type kt, et;
u_int32_t offset, buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used;
u_int16_t v16;
u_int8_t v8;
u_int16_t expected;
int size;
expected = sizeof(u_int8_t) /* type */;
*value = 0;
if(buff_diff < expected) return(-2);
kt = ndpi_deserialize_get_key_subtype(deserializer);
size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected);
if(size < 0) return(-2);
expected += size;
et = ndpi_deserialize_get_value_subtype(deserializer);
size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.buffer.size_used + expected);
if(size < 0) return(-2);
offset = deserializer->status.buffer.size_used + expected;
switch(et) {
case ndpi_serialization_uint32:
ndpi_deserialize_single_uint32(deserializer, offset, value);
break;
case ndpi_serialization_uint16:
ndpi_deserialize_single_uint16(deserializer, offset, &v16);
*value = v16;
break;
case ndpi_serialization_uint8:
ndpi_deserialize_single_uint8(deserializer, offset, &v8);
*value = v8;
break;
default:
break;
}
return(0);
}
/* ********************************** */
int ndpi_deserialize_value_uint64(ndpi_deserializer *_deserializer,
u_int64_t *value) {
ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer;
ndpi_serialization_type kt, et;
u_int32_t buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used;
u_int32_t v32;
u_int16_t expected;
int size;
int rc;
expected = sizeof(u_int8_t) /* type */;
if(buff_diff < expected) return(-2);
kt = ndpi_deserialize_get_key_subtype(deserializer);
size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected);
if(size < 0) return(-2);
expected += size;
et = ndpi_deserialize_get_value_subtype(deserializer);
size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.buffer.size_used + expected);
if(size < 0) return(-2);
if(et != ndpi_serialization_uint64) {
/* Try with smaller uint types */
rc = ndpi_deserialize_value_uint32(_deserializer, &v32);
*value = v32;
return(rc);
}
ndpi_deserialize_single_uint64(deserializer, deserializer->status.buffer.size_used + expected, value);
return(0);
}
/* ********************************** */
int ndpi_deserialize_value_int32(ndpi_deserializer *_deserializer,
int32_t *value) {
ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer;
ndpi_serialization_type kt, et;
u_int32_t offset, buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used;
int16_t v16;
int8_t v8;
u_int16_t expected;
int size;
expected = sizeof(u_int8_t) /* type */;
*value = 0;
if(buff_diff < expected) return(-2);
kt = ndpi_deserialize_get_key_subtype(deserializer);
size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected);
if(size < 0) return(-2);
expected += size;
et = ndpi_deserialize_get_value_subtype(deserializer);
size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.buffer.size_used + expected);
if(size < 0) return(-2);
offset = deserializer->status.buffer.size_used + expected;
switch(et) {
case ndpi_serialization_int32:
ndpi_deserialize_single_int32(deserializer, offset, value);
break;
case ndpi_serialization_int16:
ndpi_deserialize_single_int16(deserializer, offset, &v16);
*value = v16;
break;
case ndpi_serialization_int8:
ndpi_deserialize_single_int8(deserializer, offset, &v8);
*value = v8;
break;
default:
break;
}
return(0);
}
/* ********************************** */
int ndpi_deserialize_value_int64(ndpi_deserializer *_deserializer,
int64_t *value) {
ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer;
ndpi_serialization_type kt, et;
u_int32_t buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used;
int32_t v32;
u_int16_t expected;
int size;
int rc;
expected = sizeof(u_int8_t) /* type */;
*value = 0;
if(buff_diff < expected) return(-2);
kt = ndpi_deserialize_get_key_subtype(deserializer);
size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected);
if(size < 0) return(-2);
expected += size;
et = ndpi_deserialize_get_value_subtype(deserializer);
size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.buffer.size_used + expected);
if(size < 0) return(-2);
if(et != ndpi_serialization_int64) {
/* Try with smaller int types */
rc = ndpi_deserialize_value_int32(_deserializer, &v32);
*value = v32;
return(rc);
}
ndpi_deserialize_single_int64(deserializer, deserializer->status.buffer.size_used + expected, value);
return(0);
}
/* ********************************** */
int ndpi_deserialize_value_float(ndpi_deserializer *_deserializer,
float *value) {
ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer;
ndpi_serialization_type kt, et;
u_int32_t buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used;
u_int16_t expected;
int size;
expected = sizeof(u_int8_t) /* type */;
*value = 0;
if(buff_diff < expected) return(-2);
kt = ndpi_deserialize_get_key_subtype(deserializer);
size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected);
if(size < 0) return(-2);
expected += size;
et = ndpi_deserialize_get_value_subtype(deserializer);
size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.buffer.size_used + expected);
if(size < 0) return(-2);
if(et != ndpi_serialization_float)
return(-1);
ndpi_deserialize_single_float(deserializer, deserializer->status.buffer.size_used + expected, value);
return(0);
}
/* ********************************** */
int ndpi_deserialize_value_double(ndpi_deserializer *_deserializer,
double *value) {
ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer;
ndpi_serialization_type kt, et;
u_int32_t buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used;
u_int16_t expected;
int size;
expected = sizeof(u_int8_t) /* type */;
*value = 0;
if(buff_diff < expected) return(-2);
kt = ndpi_deserialize_get_key_subtype(deserializer);
size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected);
if(size < 0) return(-2);
expected += size;
et = ndpi_deserialize_get_value_subtype(deserializer);
size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.buffer.size_used + expected);
if(size < 0) return(-2);
if(et != ndpi_serialization_double)
return(-1);
ndpi_deserialize_single_double(deserializer, deserializer->status.buffer.size_used + expected, value);
return(0);
}
/* ********************************** */
/* Return the string value for the current element */
int ndpi_deserialize_value_string(ndpi_deserializer *_deserializer,
ndpi_string *value) {
ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer;
ndpi_serialization_type kt, et;
u_int32_t buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used;
u_int16_t expected;
int size;
expected = sizeof(u_int8_t) /* type */;
value->str = NULL;
value->str_len = 0;
if(buff_diff < expected) return(-2);
kt = ndpi_deserialize_get_key_subtype(deserializer);
size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected);
if(size < 0) return(-2);
expected += size;
et = ndpi_deserialize_get_value_subtype(deserializer);
size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.buffer.size_used + expected);
if(size < 0) return(-2);
if(et != ndpi_serialization_string)
return(-1);
ndpi_deserialize_single_string(deserializer, deserializer->status.buffer.size_used + expected, value);
return(0);
}
/* ********************************** */
/* Clone (with memcpy) the current item in deserializer to serializer (TLV only) */
int ndpi_deserialize_clone_item(ndpi_deserializer *_deserializer, ndpi_serializer *_serializer) {
ndpi_private_deserializer *deserializer = (ndpi_private_deserializer *) _deserializer;
ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
u_int32_t src_buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used;
u_int32_t dst_buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
ndpi_serialization_type kt, et;
u_int16_t expected;
int size;
if(serializer->fmt != ndpi_serialization_format_tlv)
return(-3);
expected = sizeof(u_int8_t) /* type */;
if(src_buff_diff < expected) return(-2);
kt = ndpi_deserialize_get_key_subtype(deserializer);
size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected);
if(size < 0) return(-2);
expected += size;
et = ndpi_deserialize_get_value_subtype(deserializer);
size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.buffer.size_used + expected);
if(size < 0) return(-2);
expected += size;
if(dst_buff_diff < expected) {
if(ndpi_extend_serializer_buffer(&serializer->buffer, expected - dst_buff_diff) < 0)
return(-1);
dst_buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
}
memcpy(&serializer->buffer.data[serializer->status.buffer.size_used],
&deserializer->buffer.data[deserializer->status.buffer.size_used],
expected);
serializer->status.buffer.size_used += expected;
return(0);
}
/* ********************************** */
/* Clone all elements in deserializer to serializer (this can be used to convert a TLV record to JSON) */
int ndpi_deserialize_clone_all(ndpi_deserializer *deserializer, ndpi_serializer *serializer) {
ndpi_serialization_type kt, et;
u_int32_t u32, k32;
int32_t i32;
u_int64_t u64;
int64_t i64;
float f;
ndpi_string vs, ks;
int key_is_string;
while((et = ndpi_deserialize_get_item_type(deserializer, &kt)) != ndpi_serialization_unknown) {
if(et == ndpi_serialization_end_of_record) {
ndpi_serialize_end_of_record(serializer);
goto next;
} else if(et == ndpi_serialization_start_of_block) {
ndpi_deserialize_key_string(deserializer, &ks);
ndpi_serialize_start_of_block_binary(serializer, ks.str, ks.str_len);
goto next;
} else if(et == ndpi_serialization_end_of_block) {
ndpi_serialize_end_of_block(serializer);
goto next;
} else if(et == ndpi_serialization_start_of_list) {
ndpi_deserialize_key_string(deserializer, &ks);
ndpi_serialize_start_of_list_binary(serializer, ks.str, ks.str_len);
goto next;
} else if(et == ndpi_serialization_end_of_list) {
ndpi_serialize_end_of_list(serializer);
goto next;
}
key_is_string = 0;
switch(kt) {
case ndpi_serialization_uint32:
ndpi_deserialize_key_uint32(deserializer, &k32);
break;
case ndpi_serialization_string:
ndpi_deserialize_key_string(deserializer, &ks);
key_is_string = 1;
break;
default:
return(-1);
}
switch(et) {
case ndpi_serialization_uint32:
ndpi_deserialize_value_uint32(deserializer, &u32);
if(key_is_string) ndpi_serialize_binary_uint32(serializer, ks.str, ks.str_len, u32);
else ndpi_serialize_uint32_uint32(serializer, k32, u32);
break;
case ndpi_serialization_uint64:
ndpi_deserialize_value_uint64(deserializer, &u64);
if(key_is_string) ndpi_serialize_binary_uint64(serializer, ks.str, ks.str_len, u64);
else ndpi_serialize_uint32_uint64(serializer, k32, u64);
break;
case ndpi_serialization_int32:
ndpi_deserialize_value_int32(deserializer, &i32);
if(key_is_string) ndpi_serialize_binary_int32(serializer, ks.str, ks.str_len, i32);
else ndpi_serialize_uint32_int32(serializer, k32, i32);
break;
case ndpi_serialization_int64:
ndpi_deserialize_value_int64(deserializer, &i64);
if(key_is_string) ndpi_serialize_binary_int64(serializer, ks.str, ks.str_len, i64);
else ndpi_serialize_uint32_int64(serializer, k32, i64);
break;
case ndpi_serialization_float:
ndpi_deserialize_value_float(deserializer, &f);
if(key_is_string) ndpi_serialize_binary_float(serializer, ks.str, ks.str_len, f, "%.3f");
else ndpi_serialize_uint32_float(serializer, k32, f, "%.3f");
break;
case ndpi_serialization_string:
ndpi_deserialize_value_string(deserializer, &vs);
if(key_is_string) ndpi_serialize_binary_binary(serializer, ks.str, ks.str_len, vs.str, vs.str_len);
else ndpi_serialize_uint32_binary(serializer, k32, vs.str, vs.str_len);
break;
default:
return(-2);
}
next:
ndpi_deserialize_next(deserializer);
}
return(0);
}
/* ********************************** */