1    | /*
2    |  * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
3    |  *
4    |  * Permission to use, copy, modify, and/or distribute this software for any
5    |  * purpose with or without fee is hereby granted, provided that the above
6    |  * copyright notice and this permission notice appear in all copies.
7    |  *
8    |  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9    |  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10   |  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11   |  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12   |  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13   |  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14   |  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15   |  */
16   | 
17   | #include "yajl_buf.h"
18   | 
19   | #include <assert.h>
20   | #include <stdlib.h>
21   | #include <string.h>
22   | 
23   | #define YAJL_BUF_INIT_SIZE 2048
24   | 
25   | struct yajl_buf_t {
26   |     size_t len;
27   |     size_t used;
28   |     unsigned char * data;
29   |     yajl_alloc_funcs * alloc;
30   | };
31   | 
32   | static
33   | void yajl_buf_ensure_available(yajl_buf buf, size_t want)
34   | {
35   |     size_t need;
36   | 
37   |     assert(buf != NULL);
38   | 
39   |     /* first call */
40   |     if (buf->data == NULL) {
41   |         assert(buf->used == 0);
42   |         buf->len = YAJL_BUF_INIT_SIZE;
43   |         buf->data = (unsigned char *) YA_MALLOC(buf->alloc, buf->len);
44   | #if 0
45   |         memset((void *) buf->data, 0, buf->len);
46   | #else  /* it's really just a string, albiet UTF-8.... */
47   |         buf->data[0] = 0;
48   | #endif
49   |     }
50   | 
51   |     need = buf->len;
52   | 
53   |     while (want >= (need - buf->used)) {
54   |         need <<= 1;                     /* XXX maybe this is a bit too aggressive? */
55   |     }
56   |     if (need != buf->len) {
57   |         buf->data = (unsigned char *) YA_REALLOC(buf->alloc, buf->data, need);
58   |         buf->len = need;
59   |     }
60   | }
61   | 
62   | /*+ allocate a new buffer +*/
63   | yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc)
64   | {
65   |     yajl_buf b = YA_MALLOC(alloc, sizeof(struct yajl_buf_t));
66   |     memset((void *) b, 0, sizeof(struct yajl_buf_t));
67   |     b->alloc = alloc;
68   |     return b;
69   | }
70   | 
71   | /*+ free the buffer +*/
72   | void yajl_buf_free(yajl_buf buf)
73   | {
74   |     assert(buf != NULL);
75   |     if (buf->data) {
76   |         YA_FREE(buf->alloc, buf->data);
77   |     }
78   |     YA_FREE(buf->alloc, buf);
79   | }
80   | 
81   | /*+ append a number of bytes to the buffer +*/
82   | void yajl_buf_append(yajl_buf buf, const void * data, size_t len)
83   | {
84   |     yajl_buf_ensure_available(buf, len);
85   |     if (len > 0) {
86   |         assert(data != NULL);
87   |         memcpy(buf->data + buf->used, data, len);
88   |         buf->used += len;
89   |         buf->data[buf->used] = 0;
90   |     }
91   | }
92   | 
93   | /*+ empty the buffer +*/
94   | void yajl_buf_clear(yajl_buf buf)
95   | {
96   |     buf->used = 0;
97   |     if (buf->data) {
98   |         buf->data[buf->used] = 0;
99   |     }
100  | }
101  | 
102  | /*+ get a pointer to the beginning of the buffer +*/
103  | const unsigned char * yajl_buf_data(yajl_buf buf)
104  | {
105  |     return buf->data;
106  | }
107  | 
108  | /*+ get the length of the buffer +*/
109  | size_t yajl_buf_len(yajl_buf buf)
110  | {
111  |     return buf->used;
112  | }
113  | 
114  | /*+ truncate the buffer +*/
115  | void
116  | yajl_buf_truncate(yajl_buf buf, size_t len)
117  | {
118  |     assert(len <= buf->used);
119  |     buf->used = len;
120  | }