| #ifndef _MSC_VER |
| #define _CRT_SECURE_NO_WARNINGS |
| #include <unistd.h> |
| #endif |
| #include <fcntl.h> |
| #include <io.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| |
| #include "cn-cbor/cn-cbor.h" |
| |
| #ifdef USE_CBOR_CONTEXT |
| #define CBOR_CONTEXT_PARAM , NULL |
| #else |
| #define CBOR_CONTEXT_PARAM |
| #endif |
| |
| #define ERROR(msg, p) fprintf(stderr, "ERROR: " msg " %s\n", (p)); |
| |
| static unsigned char *load_file(const char *filepath, unsigned char **end) |
| { |
| struct stat st; |
| if (stat(filepath, &st) == -1) { |
| ERROR("can't find file", filepath); |
| return 0; |
| } |
| int fd = open(filepath, _O_RDONLY | _O_BINARY); |
| if (fd == -1) { |
| ERROR("can't open file", filepath); |
| return 0; |
| } |
| unsigned char *text = malloc(st.st_size + 1); // this is not going to be freed |
| if (st.st_size != read(fd, text, st.st_size)) { |
| ERROR("can't read file", filepath); |
| close(fd); |
| return 0; |
| } |
| close(fd); |
| text[st.st_size] = '\0'; |
| *end = text + st.st_size; |
| return text; |
| } |
| |
| static void dump(const cn_cbor *cb, char *out, char **end, int indent) |
| { |
| if (!cb) |
| goto done; |
| int i; |
| cn_cbor *cp; |
| char finchar = ')'; /* most likely */ |
| |
| #define CPY(s, l) \ |
| memcpy(out, s, l); \ |
| out += l; |
| #define OUT(s) CPY(s, sizeof(s) - 1) |
| #define PRF(f, a) out += sprintf(out, f, a) |
| |
| for (i = 0; i < indent; i++) |
| *out++ = ' '; |
| switch (cb->type) { |
| case CN_CBOR_TEXT_CHUNKED: |
| OUT("(_\n"); |
| goto sequence; |
| case CN_CBOR_BYTES_CHUNKED: |
| OUT("(_\n\n"); |
| goto sequence; |
| case CN_CBOR_TAG: |
| PRF("%ld(\n", cb->v.sint); |
| goto sequence; |
| case CN_CBOR_ARRAY: |
| finchar = ']'; |
| OUT("[\n"); |
| goto sequence; |
| case CN_CBOR_MAP: |
| finchar = '}'; |
| OUT("{\n"); |
| goto sequence; |
| sequence: |
| for (cp = cb->first_child; cp; cp = cp->next) { |
| dump(cp, out, &out, indent + 2); |
| } |
| for (i = 0; i < indent; i++) |
| *out++ = ' '; |
| *out++ = finchar; |
| break; |
| case CN_CBOR_BYTES: |
| OUT("h'"); |
| for (i = 0; i < cb->length; i++) |
| PRF("%02x", cb->v.str[i] & 0xff); |
| *out++ = '\''; |
| break; |
| case CN_CBOR_TEXT: |
| *out++ = '"'; |
| CPY(cb->v.str, cb->length); /* should escape stuff */ |
| *out++ = '"'; |
| break; |
| case CN_CBOR_NULL: |
| OUT("null"); |
| break; |
| case CN_CBOR_TRUE: |
| OUT("true"); |
| break; |
| case CN_CBOR_FALSE: |
| OUT("false"); |
| break; |
| case CN_CBOR_UNDEF: |
| OUT("simple(23)"); |
| break; |
| case CN_CBOR_INT: |
| PRF("%ld", cb->v.sint); |
| break; |
| case CN_CBOR_UINT: |
| PRF("%lu", cb->v.uint); |
| break; |
| case CN_CBOR_DOUBLE: |
| PRF("%e", cb->v.dbl); |
| break; |
| case CN_CBOR_SIMPLE: |
| PRF("simple(%ld)", cb->v.sint); |
| break; |
| default: |
| PRF("???%d???", cb->type); |
| break; |
| } |
| *out++ = '\n'; |
| done: |
| *end = out; |
| } |
| |
| const char *err_name[] = { |
| "CN_CBOR_NO_ERROR", |
| "CN_CBOR_ERR_OUT_OF_DATA", |
| "CN_CBOR_ERR_NOT_ALL_DATA_CONSUMED", |
| "CN_CBOR_ERR_ODD_SIZE_INDEF_MAP", |
| "CN_CBOR_ERR_BREAK_OUTSIDE_INDEF", |
| "CN_CBOR_ERR_MT_UNDEF_FOR_INDEF", |
| "CN_CBOR_ERR_RESERVED_AI", |
| "CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING", |
| "CN_CBOR_ERR_OUT_OF_MEMORY", |
| "CN_CBOR_ERR_FLOAT_NOT_SUPPORTED", |
| }; |
| |
| static void cn_cbor_decode_test(const unsigned char *buf, int len) |
| { |
| struct cn_cbor_errback back; |
| const cn_cbor *ret = cn_cbor_decode(buf, len CBOR_CONTEXT_PARAM, &back); |
| if (ret) |
| printf("oops 1"); |
| printf("%s at %d\n", err_name[back.err], back.pos); |
| } |
| |
| int main(void) |
| { |
| char buf[100000]; |
| unsigned char *end; |
| char *bufend; |
| unsigned char *s = load_file("cases.cbor", &end); |
| printf("%zd\n", end - s); |
| cn_cbor *cb = cn_cbor_decode(s, end - s CBOR_CONTEXT_PARAM, 0); |
| if (cb) { |
| dump(cb, buf, &bufend, 0); |
| *bufend = 0; |
| printf("%s\n", buf); |
| cn_cbor_free(cb CBOR_CONTEXT_PARAM); |
| cb = 0; /* for leaks testing */ |
| } |
| cn_cbor_decode_test((const unsigned char *)"\xff", 1); /* break outside indef */ |
| cn_cbor_decode_test((const unsigned char *)"\x1f", 1); /* mt undef for indef */ |
| cn_cbor_decode_test((const unsigned char *)"\x00\x00", 2); /* not all data consumed */ |
| cn_cbor_decode_test((const unsigned char *)"\x81", 1); /* out of data */ |
| cn_cbor_decode_test((const unsigned char *)"\x1c", 1); /* reserved ai */ |
| cn_cbor_decode_test((const unsigned char *)"\xbf\x00\xff", 3); /* odd size indef map */ |
| cn_cbor_decode_test((const unsigned char *)"\x7f\x40\xff", 3); /* wrong nesting in indef string */ |
| // system("leaks test"); |
| } |
| |
| /* cn-cbor.c:112: CN_CBOR_FAIL("out of memory"); */ |