Skip to content

Commit e26ff9a

Browse files
WIP Initial API for delegated streaming out
Signed-off-by: Thiago Macieira <[email protected]>
1 parent 34c8452 commit e26ff9a

File tree

5 files changed

+108
-10
lines changed

5 files changed

+108
-10
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ script:
7575
- make -s -f Makefile.configure configure | tee .config
7676
- make -k
7777
CFLAGS="$CFLAGS -march=native -g1 -Wall -Wextra -Werror"
78-
CPPFLAGS="-DNDEBUG -DCBOR_PARSER_READER_CONTROL=-1"
78+
CPPFLAGS="-DNDEBUG -DCBOR_ENCODER_WRITER_CONTROL=-1 -DCBOR_PARSER_READER_CONTROL=-1"
7979
lib/libtinycbor.a
8080
- size lib/libtinycbor.a | tee sizes
8181
- make -s clean

src/cbor.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,13 +203,29 @@ typedef enum CborError {
203203
CBOR_API const char *cbor_error_string(CborError error);
204204

205205
/* Encoder API */
206+
207+
typedef enum CborEncoderAppendType
208+
{
209+
CborEncoderAppendCborData = 0,
210+
CborEncoderAppendStringData = 1
211+
} CborEncoderAppendType;
212+
213+
typedef CborError (*CborEncoderWriteFunction)(void *, const void *, size_t, CborEncoderAppendType);
214+
215+
enum CborEncoderFlags
216+
{
217+
CborIteratorFlag_WriterFunction = 0x01,
218+
CborIteratorFlag_ContainerIsMap_ = 0x20
219+
};
220+
206221
struct CborEncoder
207222
{
208223
union {
209224
uint8_t *ptr;
210225
ptrdiff_t bytes_needed;
226+
CborEncoderWriteFunction writer;
211227
} data;
212-
const uint8_t *end;
228+
uint8_t *end;
213229
size_t remaining;
214230
int flags;
215231
};
@@ -219,6 +235,7 @@ static const size_t CborIndefiniteLength = SIZE_MAX;
219235

220236
#ifndef CBOR_NO_ENCODER_API
221237
CBOR_API void cbor_encoder_init(CborEncoder *encoder, uint8_t *buffer, size_t size, int flags);
238+
CBOR_API void cbor_encoder_init_writer(CborEncoder *encoder, CborEncoderWriteFunction writer, void *);
222239
CBOR_API CborError cbor_encode_uint(CborEncoder *encoder, uint64_t value);
223240
CBOR_API CborError cbor_encode_int(CborEncoder *encoder, int64_t value);
224241
CBOR_API CborError cbor_encode_negative_int(CborEncoder *encoder, uint64_t absolute_value);

src/cborencoder.c

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/****************************************************************************
22
**
3-
** Copyright (C) 2016 Intel Corporation
3+
** Copyright (C) 2021 Intel Corporation
44
**
55
** Permission is hereby granted, free of charge, to any person obtaining a copy
66
** of this software and associated documentation files (the "Software"), to deal
@@ -208,6 +208,18 @@ void cbor_encoder_init(CborEncoder *encoder, uint8_t *buffer, size_t size, int f
208208
encoder->flags = flags;
209209
}
210210

211+
void cbor_encoder_init_writer(CborEncoder *encoder, CborEncoderWriteFunction writer, void *token)
212+
{
213+
#ifdef CBOR_ENCODER_WRITE_FUNCTION
214+
(void) writer;
215+
#else
216+
encoder->data.writer = writer;
217+
#endif
218+
encoder->end = (uint8_t *)token;
219+
encoder->remaining = 2;
220+
encoder->flags = CborIteratorFlag_WriterFunction;
221+
}
222+
211223
static inline void put16(void *where, uint16_t v)
212224
{
213225
uint16_t v_be = cbor_htons(v);
@@ -221,8 +233,12 @@ static inline void put16(void *where, uint16_t v)
221233
* being created in the tinycbor output */
222234
static inline bool isOomError(CborError err)
223235
{
224-
(void) err;
225-
return true;
236+
if (CBOR_ENCODER_WRITER_CONTROL < 0)
237+
return true;
238+
239+
/* CborErrorOutOfMemory is the only negative error code, intentionally
240+
* so we can write the test like this */
241+
return (int)err < 0;
226242
}
227243

228244
static inline void put32(void *where, uint32_t v)
@@ -253,8 +269,20 @@ static inline void advance_ptr(CborEncoder *encoder, size_t n)
253269
encoder->data.bytes_needed += n;
254270
}
255271

256-
static inline CborError append_to_buffer(CborEncoder *encoder, const void *data, size_t len)
272+
static inline CborError append_to_buffer(CborEncoder *encoder, const void *data, size_t len,
273+
CborEncoderAppendType appendType)
257274
{
275+
if (CBOR_ENCODER_WRITER_CONTROL >= 0) {
276+
if (encoder->flags & CborIteratorFlag_WriterFunction || CBOR_ENCODER_WRITER_CONTROL != 0) {
277+
# ifdef CBOR_ENCODER_WRITE_FUNCTION
278+
return CBOR_ENCODER_WRITE_FUNCTION(encoder->end, data, len, appendType);
279+
# else
280+
return encoder->data.writer(encoder->end, data, len, appendType);
281+
# endif
282+
}
283+
}
284+
285+
#if CBOR_ENCODER_WRITER_CONTROL <= 0
258286
if (would_overflow(encoder, len)) {
259287
if (encoder->end != NULL) {
260288
len -= encoder->end - encoder->data.ptr;
@@ -268,12 +296,13 @@ static inline CborError append_to_buffer(CborEncoder *encoder, const void *data,
268296

269297
memcpy(encoder->data.ptr, data, len);
270298
encoder->data.ptr += len;
299+
#endif
271300
return CborNoError;
272301
}
273302

274303
static inline CborError append_byte_to_buffer(CborEncoder *encoder, uint8_t byte)
275304
{
276-
return append_to_buffer(encoder, &byte, 1);
305+
return append_to_buffer(encoder, &byte, 1, CborEncoderAppendCborData);
277306
}
278307

279308
static inline CborError encode_number_no_update(CborEncoder *encoder, uint64_t ui, uint8_t shiftedMajorType)
@@ -302,7 +331,7 @@ static inline CborError encode_number_no_update(CborEncoder *encoder, uint64_t u
302331
*bufstart = shiftedMajorType + Value8Bit + more;
303332
}
304333

305-
return append_to_buffer(encoder, bufstart, bufend - bufstart);
334+
return append_to_buffer(encoder, bufstart, bufend - bufstart, CborEncoderAppendCborData);
306335
}
307336

308337
static inline void saturated_decrement(CborEncoder *encoder)
@@ -399,7 +428,7 @@ CborError cbor_encode_floating_point(CborEncoder *encoder, CborType fpType, cons
399428
else
400429
put16(buf + 1, *(const uint16_t*)value);
401430
saturated_decrement(encoder);
402-
return append_to_buffer(encoder, buf, size + 1);
431+
return append_to_buffer(encoder, buf, size + 1, CborEncoderAppendCborData);
403432
}
404433

405434
/**
@@ -418,7 +447,7 @@ static CborError encode_string(CborEncoder *encoder, size_t length, uint8_t shif
418447
CborError err = encode_number(encoder, length, shiftedMajorType);
419448
if (err && !isOomError(err))
420449
return err;
421-
return append_to_buffer(encoder, string, length);
450+
return append_to_buffer(encoder, string, length, CborEncoderAppendStringData);
422451
}
423452

424453
/**
@@ -466,9 +495,12 @@ static CborError create_container(CborEncoder *encoder, CborEncoder *container,
466495
saturated_decrement(encoder);
467496
container->remaining = length + 1; /* overflow ok on CborIndefiniteLength */
468497

498+
cbor_static_assert((int)CborIteratorFlag_ContainerIsMap_ == (int)CborIteratorFlag_ContainerIsMap);
469499
cbor_static_assert(((MapType << MajorTypeShift) & CborIteratorFlag_ContainerIsMap) == CborIteratorFlag_ContainerIsMap);
470500
cbor_static_assert(((ArrayType << MajorTypeShift) & CborIteratorFlag_ContainerIsMap) == 0);
471501
container->flags = shiftedMajorType & CborIteratorFlag_ContainerIsMap;
502+
if (CBOR_ENCODER_WRITER_CONTROL == 0)
503+
container->flags |= encoder->flags & CborIteratorFlag_WriterFunction;
472504

473505
if (length == CborIndefiniteLength) {
474506
container->flags |= CborIteratorFlag_UnknownLength;

src/cborinternal_p.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,13 @@ static inline double decode_half(unsigned short half)
106106
# define CBOR_PARSER_MAX_RECURSIONS 1024
107107
#endif
108108

109+
#ifndef CBOR_ENCODER_WRITER_CONTROL
110+
# define CBOR_ENCODER_WRITER_CONTROL 0
111+
#endif
109112
#ifndef CBOR_PARSER_READER_CONTROL
110113
# define CBOR_PARSER_READER_CONTROL 0
111114
#endif
115+
112116
/*
113117
* CBOR Major types
114118
* Encoded in the high 3 bits of the descriptor byte

tests/encoder/tst_encoder.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ private slots:
6161
void maps_data() { tags_data(); }
6262
void maps();
6363

64+
void writerApi_data() { tags_data(); }
65+
void writerApi();
66+
void writerApiFail_data() { tags_data(); }
67+
void writerApiFail();
6468
void shortBuffer_data() { tags_data(); }
6569
void shortBuffer();
6670
void tooShortArrays_data() { tags_data(); }
@@ -784,6 +788,47 @@ void tst_Encoder::maps()
784788
if (QTest::currentTestFailed()) return;
785789
}
786790

791+
void tst_Encoder::writerApi()
792+
{
793+
QFETCH(QVariant, input);
794+
QFETCH(QByteArray, output);
795+
796+
// instead of writing to a QByteArray like all other tests, write to a QBuffer
797+
QBuffer buffer;
798+
buffer.open(QIODevice::ReadWrite);
799+
auto callback = [](void *token, const void *data, size_t len, CborEncoderAppendType) {
800+
auto buffer = static_cast<QBuffer *>(token);
801+
buffer->write(static_cast<const char *>(data), len);
802+
return CborNoError;
803+
};
804+
805+
CborEncoder encoder;
806+
cbor_encoder_init_writer(&encoder, callback, &buffer);
807+
QCOMPARE(encodeVariant(&encoder, input), CborNoError);
808+
809+
buffer.reset();
810+
QCOMPARE(buffer.readAll(), output);
811+
}
812+
813+
void tst_Encoder::writerApiFail()
814+
{
815+
QFETCH(QVariant, input);
816+
QFETCH(QByteArray, output);
817+
818+
// same as above, but we'll produce an error during writing and we expect
819+
// it to be returned
820+
int callCount = 0;
821+
auto callback = [](void *token, const void *, size_t, CborEncoderAppendType) {
822+
++*static_cast<int *>(token);
823+
return CborErrorIO;
824+
};
825+
826+
CborEncoder encoder;
827+
cbor_encoder_init_writer(&encoder, callback, &callCount);
828+
QCOMPARE(encodeVariant(&encoder, input), CborErrorIO);
829+
QCOMPARE(callCount, 1);
830+
}
831+
787832
void tst_Encoder::shortBuffer()
788833
{
789834
QFETCH(QVariant, input);

0 commit comments

Comments
 (0)