Skip to content

Document and improve abstract reader/writer interface #208

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 26 commits into
base: dev
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
0ff814d
CI: add dependabot configuration
pjonsson Nov 2, 2023
2265e82
CI: add Github CI
pjonsson Nov 2, 2023
ad60cea
follow-up commit to 75eaa19
lightyear15 Feb 13, 2024
8907f20
Tests: disable the C90 test
thiagomacieira May 2, 2024
89723e2
CI: Get Homebrew to use a bottle (precompiled) Qt
thiagomacieira May 2, 2024
f9fd089
CI: remove Valgrind on macOS: it doesn't work
thiagomacieira May 2, 2024
e9963de
CI/Makefile: do allow Qt 6
thiagomacieira May 2, 2024
6550f66
CI: unbreak macOS: need to have CXX set
thiagomacieira May 2, 2024
a38a520
CI: Run the configure step in verbose mode and print the config output
thiagomacieira May 2, 2024
5d167a0
Makefile: disable cJSON support when building without math support
thiagomacieira May 1, 2024
722318d
add required SECURITY.md file for OSSF Scorecard compliance
rdower May 3, 2024
b4e1cc7
CI: add 'permissions' token to the GitHub actions file
thiagomacieira May 13, 2024
f994144
cborparser: Move parser initialisation to common routine.
sjlongland Jun 30, 2021
167eef6
cborparser: Document `cbor_parser_init_reader`.
sjlongland Jun 30, 2021
286d132
cbor: Document the reader interface.
sjlongland Jun 30, 2021
3394f51
cborparser: Pass CborValue to operation routines.
sjlongland Jul 2, 2021
b7287ff
cborparser: Move `ops` outside of `union`
sjlongland Jul 2, 2021
da482b2
cborparser: Move the reader context to CborParser.
sjlongland Jul 2, 2021
72d59f1
cborparser: Update documentation
sjlongland Jul 3, 2021
1ef9a05
reader unit tests: Simplify the example reader
sjlongland Jul 3, 2021
b4b41d3
cborencoder: Document the write callback function.
sjlongland Jul 3, 2021
914bee9
examples: Add buffered writer example.
sjlongland Jul 7, 2021
34e931e
examples: Add buffered reader example
sjlongland Jul 7, 2021
0c17e0f
cbor.h, cborencoder.c: Migrate documentation for encoder functions
sjlongland Sep 7, 2021
a4a6364
cbor.h, cborparser.c: Migrate parser documentation.
sjlongland Sep 7, 2021
427e009
parser unit tests: Do not use `auto`, use reinterpret_cast
sjlongland Sep 7, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: "daily"
target-branch: "main"
140 changes: 140 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
name: CI
permissions: read-all

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]


# When a PR is updated, cancel the jobs from the previous version. Merges
# do not define head_ref, so use run_id to never cancel those jobs.
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

jobs:
TinyCBOR:
timeout-minutes: 45
# Common environment variables
env:
HOMEBREW_NO_INSTALL_CLEANUP: 1
HOMEBREW_NO_ANALYTICS: 1

strategy:
# Always run all jobs in the matrix, even if one fails.
fail-fast: false
matrix:
os: [ ubuntu-latest ]
build_cfg: [
{ "name": "gcc-no-math",
"flags":
'{ "QMAKESPEC": "linux-gcc-no-math",
"EVAL": "export CXX=false && touch math.h float.h",
"CFLAGS": "-ffreestanding -DCBOR_NO_FLOATING_POINT -Os",
"LDFLAGS": "-Wl,--no-undefined",
"LDLIBS": ""
}',
},
{ "name": "gcc-freestanding",
"flags":
'{ "QMAKESPEC": "linux-gcc-freestanding",
"EVAL": "export CXX=false",
"CFLAGS": "-ffreestanding -Os",
"LDFLAGS": "-Wl,--no-undefined -lm"
}',
},
{ "name": "clang",
"flags":
'{ "QMAKESPEC": "linux-clang",
"EVAL": "export CC=clang && export CXX=clang++",
"CFLAGS": "-Oz",
"LDFLAGS": "-Wl,--no-undefined -lm",
"QMAKEFLAGS": "-config release",
"MAKEFLAGS": "-s",
"TESTARGS": "-silent"
}',
},
{ "name": "linux-g++",
"flags":
'{ "QMAKESPEC": "linux-g++",
"EVAL": "export CC=gcc && export CXX=g++",
"CFLAGS": "-Os",
"LDFLAGS": "-Wl,--no-undefined -lm",
"QMAKEFLAGS": "-config release",
"QT_NO_CPU_FEATURE": "rdrnd"
}'
}
]
include:
- os: macos-13
build_cfg: { "name": "clang",
"flags":
'{ "QMAKESPEC": "macx-clang",
"EVAL": "export CC=clang && export CXX=clang++",
"CFLAGS": "-Oz",
"QMAKEFLAGS": "-config debug",
"MAKEFLAGS": "-s",
"TESTARGS": "-silent",
"PATH": "/usr/local/opt/qt/bin:$PATH"
}'
}

# Default job name is too long to be visible in the "Checks" tab.
name: ${{ matrix.os }}/${{ matrix.build_cfg.name }}
# The type of runner that the job will run on
runs-on: ${{ matrix.os }}
steps:
- name: Clone tinycbor
uses: actions/checkout@v4

- name: install Linux software
if: matrix.os == 'ubuntu-latest'
run: |
# Need a recent Valgrind, otherwise debug info cannot be read.
sudo snap install valgrind --classic
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
doxygen \
jq \
libc6-dbg \
libcjson-dev \
libfuntools-dev \
qtbase5-dev
- name: install macOS software
if: runner.os == 'macOS'
run: |
# Doxygen 1.9.7 is broken with ifdefs again, install 1.9.4 which works.
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/41828ee36b96e35b63b2a4c8cfc2df2c3728944a/Formula/doxygen.rb
brew install doxygen.rb
rm doxygen.rb
brew install qt cjson
- name: Execute tests
run: |
set -x
PATH=`echo /opt/qt*/bin`:$PATH
eval $(echo '${{ matrix.build_cfg.flags }}' | jq -r 'to_entries[] | "\(.key)=\"\(.value)\""')
eval "$EVAL"
# FIXME: remove -Wno-error-line below.
export CFLAGS="$CFLAGS -Wno-error=implicit-function-declaration"
make OUT=.config V=1 -s -f Makefile.configure configure && cat .config
make -k \
CFLAGS="$CFLAGS -march=native -g1 -Wall -Wextra -Werror" \
CPPFLAGS="-DNDEBUG -DCBOR_ENCODER_WRITER_CONTROL=-1 -DCBOR_PARSER_READER_CONTROL=-1" \
lib/libtinycbor.a
size lib/libtinycbor.a | tee sizes
make -s clean
make -k \
CFLAGS="$CFLAGS -O0 -g" \
LDFLAGS="$LDFLAGS" ${LDLIBS+LDLIBS="$LDLIBS"}
grep -q freestanding-pass .config || make \
QMAKEFLAGS="$QMAKEFLAGS QMAKE_CXX=$CXX" \
tests/Makefile
grep -q freestanding-pass .config || \
(cd tests && make TESTARGS=-silent check -k \
TESTRUNNER=`which valgrind 2>/dev/null`)
make -s clean
! [ $BUILD_DOCS ] || ./scripts/update-docs.sh
14 changes: 0 additions & 14 deletions Makefile
Original file line number Diff line number Diff line change
@@ -65,20 +65,6 @@ VERSION = $(shell cat $(SRCDIR)VERSION)
SOVERSION = $(shell cut -f1-2 -d. $(SRCDIR)VERSION)
PACKAGE = tinycbor-$(VERSION)

# Check that QMAKE is Qt 5
ifeq ($(origin QMAKE),file)
check_qmake = $(strip $(shell $(1) -query QT_VERSION 2>/dev/null | cut -b1))
ifneq ($(call check_qmake,$(QMAKE)),5)
QMAKE := qmake -qt5
ifneq ($(call check_qmake,$(QMAKE)),5)
QMAKE := qmake-qt5
ifneq ($(call check_qmake,$(QMAKE)),5)
QMAKE := @echo >&2 $(MAKEFILE): Cannot find a Qt 5 qmake; false
endif
endif
endif
endif

-include .config

ifeq ($(wildcard .config),)
7 changes: 4 additions & 3 deletions Makefile.configure
Original file line number Diff line number Diff line change
@@ -15,11 +15,12 @@ PROGRAM-freestanding += int main() {}
CCFLAGS-freestanding = $(CFLAGS)

PROGRAM-cjson = \#include <stdlib.h>\n
PROGRAM-cjson += \#include <math.h>\n
PROGRAM-cjson += \#include <cjson/cJSON.h>\n
PROGRAM-cjson += int main() { return cJSON_False; }
CCFLAGS-cjson = -I$(dir $(MAKEFILE))src
PROGRAM-cjson += int main() { double d = NAN; return cJSON_False; }
CCFLAGS-cjson = -I. -I$(dir $(MAKEFILE))src
PROGRAM-system-cjson = $(PROGRAM-cjson)
CCFLAGS-system-cjson = -lcjson
CCFLAGS-system-cjson = -I. -lcjson

sink:
@echo >&2 Please run from the top-level Makefile.
5 changes: 5 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Security Policy
Intel is committed to rapidly addressing security vulnerabilities affecting our customers and providing clear guidance on the solution, impact, severity and mitigation.

## Reporting a Vulnerability
Please report any security vulnerabilities in this project utilizing the guidelines [here](https://www.intel.com/content/www/us/en/security-center/vulnerability-handling-guidelines.html).
783 changes: 783 additions & 0 deletions examples/bufferedreader.c

Large diffs are not rendered by default.

711 changes: 711 additions & 0 deletions examples/bufferedwriter.c

Large diffs are not rendered by default.

17 changes: 10 additions & 7 deletions src/cbor.h
Original file line number Diff line number Diff line change
@@ -216,7 +216,7 @@ typedef enum CborEncoderAppendType
CborEncoderApendRawData = 2
} CborEncoderAppendType;

typedef CborError (*CborEncoderWriteFunction)(void *, const void *, size_t, CborEncoderAppendType);
typedef CborError (*CborEncoderWriteFunction)(void *token, const void *data, size_t len, CborEncoderAppendType append);

enum CborEncoderFlags
{
@@ -321,20 +321,23 @@ enum CborParserIteratorFlags
};

struct CborValue;


struct CborParserOperations
{
bool (*can_read_bytes)(void *token, size_t len);
void *(*read_bytes)(void *token, void *dst, size_t offset, size_t len);
void (*advance_bytes)(void *token, size_t len);
CborError (*transfer_string)(void *token, const void **userptr, size_t offset, size_t len);
bool (*can_read_bytes)(const struct CborValue *value, size_t len);
void *(*read_bytes)(const struct CborValue *value, void *dst, size_t offset, size_t len);
void (*advance_bytes)(struct CborValue *value, size_t len);
CborError (*transfer_string)(struct CborValue *value, const void **userptr, size_t offset, size_t len);
};

struct CborParser
{
union {
const uint8_t *end;
const struct CborParserOperations *ops;
} source;
void *ctx;
} data;
const struct CborParserOperations *ops;
enum CborParserGlobalFlags flags;
};
typedef struct CborParser CborParser;
17 changes: 17 additions & 0 deletions src/cborencoder.c
Original file line number Diff line number Diff line change
@@ -196,6 +196,23 @@
* Structure used to encode to CBOR.
*/

/**
* \file cbor.h
* \typedef CborEncoderWriteFunction
*
* Writer interface call-back function. When there is data to be written to
* the CBOR document, this routine will be called. The \a token parameter is
* taken from the \a token argument provided to \ref cbor_encoder_init_writer
* and may be used in any way the writer function sees fit.
*
* The \a data parameter contains a pointer to the raw bytes to be copied to
* the output buffer, with \a len specifying how long the payload is, which
* can be as small as a single byte or an entire (byte or text) string.
*
* The \a append parameter informs the writer function whether it is writing
* a string or general CBOR data.
*/

/**
* Initializes a CborEncoder structure \a encoder by pointing it to buffer \a
* buffer of size \a size. The \a flags field is currently unused and must be
18 changes: 9 additions & 9 deletions src/cborinternal_p.h
Original file line number Diff line number Diff line change
@@ -203,27 +203,27 @@ static inline bool can_read_bytes(const CborValue *it, size_t n)
if (CBOR_PARSER_READER_CONTROL >= 0) {
if (it->parser->flags & CborParserFlag_ExternalSource || CBOR_PARSER_READER_CONTROL != 0) {
#ifdef CBOR_PARSER_CAN_READ_BYTES_FUNCTION
return CBOR_PARSER_CAN_READ_BYTES_FUNCTION(it->source.token, n);
return CBOR_PARSER_CAN_READ_BYTES_FUNCTION(it, n);
#else
return it->parser->source.ops->can_read_bytes(it->source.token, n);
return it->parser->ops->can_read_bytes(it, n);
#endif
}
}

/* Convert the pointer subtraction to size_t since end >= ptr
* (this prevents issues with (ptrdiff_t)n becoming negative).
*/
return (size_t)(it->parser->source.end - it->source.ptr) >= n;
return (size_t)(it->parser->data.end - it->source.ptr) >= n;
}

static inline void advance_bytes(CborValue *it, size_t n)
{
if (CBOR_PARSER_READER_CONTROL >= 0) {
if (it->parser->flags & CborParserFlag_ExternalSource || CBOR_PARSER_READER_CONTROL != 0) {
#ifdef CBOR_PARSER_ADVANCE_BYTES_FUNCTION
CBOR_PARSER_ADVANCE_BYTES_FUNCTION(it->source.token, n);
CBOR_PARSER_ADVANCE_BYTES_FUNCTION(it, n);
#else
it->parser->source.ops->advance_bytes(it->source.token, n);
it->parser->ops->advance_bytes(it, n);
#endif
return;
}
@@ -237,9 +237,9 @@ static inline CborError transfer_string(CborValue *it, const void **ptr, size_t
if (CBOR_PARSER_READER_CONTROL >= 0) {
if (it->parser->flags & CborParserFlag_ExternalSource || CBOR_PARSER_READER_CONTROL != 0) {
#ifdef CBOR_PARSER_TRANSFER_STRING_FUNCTION
return CBOR_PARSER_TRANSFER_STRING_FUNCTION(it->source.token, ptr, offset, len);
return CBOR_PARSER_TRANSFER_STRING_FUNCTION(it, ptr, offset, len);
#else
return it->parser->source.ops->transfer_string(it->source.token, ptr, offset, len);
return it->parser->ops->transfer_string(it, ptr, offset, len);
#endif
}
}
@@ -258,9 +258,9 @@ static inline void *read_bytes_unchecked(const CborValue *it, void *dst, size_t
if (CBOR_PARSER_READER_CONTROL >= 0) {
if (it->parser->flags & CborParserFlag_ExternalSource || CBOR_PARSER_READER_CONTROL != 0) {
#ifdef CBOR_PARSER_READ_BYTES_FUNCTION
return CBOR_PARSER_READ_BYTES_FUNCTION(it->source.token, dst, offset, n);
return CBOR_PARSER_READ_BYTES_FUNCTION(it, dst, offset, n);
#else
return it->parser->source.ops->read_bytes(it->source.token, dst, offset, n);
return it->parser->ops->read_bytes(it, dst, offset, n);
#endif
}
}
114 changes: 103 additions & 11 deletions src/cborparser.c
Original file line number Diff line number Diff line change
@@ -141,6 +141,75 @@
* \endif
*/

/**
* \struct CborParserOperations
*
* Defines an interface for abstract document readers. This structure is used
* in conjunction with \ref cbor_parser_init_reader to define how the various
* required operations are to be implemented.
*
*
* \var CborParserOperations::can_read_bytes
*
* Determines whether \a len bytes may be read from the reader. This is
* called before \ref read_bytes and \ref transfer_bytes to ensure it is safe
* to read the requested number of bytes from the reader.
*
* \param value The CBOR value being parsed.
*
* \param len The number of bytes sought.
*
* \retval true \a len bytes may be read from the reader.
* \retval false Insufficient data is available to be read at this time.
*
*
* \var CborParserOperations::read_bytes
*
* Reads \a len bytes from the reader starting at \a offset bytes from
* the current read position and copies them to \a dst. The read pointer
* is *NOT* modified by this operation.
*
* \param value The CBOR value being parsed.
*
* \param dst The buffer the read bytes will be copied to.
*
* \param offset The starting position for the read relative to the
* current read position.
*
* \param len The number of bytes sought.
*
*
* \var CborParserOperations::advance_bytes
*
* Skips past \a len bytes from the reader without reading them. The read
* pointer is advanced in the process.
*
* \param value The CBOR value being parsed.
*
* \param len The number of bytes skipped.
*
*
* \var CborParserOperations::transfer_string
*
* Overwrite the user-supplied pointer \a userptr with the address where the
* data indicated by \a offset is located, then advance the read pointer
* \a len bytes beyond that point.
*
* This routine is used for accessing strings embedded in CBOR documents
* (both text and binary strings).
*
* \param value The CBOR value being parsed.
*
* \param userptr The pointer that will be updated to reference the location
* of the data in the buffer.
*
* \param offset The starting position for the read relative to the
* current read position.
*
* \param len The number of bytes sought.
*/


static uint64_t extract_number_and_advance(CborValue *it)
{
/* This function is only called after we've verified that the number
@@ -332,6 +401,14 @@ uint64_t _cbor_value_decode_int64_internal(const CborValue *value)
return read_uint32(value, 1);
}

static void cbor_parser_init_common(CborParser *parser, CborValue *it)
{
memset(parser, 0, sizeof(*parser));
it->parser = parser;
it->remaining = 1; /* there's one type altogether, usually an array or map */
it->flags = 0;
}

/**
* Initializes the CBOR parser for parsing \a size bytes beginning at \a
* buffer. Parsing will use flags set in \a flags. The iterator to the first
@@ -344,24 +421,39 @@ uint64_t _cbor_value_decode_int64_internal(const CborValue *value)
*/
CborError cbor_parser_init(const uint8_t *buffer, size_t size, uint32_t flags, CborParser *parser, CborValue *it)
{
memset(parser, 0, sizeof(*parser));
parser->source.end = buffer + size;
cbor_parser_init_common(parser, it);
parser->data.end = buffer + size;
parser->flags = (enum CborParserGlobalFlags)flags;
it->parser = parser;
it->source.ptr = buffer;
it->remaining = 1; /* there's one type altogether, usually an array or map */
it->flags = 0;
return preparse_value(it);
}

CborError cbor_parser_init_reader(const struct CborParserOperations *ops, CborParser *parser, CborValue *it, void *token)
/**
* Initializes the CBOR parser for parsing a document that is read by an
* abstract reader interface defined by \a ops. The iterator to the first
* element is returned in \a it.
*
* The \a parser structure needs to remain valid throughout the decoding
* process. It is not thread-safe to share one CborParser among multiple
* threads iterating at the same time, but the object can be copied so multiple
* threads can iterate.
*
* The \a ops structure defines functions that implement the read process from
* the buffer given, see \ref CborParserOperations for further details.
*
* The \a ctx is stored in the \ref CborParser object as `data.ctx` and may be
* used however the reader implementation sees fit. For cursor-specific
* context information, the \ref CborValue `source.token` union member is
* initialised to `NULL` and may be used however the reader implementation
* sees fit.
*/
CborError cbor_parser_init_reader(const struct CborParserOperations *ops, CborParser *parser, CborValue *it, void *ctx)
{
memset(parser, 0, sizeof(*parser));
parser->source.ops = ops;
cbor_parser_init_common(parser, it);
parser->ops = ops;
parser->flags = CborParserFlag_ExternalSource;
it->parser = parser;
it->source.token = token;
it->remaining = 1;
parser->data.ctx = ctx;
it->source.token = NULL;
return preparse_value(it);
}

8 changes: 1 addition & 7 deletions src/cborparser_dup_string.c
Original file line number Diff line number Diff line change
@@ -35,14 +35,8 @@

#include "cbor.h"
#include "compilersupport_p.h"
#include "memory.h"

#if defined(CBOR_CUSTOM_ALLOC_INCLUDE)
# include CBOR_CUSTOM_ALLOC_INCLUDE
#else
# include <stdlib.h>
# define cbor_malloc malloc
# define cbor_free free
#endif

/**
* \fn CborError cbor_value_dup_text_string(const CborValue *value, char **buffer, size_t *buflen, CborValue *next)
13 changes: 7 additions & 6 deletions src/cbortojson.c
Original file line number Diff line number Diff line change
@@ -35,6 +35,7 @@
#include "cborinternal_p.h"
#include "compilersupport_p.h"
#include "cborinternal_p.h"
#include <memory.h>

#include <inttypes.h>
#include <stdio.h>
@@ -179,7 +180,7 @@ static CborError dump_bytestring_base16(char **result, CborValue *it)
return err;

/* a Base16 (hex) output is twice as big as our buffer */
buffer = (uint8_t *)malloc(n * 2 + 1);
buffer = (uint8_t *)cbor_malloc(n * 2 + 1);
if (buffer == NULL)
/* out of memory */
return CborErrorOutOfMemory;
@@ -209,7 +210,7 @@ static CborError generic_dump_base64(char **result, CborValue *it, const char al

/* a Base64 output (untruncated) has 4 bytes for every 3 in the input */
size_t len = (n + 5) / 3 * 4;
buffer = (uint8_t *)malloc(len + 1);
buffer = (uint8_t *)cbor_malloc(len + 1);
if (buffer == NULL)
/* out of memory */
return CborErrorOutOfMemory;
@@ -395,7 +396,7 @@ static CborError tagged_value_to_json(FILE *out, CborValue *it, int flags, Conve
if (err)
return err;
err = fprintf(out, "\"%s%s\"", pre, str) < 0 ? CborErrorIO : CborNoError;
free(str);
cbor_free(str);
status->flags = TypeWasNotNative | TypeWasTagged | CborByteStringType;
return err;
}
@@ -467,7 +468,7 @@ static CborError map_to_json(FILE *out, CborValue *it, int flags, ConversionStat

/* first, print the key */
if (fprintf(out, "\"%s\":", key) < 0) {
free(key);
cbor_free(key);
return CborErrorIO;
}

@@ -489,7 +490,7 @@ static CborError map_to_json(FILE *out, CborValue *it, int flags, ConversionStat
}
}

free(key);
cbor_free(key);
if (err)
return err;
}
@@ -568,7 +569,7 @@ static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType typ
if (err)
return err;
err = (fprintf(out, "\"%s\"", str) < 0) ? CborErrorIO : CborNoError;
free(str);
cbor_free(str);
return err;
}

31 changes: 31 additions & 0 deletions src/memory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/****************************************************************************
**
** Copyright (C) 2016 Intel Corporation
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
** copies of the Software, and to permit persons to whom the Software is
** furnished to do so, subject to the following conditions:
**
** The above copyright notice and this permission notice shall be included in
** all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
** THE SOFTWARE.
**
****************************************************************************/

#if defined(CBOR_CUSTOM_ALLOC_INCLUDE)
# include CBOR_CUSTOM_ALLOC_INCLUDE
#else
# include <stdlib.h>
# define cbor_malloc malloc
# define cbor_free free
#endif
58 changes: 28 additions & 30 deletions tests/parser/tst_parser.cpp
Original file line number Diff line number Diff line change
@@ -759,32 +759,32 @@ void tst_Parser::mapsAndArrays()
"{_ 1: [_ " + expected + "], \"Hello\": {_ " + expected + ": (_ )}}");
}

struct Input {
QByteArray data;
int consumed;
};

static const CborParserOperations byteArrayOps = {
/* can_read_bytes = */ [](void *token, size_t len) {
auto input = static_cast<Input *>(token);
return input->data.size() - input->consumed >= int(len);
/* can_read_bytes = */ [](const CborValue *value, size_t len) {
QByteArray *data = static_cast<QByteArray *>(value->parser->data.ctx);
uintptr_t consumed = uintptr_t(value->source.token);
return uintptr_t(data->size()) - consumed >= uintptr_t(len);
},
/* read_bytes = */ [](void *token, void *dst, size_t offset, size_t len) {
auto input = static_cast<Input *>(token);
return memcpy(dst, input->data.constData() + input->consumed + offset, len);
/* read_bytes = */ [](const CborValue *value, void *dst, size_t offset, size_t len) {
QByteArray *data = static_cast<QByteArray *>(value->parser->data.ctx);
uintptr_t consumed = uintptr_t(value->source.token);
return memcpy(dst, data->constData() + consumed + offset, len);
},
/* advance_bytes = */ [](void *token, size_t len) {
auto input = static_cast<Input *>(token);
input->consumed += int(len);
/* advance_bytes = */ [](CborValue *value, size_t len) {
uintptr_t consumed = uintptr_t(value->source.token);
consumed += uintptr_t(len);
value->source.token = reinterpret_cast<void *>(consumed);
},
/* transfer_string = */ [](void *token, const void **userptr, size_t offset, size_t len) {
/* transfer_string = */ [](CborValue *value, const void **userptr, size_t offset, size_t len) {
// ###
auto input = static_cast<Input *>(token);
if (input->data.size() - input->consumed < int(len + offset))
QByteArray *data = static_cast<QByteArray *>(value->parser->data.ctx);
uintptr_t consumed = uintptr_t(value->source.token);
if (uintptr_t(data->size()) - consumed < uintptr_t(len + offset))
return CborErrorUnexpectedEOF;
input->consumed += int(offset);
*userptr = input->data.constData() + input->consumed;
input->consumed += int(len);
consumed += uintptr_t(offset);
*userptr = data->constData() + consumed;
consumed += uintptr_t(len);
value->source.token = reinterpret_cast<void *>(consumed);
return CborNoError;
}
};
@@ -794,11 +794,9 @@ void tst_Parser::readerApi()
QFETCH(QByteArray, data);
QFETCH(QString, expected);

Input input = { data, 0 };

CborParser parser;
CborValue first;
CborError err = cbor_parser_init_reader(&byteArrayOps, &parser, &first, &input);
CborError err = cbor_parser_init_reader(&byteArrayOps, &parser, &first, &data);
QCOMPARE(err, CborNoError);

QString decoded;
@@ -807,7 +805,7 @@ void tst_Parser::readerApi()
QCOMPARE(decoded, expected);

// check we consumed everything
QCOMPARE(input.consumed, data.size());
QCOMPARE(uintptr_t(first.source.token), uintptr_t(data.size()));
}

void tst_Parser::reparse_data()
@@ -822,23 +820,23 @@ void tst_Parser::reparse()
QFETCH(QByteArray, data);
QFETCH(QString, expected);

Input input = { QByteArray(), 0 };
QByteArray buffer;
CborParser parser;
CborValue first;
CborError err = cbor_parser_init_reader(&byteArrayOps, &parser, &first, &input);
CborError err = cbor_parser_init_reader(&byteArrayOps, &parser, &first, &buffer);
QCOMPARE(err, CborErrorUnexpectedEOF);

for (int i = 0; i < data.size(); ++i) {
input.data = data.left(i);
buffer = data.left(i);
err = cbor_value_reparse(&first);
if (err != CborErrorUnexpectedEOF)
qDebug() << "At" << i;
QCOMPARE(err, CborErrorUnexpectedEOF);
QCOMPARE(input.consumed, 0);
QCOMPARE(uintptr_t(first.source.token), 0U);
}

// now it should work
input.data = data;
buffer = data;
err = cbor_value_reparse(&first);
QCOMPARE(err, CborNoError);

@@ -848,7 +846,7 @@ void tst_Parser::reparse()
QCOMPARE(decoded, expected);

// check we consumed everything
QCOMPARE(input.consumed, data.size());
QCOMPARE(uintptr_t(first.source.token), uintptr_t(data.size()));
}

void tst_Parser::chunkedString_data()
2 changes: 1 addition & 1 deletion tests/tests.pro
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
TEMPLATE = subdirs
SUBDIRS = parser encoder c90 cpp tojson
SUBDIRS = parser encoder cpp tojson
msvc: SUBDIRS -= tojson