Skip to content

Commit a7430fd

Browse files
committed
Various improvements to encoding/decoding functions
1 parent 24e13d1 commit a7430fd

File tree

2 files changed

+69
-24
lines changed

2 files changed

+69
-24
lines changed

src/cloudsync.c

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2011,14 +2011,6 @@ int cloudsync_payload_encode_step (cloudsync_payload_context *payload, cloudsync
20112011
return DBRES_OK;
20122012
}
20132013

2014-
char *cloudsync_payload_blob (cloudsync_payload_context *payload, int64_t *blob_size, int64_t *nrows) {
2015-
DEBUG_FUNCTION("cloudsync_payload_blob");
2016-
2017-
if (blob_size) *blob_size = (int64_t)payload->bsize;
2018-
if (nrows) *nrows = (int64_t)payload->nrows;
2019-
return payload->buffer;
2020-
}
2021-
20222014
int cloudsync_payload_encode_final (cloudsync_payload_context *payload, cloudsync_context *data) {
20232015
DEBUG_FUNCTION("cloudsync_payload_encode_final");
20242016

@@ -2037,9 +2029,25 @@ int cloudsync_payload_encode_final (cloudsync_payload_context *payload, cloudsyn
20372029
return DBRES_ERROR;
20382030
}
20392031

2040-
// try to allocate buffer used for compressed data
2032+
// sanity check about buffer size
20412033
int header_size = (int)sizeof(cloudsync_payload_header);
2042-
int real_buffer_size = (int)(payload->bused - header_size);
2034+
int64_t buffer_size = (int64_t)payload->bused - (int64_t)header_size;
2035+
if (buffer_size < 0) {
2036+
if (payload->buffer) cloudsync_memory_free(payload->buffer);
2037+
payload->buffer = NULL;
2038+
payload->bsize = 0;
2039+
cloudsync_set_error(data, "cloudsync_encode: internal size underflow", DBRES_ERROR);
2040+
return DBRES_ERROR;
2041+
}
2042+
if (buffer_size > INT_MAX) {
2043+
if (payload->buffer) cloudsync_memory_free(payload->buffer);
2044+
payload->buffer = NULL;
2045+
payload->bsize = 0;
2046+
cloudsync_set_error(data, "cloudsync_encode: payload too large to compress (INT_MAX limit)", DBRES_ERROR);
2047+
return DBRES_ERROR;
2048+
}
2049+
// try to allocate buffer used for compressed data
2050+
int real_buffer_size = (int)buffer_size;
20432051
int zbound = LZ4_compressBound(real_buffer_size);
20442052
char *zbuffer = cloudsync_memory_alloc(zbound + header_size); // if for some reasons allocation fails then just skip compression
20452053

@@ -2075,6 +2083,14 @@ int cloudsync_payload_encode_final (cloudsync_payload_context *payload, cloudsyn
20752083
return DBRES_OK;
20762084
}
20772085

2086+
char *cloudsync_payload_blob (cloudsync_payload_context *payload, int64_t *blob_size, int64_t *nrows) {
2087+
DEBUG_FUNCTION("cloudsync_payload_blob");
2088+
2089+
if (blob_size) *blob_size = (int64_t)payload->bsize;
2090+
if (nrows) *nrows = (int64_t)payload->nrows;
2091+
return payload->buffer;
2092+
}
2093+
20782094
static int cloudsync_payload_decode_callback (void *xdata, int index, int type, int64_t ival, double dval, char *pval) {
20792095
cloudsync_pk_decode_bind_context *decode_context = (cloudsync_pk_decode_bind_context*)xdata;
20802096
int rc = pk_decode_bind_callback(decode_context->vm, index, type, ival, dval, pval);

src/pk.c

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@
6464
* Versatility: The ability to handle multiple data types and variable-length data makes this solution suitable for complex data structures.
6565
* Simplicity: The functions are designed to be straightforward to use, with clear memory management responsibilities.
6666
67+
Notes
68+
69+
* Floating point values are encoded as IEEE754 double, 64-bit, big-endian byte order.
70+
6771
*/
6872

6973
// Three bits are reserved for the type field, so only values in the 0..7 range can be used (8 values)
@@ -77,6 +81,24 @@
7781
#define DATABASE_TYPE_MAX_NEGATIVE_INTEGER 6 // was SQLITE_MAX_NEGATIVE_INTEGER
7882
#define DATABASE_TYPE_NEGATIVE_FLOAT 7 // was SQLITE_NEGATIVE_FLOAT
7983

84+
// MARK: - Utils -
85+
86+
static inline uint64_t host_to_be64(uint64_t v) {
87+
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
88+
return __builtin_bswap64(v);
89+
#else
90+
return v;
91+
#endif
92+
}
93+
94+
static inline uint64_t be64_to_host(uint64_t v) {
95+
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
96+
return __builtin_bswap64(v);
97+
#else
98+
return v;
99+
#endif
100+
}
101+
80102
// MARK: - Decoding -
81103

82104
int pk_decode_bind_callback (void *xdata, int index, int type, int64_t ival, double dval, char *pval) {
@@ -123,7 +145,7 @@ int pk_decode_print_callback (void *xdata, int index, int type, int64_t ival, do
123145
break;
124146

125147
case DBTYPE_TEXT:
126-
printf("%d\tTEXT:\t%s\n", index, pval);
148+
printf("%d\tTEXT:\t%.*s\n", index, (int)ival, pval);
127149
break;
128150

129151
case DBTYPE_BLOB:
@@ -160,9 +182,13 @@ char *pk_decode_data (char *buffer, size_t *bseek, int32_t blen) {
160182
}
161183

162184
double pk_decode_double (char *buffer, size_t *bseek) {
185+
// Doubles are encoded as IEEE754 64-bit, big-endian.
186+
// Convert back to host order before memcpy into double.
187+
163188
double value = 0;
164-
int64_t int64value = pk_decode_int64(buffer, bseek, sizeof(int64_t));
165-
memcpy(&value, &int64value, sizeof(int64_t));
189+
uint64_t bits_be = (uint64_t)pk_decode_int64(buffer, bseek, sizeof(uint64_t));
190+
uint64_t bits = be64_to_host(bits_be);
191+
memcpy(&value, &bits, sizeof(bits));
166192

167193
return value;
168194
}
@@ -228,14 +254,15 @@ int pk_decode_prikey (char *buffer, size_t blen, int (*cb) (void *xdata, int ind
228254
// MARK: - Encoding -
229255

230256
size_t pk_encode_nbytes_needed (int64_t value) {
231-
if (value <= 0x7F) return 1; // 7 bits
232-
if (value <= 0x7FFF) return 2; // 15 bits
233-
if (value <= 0x7FFFFF) return 3; // 23 bits
234-
if (value <= 0x7FFFFFFF) return 4; // 31 bits
235-
if (value <= 0x7FFFFFFFFF) return 5; // 39 bits
236-
if (value <= 0x7FFFFFFFFFFF) return 6; // 47 bits
237-
if (value <= 0x7FFFFFFFFFFFFF) return 7; // 55 bits
238-
return 8; // Larger than 7-byte range, needs 8 bytes
257+
uint64_t v = (uint64_t)value;
258+
if (v <= 0xFFULL) return 1;
259+
if (v <= 0xFFFFULL) return 2;
260+
if (v <= 0xFFFFFFULL) return 3;
261+
if (v <= 0xFFFFFFFFULL) return 4;
262+
if (v <= 0xFFFFFFFFFFULL) return 5;
263+
if (v <= 0xFFFFFFFFFFFFULL) return 6;
264+
if (v <= 0xFFFFFFFFFFFFFFULL) return 7;
265+
return 8;
239266
}
240267

241268
size_t pk_encode_size (dbvalue_t **argv, int argc, int reserved) {
@@ -326,12 +353,14 @@ char *pk_encode (dbvalue_t **argv, int argc, char *b, bool is_prikey, size_t *bs
326353
}
327354
break;
328355
case DBTYPE_FLOAT: {
356+
// Encode doubles as IEEE754 64-bit, big-endian
329357
double value = database_value_double(argv[i]);
330358
if (value < 0) {value = -value; type = DATABASE_TYPE_NEGATIVE_FLOAT;}
331-
int64_t net_double;
332-
memcpy(&net_double, &value, sizeof(int64_t));
359+
uint64_t bits;
360+
memcpy(&bits, &value, sizeof(bits));
361+
bits = host_to_be64(bits);
333362
bseek = pk_encode_u8(buffer, bseek, (uint8_t)type);
334-
bseek = pk_encode_int64(buffer, bseek, net_double, sizeof(int64_t));
363+
bseek = pk_encode_int64(buffer, bseek, (int64_t)bits, sizeof(bits));
335364
}
336365
break;
337366
case DBTYPE_TEXT:

0 commit comments

Comments
 (0)