int serialize_table_as_pb(lua_sandbox* lsb, int index) { output_data* d = &lsb->output; d->pos = 0; size_t needed = 18; if (needed > d->size) { if (realloc_output(d, needed)) return 1; } // create a type 4 uuid d->data[d->pos++] = 2 | (1 << 3); d->data[d->pos++] = 16; for (int x = 0; x < 16; ++x) { d->data[d->pos++] = rand() % 255; } d->data[8] = (d->data[8] & 0x0F) | 0x40; d->data[10] = (d->data[10] & 0x0F) | 0xA0; // use existing or create a timestamp lua_getfield(lsb->lua, index, "Timestamp"); long long ts; if (lua_isnumber(lsb->lua, -1)) { ts = (long long)lua_tonumber(lsb->lua, -1); } else { ts = (long long)(time(NULL) * 1e9); } lua_pop(lsb->lua, 1); if (pb_write_tag(d, 2, 0)) return 1; if (pb_write_varint(d, ts)) return 1; if (encode_string(lsb, d, 3, "Type", index)) return 1; if (encode_string(lsb, d, 4, "Logger", index)) return 1; if (encode_int(lsb, d, 5, "Severity", index)) return 1; if (encode_string(lsb, d, 6, "Payload", index)) return 1; if (encode_string(lsb, d, 7, "EnvVersion", index)) return 1; if (encode_int(lsb, d, 8, "Pid", index)) return 1; if (encode_string(lsb, d, 9, "Hostname", index)) return 1; if (encode_fields(lsb, d, 10, "Fields", index)) return 1; // if we go above 15 pb_write_tag will need to start varint encoding needed = 1; if (needed > d->size - d->pos) { if (realloc_output(d, needed)) return 1; } d->data[d->pos] = 0; // NULL terminate incase someone tries to treat this // as a string return 0; }
int appendc(output_data* output, char ch) { size_t needed = 2; if (output->size - output->pos < needed) { if (realloc_output(output, needed)) return 1; } output->data[output->pos++] = ch; output->data[output->pos] = 0; return 0; }
int appends(output_data* output, const char* str) { size_t needed = strlen(str) + 1; if (output->size - output->pos < needed) { if (realloc_output(output, needed)) return 1; } memcpy(output->data + output->pos, str, needed); output->pos += needed - 1; return 0; }
int pb_write_tag(output_data* d, char id, char wire_type) { size_t needed = 1; if (needed > d->size - d->pos) { if (realloc_output(d, needed)) return 1; } d->data[d->pos++] = wire_type | (id << 3); return 0; }
int pb_write_double(output_data* d, double i) { size_t needed = sizeof(double); if (needed > d->size - d->pos) { if (realloc_output(d, needed)) return 1; } memcpy(&d->data[d->pos], &i, needed); d->pos += needed; return 0; }
int pb_write_bool(output_data* d, int i) { size_t needed = 1; if (needed > d->size - d->pos) { if (realloc_output(d, needed)) return 1; } if (i) { d->data[d->pos++] = 1; } else { d->data[d->pos++] = 0; } return 0; }
int pb_write_string(output_data* d, char id, const char* s, size_t len) { if (pb_write_tag(d, id, 2)) return 1; if (pb_write_varint(d, len)) return 1; size_t needed = len; if (needed > d->m_size - d->m_pos) { if (realloc_output(d, needed)) return 1; } memcpy(&d->m_data[d->m_pos], s, len); d->m_pos += len; return 0; }
int pb_write_varint(output_data* d, long long i) { size_t needed = 10; if (needed > d->size - d->pos) { if (realloc_output(d, needed)) return 1; } if (i == 0) { d->data[d->pos++] = 0; return 0; } while (i) { d->data[d->pos++] = (i & 0x7F) | 0x80; i >>= 7; } d->data[d->pos - 1] &= 0x7F; // end the varint return 0; }
int update_field_length(output_data* d, size_t len_pos) { size_t len = d->pos - len_pos - 1; if (len < 128) { d->data[len_pos] = (char)len; return 0; } size_t l = len, cnt = 0; while (l) { l >>= 7; ++cnt; // compute the number of bytes needed for the varint length } size_t needed = cnt - 1; if (needed > d->size - d->pos) { if (realloc_output(d, needed)) return 1; } size_t end_pos = d->pos + needed; memmove(&d->data[len_pos + cnt], &d->data[len_pos + 1], len); d->pos = len_pos; if (pb_write_varint(d, len)) return 1; d->pos = end_pos; return 0; }
int serialize_data_as_json(lua_sandbox* lsb, int index, output_data* output) { const char* s; size_t len = 0; size_t start_pos = output->pos; size_t escaped_len = 0; switch (lua_type(lsb->lua, index)) { case LUA_TNUMBER: if (serialize_double(output, lua_tonumber(lsb->lua, index))) { return 1; } break; case LUA_TSTRING: s = lua_tolstring(lsb->lua, index, &len); escaped_len = len + 3; // account for the quotes and terminator if (output->pos + escaped_len > output->size) { if (realloc_output(output, escaped_len)) return 1; } output->data[output->pos++] = '"'; for (size_t i = 0; i < len; ++i) { // buffer needs at least enough room for an escaped character, an end // quote and a null terminator if (output->pos + 4 > output->size) { size_t needed = escaped_len - (output->pos - start_pos); if (realloc_output(output, needed)) return 1; } switch (s[i]) { case '"': output->data[output->pos++] = '\\'; output->data[output->pos++] = '"'; ++escaped_len; break; case '\\': output->data[output->pos++] = '\\'; output->data[output->pos++] = '\\'; ++escaped_len; break; case '/': output->data[output->pos++] = '\\'; output->data[output->pos++] = '/'; ++escaped_len; break; case '\b': output->data[output->pos++] = '\\'; output->data[output->pos++] = 'b'; ++escaped_len; break; case '\f': output->data[output->pos++] = '\\'; output->data[output->pos++] = 'f'; ++escaped_len; break; case '\n': output->data[output->pos++] = '\\'; output->data[output->pos++] = 'n'; ++escaped_len; break; case '\r': output->data[output->pos++] = '\\'; output->data[output->pos++] = 'r'; ++escaped_len; break; case '\t': output->data[output->pos++] = '\\'; output->data[output->pos++] = 't'; ++escaped_len; break; default: output->data[output->pos++] = s[i]; } } output->data[output->pos++] = '"'; output->data[output->pos] = 0; break; case LUA_TBOOLEAN: if (appendf(output, "%s", lua_toboolean(lsb->lua, index) ? "true" : "false")) { return 1; } case LUA_TNIL: break; default: snprintf(lsb->error_message, LSB_ERROR_SIZE, "serialize_data_as_json cannot preserve type '%s'", lua_typename(lsb->lua, lua_type(lsb->lua, index))); return 1; } return 0; }