1/*
2 * particle_blob.c
3 *
4 * Copyright (C) 2015 Aerospike, Inc.
5 *
6 * Portions may be licensed to Aerospike, Inc. under one or more contributor
7 * license agreements.
8 *
9 * This program is free software: you can redistribute it and/or modify it under
10 * the terms of the GNU Affero General Public License as published by the Free
11 * Software Foundation, either version 3 of the License, or (at your option) any
12 * later version.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see http://www.gnu.org/licenses/
21 */
22
23
24#include "base/particle_blob.h"
25
26#include <stddef.h>
27#include <stdint.h>
28#include <string.h>
29
30#include "aerospike/as_bytes.h"
31#include "aerospike/as_msgpack.h"
32#include "aerospike/as_val.h"
33#include "citrusleaf/alloc.h"
34#include "citrusleaf/cf_byte_order.h"
35
36#include "bits.h"
37#include "fault.h"
38
39#include "base/datamodel.h"
40#include "base/particle.h"
41#include "base/proto.h"
42
43#include "warnings.h"
44
45
46// BLOB particle interface function declarations are in particle_blob.h since
47// BLOB functions are used by other particles derived from BLOB.
48
49
50//==========================================================
51// BLOB particle interface - vtable.
52//
53
54const as_particle_vtable blob_vtable = {
55 blob_destruct,
56 blob_size,
57
58 blob_concat_size_from_wire,
59 blob_append_from_wire,
60 blob_prepend_from_wire,
61 blob_incr_from_wire,
62 blob_size_from_wire,
63 blob_from_wire,
64 blob_compare_from_wire,
65 blob_wire_size,
66 blob_to_wire,
67
68 blob_size_from_asval,
69 blob_from_asval,
70 blob_to_asval,
71 blob_asval_wire_size,
72 blob_asval_to_wire,
73
74 blob_size_from_msgpack,
75 blob_from_msgpack,
76
77 blob_skip_flat,
78 blob_cast_from_flat,
79 blob_from_flat,
80 blob_flat_size,
81 blob_to_flat
82};
83
84
85//==========================================================
86// Typedefs & constants.
87//
88
89typedef struct blob_mem_s {
90 uint8_t type;
91 uint32_t sz;
92 uint8_t data[];
93} __attribute__ ((__packed__)) blob_mem;
94
95typedef struct blob_flat_s {
96 uint8_t type;
97 uint32_t size; // host order on device
98 uint8_t data[];
99} __attribute__ ((__packed__)) blob_flat;
100
101typedef struct bits_op_s {
102 int32_t offset;
103 uint32_t size;
104 uint64_t value;
105 const uint8_t* buf;
106 uint64_t subflags;
107 uint64_t flags;
108} bits_op;
109
110struct bits_state_s;
111
112typedef bool (*bits_parse_fn) (struct bits_state_s* state, bits_op* op);
113typedef bool (*bits_modify_fn) (const bits_op* op, uint8_t* to,
114 const uint8_t* from, uint32_t n_bytes);
115typedef bool (*bits_read_fn) (const bits_op* op, const uint8_t* from,
116 as_bin* rb, uint32_t n_bytes);
117typedef int (*bits_prepare_op_fn)(struct bits_state_s* state, bits_op* op,
118 uint32_t byte_offset, uint32_t op_size);
119
120typedef struct bits_op_def_s {
121 const bits_prepare_op_fn prepare;
122 union {
123 const bits_modify_fn modify;
124 const bits_read_fn read;
125 } fn;
126 uint64_t bad_flags;
127 uint32_t min_args;
128 uint32_t max_args;
129 const bits_parse_fn* args;
130 const char* name;
131} bits_op_def;
132
133typedef enum {
134 OP_ACTION_OVERWRITE,
135 OP_ACTION_EXPAND,
136 OP_ACTION_REMOVE
137} op_action;
138
139typedef struct bits_state_s {
140 as_bits_op_type op_type;
141 as_unpacker pk;
142 uint32_t ele_count;
143 bits_op_def* def;
144
145 uint32_t n_bytes_head;
146 uint32_t n_bytes_expand;
147 uint32_t n_bytes_op;
148 uint32_t n_bytes_tail;
149 op_action action;
150
151 uint32_t old_size;
152 uint32_t new_size;
153} bits_state;
154
155
156//==========================================================
157// Forward declarations.
158//
159
160static bool bits_state_init(bits_state* state, const as_msg_op* msg_op, bool is_read);
161static bool bits_parse_op(bits_state* state, bits_op* op);
162static bool bits_parse_byte_offset(bits_state* state, bits_op* op);
163static bool bits_parse_offset(bits_state* state, bits_op* op);
164static bool bits_parse_byte_size(bits_state* state, bits_op* op);
165static bool bits_parse_byte_size_allow_zero(bits_state* state, bits_op* op);
166static bool bits_parse_integer_size(bits_state* state, bits_op* op);
167static bool bits_parse_size(bits_state* state, bits_op* op);
168static bool bits_parse_boolean_value(bits_state* state, bits_op* op);
169static bool bits_parse_n_bits_value(bits_state* state, bits_op* op);
170static bool bits_parse_integer_value(bits_state* state, bits_op* op);
171static bool bits_parse_buf(bits_state* state, bits_op* op);
172static bool bits_parse_flags(bits_state* state, bits_op* op);
173static bool bits_parse_resize_subflags(bits_state* state, bits_op* op);
174static bool bits_parse_arithmetic_subflags(bits_state* state, bits_op* op);
175static bool bits_parse_get_integer_subflags(bits_state* state, bits_op* op);
176static bool bits_parse_subflags(bits_state* state, bits_op* op);
177
178static int bits_prepare_read(bits_state* state, bits_op* op, const as_bin* b);
179static int bits_prepare_modify(bits_state* state, bits_op* op, const as_bin* b);
180static int bits_prepare_op(bits_state* state, bits_op* op, const as_bin* b);
181static int32_t bits_normalize_offset(const bits_state* state, bits_op* op);
182static int bits_prepare_resize_op(bits_state* state, bits_op* op, uint32_t byte_offset, uint32_t op_size);
183static int bits_prepare_insert_op(bits_state* state, bits_op* op, uint32_t byte_offset, uint32_t op_size);
184static int bits_prepare_remove_op(bits_state* state, bits_op* op, uint32_t byte_offset, uint32_t op_size);
185static int bits_prepare_modify_op(bits_state* state, bits_op* op, uint32_t byte_offset, uint32_t op_size);
186static int bits_prepare_integer_op(bits_state* state, bits_op* op, uint32_t byte_offset, uint32_t op_size);
187static int bits_prepare_read_op(bits_state* state, bits_op* op, uint32_t byte_offset, uint32_t op_size);
188
189static bool bits_execute_modify_op(const bits_state* state, const bits_op* op, const as_particle* old_blob, as_particle* new_blob);
190static bool bits_execute_read_op(const bits_state* state, const bits_op* op, const as_particle* blob, as_bin* rb);
191
192static bool bits_modify_op_resize(const bits_op* op, uint8_t* to, const uint8_t* from, uint32_t n_bytes);
193static bool bits_modify_op_insert(const bits_op* op, uint8_t* to, const uint8_t* from, uint32_t n_bytes);
194static bool bits_modify_op_set(const bits_op* op, uint8_t* to, const uint8_t* from, uint32_t n_bytes);
195static bool bits_modify_op_or(const bits_op* op, uint8_t* to, const uint8_t* from, uint32_t n_bytes);
196static bool bits_modify_op_xor(const bits_op* op, uint8_t* to, const uint8_t* from, uint32_t n_bytes);
197static bool bits_modify_op_and(const bits_op* op, uint8_t* to, const uint8_t* from, uint32_t n_bytes);
198static bool bits_modify_op_not(const bits_op* op, uint8_t* to, const uint8_t* from, uint32_t n_bytes);
199static bool bits_modify_op_lshift(const bits_op* op, uint8_t* to, const uint8_t* from, uint32_t n_bytes);
200static bool bits_modify_op_rshift(const bits_op* op, uint8_t* to, const uint8_t* from, uint32_t n_bytes);
201static bool bits_modify_op_add(const bits_op* op, uint8_t* to, const uint8_t* from, uint32_t n_bytes);
202static bool bits_modify_op_subtract(const bits_op* op, uint8_t* to, const uint8_t* from, uint32_t n_bytes);
203static bool bits_modify_op_set_int(const bits_op* op, uint8_t* to, const uint8_t* from, uint32_t n_bytes);
204
205static bool bits_read_op_get(const bits_op* op, const uint8_t* from, as_bin* rb, uint32_t n_bytes);
206static bool bits_read_op_count(const bits_op* op, const uint8_t* from, as_bin* rb, uint32_t n_bytes);
207static bool bits_read_op_lscan(const bits_op* op, const uint8_t* from, as_bin* rb, uint32_t n_bytes);
208static bool bits_read_op_rscan(const bits_op* op, const uint8_t* from, as_bin* rb, uint32_t n_bytes);
209static bool bits_read_op_get_integer(const bits_op* op, const uint8_t* from, as_bin* rb, uint32_t n_bytes);
210
211static void lshift(const bits_op* op, uint8_t* to, const uint8_t* from, uint32_t n_bytes);
212static void rshift(const bits_op* op, uint8_t* to, const uint8_t* from, uint32_t n_bytes);
213static void rshift_with_or(const bits_op* op, uint8_t* to, const uint8_t* from, uint32_t n_bytes);
214static void rshift_with_xor(const bits_op* op, uint8_t* to, const uint8_t* from, uint32_t n_bytes);
215static void rshift_with_and(const bits_op* op, uint8_t* to, const uint8_t* from, uint32_t n_bytes);
216static uint64_t load_int(const bits_op* op, const uint8_t* from, uint32_t n_bytes);
217static bool handle_signed_overflow(uint32_t n_bits, bool is_saturate, uint64_t load, uint64_t value, uint64_t* result);
218static void store_int(const bits_op* op, uint8_t* to, uint64_t value, uint32_t n_bytes);
219static void restore_ends(const bits_op* op, uint8_t* to, const uint8_t* from, uint32_t n_bytes);
220
221
222//==========================================================
223// Inlines & macros.
224//
225
226static inline as_particle_type
227blob_bytes_type_to_particle_type(as_bytes_type type)
228{
229 switch (type) {
230 case AS_BYTES_STRING:
231 return AS_PARTICLE_TYPE_STRING;
232 case AS_BYTES_BLOB:
233 return AS_PARTICLE_TYPE_BLOB;
234 case AS_BYTES_JAVA:
235 return AS_PARTICLE_TYPE_JAVA_BLOB;
236 case AS_BYTES_CSHARP:
237 return AS_PARTICLE_TYPE_CSHARP_BLOB;
238 case AS_BYTES_PYTHON:
239 return AS_PARTICLE_TYPE_PYTHON_BLOB;
240 case AS_BYTES_RUBY:
241 return AS_PARTICLE_TYPE_RUBY_BLOB;
242 case AS_BYTES_PHP:
243 return AS_PARTICLE_TYPE_PHP_BLOB;
244 case AS_BYTES_ERLANG:
245 return AS_PARTICLE_TYPE_ERLANG_BLOB;
246 case AS_BYTES_GEOJSON:
247 return AS_PARTICLE_TYPE_GEOJSON;
248 case AS_BYTES_INTEGER:
249 case AS_BYTES_DOUBLE:
250 case AS_BYTES_MAP:
251 case AS_BYTES_LIST:
252 case AS_BYTES_UNDEF:
253 default:
254 break;
255 }
256
257 // Invalid blob types remain as blobs.
258 return AS_PARTICLE_TYPE_BLOB;
259}
260
261#define RSHIFT_WITH_OP(_bop) \
262{ \
263 uint32_t n_shift = (uint32_t)op->value; \
264 const uint8_t* buf = &op->buf[0]; \
265 const uint8_t* end = &op->buf[n_bytes]; \
266 uint32_t r8 = n_shift % 8; \
267 uint32_t l8 = 8 - r8; \
268 uint32_t l64 = 64 - r8; \
269 \
270 if (r8 == 0) { \
271 while (buf < end) { \
272 *to++ = *buf++ _bop *from++; \
273 } \
274 \
275 return; \
276 } \
277 \
278 *to++ = (uint8_t)((*buf++ >> r8) _bop *from++); \
279 \
280 while (buf < end && (buf - op->buf < 8 || (uint64_t)buf % 8 != 0)) { \
281 *to++ = (uint8_t)((((*(buf - 1) << l8) | (*buf >> r8))) _bop *from++); \
282 buf++; \
283 } \
284 \
285 while (end - buf >= 64) { \
286 for (uint32_t i = 0; i < 8; i++) { \
287 uint64_t v = cf_swap_from_be64(*(uint64_t*)(buf - 8)); \
288 uint64_t n = cf_swap_from_be64(*(uint64_t*)buf); \
289 \
290 *(uint64_t*)to = cf_swap_to_be64((v << l64) | (n >> r8)) _bop \
291 *(uint64_t*)from; \
292 to += 8; \
293 buf += 8; \
294 from += 8; \
295 } \
296 } \
297 \
298 while (end - buf >= 8) { \
299 uint64_t v = cf_swap_from_be64(*(uint64_t*)(buf - 8)); \
300 uint64_t n = cf_swap_from_be64(*(uint64_t*)buf); \
301 \
302 *(uint64_t*)to = cf_swap_to_be64((v << l64) | (n >> r8)) _bop \
303 *(uint64_t*)from; \
304 to += 8; \
305 buf += 8; \
306 from += 8; \
307 } \
308 \
309 while (buf < end) { \
310 *to++ = (uint8_t)((((*(buf - 1) << l8) | (*buf >> r8))) _bop *from++); \
311 buf++; \
312 } \
313}
314
315#define BITS_MODIFY_OP_ENTRY(_op, _op_fn, _prep_fn, _flags, _min_args, \
316 _max_args, ...) \
317 [_op].name = # _op, [_op].prepare = _prep_fn, [_op].fn.modify = _op_fn, \
318 [_op].bad_flags = ~((uint64_t)(_flags)), [_op].min_args = _min_args, \
319 [_op].max_args = _max_args, [_op].args = (bits_parse_fn[]){__VA_ARGS__}
320#define BITS_READ_OP_ENTRY(_op, _op_fn, _min_args, _max_args, ...) \
321 [_op].name = # _op, [_op].prepare = bits_prepare_read_op, \
322 [_op].fn.read = _op_fn, [_op].bad_flags = ~((uint64_t)(0)), \
323 [_op].min_args = _min_args, [_op].max_args = _max_args, \
324 [_op].args = (bits_parse_fn[]){__VA_ARGS__}
325
326
327//==========================================================
328// Op tables.
329//
330
331static const bits_op_def bits_modify_op_table[] = {
332 BITS_MODIFY_OP_ENTRY(AS_BITS_OP_RESIZE, bits_modify_op_resize,
333 bits_prepare_resize_op,
334 (AS_BITS_FLAG_CREATE_ONLY | AS_BITS_FLAG_UPDATE_ONLY |
335 AS_BITS_FLAG_NO_FAIL),
336 1, 3, bits_parse_byte_size_allow_zero, bits_parse_flags,
337 bits_parse_resize_subflags),
338 BITS_MODIFY_OP_ENTRY(AS_BITS_OP_INSERT, bits_modify_op_insert,
339 bits_prepare_insert_op,
340 (AS_BITS_FLAG_CREATE_ONLY | AS_BITS_FLAG_UPDATE_ONLY |
341 AS_BITS_FLAG_NO_FAIL),
342 2, 3, bits_parse_byte_offset, bits_parse_buf, bits_parse_flags),
343 BITS_MODIFY_OP_ENTRY(AS_BITS_OP_REMOVE, NULL,
344 bits_prepare_remove_op,
345 (AS_BITS_FLAG_UPDATE_ONLY | AS_BITS_FLAG_NO_FAIL |
346 AS_BITS_FLAG_PARTIAL),
347 2, 3, bits_parse_byte_offset, bits_parse_byte_size,
348 bits_parse_flags),
349 BITS_MODIFY_OP_ENTRY(AS_BITS_OP_SET, bits_modify_op_set,
350 bits_prepare_modify_op,
351 (AS_BITS_FLAG_UPDATE_ONLY | AS_BITS_FLAG_NO_FAIL |
352 AS_BITS_FLAG_PARTIAL),
353 3, 4, bits_parse_offset, bits_parse_size, bits_parse_buf,
354 bits_parse_flags),
355 BITS_MODIFY_OP_ENTRY(AS_BITS_OP_OR, bits_modify_op_or,
356 bits_prepare_modify_op,
357 (AS_BITS_FLAG_UPDATE_ONLY | AS_BITS_FLAG_NO_FAIL |
358 AS_BITS_FLAG_PARTIAL),
359 3, 4, bits_parse_offset, bits_parse_size, bits_parse_buf,
360 bits_parse_flags),
361 BITS_MODIFY_OP_ENTRY(AS_BITS_OP_XOR, bits_modify_op_xor,
362 bits_prepare_modify_op,
363 (AS_BITS_FLAG_UPDATE_ONLY | AS_BITS_FLAG_NO_FAIL |
364 AS_BITS_FLAG_PARTIAL),
365 3, 4, bits_parse_offset, bits_parse_size, bits_parse_buf,
366 bits_parse_flags),
367 BITS_MODIFY_OP_ENTRY(AS_BITS_OP_AND, bits_modify_op_and,
368 bits_prepare_modify_op,
369 (AS_BITS_FLAG_UPDATE_ONLY | AS_BITS_FLAG_NO_FAIL |
370 AS_BITS_FLAG_PARTIAL),
371 3, 4, bits_parse_offset, bits_parse_size, bits_parse_buf,
372 bits_parse_flags),
373 BITS_MODIFY_OP_ENTRY(AS_BITS_OP_NOT, bits_modify_op_not,
374 bits_prepare_modify_op,
375 (AS_BITS_FLAG_UPDATE_ONLY | AS_BITS_FLAG_NO_FAIL |
376 AS_BITS_FLAG_PARTIAL),
377 2, 3, bits_parse_offset, bits_parse_size, bits_parse_flags),
378 BITS_MODIFY_OP_ENTRY(AS_BITS_OP_LSHIFT, bits_modify_op_lshift,
379 bits_prepare_modify_op,
380 (AS_BITS_FLAG_UPDATE_ONLY | AS_BITS_FLAG_NO_FAIL |
381 AS_BITS_FLAG_PARTIAL),
382 3, 4, bits_parse_offset, bits_parse_size,
383 bits_parse_n_bits_value, bits_parse_flags),
384 BITS_MODIFY_OP_ENTRY(AS_BITS_OP_RSHIFT, bits_modify_op_rshift,
385 bits_prepare_modify_op,
386 (AS_BITS_FLAG_UPDATE_ONLY | AS_BITS_FLAG_NO_FAIL |
387 AS_BITS_FLAG_PARTIAL),
388 3, 4, bits_parse_offset, bits_parse_size,
389 bits_parse_n_bits_value, bits_parse_flags),
390 BITS_MODIFY_OP_ENTRY(AS_BITS_OP_ADD, bits_modify_op_add,
391 bits_prepare_integer_op,
392 (AS_BITS_FLAG_UPDATE_ONLY | AS_BITS_FLAG_NO_FAIL),
393 3, 5, bits_parse_offset, bits_parse_integer_size,
394 bits_parse_integer_value, bits_parse_flags,
395 bits_parse_arithmetic_subflags),
396 BITS_MODIFY_OP_ENTRY(AS_BITS_OP_SUBTRACT, bits_modify_op_subtract,
397 bits_prepare_integer_op,
398 (AS_BITS_FLAG_UPDATE_ONLY | AS_BITS_FLAG_NO_FAIL),
399 3, 5, bits_parse_offset, bits_parse_integer_size,
400 bits_parse_integer_value, bits_parse_flags,
401 bits_parse_arithmetic_subflags),
402 BITS_MODIFY_OP_ENTRY(AS_BITS_OP_SET_INT, bits_modify_op_set_int,
403 bits_prepare_integer_op,
404 (AS_BITS_FLAG_UPDATE_ONLY | AS_BITS_FLAG_NO_FAIL),
405 3, 4, bits_parse_offset, bits_parse_integer_size,
406 bits_parse_integer_value, bits_parse_flags),
407};
408
409static const bits_op_def bits_read_op_table[] = {
410 BITS_READ_OP_ENTRY(AS_BITS_OP_GET, bits_read_op_get,
411 2, 2, bits_parse_offset, bits_parse_size),
412 BITS_READ_OP_ENTRY(AS_BITS_OP_COUNT, bits_read_op_count,
413 2, 2, bits_parse_offset, bits_parse_size),
414 BITS_READ_OP_ENTRY(AS_BITS_OP_LSCAN, bits_read_op_lscan,
415 3, 3, bits_parse_offset, bits_parse_size,
416 bits_parse_boolean_value),
417 BITS_READ_OP_ENTRY(AS_BITS_OP_RSCAN, bits_read_op_rscan,
418 3, 3, bits_parse_offset, bits_parse_size,
419 bits_parse_boolean_value),
420 BITS_READ_OP_ENTRY(AS_BITS_OP_GET_INT, bits_read_op_get_integer,
421 2, 3, bits_parse_offset, bits_parse_integer_size,
422 bits_parse_get_integer_subflags),
423};
424
425
426//==========================================================
427// BLOB particle interface - function definitions.
428//
429
430//------------------------------------------------
431// Destructor, etc.
432//
433
434void
435blob_destruct(as_particle* p)
436{
437 cf_free(p);
438}
439
440uint32_t
441blob_size(const as_particle* p)
442{
443 return (uint32_t)(sizeof(blob_mem) + ((blob_mem*)p)->sz);
444}
445
446//------------------------------------------------
447// Handle "wire" format.
448//
449
450int32_t
451blob_concat_size_from_wire(as_particle_type wire_type,
452 const uint8_t* wire_value, uint32_t value_size, as_particle** pp)
453{
454 (void)wire_value;
455 blob_mem* p_blob_mem = (blob_mem*)*pp;
456
457 if (wire_type != p_blob_mem->type) {
458 cf_warning(AS_PARTICLE, "type mismatch concat sizing blob/string, %d:%d",
459 p_blob_mem->type, wire_type);
460 return -AS_ERR_INCOMPATIBLE_TYPE;
461 }
462
463 return (int32_t)(sizeof(blob_mem) + p_blob_mem->sz + value_size);
464}
465
466int
467blob_append_from_wire(as_particle_type wire_type, const uint8_t* wire_value,
468 uint32_t value_size, as_particle** pp)
469{
470 blob_mem* p_blob_mem = (blob_mem*)*pp;
471
472 if (wire_type != p_blob_mem->type) {
473 cf_warning(AS_PARTICLE, "type mismatch appending to blob/string, %d:%d",
474 p_blob_mem->type, wire_type);
475 return -AS_ERR_INCOMPATIBLE_TYPE;
476 }
477
478 memcpy(p_blob_mem->data + p_blob_mem->sz, wire_value, value_size);
479 p_blob_mem->sz += value_size;
480
481 return 0;
482}
483
484int
485blob_prepend_from_wire(as_particle_type wire_type, const uint8_t* wire_value,
486 uint32_t value_size, as_particle** pp)
487{
488 blob_mem* p_blob_mem = (blob_mem*)*pp;
489
490 if (wire_type != p_blob_mem->type) {
491 cf_warning(AS_PARTICLE, "type mismatch prepending to blob/string, %d:%d",
492 p_blob_mem->type, wire_type);
493 return -AS_ERR_INCOMPATIBLE_TYPE;
494 }
495
496 memmove(p_blob_mem->data + value_size, p_blob_mem->data, p_blob_mem->sz);
497 memcpy(p_blob_mem->data, wire_value, value_size);
498 p_blob_mem->sz += value_size;
499
500 return 0;
501}
502
503int
504blob_incr_from_wire(as_particle_type wire_type, const uint8_t* wire_value,
505 uint32_t value_size, as_particle** pp)
506{
507 (void)wire_type;
508 (void)wire_value;
509 (void)value_size;
510 (void)pp;
511 cf_warning(AS_PARTICLE, "unexpected increment of blob/string");
512 return -AS_ERR_INCOMPATIBLE_TYPE;
513}
514
515int32_t
516blob_size_from_wire(const uint8_t* wire_value, uint32_t value_size)
517{
518 (void)wire_value;
519 // Wire value is same as in-memory value.
520 return (int32_t)(sizeof(blob_mem) + value_size);
521}
522
523int
524blob_from_wire(as_particle_type wire_type, const uint8_t* wire_value,
525 uint32_t value_size, as_particle** pp)
526{
527 blob_mem* p_blob_mem = (blob_mem*)*pp;
528
529 p_blob_mem->type = wire_type;
530 p_blob_mem->sz = value_size;
531 memcpy(p_blob_mem->data, wire_value, p_blob_mem->sz);
532
533 return 0;
534}
535
536int
537blob_compare_from_wire(const as_particle* p, as_particle_type wire_type,
538 const uint8_t* wire_value, uint32_t value_size)
539{
540 blob_mem* p_blob_mem = (blob_mem*)p;
541
542 return (wire_type == p_blob_mem->type &&
543 value_size == p_blob_mem->sz &&
544 memcmp(wire_value, p_blob_mem->data, value_size) == 0) ? 0 : 1;
545}
546
547uint32_t
548blob_wire_size(const as_particle* p)
549{
550 blob_mem* p_blob_mem = (blob_mem*)p;
551
552 return p_blob_mem->sz;
553}
554
555uint32_t
556blob_to_wire(const as_particle* p, uint8_t* wire)
557{
558 blob_mem* p_blob_mem = (blob_mem*)p;
559
560 memcpy(wire, p_blob_mem->data, p_blob_mem->sz);
561
562 return p_blob_mem->sz;
563}
564
565//------------------------------------------------
566// Handle as_val translation.
567//
568
569uint32_t
570blob_size_from_asval(const as_val* val)
571{
572 return (uint32_t)sizeof(blob_mem) + as_bytes_size(as_bytes_fromval(val));
573}
574
575void
576blob_from_asval(const as_val* val, as_particle** pp)
577{
578 blob_mem* p_blob_mem = (blob_mem*)*pp;
579
580 as_bytes* bytes = as_bytes_fromval(val);
581
582 p_blob_mem->type = (uint8_t)blob_bytes_type_to_particle_type(bytes->type);
583 p_blob_mem->sz = as_bytes_size(bytes);
584 memcpy(p_blob_mem->data, as_bytes_get(bytes), p_blob_mem->sz);
585}
586
587as_val*
588blob_to_asval(const as_particle* p)
589{
590 blob_mem* p_blob_mem = (blob_mem*)p;
591
592 uint8_t* value = cf_malloc(p_blob_mem->sz);
593
594 memcpy(value, p_blob_mem->data, p_blob_mem->sz);
595
596 return (as_val*)as_bytes_new_wrap(value, p_blob_mem->sz, true);
597}
598
599uint32_t
600blob_asval_wire_size(const as_val* val)
601{
602 return as_bytes_size(as_bytes_fromval(val));
603}
604
605uint32_t
606blob_asval_to_wire(const as_val* val, uint8_t* wire)
607{
608 as_bytes* bytes = as_bytes_fromval(val);
609 uint32_t size = as_bytes_size(bytes);
610
611 memcpy(wire, as_bytes_get(bytes), size);
612
613 return size;
614}
615
616//------------------------------------------------
617// Handle msgpack translation.
618//
619
620uint32_t
621blob_size_from_msgpack(const uint8_t* packed, uint32_t packed_size)
622{
623 (void)packed;
624 // Ok to oversize by a few bytes - only used for allocation sizing.
625 // -1 for blob internal type and -1 for blob header.
626 return (uint32_t)sizeof(blob_mem) + packed_size - 2;
627}
628
629void
630blob_from_msgpack(const uint8_t* packed, uint32_t packed_size, as_particle** pp)
631{
632 as_unpacker pk = {
633 .buffer = packed,
634 .offset = 0,
635 .length = packed_size
636 };
637
638 int64_t size = as_unpack_blob_size(&pk); // FIXME - what if error?
639 const uint8_t* ptr = pk.buffer + pk.offset;
640
641 uint8_t type = *ptr;
642
643 // Adjust for type (1 byte).
644 ptr++;
645 size--;
646
647 blob_mem* p_blob_mem = (blob_mem*)*pp;
648
649 p_blob_mem->type = (uint8_t)blob_bytes_type_to_particle_type(
650 (as_bytes_type)type);
651 p_blob_mem->sz = (uint32_t)size;
652 memcpy(p_blob_mem->data, ptr, p_blob_mem->sz);
653}
654
655//------------------------------------------------
656// Handle on-device "flat" format.
657//
658
659const uint8_t*
660blob_skip_flat(const uint8_t* flat, const uint8_t* end)
661{
662 if (flat + sizeof(blob_flat) > end) {
663 cf_warning(AS_PARTICLE, "incomplete flat blob/string");
664 return NULL;
665 }
666
667 blob_flat* p_blob_flat = (blob_flat*)flat;
668
669 return flat + sizeof(blob_flat) + p_blob_flat->size;
670}
671
672const uint8_t*
673blob_cast_from_flat(const uint8_t* flat, const uint8_t* end, as_particle** pp)
674{
675 if (flat + sizeof(blob_flat) > end) {
676 cf_warning(AS_PARTICLE, "incomplete flat blob/string");
677 return NULL;
678 }
679
680 const blob_flat* p_blob_flat = (const blob_flat*)flat;
681
682 // We can do this only because the flat and in-memory formats are identical.
683 *pp = (as_particle*)p_blob_flat;
684
685 return flat + sizeof(blob_flat) + p_blob_flat->size;
686}
687
688const uint8_t*
689blob_from_flat(const uint8_t* flat, const uint8_t* end, as_particle** pp)
690{
691 if (flat + sizeof(blob_flat) > end) {
692 cf_warning(AS_PARTICLE, "incomplete flat blob/string");
693 return NULL;
694 }
695
696 const blob_flat* p_blob_flat = (const blob_flat*)flat;
697
698 // Flat value is same as in-memory value.
699 size_t mem_size = sizeof(blob_mem) + p_blob_flat->size;
700
701 flat += mem_size; // blob_mem same size as blob_flat
702
703 if (flat > end) {
704 cf_warning(AS_PARTICLE, "incomplete flat blob/string");
705 return NULL;
706 }
707
708 blob_mem* p_blob_mem = (blob_mem*)cf_malloc_ns(mem_size);
709
710 p_blob_mem->type = p_blob_flat->type;
711 p_blob_mem->sz = p_blob_flat->size;
712 memcpy(p_blob_mem->data, p_blob_flat->data, p_blob_mem->sz);
713
714 *pp = (as_particle*)p_blob_mem;
715
716 return flat;
717}
718
719uint32_t
720blob_flat_size(const as_particle* p)
721{
722 return (uint32_t)(sizeof(blob_flat) + ((blob_mem*)p)->sz);
723}
724
725uint32_t
726blob_to_flat(const as_particle* p, uint8_t* flat)
727{
728 blob_mem* p_blob_mem = (blob_mem*)p;
729 blob_flat* p_blob_flat = (blob_flat*)flat;
730
731 // Already wrote the type.
732 p_blob_flat->size = p_blob_mem->sz;
733 memcpy(p_blob_flat->data, p_blob_mem->data, p_blob_flat->size);
734
735 return blob_flat_size(p);
736}
737
738
739//==========================================================
740// as_bin particle functions specific to BLOB.
741//
742
743int
744as_bin_bits_packed_read(const as_bin* b, const as_msg_op* msg_op, as_bin* rb)
745{
746 cf_assert(as_bin_inuse(b), AS_PARTICLE, "unused bin");
747
748 if ((as_particle_type)msg_op->particle_type != AS_PARTICLE_TYPE_BLOB) {
749 cf_warning(AS_PARTICLE, "as_bin_bits_packed_read - unexpected particle type %u for bin %.*s",
750 msg_op->particle_type, (int)msg_op->name_sz, msg_op->name);
751 return -AS_ERR_INCOMPATIBLE_TYPE;
752 }
753
754 bits_state state = { 0 };
755
756 if (! bits_state_init(&state, msg_op, true)) {
757 return -AS_ERR_PARAMETER;
758 }
759
760 bits_op op = { 0 };
761
762 if (! bits_parse_op(&state, &op)) {
763 return -AS_ERR_PARAMETER;
764 }
765
766 if (as_bin_get_particle_type(b) != AS_PARTICLE_TYPE_BLOB) {
767 cf_warning(AS_PARTICLE, "as_bin_bits_packed_read - operation (%s) on bin %.*s bin type must be blob found %u",
768 state.def->name, (int)msg_op->name_sz, msg_op->name,
769 as_bin_get_particle_type(b));
770 return -AS_ERR_INCOMPATIBLE_TYPE;
771 }
772
773 int result = bits_prepare_read(&state, &op, b);
774
775 if (result < 1) {
776 return result;
777 }
778
779 if (! bits_execute_read_op(&state, &op, b->particle, rb)) {
780 as_bin_set_empty(rb);
781 }
782
783 return AS_OK;
784}
785
786int
787as_bin_bits_packed_modify(as_bin* b, const as_msg_op* msg_op,
788 cf_ll_buf* particles_llb)
789{
790 if ((as_particle_type)msg_op->particle_type != AS_PARTICLE_TYPE_BLOB) {
791 cf_warning(AS_PARTICLE, "as_bin_bits_packed_modify - unexpected particle type %u for bin %.*s",
792 msg_op->particle_type, (int)msg_op->name_sz, msg_op->name);
793 return -AS_ERR_INCOMPATIBLE_TYPE;
794 }
795
796 bits_state state = { 0 };
797
798 if (! bits_state_init(&state, msg_op, false)) {
799 return -AS_ERR_PARAMETER;
800 }
801
802 bits_op op = { 0 };
803
804 if (! bits_parse_op(&state, &op)) {
805 return -AS_ERR_PARAMETER;
806 }
807
808 as_particle* old_blob;
809
810 if (as_bin_inuse(b)) {
811 if ((op.flags & AS_BITS_FLAG_CREATE_ONLY) != 0) {
812 if ((op.flags & AS_BITS_FLAG_NO_FAIL) != 0) {
813 return AS_OK;
814 }
815
816 cf_detail(AS_PARTICLE, "as_bin_bits_packed_modify - operation (%s) on bin %.*s would update - not allowed",
817 state.def->name, (int)msg_op->name_sz, msg_op->name);
818 return -AS_ERR_BIN_EXISTS;
819 }
820
821 if (as_bin_get_particle_type(b) != AS_PARTICLE_TYPE_BLOB) {
822 cf_warning(AS_PARTICLE, "as_bin_bits_packed_modify - operation (%s) on bin %.*s must be on a blob - found %u",
823 state.def->name, (int)msg_op->name_sz, msg_op->name,
824 as_bin_get_particle_type(b));
825 return -AS_ERR_INCOMPATIBLE_TYPE;
826 }
827 // else - there is an existing blob particle, which we will modify.
828
829 old_blob = b->particle;
830 }
831 else {
832 if ((state.op_type != AS_BITS_OP_INSERT &&
833 state.op_type != AS_BITS_OP_RESIZE) ||
834 (op.flags & AS_BITS_FLAG_UPDATE_ONLY) != 0) {
835 if ((op.flags & AS_BITS_FLAG_NO_FAIL) != 0) {
836 return AS_OK;
837 }
838
839 cf_warning(AS_PARTICLE, "as_bin_bits_packed_modify - operation (%s) on bin %.*s would create - not allowed",
840 state.def->name, (int)msg_op->name_sz, msg_op->name);
841 return -AS_ERR_BIN_NOT_FOUND;
842 }
843
844 cf_assert(b->particle == NULL, AS_PARTICLE, "particle not null");
845
846 old_blob = NULL;
847 }
848
849 int result = bits_prepare_modify(&state, &op, b);
850
851 if (result < 1) {
852 return result;
853 }
854
855 size_t alloc_size = sizeof(blob_mem) + (size_t)state.new_size;
856
857 if (particles_llb == NULL) {
858 b->particle = cf_malloc_ns(alloc_size);
859 }
860 else {
861 cf_ll_buf_reserve(particles_llb, alloc_size, (uint8_t**)&b->particle);
862 }
863
864 if (! bits_execute_modify_op(&state, &op, old_blob, b->particle)) {
865 if (particles_llb == NULL) {
866 cf_free(b->particle);
867 }
868
869 b->particle = old_blob;
870
871 return ((op.flags & AS_BITS_FLAG_NO_FAIL) != 0) ?
872 AS_OK : -AS_ERR_OP_NOT_APPLICABLE;
873 }
874
875 if (old_blob == NULL) {
876 // Set the bin's iparticle metadata.
877 as_bin_state_set_from_type(b, AS_PARTICLE_TYPE_BLOB);
878 }
879
880 return AS_OK;
881}
882
883
884//==========================================================
885// Local helpers - bits parsing.
886//
887
888static bool
889bits_state_init(bits_state* state, const as_msg_op* msg_op, bool is_read)
890{
891 const uint8_t* data = msg_op->name + msg_op->name_sz;
892 uint32_t sz = msg_op->op_sz - (uint32_t)OP_FIXED_SZ - msg_op->name_sz;
893
894 state->pk.buffer = data;
895 state->pk.length = sz;
896 state->pk.offset = 0;
897
898 int64_t ele_count = as_unpack_list_header_element_count(&state->pk);
899
900 if (ele_count < 1) {
901 cf_warning(AS_PARTICLE, "bits_state_init - not enough args or unable to parse args for bin %.*s err %ld",
902 (int)msg_op->name_sz, msg_op->name, ele_count);
903 return false;
904 }
905
906 state->ele_count = (uint32_t)ele_count - 1; // ignore the 'op' arg.
907
908 uint64_t type64;
909 int result = as_unpack_uint64(&state->pk, &type64);
910
911 if (result != 0) {
912 cf_warning(AS_PARTICLE, "bits_state_init - unable to parse op (error %d) for bin %.*s",
913 result, (int)msg_op->name_sz, msg_op->name);
914 return false;
915 }
916
917 state->op_type = (as_bits_op_type)type64;
918
919 if (is_read) {
920 if (! (state->op_type >= AS_BITS_READ_OP_START &&
921 state->op_type < AS_BITS_READ_OP_END)) {
922 cf_warning(AS_PARTICLE, "bits_state_init - expected read op but got %u n_args %u for bin %.*s",
923 state->op_type, state->ele_count, (int)msg_op->name_sz,
924 msg_op->name);
925 return false;
926 }
927
928 state->def = (bits_op_def*)&bits_read_op_table[state->op_type];
929 }
930 else {
931 if (! (state->op_type >= AS_BITS_MODIFY_OP_START &&
932 state->op_type < AS_BITS_MODIFY_OP_END)) {
933 cf_warning(AS_PARTICLE, "bits_state_init - expected modify op but got %u n_args %u for bin %.*s",
934 state->op_type, state->ele_count, (int)msg_op->name_sz,
935 msg_op->name);
936 return false;
937 }
938
939 state->def = (bits_op_def*)&bits_modify_op_table[state->op_type];
940 }
941
942 return true;
943}
944
945static bool
946bits_parse_op(bits_state* state, bits_op* op)
947{
948 bits_op_def* def = state->def;
949
950 if (state->ele_count < def->min_args || state->ele_count > def->max_args) {
951 cf_warning(AS_PARTICLE, "bits_parse_op - unexpected number of args %u for op %s",
952 state->ele_count, state->def->name);
953 return false;
954 }
955
956 for (uint32_t i = 0; i < state->ele_count; i++) {
957 if (! def->args[i](state, op)) {
958 return false;
959 }
960 }
961
962 return true;
963}
964
965static bool
966bits_parse_byte_offset(bits_state* state, bits_op* op)
967{
968 int64_t offset;
969 int result = as_unpack_int64(&state->pk, &offset);
970
971 if (result != 0) {
972 cf_warning(AS_PARTICLE, "bits_parse_byte_offset - unable to parse offset (error %d) for op %s",
973 result, state->def->name);
974 return false;
975 }
976
977 if (labs(offset) > PROTO_SIZE_MAX) {
978 cf_warning(AS_PARTICLE, "bits_parse_byte_offset - offset (%ld) larger than max (%d) for op %s",
979 offset, PROTO_SIZE_MAX, state->def->name);
980 return false;
981 }
982
983 op->offset = (int32_t)offset * 8; // normalize to bits
984
985 return true;
986}
987
988static bool
989bits_parse_offset(bits_state* state, bits_op* op)
990{
991 int64_t offset;
992 int result = as_unpack_int64(&state->pk, &offset);
993
994 if (result != 0) {
995 cf_warning(AS_PARTICLE, "bits_parse_offset - unable to parse offset (error %d) for op %s",
996 result, state->def->name);
997 return false;
998 }
999
1000 if (labs(offset) > PROTO_SIZE_MAX * 8) {
1001 cf_warning(AS_PARTICLE, "bits_parse_offset - offset (%ld) is larger than max (%d) for op %s",
1002 offset, PROTO_SIZE_MAX * 8, state->def->name);
1003 return false;
1004 }
1005
1006 op->offset = (int32_t)offset;
1007
1008 return true;
1009}
1010
1011static bool
1012bits_parse_integer_size(bits_state* state, bits_op* op)
1013{
1014 uint64_t size;
1015 int result = as_unpack_uint64(&state->pk, &size);
1016
1017 if (result != 0) {
1018 cf_warning(AS_PARTICLE, "bits_parse_integer_size - unable to parse byte_size (error %d) for op %s",
1019 result, state->def->name);
1020 return false;
1021 }
1022
1023 if (size == 0) {
1024 cf_warning(AS_PARTICLE, "bits_parse_integer_size - size may not be 0 for op %s",
1025 state->def->name);
1026 return false;
1027 }
1028
1029 if (size > 64) {
1030 cf_warning(AS_PARTICLE, "bits_parse_integer_size - size (%lu) larger than max (64) for op %s",
1031 size, state->def->name);
1032 return false;
1033 }
1034
1035 op->size = (uint32_t)size;
1036
1037 return true;
1038}
1039
1040static bool
1041bits_parse_byte_size(bits_state* state, bits_op* op)
1042{
1043 uint64_t size;
1044 int result = as_unpack_uint64(&state->pk, &size);
1045
1046 if (result != 0) {
1047 cf_warning(AS_PARTICLE, "bits_parse_byte_size - unable to parse byte_size (error %d) for op %s",
1048 result, state->def->name);
1049 return false;
1050 }
1051
1052 if (size == 0) {
1053 cf_warning(AS_PARTICLE, "bits_parse_byte_size - size may not be 0 for op %s",
1054 state->def->name);
1055 return false;
1056 }
1057
1058 if (size > PROTO_SIZE_MAX) {
1059 cf_warning(AS_PARTICLE, "bits_parse_byte_size - size (%lu) larger than max (%d) for op %s",
1060 size, PROTO_SIZE_MAX, state->def->name);
1061 return false;
1062 }
1063
1064 op->size = (uint32_t)size * 8; // normalize to bits
1065
1066 return true;
1067}
1068
1069static bool
1070bits_parse_byte_size_allow_zero(bits_state* state, bits_op* op)
1071{
1072 uint64_t size;
1073 int result = as_unpack_uint64(&state->pk, &size);
1074
1075 if (result != 0) {
1076 cf_warning(AS_PARTICLE, "bits_parse_byte_size_allow_zero - unable to parse byte_size (error %d) for op %s",
1077 result, state->def->name);
1078 return false;
1079 }
1080
1081 if (size > PROTO_SIZE_MAX) {
1082 cf_warning(AS_PARTICLE, "bits_parse_byte_size_allow_zero - size (%lu) larger than max (%d) for op %s",
1083 size, PROTO_SIZE_MAX, state->def->name);
1084 return false;
1085 }
1086
1087 op->size = (uint32_t)size * 8; // normalize to bits
1088
1089 return true;
1090}
1091
1092static bool
1093bits_parse_size(bits_state* state, bits_op* op)
1094{
1095 uint64_t size;
1096 int result = as_unpack_uint64(&state->pk, &size);
1097
1098 if (result != 0) {
1099 cf_warning(AS_PARTICLE, "bits_parse_size - unable to parse size (error %d) for op %s",
1100 result, state->def->name);
1101 return false;
1102 }
1103
1104 if (size == 0) {
1105 cf_warning(AS_PARTICLE, "bits_parse_size - size may not be 0 for op %s",
1106 state->def->name);
1107 return false;
1108 }
1109
1110 if (size > PROTO_SIZE_MAX * 8) {
1111 cf_warning(AS_PARTICLE, "bits_parse_size - size (%lu) is larger than max (%d) for op %s",
1112 size, PROTO_SIZE_MAX * 8, state->def->name);
1113 return false;
1114 }
1115
1116 op->size = (uint32_t)size;
1117
1118 return true;
1119}
1120
1121static bool
1122bits_parse_boolean_value(bits_state* state, bits_op* op)
1123{
1124 bool value;
1125 int result = as_unpack_boolean(&state->pk, &value);
1126
1127 if (result != 0) {
1128 cf_warning(AS_PARTICLE, "bits_parse_boolean_value - unable to parse boolean (error %d) for op %s",
1129 result, state->def->name);
1130 return false;
1131 }
1132
1133 op->value = value ? 1 : 0;
1134
1135 return true;
1136}
1137
1138static bool
1139bits_parse_n_bits_value(bits_state* state, bits_op* op)
1140{
1141 if (! bits_parse_integer_value(state, op)) {
1142 return false;
1143 }
1144
1145 if (op->value > PROTO_SIZE_MAX * 8) {
1146 cf_warning(AS_PARTICLE, "bits_parse_n_bits_value - n_bits value (%lu) is larger than max (%d) for op %s",
1147 op->value, PROTO_SIZE_MAX * 8, state->def->name);
1148 return false;
1149 }
1150
1151 return true;
1152}
1153
1154static bool
1155bits_parse_integer_value(bits_state* state, bits_op* op)
1156{
1157 int result = as_unpack_uint64(&state->pk, &op->value);
1158
1159 if (result != 0) {
1160 cf_warning(AS_PARTICLE, "bits_parse_integer_value - unable to parse number (error %d) for op %s",
1161 result, state->def->name);
1162 return false;
1163 }
1164
1165 return true;
1166}
1167
1168static bool
1169bits_parse_buf(bits_state* state, bits_op* op)
1170{
1171 uint32_t size;
1172
1173 op->buf = as_unpack_bin(&state->pk, &size);
1174
1175 // AS msgpack has a one byte blob type field which we ignore here.
1176 if (op->buf == NULL || size == 1) {
1177 cf_warning(AS_PARTICLE, "bits_parse_buf - parsed invalid buffer with size %u for op %s",
1178 size, state->def->name);
1179 return false;
1180 }
1181
1182 op->buf++;
1183 size = (size - 1) * 8;
1184
1185 if (op->size != 0) {
1186 if (size < op->size) {
1187 cf_warning(AS_PARTICLE, "bits_parse_buf - parsed buffer size less than size buf_sz %u sz %u for op %s",
1188 size, op->size, state->def->name);
1189 return false;
1190 }
1191 }
1192 else {
1193 op->size = size;
1194 }
1195
1196 return true;
1197}
1198
1199static bool
1200bits_parse_flags(bits_state* state, bits_op* op)
1201{
1202 int result = as_unpack_uint64(&state->pk, &op->flags);
1203
1204 if (result != 0) {
1205 cf_warning(AS_PARTICLE, "bits_parse_flags - unable to parse subflags (error %d) for op %s",
1206 result, state->def->name);
1207 return false;
1208 }
1209
1210 if ((op->flags & state->def->bad_flags) != 0) {
1211 cf_warning(AS_PARTICLE, "bits_parse_flags - invalid flags (0x%lx) for op %s",
1212 op->flags, state->def->name);
1213 return false;
1214 }
1215
1216 if ((op->flags & AS_BITS_FLAG_CREATE_ONLY) != 0 &&
1217 (op->flags & AS_BITS_FLAG_UPDATE_ONLY) != 0) {
1218 cf_warning(AS_PARTICLE, "bits_parse_flags - invalid flags combination (0x%lx) for op %s",
1219 op->flags, state->def->name);
1220 return false;
1221 }
1222
1223 return true;
1224}
1225
1226static bool
1227bits_parse_resize_subflags(bits_state* state, bits_op* op)
1228{
1229 if (! bits_parse_subflags(state, op)) {
1230 return false;
1231 }
1232
1233 uint64_t bad_flags = (uint64_t)~(AS_BITS_SUBFLAG_RESIZE_FROM_FRONT |
1234 AS_BITS_SUBFLAG_RESIZE_GROW_ONLY |
1235 AS_BITS_SUBFLAG_RESIZE_SHRINK_ONLY);
1236
1237 if ((op->subflags & bad_flags) != 0) {
1238 cf_warning(AS_PARTICLE, "bits_parse_resize_subflags - invalid subflags (0x%lx) for op %s",
1239 op->subflags, state->def->name);
1240 return false;
1241 }
1242
1243 if ((op->subflags & AS_BITS_SUBFLAG_RESIZE_GROW_ONLY) != 0 &&
1244 (op->subflags & AS_BITS_SUBFLAG_RESIZE_SHRINK_ONLY) != 0) {
1245 cf_warning(AS_PARTICLE, "bits_parse_resize_subflags - invalid subflags combination (0x%lx) for op %s",
1246 op->subflags, state->def->name);
1247 return false;
1248 }
1249
1250 return true;
1251}
1252
1253static bool
1254bits_parse_arithmetic_subflags(bits_state* state, bits_op* op)
1255{
1256 if (! bits_parse_subflags(state, op)) {
1257 return false;
1258 }
1259
1260 uint64_t bad_flags = (uint64_t)~(AS_BITS_INT_SUBFLAG_SIGNED |
1261 AS_BITS_INT_SUBFLAG_SATURATE | AS_BITS_INT_SUBFLAG_WRAP);
1262
1263 if ((op->subflags & bad_flags) != 0) {
1264 cf_warning(AS_PARTICLE, "bits_parse_arithmetic_subflags - invalid subflags (0x%lx) for op %s",
1265 op->subflags, state->def->name);
1266 return false;
1267 }
1268
1269 if ((op->subflags & AS_BITS_INT_SUBFLAG_SATURATE) != 0 &&
1270 (op->subflags & AS_BITS_INT_SUBFLAG_WRAP) != 0) {
1271 cf_warning(AS_PARTICLE, "bits_parse_arithmetic_subflags - invalid subflags combination (0x%lx) for op %s",
1272 op->subflags, state->def->name);
1273 return false;
1274 }
1275
1276 return true;
1277}
1278
1279static bool
1280bits_parse_get_integer_subflags(bits_state* state, bits_op* op)
1281{
1282 if (! bits_parse_subflags(state, op)) {
1283 return false;
1284 }
1285
1286 uint64_t bad_flags = (uint64_t)~(AS_BITS_INT_SUBFLAG_SIGNED);
1287
1288 if ((op->subflags & bad_flags) != 0) {
1289 cf_warning(AS_PARTICLE, "bits_parse_get_integer_subflags - invalid subflags (0x%lx) for op %s",
1290 op->subflags, state->def->name);
1291 return false;
1292 }
1293
1294 return true;
1295}
1296
1297static bool
1298bits_parse_subflags(bits_state* state, bits_op* op)
1299{
1300 int result = as_unpack_uint64(&state->pk, &op->subflags);
1301
1302 if (result != 0) {
1303 cf_warning(AS_PARTICLE, "bits_parse_subflags - unable to parse subflags (error %d) for op %s",
1304 result, state->def->name);
1305 return false;
1306 }
1307
1308 return true;
1309}
1310
1311
1312//==========================================================
1313// Local helpers - prepare ops.
1314//
1315
1316static int
1317bits_prepare_read(bits_state* state, bits_op* op, const as_bin* b)
1318{
1319 return bits_prepare_op(state, op, b);
1320}
1321
1322static int
1323bits_prepare_modify(bits_state* state, bits_op* op, const as_bin* b)
1324{
1325 int result = bits_prepare_op(state, op, b);
1326
1327 if (result != 1) {
1328 return result;
1329 }
1330
1331 state->new_size = state->n_bytes_head + state->n_bytes_expand +
1332 state->n_bytes_tail;
1333
1334 if (state->action != OP_ACTION_REMOVE) {
1335 state->new_size += state->n_bytes_op;
1336 }
1337
1338 as_bits_op_type op_type = state->op_type;
1339
1340 cf_assert(op_type == AS_BITS_OP_RESIZE || op_type == AS_BITS_OP_INSERT ||
1341 op_type == AS_BITS_OP_REMOVE || state->old_size == state->new_size,
1342 AS_PARTICLE, "size changed op %u old %u new %u",
1343 op_type, state->old_size, state->new_size);
1344
1345 if (state->new_size >= PROTO_SIZE_MAX) {
1346 cf_warning(AS_PARTICLE, "bits_prepare_op - operation %s result blob size %u is larger than max %u",
1347 state->def->name, state->new_size, PROTO_SIZE_MAX);
1348 return -AS_ERR_PARAMETER;
1349 }
1350
1351 return 1; // success
1352}
1353
1354static int
1355bits_prepare_op(bits_state* state, bits_op* op, const as_bin* b)
1356{
1357 bits_op_def* def = state->def;
1358
1359 if (as_bin_inuse(b)) {
1360 state->old_size = ((blob_mem*)b->particle)->sz;
1361 }
1362 else if (op->offset < 0) {
1363 cf_warning(AS_PARTICLE, "bits_prepare_op - operation %s cannot use negative offset on non-existent bin",
1364 state->def->name);
1365 return -AS_ERR_PARAMETER;
1366 }
1367
1368 int32_t byte_offset = bits_normalize_offset(state, op);
1369
1370 if (byte_offset < 0) {
1371 return byte_offset;
1372 }
1373
1374 uint32_t op_size = ((uint32_t)op->offset + op->size + 7) / 8;
1375
1376 return def->prepare(state, op, (uint32_t)byte_offset, op_size);
1377}
1378
1379static int32_t
1380bits_normalize_offset(const bits_state* state, bits_op* op)
1381{
1382 if (op->offset < 0) {
1383 if ((uint32_t)abs(op->offset) > state->old_size * 8) {
1384 return -AS_ERR_PARAMETER;
1385 }
1386
1387 op->offset = (int32_t)(state->old_size * 8) + op->offset;
1388 }
1389
1390 uint32_t byte_offset = (uint32_t)op->offset / 8;
1391
1392 op->offset %= 8;
1393
1394 return (int32_t)byte_offset;
1395}
1396
1397static int
1398bits_prepare_resize_op(bits_state* state, bits_op* op, uint32_t byte_offset,
1399 uint32_t op_size)
1400{
1401 (void)byte_offset;
1402
1403 bool from_front = (op->subflags & AS_BITS_SUBFLAG_RESIZE_FROM_FRONT) != 0;
1404 bool grow_only = (op->subflags & AS_BITS_SUBFLAG_RESIZE_GROW_ONLY) != 0;
1405 bool shrink_only = (op->subflags & AS_BITS_SUBFLAG_RESIZE_SHRINK_ONLY) != 0;
1406
1407 if (op_size < state->old_size) {
1408 if (grow_only) {
1409 if ((op->flags & AS_BITS_FLAG_NO_FAIL) != 0) {
1410 return AS_OK;
1411 }
1412
1413 cf_warning(AS_PARTICLE, "bits_prepare_resize_op - cannot shrink with grow_only set");
1414 return -AS_ERR_PARAMETER;
1415 }
1416
1417 uint32_t n_bytes_remove = state->old_size - op_size;
1418
1419 state->action = OP_ACTION_REMOVE;
1420
1421 if (from_front) {
1422 state->n_bytes_op = n_bytes_remove;
1423 state->n_bytes_tail = state->old_size - n_bytes_remove;
1424 }
1425 else {
1426 state->n_bytes_head = state->old_size - n_bytes_remove;
1427 state->n_bytes_op = n_bytes_remove;
1428 }
1429 }
1430 else if (op_size > state->old_size) {
1431 if (shrink_only) {
1432 if ((op->flags & AS_BITS_FLAG_NO_FAIL) != 0) {
1433 return AS_OK;
1434 }
1435
1436 cf_warning(AS_PARTICLE, "bits_prepare_resize_op - cannot grow with shrink_only set");
1437 return -AS_ERR_PARAMETER;
1438 }
1439
1440 uint32_t n_bytes_add = op_size - state->old_size;
1441
1442 state->action = OP_ACTION_EXPAND;
1443
1444 if (from_front) {
1445 state->n_bytes_op = n_bytes_add;
1446 state->n_bytes_tail = state->old_size;
1447 }
1448 else {
1449 state->n_bytes_head = state->old_size;
1450 state->n_bytes_op = n_bytes_add;
1451 }
1452 }
1453 else {
1454 return AS_OK; // already the specified size - no-op
1455 }
1456
1457 return 1;
1458}
1459
1460static int
1461bits_prepare_insert_op(bits_state* state, bits_op* op, uint32_t byte_offset,
1462 uint32_t op_size)
1463{
1464 (void)op;
1465
1466 state->action = OP_ACTION_EXPAND;
1467
1468 if (byte_offset >= state->old_size) {
1469 state->n_bytes_head = state->old_size;
1470 state->n_bytes_expand = byte_offset - state->old_size;
1471 state->n_bytes_op = op_size;
1472 }
1473 else {
1474 state->n_bytes_head = byte_offset;
1475 state->n_bytes_op = op_size;
1476 state->n_bytes_tail = state->old_size - byte_offset;
1477 }
1478
1479 return 1;
1480}
1481
1482static int
1483bits_prepare_remove_op(bits_state* state, bits_op* op, uint32_t byte_offset,
1484 uint32_t op_size)
1485{
1486 if (byte_offset >= state->old_size) {
1487 if ((op->flags & AS_BITS_FLAG_NO_FAIL) != 0) {
1488 return AS_OK;
1489 }
1490
1491 cf_warning(AS_PARTICLE, "bits_prepare_remove_op - tried to remove past the end of blob");
1492 return -AS_ERR_PARAMETER;
1493 }
1494
1495 state->action = OP_ACTION_REMOVE;
1496
1497 if (byte_offset + op_size > state->old_size) {
1498 if ((op->flags & AS_BITS_FLAG_PARTIAL) == 0) {
1499 if ((op->flags & AS_BITS_FLAG_NO_FAIL) != 0) {
1500 return AS_OK;
1501 }
1502
1503 cf_warning(AS_PARTICLE, "bits_prepare_remove_op - remove size extended past end of blob without the partial policy");
1504 return -AS_ERR_PARAMETER;
1505 }
1506
1507 state->n_bytes_head = byte_offset;
1508 state->n_bytes_op= state->old_size - byte_offset;
1509 op->size = (state->old_size * 8) - (uint32_t)op->offset;
1510 }
1511 else {
1512 state->n_bytes_head = byte_offset;
1513 state->n_bytes_op= op_size;
1514 state->n_bytes_tail = state->old_size - (byte_offset + op_size);
1515 }
1516
1517 return 1;
1518}
1519
1520static int
1521bits_prepare_modify_op(bits_state* state, bits_op* op, uint32_t byte_offset,
1522 uint32_t op_size)
1523{
1524 if (byte_offset >= state->old_size) {
1525 if ((op->flags & AS_BITS_FLAG_NO_FAIL) != 0) {
1526 return AS_OK;
1527 }
1528
1529 cf_warning(AS_PARTICLE, "bits_prepare_modify_op - operation may not expand blob");
1530 return -AS_ERR_OP_NOT_APPLICABLE;
1531 }
1532
1533 state->action = OP_ACTION_OVERWRITE;
1534
1535 if (byte_offset + op_size > state->old_size) {
1536 if ((op->flags & AS_BITS_FLAG_PARTIAL) == 0) {
1537 if ((op->flags & AS_BITS_FLAG_NO_FAIL) != 0) {
1538 return AS_OK;
1539 }
1540
1541 cf_warning(AS_PARTICLE, "bits_prepare_modify_op - operation too large - either use partial or increase size of blob");
1542 return -AS_ERR_OP_NOT_APPLICABLE;
1543 }
1544
1545 state->n_bytes_head = byte_offset;
1546 state->n_bytes_op = state->old_size - byte_offset;
1547 op->size = (state->old_size * 8) - (uint32_t)op->offset;
1548 }
1549 else {
1550 state->n_bytes_head = byte_offset;
1551 state->n_bytes_op = op_size;
1552 state->n_bytes_tail = state->old_size - (byte_offset + op_size);
1553 }
1554
1555 return 1;
1556}
1557
1558static int
1559bits_prepare_integer_op(bits_state* state, bits_op* op, uint32_t byte_offset,
1560 uint32_t op_size)
1561{
1562 state->action = OP_ACTION_OVERWRITE;
1563
1564 return bits_prepare_read_op(state, op, byte_offset, op_size);
1565}
1566
1567static int
1568bits_prepare_read_op(bits_state* state, bits_op* op, uint32_t byte_offset,
1569 uint32_t op_size)
1570{
1571 if (byte_offset >= state->old_size) {
1572 if ((op->flags & AS_BITS_FLAG_NO_FAIL) != 0) {
1573 return AS_OK;
1574 }
1575
1576 cf_warning(AS_PARTICLE, "bits_prepare_read_op - operation would expand blob");
1577 return -AS_ERR_OP_NOT_APPLICABLE;
1578 }
1579
1580 if (byte_offset + op_size > state->old_size) {
1581 if ((op->flags & AS_BITS_FLAG_NO_FAIL) != 0) {
1582 return AS_OK;
1583 }
1584
1585 cf_warning(AS_PARTICLE, "bits_prepare_read_op - operation too large for blob");
1586 return -AS_ERR_OP_NOT_APPLICABLE;
1587 }
1588
1589 state->n_bytes_head = byte_offset;
1590 state->n_bytes_op = op_size;
1591 state->n_bytes_tail = state->old_size - (byte_offset + op_size);
1592
1593 return 1;
1594}
1595
1596
1597//==========================================================
1598// Local helpers - execute ops.
1599//
1600
1601static bool
1602bits_execute_modify_op(const bits_state* state, const bits_op* op,
1603 const as_particle* old_blob, as_particle* new_blob)
1604{
1605 uint8_t* to = ((blob_mem*)new_blob)->data;
1606 const uint8_t* end_to = to + state->new_size; // paranoia
1607
1608 if (old_blob != NULL) {
1609 const uint8_t* from = ((const blob_mem*)old_blob)->data;
1610 const uint8_t* end_from = from + state->old_size; // paranoia
1611
1612 if (state->n_bytes_head != 0) {
1613 memcpy(to, from, state->n_bytes_head);
1614 to += state->n_bytes_head;
1615 from += state->n_bytes_head;
1616 }
1617
1618 if (state->action == OP_ACTION_OVERWRITE) {
1619 if (! state->def->fn.modify(op, to, from, state->n_bytes_op)) {
1620 return false;
1621 }
1622
1623 to += state->n_bytes_op;
1624 from += state->n_bytes_op;
1625 }
1626 else if (state->action == OP_ACTION_EXPAND) {
1627 if (state->n_bytes_expand != 0) {
1628 memset(to, 0, state->n_bytes_expand);
1629 to += state->n_bytes_expand;
1630 }
1631
1632 if (! state->def->fn.modify(op, to, NULL, state->n_bytes_op)) {
1633 return false;
1634 }
1635
1636 to += state->n_bytes_op;
1637 }
1638 else { // OP_ACTION_REMOVE
1639 from += state->n_bytes_op;
1640 }
1641
1642 if (state->n_bytes_tail != 0) {
1643 memcpy(to, from, state->n_bytes_tail);
1644 to += state->n_bytes_tail;
1645 from += state->n_bytes_tail;
1646 }
1647
1648 // Paranoia.
1649 cf_assert(to == end_to && from == end_from, AS_PARTICLE,
1650 "either to or from didn't stop at end - to (%p %p) from (%p %p)",
1651 to, end_to, from, end_from);
1652 }
1653 else {
1654 memset(to, 0, state->new_size);
1655 to += state->n_bytes_expand;
1656
1657 cf_assert(state->action == OP_ACTION_EXPAND, AS_PARTICLE,
1658 "creating a blob expected expand action - found %u",
1659 state->action);
1660
1661 if (! state->def->fn.modify(op, to, NULL, state->n_bytes_op)) {
1662 return false;
1663 }
1664
1665 to += state->n_bytes_op; // paranoia
1666
1667 // Paranoia.
1668 cf_assert(to == end_to, AS_PARTICLE, "to didn't stop at end - to (%p %p)",
1669 to, end_to);
1670 }
1671
1672 ((blob_mem*)new_blob)->sz = state->new_size;
1673 ((blob_mem*)new_blob)->type = AS_PARTICLE_TYPE_BLOB;
1674
1675 return true;
1676}
1677
1678static bool
1679bits_execute_read_op(const bits_state* state, const bits_op* op,
1680 const as_particle* blob, as_bin* rb)
1681{
1682 const uint8_t* from = ((const blob_mem*)blob)->data + state->n_bytes_head;
1683
1684 return state->def->fn.read(op, from, rb, state->n_bytes_op);
1685}
1686
1687
1688//==========================================================
1689// Local helpers - bits modify ops.
1690//
1691
1692static bool
1693bits_modify_op_resize(const bits_op* op, uint8_t* to, const uint8_t* from,
1694 uint32_t n_bytes)
1695{
1696 (void)op;
1697 (void)from;
1698
1699 // Note - this function isn't called when sizing down.
1700
1701 memset(to, 0, n_bytes);
1702
1703 return true;
1704}
1705
1706static bool
1707bits_modify_op_insert(const bits_op* op, uint8_t* to, const uint8_t* from,
1708 uint32_t n_bytes)
1709{
1710 (void)from;
1711
1712 memcpy(to, op->buf, n_bytes);
1713
1714 return true;
1715}
1716
1717static bool
1718bits_modify_op_set(const bits_op* op, uint8_t* to, const uint8_t* from,
1719 uint32_t n_bytes)
1720{
1721 const bits_op cmd = {
1722 .size = ((op->size + 7) / 8) * 8,
1723 .value = (uint64_t)op->offset
1724 };
1725
1726 rshift(&cmd, to, op->buf, n_bytes);
1727 restore_ends(op, to, from, n_bytes);
1728
1729 return true;
1730}
1731
1732static bool
1733bits_modify_op_or(const bits_op* op, uint8_t* to, const uint8_t* from,
1734 uint32_t n_bytes)
1735{
1736 const bits_op cmd = {
1737 .size = op->size,
1738 .value = (uint64_t)op->offset,
1739 .buf = op->buf
1740 };
1741
1742 rshift_with_or(&cmd, to, from, n_bytes);
1743 restore_ends(op, to, from, n_bytes);
1744
1745 return true;
1746}
1747
1748static bool
1749bits_modify_op_xor(const bits_op* op, uint8_t* to, const uint8_t* from,
1750 uint32_t n_bytes)
1751{
1752 const bits_op cmd = {
1753 .size = op->size,
1754 .value = (uint64_t)op->offset,
1755 .buf = op->buf
1756 };
1757
1758 rshift_with_xor(&cmd, to, from, n_bytes);
1759 restore_ends(op, to, from, n_bytes);
1760
1761 return true;
1762}
1763
1764static bool
1765bits_modify_op_and(const bits_op* op, uint8_t* to, const uint8_t* from,
1766 uint32_t n_bytes)
1767{
1768 const bits_op cmd = {
1769 .size = op->size,
1770 .value = (uint64_t)op->offset,
1771 .buf = op->buf
1772 };
1773
1774 rshift_with_and(&cmd, to, from, n_bytes);
1775 restore_ends(op, to, from, n_bytes);
1776
1777 return true;
1778}
1779
1780static bool
1781bits_modify_op_not(const bits_op* op, uint8_t* to, const uint8_t* from,
1782 uint32_t n_bytes)
1783{
1784 uint8_t* orig_to = &to[0];
1785 const uint8_t* orig_from = &from[0];
1786 const uint8_t* cur = &from[0];
1787 const uint8_t* end = &from[n_bytes];
1788
1789 while (cur < end) {
1790 *to++ = (uint8_t)~*cur++;
1791 }
1792
1793 restore_ends(op, orig_to, orig_from, n_bytes);
1794
1795 return true;
1796}
1797
1798static bool
1799bits_modify_op_lshift(const bits_op* op, uint8_t* to, const uint8_t* from,
1800 uint32_t n_bytes)
1801{
1802 lshift(op, to, from, n_bytes);
1803 restore_ends(op, to, from, n_bytes);
1804
1805 return true;
1806}
1807
1808static bool
1809bits_modify_op_rshift(const bits_op* op, uint8_t* to, const uint8_t* from,
1810 uint32_t n_bytes)
1811{
1812 rshift(op, to, from, n_bytes);
1813 restore_ends(op, to, from, n_bytes);
1814
1815 return true;
1816}
1817
1818static bool
1819bits_modify_op_add(const bits_op* op, uint8_t* to, const uint8_t* from,
1820 uint32_t n_bytes)
1821{
1822 uint64_t load = load_int(op, from, n_bytes);
1823 uint32_t n_bits = op->size;
1824 uint32_t leading = 64 - n_bits;
1825 uint64_t value_m = 0xFFFFffffFFFFffff >> leading;
1826 uint64_t value = op->value & value_m;
1827
1828 uint64_t result = (load + value) & value_m;
1829 bool is_signed = (op->subflags & AS_BITS_INT_SUBFLAG_SIGNED) != 0;
1830 bool is_wrap = (op->subflags & AS_BITS_INT_SUBFLAG_WRAP) != 0;
1831 bool is_saturate = (op->subflags & AS_BITS_INT_SUBFLAG_SATURATE) != 0;
1832
1833 if (! is_wrap) {
1834 if (is_signed) {
1835 if (! handle_signed_overflow(n_bits, is_saturate, load, value,
1836 &result)) {
1837 return false;
1838 }
1839 }
1840 else if (result < load) {
1841 if (is_saturate) {
1842 result = value_m;
1843 }
1844 else {
1845 return false;
1846 }
1847 }
1848 }
1849
1850 store_int(op, to, result, n_bytes);
1851 restore_ends(op, to, from, n_bytes);
1852
1853 return true;
1854}
1855
1856static bool
1857bits_modify_op_subtract(const bits_op* op, uint8_t* to, const uint8_t* from,
1858 uint32_t n_bytes)
1859{
1860 uint64_t load = load_int(op, from, n_bytes);
1861 uint32_t n_bits = op->size;
1862 uint32_t leading = 64 - n_bits;
1863 uint64_t value_m = 0xFFFFffffFFFFffff >> leading;
1864 uint64_t value = op->value & value_m;
1865
1866 uint64_t result = (load - value) & value_m;
1867 bool is_signed = (op->subflags & AS_BITS_INT_SUBFLAG_SIGNED) != 0;
1868 bool is_wrap = (op->subflags & AS_BITS_INT_SUBFLAG_WRAP) != 0;
1869 bool is_saturate = (op->subflags & AS_BITS_INT_SUBFLAG_SATURATE) != 0;
1870
1871 if (! is_wrap) {
1872 if (is_signed) {
1873 if (! handle_signed_overflow(n_bits, is_saturate, load,
1874 (uint64_t)((int64_t)value * -1), &result)) {
1875 return false;
1876 }
1877 }
1878 else if (result > load) {
1879 if (is_saturate) {
1880 result = 0;
1881 }
1882 else {
1883 return false;
1884 }
1885 }
1886 }
1887
1888 store_int(op, to, result, n_bytes);
1889 restore_ends(op, to, from, n_bytes);
1890
1891 return true;
1892}
1893
1894static bool
1895bits_modify_op_set_int(const bits_op* op, uint8_t* to, const uint8_t* from,
1896 uint32_t n_bytes)
1897{
1898 uint64_t value_m = 0xFFFFffffFFFFffff >> (64 - op->size);
1899 uint64_t value = op->value & value_m;
1900
1901 store_int(op, to, value, n_bytes);
1902 restore_ends(op, to, from, n_bytes);
1903
1904 return true;
1905}
1906
1907
1908//==========================================================
1909// Local helpers - bits read ops.
1910//
1911
1912static bool
1913bits_read_op_get(const bits_op* op, const uint8_t* from, as_bin* rb,
1914 uint32_t n_bytes)
1915{
1916 uint32_t answer_sz = (op->size + 7) / 8;
1917
1918 const bits_op cmd = {
1919 .size = answer_sz * 8,
1920 .value = (uint64_t)op->offset
1921 };
1922
1923 blob_mem* answer = cf_malloc(sizeof(blob_mem) + n_bytes);
1924
1925 lshift(&cmd, answer->data, from, n_bytes);
1926
1927 // Zero end.
1928 uint32_t size = op->size % 8;
1929
1930 if (size != 0) {
1931 uint8_t from_tail_m = (uint8_t)(0xFF << (8 - size));
1932
1933 answer->data[answer_sz - 1] &= from_tail_m;
1934 }
1935
1936 answer->sz = answer_sz;
1937 answer->type = AS_PARTICLE_TYPE_BLOB;
1938 rb->particle = (as_particle*)answer;
1939 as_bin_state_set_from_type(rb, AS_PARTICLE_TYPE_BLOB);
1940
1941 return true;
1942}
1943
1944static bool
1945bits_read_op_count(const bits_op* op, const uint8_t* from, as_bin* rb,
1946 uint32_t n_bytes)
1947{
1948 const uint8_t* end = &from[n_bytes - 1];
1949 const uint8_t* cur = &from[0];
1950 uint8_t head_m = (uint8_t)(0xFF << (8 - op->offset));
1951 uint32_t tail_len = (op->size + (uint32_t)op->offset) % 8;
1952 uint8_t tail_m = (uint8_t)(tail_len != 0 ? 0xFF >> tail_len : 0x00);
1953 uint64_t answer = 0;
1954
1955 if (n_bytes == 1) {
1956 uint8_t m = (uint8_t)~(head_m | tail_m);
1957
1958 answer = cf_bit_count64((uint64_t)(*cur & m));
1959 }
1960 else {
1961 answer = cf_bit_count64((uint64_t)(*cur++ & ~head_m));
1962
1963 while (cur < end && (cur - from < 8 || (uint64_t)cur % 8 != 0)) {
1964 answer += cf_bit_count64(*cur++);
1965 }
1966
1967 while (end - cur >= 64) {
1968 for (uint32_t i = 0; i < 8; i++) {
1969 answer += cf_bit_count64(*(uint64_t*)cur);
1970 cur += 8;
1971 }
1972 }
1973
1974 while (cur < end) {
1975 answer += cf_bit_count64((uint64_t)*cur++);
1976 }
1977
1978 answer += cf_bit_count64((uint64_t)(*end & ~tail_m));
1979 }
1980
1981 rb->particle = (as_particle*)answer;
1982 as_bin_state_set_from_type(rb, AS_PARTICLE_TYPE_INTEGER);
1983
1984 return true;
1985}
1986
1987static bool
1988bits_read_op_lscan(const bits_op* op, const uint8_t* from, as_bin* rb,
1989 uint32_t n_bytes)
1990{
1991 const uint8_t* end = &from[n_bytes - 1];
1992 const uint8_t* cur = from;
1993 uint8_t head_m = (uint8_t)(0xFF >> op->offset);
1994 uint8_t last = (uint8_t)(op->value == 1 ? *cur & head_m : ~*cur & head_m);
1995 uint8_t skip = (uint8_t)(op->value == 1 ? 0x00 : 0xFF);
1996
1997 if (last == 0 && n_bytes != 1) {
1998 cur++;
1999
2000 while (*cur == skip && cur < end) {
2001 cur++;
2002 }
2003
2004 last = (uint8_t)(op->value == 1 ? *cur : ~*cur);
2005 }
2006
2007 int64_t answer;
2008
2009 if (last != 0) {
2010 uint32_t bit_ix = 0;
2011 uint8_t m = (uint8_t)0x80;
2012
2013 while ((last & (m >> bit_ix)) == 0) {
2014 bit_ix++;
2015 }
2016
2017 answer = ((cur - from) * 8 + bit_ix) - op->offset;
2018
2019 if (answer >= op->size) {
2020 answer = -1;
2021 }
2022 }
2023 else {
2024 answer = -1;
2025 }
2026
2027 rb->particle = (as_particle*)answer;
2028 as_bin_state_set_from_type(rb, AS_PARTICLE_TYPE_INTEGER);
2029
2030 return true;
2031}
2032
2033static bool
2034bits_read_op_rscan(const bits_op* op, const uint8_t* from, as_bin* rb,
2035 uint32_t n_bytes)
2036{
2037 const uint8_t* cur = &from[n_bytes - 1];
2038 uint8_t head_m = (uint8_t)(0xFF << ((8 - (op->size +
2039 (uint32_t)op->offset) % 8) % 8));
2040 uint8_t last = (uint8_t)(op->value == 1 ? *cur & head_m : ~*cur & head_m);
2041 uint8_t skip = (uint8_t)(op->value == 1 ? 0x00 : 0xFF);
2042
2043 if (last == 0 && n_bytes != 1) {
2044 cur--;
2045
2046 while (*cur == skip && cur > from) {
2047 cur--;
2048 }
2049
2050 last = (uint8_t)(op->value == 1 ? *cur : ~*cur);
2051 }
2052
2053 int64_t answer;
2054
2055 if (last != 0) {
2056 uint32_t bit_ix = 7;
2057 uint8_t m = (uint8_t)0x80;
2058
2059 while ((last & (m >> bit_ix)) == 0) {
2060 bit_ix--;
2061 }
2062
2063 answer = ((cur - from) * 8 + bit_ix) - op->offset;
2064
2065 if (answer >= op->size) {
2066 answer = -1;
2067 }
2068 }
2069 else {
2070 answer = -1;
2071 }
2072
2073 rb->particle = (as_particle*)answer;
2074 as_bin_state_set_from_type(rb, AS_PARTICLE_TYPE_INTEGER);
2075
2076 return true;
2077}
2078
2079static bool
2080bits_read_op_get_integer(const bits_op* op, const uint8_t* from, as_bin* rb,
2081 uint32_t n_bytes)
2082{
2083 uint32_t leading = 64 - op->size;
2084 int64_t answer = (int64_t)load_int(op, from, n_bytes);
2085
2086 if ((op->subflags & AS_BITS_INT_SUBFLAG_SIGNED) != 0) {
2087 // Sign extend values.
2088 answer = ((answer << leading) >> leading);
2089 }
2090
2091 rb->particle = (as_particle*)answer;
2092 as_bin_state_set_from_type(rb, AS_PARTICLE_TYPE_INTEGER);
2093
2094 return true;
2095}
2096
2097
2098//==========================================================
2099// Local helpers - bits op helpers.
2100//
2101
2102static void
2103lshift(const bits_op* op, uint8_t* to, const uint8_t* from, uint32_t n_bytes)
2104{
2105 uint32_t n_shift = (uint32_t)op->value;
2106 uint32_t n_shift_bytes = n_shift / 8;
2107 const uint8_t* cur = &from[n_shift_bytes];
2108 const uint8_t* end = &from[n_bytes - 1];
2109 uint8_t last_m = (uint8_t)(0xFF <<
2110 ((8 - ((uint32_t)op->offset + op->size) % 8) % 8));
2111 uint8_t last_byte = (uint8_t)(from[n_bytes - 1] & last_m);
2112 uint32_t l8 = n_shift % 8;
2113 uint32_t r8 = 8 - l8;
2114 uint32_t r64 = 64 - l8;
2115
2116 if (n_shift >= op->size) {
2117 // This condition needs to be in terms of bits.
2118 memset(to, 0, n_bytes);
2119
2120 return;
2121 }
2122
2123 if (l8 == 0) {
2124 size_t copy_bytes = (size_t)(end - cur);
2125
2126 memcpy(to, cur, copy_bytes);
2127 to += copy_bytes;
2128 cur += copy_bytes;
2129 *to++ = last_byte;
2130 memset(to, 0, n_shift_bytes);
2131
2132 return;
2133 }
2134
2135 // Begin - optimize enveloped 8-byte groups.
2136
2137 while (end - cur > 1 && (uint64_t)cur % 8 != 0) {
2138 *to++ = (uint8_t)((*cur << l8) | ((*(cur + 1)) >> r8));
2139 cur++;
2140 }
2141
2142 if (end - cur >= 16) {
2143 while (end - cur >= 64 + 8) {
2144 for (uint32_t i = 0; i < 8; i++) {
2145 uint64_t v = cf_swap_from_be64(*(uint64_t*)cur);
2146 cur += 8;
2147 uint64_t n = cf_swap_from_be64(*(uint64_t*)cur);
2148
2149 *(uint64_t*)to = cf_swap_to_be64((v << l8) | (n >> r64));
2150 to += 8;
2151 }
2152 }
2153
2154 while (end - cur >= 16) {
2155 uint64_t v = cf_swap_from_be64(*(uint64_t*)cur);
2156 cur += 8;
2157 uint64_t n = cf_swap_from_be64(*(uint64_t*)cur);
2158
2159 *(uint64_t*)to = cf_swap_to_be64((v << l8) | (n >> r64));
2160 to += 8;
2161 }
2162 }
2163
2164 // End - optimize enveloped 8-byte groups.
2165
2166 while (end - cur > 1) {
2167 *to++ = (uint8_t)((*cur << l8) | (*(cur + 1) >> r8));
2168 cur++;
2169 }
2170
2171 if (cur < end) {
2172 *to++ = (uint8_t)((*cur++ << l8) | (last_byte >> r8));
2173 }
2174
2175 *to++ = (uint8_t)(last_byte << l8);
2176 memset(to, 0, n_shift_bytes);
2177}
2178
2179static void
2180rshift(const bits_op* op, uint8_t* to, const uint8_t* from, uint32_t n_bytes)
2181{
2182 uint32_t n_shift = (uint32_t)op->value;
2183 uint32_t n_shift_bytes = n_shift / 8;
2184 uint8_t first_byte = (uint8_t)(from[0] & (0xFF >> op->offset));
2185 const uint8_t* cur = &from[1];
2186 const uint8_t* end = &from[n_bytes - n_shift_bytes];
2187 uint32_t r8 = n_shift % 8;
2188 uint32_t l8 = 8 - r8;
2189 uint32_t l64 = 64 - r8;
2190
2191 if (n_shift >= op->size) {
2192 memset(to, 0, n_bytes);
2193
2194 return;
2195 }
2196
2197 memset(to, 0, n_shift_bytes);
2198 to += n_shift_bytes;
2199
2200 if (r8 == 0) {
2201 *to++ = first_byte;
2202 memcpy(to, cur, n_bytes - n_shift_bytes - 1);
2203
2204 return;
2205 }
2206
2207 *to++ = (uint8_t)(first_byte >> r8);
2208
2209 if (cur < end) {
2210 *to++ = (uint8_t)((first_byte << l8) | (*cur++ >> r8));
2211 }
2212
2213 // Begin - optimize enveloped 8-byte groups.
2214
2215 while (cur < end && (cur - from < 8 || (uint64_t)cur % 8 != 0)) {
2216 *to++ = (uint8_t)((*(cur - 1) << l8) | (*cur >> r8));
2217 cur++;
2218 }
2219
2220 while (end - cur >= 64) {
2221 for (uint32_t i = 0; i < 8; i++) {
2222 uint64_t v = cf_swap_from_be64(*(uint64_t*)(cur - 8));
2223 uint64_t n = cf_swap_from_be64(*(uint64_t*)cur);
2224
2225 *(uint64_t*)to = cf_swap_to_be64((v << l64) | (n >> r8));
2226 to += sizeof(uint64_t);
2227 cur += sizeof(uint64_t);
2228 }
2229 }
2230
2231 while (end - cur >= 8) {
2232 uint64_t v = cf_swap_from_be64(*(uint64_t*)(cur - 8));
2233 uint64_t n = cf_swap_from_be64(*(uint64_t*)cur);
2234
2235 *(uint64_t*)to = cf_swap_to_be64((v << l64) | (n >> r8));
2236 to += sizeof(uint64_t);
2237 cur += sizeof(uint64_t);
2238 }
2239
2240 // End - optimize enveloped 8-byte groups.
2241
2242 while (cur < end) {
2243 *to++ = (uint8_t)((*(cur - 1) << l8) | (*cur >> r8));
2244 cur++;
2245 }
2246}
2247
2248static void
2249rshift_with_or(const bits_op* op, uint8_t* to, const uint8_t* from,
2250 uint32_t n_bytes)
2251{
2252 RSHIFT_WITH_OP(|)
2253}
2254
2255static void
2256rshift_with_xor(const bits_op* op, uint8_t* to, const uint8_t* from,
2257 uint32_t n_bytes)
2258{
2259 RSHIFT_WITH_OP(^)
2260}
2261
2262static void
2263rshift_with_and(const bits_op* op, uint8_t* to, const uint8_t* from,
2264 uint32_t n_bytes)
2265{
2266 RSHIFT_WITH_OP(&)
2267}
2268
2269static uint64_t
2270load_int(const bits_op* op, const uint8_t* from, uint32_t n_bytes)
2271{
2272 const bits_op load_cmd = {
2273 .offset = 0,
2274 .size = 64,
2275 .value = (uint64_t)op->offset
2276 };
2277
2278 uint8_t load[9]; // last byte is needed for overflow but never read
2279
2280 lshift(&load_cmd, load, from, n_bytes);
2281 *(uint64_t*)load = cf_swap_from_be64(*(uint64_t*)load) >> (64 - op->size);
2282
2283 return *(uint64_t*)load;
2284}
2285
2286static bool
2287handle_signed_overflow(uint32_t n_bits, bool is_saturate, uint64_t load,
2288 uint64_t value, uint64_t* result)
2289{
2290 uint32_t leading = 64 - n_bits;
2291 uint64_t value_m = 0xFFFFffffFFFFffff >> leading;
2292
2293 // Sign extend values.
2294 int64_t s_result = (((int64_t)*result) << leading) >> leading;
2295 int64_t s_load = (((int64_t)load) << leading) >> leading;
2296 int64_t s_value = (((int64_t)value) << leading) >> leading;
2297
2298 if (s_load < 0 && s_value < 0 && s_result > 0) {
2299 if (is_saturate) {
2300 // Max negative.
2301 *result = (value_m >> (n_bits - 1)) << (n_bits - 1);
2302 }
2303 else {
2304 return false;
2305 }
2306 }
2307 else if (s_load > 0 && s_value > 0 && s_result < 0) {
2308 if (is_saturate) {
2309 // Max positive.
2310 *result = value_m >> 1;
2311 }
2312 else {
2313 return false;
2314 }
2315 }
2316
2317 return true;
2318}
2319
2320static void
2321store_int(const bits_op* op, uint8_t* to, uint64_t value,
2322 uint32_t n_bytes)
2323{
2324 uint64_t store = cf_swap_to_be64(value << (64 - op->size));
2325
2326 const bits_op store_cmd = {
2327 .size = ((op->size + 7) / 8) * 8,
2328 .value = (uint64_t)op->offset
2329 };
2330
2331 rshift(&store_cmd, to, (uint8_t*)&store, n_bytes);
2332}
2333
2334static void
2335restore_ends(const bits_op* op, uint8_t* to, const uint8_t* from,
2336 uint32_t n_bytes)
2337{
2338 uint32_t offset = (uint32_t)op->offset;
2339 uint32_t size = op->size;
2340 uint8_t from_head = from[0];
2341
2342 if (n_bytes == 1) {
2343 uint32_t from_head_len = offset;
2344 uint8_t from_head_m = (uint8_t)(0xFF << (8 - from_head_len));
2345 uint32_t from_tail_len = (8 - (offset + size) % 8) % 8;
2346 uint8_t from_tail_m = (uint8_t)(0xFF >> (8 - from_tail_len));
2347 uint8_t m = from_head_m | from_tail_m;
2348
2349 *to = (uint8_t)((*to & ~m) | (from_head & m));
2350
2351 return;
2352 }
2353
2354 if (offset != 0) {
2355 uint32_t from_head_len = offset;
2356 uint8_t from_head_m = (uint8_t)(0xFF << (8 - from_head_len));
2357
2358 *to = (uint8_t)((*to & ~from_head_m) | (from_head & from_head_m));
2359 }
2360
2361 if ((offset + size) % 8 != 0) {
2362 uint8_t from_tail = from[n_bytes - 1];
2363 uint32_t from_tail_len = 8 - ((offset + size) % 8);
2364 uint8_t from_tail_m = (uint8_t)(0xFF >> (8 - from_tail_len));
2365
2366 to += (n_bytes - 1);
2367 *to = (uint8_t)((*to & ~from_tail_m) | (from_tail & from_tail_m));
2368 }
2369}
2370