|
64 | 64 | * Versatility: The ability to handle multiple data types and variable-length data makes this solution suitable for complex data structures. |
65 | 65 | * Simplicity: The functions are designed to be straightforward to use, with clear memory management responsibilities. |
66 | 66 | |
| 67 | + Notes |
| 68 | + |
| 69 | + * Floating point values are encoded as IEEE754 double, 64-bit, big-endian byte order. |
| 70 | + |
67 | 71 | */ |
68 | 72 |
|
69 | 73 | // Three bits are reserved for the type field, so only values in the 0..7 range can be used (8 values) |
|
77 | 81 | #define DATABASE_TYPE_MAX_NEGATIVE_INTEGER 6 // was SQLITE_MAX_NEGATIVE_INTEGER |
78 | 82 | #define DATABASE_TYPE_NEGATIVE_FLOAT 7 // was SQLITE_NEGATIVE_FLOAT |
79 | 83 |
|
| 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 | + |
80 | 102 | // MARK: - Decoding - |
81 | 103 |
|
82 | 104 | 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 |
123 | 145 | break; |
124 | 146 |
|
125 | 147 | case DBTYPE_TEXT: |
126 | | - printf("%d\tTEXT:\t%s\n", index, pval); |
| 148 | + printf("%d\tTEXT:\t%.*s\n", index, (int)ival, pval); |
127 | 149 | break; |
128 | 150 |
|
129 | 151 | case DBTYPE_BLOB: |
@@ -160,9 +182,13 @@ char *pk_decode_data (char *buffer, size_t *bseek, int32_t blen) { |
160 | 182 | } |
161 | 183 |
|
162 | 184 | 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 | + |
163 | 188 | 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)); |
166 | 192 |
|
167 | 193 | return value; |
168 | 194 | } |
@@ -228,14 +254,15 @@ int pk_decode_prikey (char *buffer, size_t blen, int (*cb) (void *xdata, int ind |
228 | 254 | // MARK: - Encoding - |
229 | 255 |
|
230 | 256 | 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; |
239 | 266 | } |
240 | 267 |
|
241 | 268 | 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 |
326 | 353 | } |
327 | 354 | break; |
328 | 355 | case DBTYPE_FLOAT: { |
| 356 | + // Encode doubles as IEEE754 64-bit, big-endian |
329 | 357 | double value = database_value_double(argv[i]); |
330 | 358 | 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); |
333 | 362 | 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)); |
335 | 364 | } |
336 | 365 | break; |
337 | 366 | case DBTYPE_TEXT: |
|
0 commit comments