1*b5b9517bSEd Maste /* 2*b5b9517bSEd Maste * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com> 3*b5b9517bSEd Maste * 4*b5b9517bSEd Maste * libcbor is free software; you can redistribute it and/or modify 5*b5b9517bSEd Maste * it under the terms of the MIT license. See LICENSE for details. 6*b5b9517bSEd Maste */ 7*b5b9517bSEd Maste 8*b5b9517bSEd Maste #include <stdbool.h> 9*b5b9517bSEd Maste #include <stdio.h> 10*b5b9517bSEd Maste #include <string.h> 11*b5b9517bSEd Maste #include "cbor.h" 12*b5b9517bSEd Maste 13*b5b9517bSEd Maste // Part 1: Begin 14*b5b9517bSEd Maste void item_examples() { 15*b5b9517bSEd Maste // A cbor_item_t can contain any CBOR data type 16*b5b9517bSEd Maste cbor_item_t* float_item = cbor_build_float4(3.14f); 17*b5b9517bSEd Maste cbor_item_t* string_item = cbor_build_string("Hello World!"); 18*b5b9517bSEd Maste cbor_item_t* array_item = cbor_new_indefinite_array(); 19*b5b9517bSEd Maste 20*b5b9517bSEd Maste // They can be inspected 21*b5b9517bSEd Maste assert(cbor_is_float(float_item)); 22*b5b9517bSEd Maste assert(cbor_typeof(string_item) == CBOR_TYPE_STRING); 23*b5b9517bSEd Maste assert(cbor_array_is_indefinite(array_item)); 24*b5b9517bSEd Maste assert(cbor_array_size(array_item) == 0); 25*b5b9517bSEd Maste 26*b5b9517bSEd Maste // The data can be accessed 27*b5b9517bSEd Maste assert(cbor_float_get_float4(float_item) == 3.14f); 28*b5b9517bSEd Maste assert(memcmp(cbor_string_handle(string_item), "Hello World!", 29*b5b9517bSEd Maste cbor_string_length(string_item)) == 0); 30*b5b9517bSEd Maste 31*b5b9517bSEd Maste // And they can be modified 32*b5b9517bSEd Maste assert(cbor_array_push(array_item, float_item)); 33*b5b9517bSEd Maste assert(cbor_array_push(array_item, string_item)); 34*b5b9517bSEd Maste assert(cbor_array_size(array_item) == 2); 35*b5b9517bSEd Maste 36*b5b9517bSEd Maste // At the end of their lifetime, items must be freed 37*b5b9517bSEd Maste cbor_decref(&float_item); 38*b5b9517bSEd Maste cbor_decref(&string_item); 39*b5b9517bSEd Maste cbor_decref(&array_item); 40*b5b9517bSEd Maste } 41*b5b9517bSEd Maste // Part 1: End 42*b5b9517bSEd Maste 43*b5b9517bSEd Maste // Part 2: Begin 44*b5b9517bSEd Maste void encode_decode() { 45*b5b9517bSEd Maste cbor_item_t* item = cbor_build_uint8(42); 46*b5b9517bSEd Maste 47*b5b9517bSEd Maste // Serialize the item to a buffer (it will be allocated by libcbor) 48*b5b9517bSEd Maste unsigned char* buffer; 49*b5b9517bSEd Maste size_t buffer_size; 50*b5b9517bSEd Maste cbor_serialize_alloc(item, &buffer, &buffer_size); 51*b5b9517bSEd Maste assert(buffer_size == 2); 52*b5b9517bSEd Maste assert(buffer[0] == 0x18); // Encoding byte for uint8 53*b5b9517bSEd Maste assert(buffer[1] == 42); // The value itself 54*b5b9517bSEd Maste 55*b5b9517bSEd Maste // And deserialize bytes back to an item 56*b5b9517bSEd Maste struct cbor_load_result result; 57*b5b9517bSEd Maste cbor_item_t* decoded_item = cbor_load(buffer, buffer_size, &result); 58*b5b9517bSEd Maste assert(result.error.code == CBOR_ERR_NONE); 59*b5b9517bSEd Maste assert(cbor_isa_uint(decoded_item)); 60*b5b9517bSEd Maste assert(cbor_get_uint8(decoded_item) == 42); 61*b5b9517bSEd Maste 62*b5b9517bSEd Maste // Free the allocated buffer and items 63*b5b9517bSEd Maste free(buffer); 64*b5b9517bSEd Maste cbor_decref(&decoded_item); 65*b5b9517bSEd Maste cbor_decref(&item); 66*b5b9517bSEd Maste } 67*b5b9517bSEd Maste // Part 2: End 68*b5b9517bSEd Maste 69*b5b9517bSEd Maste // Part 3: Begin 70*b5b9517bSEd Maste void reference_counting() { 71*b5b9517bSEd Maste // cbor_item_t is a reference counted pointer under the hood 72*b5b9517bSEd Maste cbor_item_t* item = cbor_build_uint8(42); 73*b5b9517bSEd Maste 74*b5b9517bSEd Maste // Reference count starts at 1 75*b5b9517bSEd Maste assert(cbor_refcount(item) == 1); 76*b5b9517bSEd Maste 77*b5b9517bSEd Maste // Most operations have reference semantics 78*b5b9517bSEd Maste cbor_item_t* array_item = cbor_new_definite_array(1); 79*b5b9517bSEd Maste assert(cbor_array_push(array_item, item)); 80*b5b9517bSEd Maste assert(cbor_refcount(item) == 2); // item and array_item reference it 81*b5b9517bSEd Maste cbor_item_t* first_array_element = cbor_array_get(array_item, 0); 82*b5b9517bSEd Maste assert(first_array_element == item); // same item under the hood 83*b5b9517bSEd Maste assert(cbor_refcount(item) == 84*b5b9517bSEd Maste 3); // and now first_array_element also points to it 85*b5b9517bSEd Maste 86*b5b9517bSEd Maste // To release the reference, use cbor_decref 87*b5b9517bSEd Maste cbor_decref(&first_array_element); 88*b5b9517bSEd Maste 89*b5b9517bSEd Maste // When reference count reaches 0, the item is freed 90*b5b9517bSEd Maste assert(cbor_refcount(array_item) == 1); 91*b5b9517bSEd Maste cbor_decref(&array_item); 92*b5b9517bSEd Maste assert(array_item == NULL); 93*b5b9517bSEd Maste assert(cbor_refcount(item) == 1); 94*b5b9517bSEd Maste 95*b5b9517bSEd Maste // Be careful, loops leak memory! 96*b5b9517bSEd Maste 97*b5b9517bSEd Maste // Deep copy copies the whole item tree 98*b5b9517bSEd Maste cbor_item_t* item_copy = cbor_copy(item); 99*b5b9517bSEd Maste assert(cbor_refcount(item) == 1); 100*b5b9517bSEd Maste assert(cbor_refcount(item_copy) == 1); 101*b5b9517bSEd Maste assert(item_copy != item); 102*b5b9517bSEd Maste cbor_decref(&item); 103*b5b9517bSEd Maste cbor_decref(&item_copy); 104*b5b9517bSEd Maste } 105*b5b9517bSEd Maste // Part 3: End 106*b5b9517bSEd Maste 107*b5b9517bSEd Maste // Part 4: Begin 108*b5b9517bSEd Maste void moving_values() { 109*b5b9517bSEd Maste { 110*b5b9517bSEd Maste // Move the "42" into an array. 111*b5b9517bSEd Maste cbor_item_t* array_item = cbor_new_definite_array(1); 112*b5b9517bSEd Maste // The line below leaks memory! 113*b5b9517bSEd Maste assert(cbor_array_push(array_item, cbor_build_uint8(42))); 114*b5b9517bSEd Maste cbor_item_t* first_array_element = cbor_array_get(array_item, 0); 115*b5b9517bSEd Maste assert(cbor_refcount(first_array_element) == 3); // Should be 2! 116*b5b9517bSEd Maste cbor_decref(&first_array_element); 117*b5b9517bSEd Maste cbor_decref(&array_item); 118*b5b9517bSEd Maste assert(cbor_refcount(first_array_element) == 1); // Shouldn't exist! 119*b5b9517bSEd Maste // Clean up 120*b5b9517bSEd Maste cbor_decref(&first_array_element); 121*b5b9517bSEd Maste } 122*b5b9517bSEd Maste 123*b5b9517bSEd Maste { 124*b5b9517bSEd Maste // A correct way to move values is to decref them in the caller scope. 125*b5b9517bSEd Maste cbor_item_t* array_item = cbor_new_definite_array(1); 126*b5b9517bSEd Maste cbor_item_t* item = cbor_build_uint8(42); 127*b5b9517bSEd Maste assert(cbor_array_push(array_item, item)); 128*b5b9517bSEd Maste assert(cbor_refcount(item) == 2); 129*b5b9517bSEd Maste // "Give up" the item 130*b5b9517bSEd Maste cbor_decref(&item); 131*b5b9517bSEd Maste cbor_decref(&array_item); 132*b5b9517bSEd Maste // item is a dangling pointer at this point 133*b5b9517bSEd Maste } 134*b5b9517bSEd Maste 135*b5b9517bSEd Maste { 136*b5b9517bSEd Maste // cbor_move avoids the need to decref and the dangling pointer 137*b5b9517bSEd Maste cbor_item_t* array_item = cbor_new_definite_array(1); 138*b5b9517bSEd Maste assert(cbor_array_push(array_item, cbor_move(cbor_build_uint8(42)))); 139*b5b9517bSEd Maste cbor_item_t* first_array_element = cbor_array_get(array_item, 0); 140*b5b9517bSEd Maste assert(cbor_refcount(first_array_element) == 2); 141*b5b9517bSEd Maste cbor_decref(&first_array_element); 142*b5b9517bSEd Maste cbor_decref(&array_item); 143*b5b9517bSEd Maste } 144*b5b9517bSEd Maste } 145*b5b9517bSEd Maste // Part 4: End 146*b5b9517bSEd Maste 147*b5b9517bSEd Maste // Part 5: Begin 148*b5b9517bSEd Maste // Refcount can be managed in conjunction with ownership 149*b5b9517bSEd Maste static cbor_item_t* global_item = NULL; 150*b5b9517bSEd Maste 151*b5b9517bSEd Maste // This function takes shared ownership of the item 152*b5b9517bSEd Maste void borrow_item(cbor_item_t* item) { 153*b5b9517bSEd Maste global_item = item; 154*b5b9517bSEd Maste // Mark the extra reference 155*b5b9517bSEd Maste cbor_incref(item); 156*b5b9517bSEd Maste } 157*b5b9517bSEd Maste 158*b5b9517bSEd Maste void return_item() { 159*b5b9517bSEd Maste cbor_decref(&global_item); 160*b5b9517bSEd Maste global_item = NULL; 161*b5b9517bSEd Maste } 162*b5b9517bSEd Maste 163*b5b9517bSEd Maste void reference_ownership() { 164*b5b9517bSEd Maste cbor_item_t* item = cbor_build_uint8(42); 165*b5b9517bSEd Maste 166*b5b9517bSEd Maste // Lend the item 167*b5b9517bSEd Maste borrow_item(item); 168*b5b9517bSEd Maste assert(cbor_refcount(item) == 2); 169*b5b9517bSEd Maste cbor_decref(&item); 170*b5b9517bSEd Maste 171*b5b9517bSEd Maste // Release the shared ownership. return_item will deallocate the item. 172*b5b9517bSEd Maste return_item(); 173*b5b9517bSEd Maste } 174*b5b9517bSEd Maste // Part 5: End 175*b5b9517bSEd Maste 176*b5b9517bSEd Maste int main(void) { 177*b5b9517bSEd Maste item_examples(); 178*b5b9517bSEd Maste encode_decode(); 179*b5b9517bSEd Maste reference_counting(); 180*b5b9517bSEd Maste moving_values(); 181*b5b9517bSEd Maste reference_ownership(); 182*b5b9517bSEd Maste return 0; 183*b5b9517bSEd Maste } 184