File Coverage

src/pdfmake_buf.c
Criterion Covered Total %
statement 67 81 82.7
branch 24 48 50.0
condition n/a
subroutine n/a
pod n/a
total 91 129 70.5


line stmt bran cond sub pod time code
1             /*
2             * libpdfmake — growable byte buffer implementation.
3             */
4              
5             #include "pdfmake_buf.h"
6             #include
7             #include
8             #include
9             #include
10              
11             /*----------------------------------------------------------------------------
12             * Internal helpers
13             *--------------------------------------------------------------------------*/
14              
15             /* Grow buffer to at least `needed` total capacity. */
16 4800232           static pdfmake_err_t buf_grow(pdfmake_buf_t *buf, size_t needed) {
17             size_t new_cap;
18             uint8_t *new_data;
19              
20 4800232 100         if (needed <= buf->cap) return PDFMAKE_OK;
21              
22             /* Geometric growth: double, but at least `needed`. */
23 675           new_cap = buf->cap * 2;
24 675 100         if (new_cap < needed) new_cap = needed;
25 675 50         if (new_cap < PDFMAKE_BUF_INIT_CAP) new_cap = PDFMAKE_BUF_INIT_CAP;
26              
27 675           new_data = realloc(buf->data, new_cap);
28 675 50         if (!new_data) return PDFMAKE_ENOMEM;
29              
30 675           buf->data = new_data;
31 675           buf->cap = new_cap;
32 675           return PDFMAKE_OK;
33             }
34              
35             /*----------------------------------------------------------------------------
36             * Lifecycle
37             *--------------------------------------------------------------------------*/
38              
39 3297           pdfmake_err_t pdfmake_buf_init(pdfmake_buf_t *buf) {
40 3297           return pdfmake_buf_init_cap(buf, PDFMAKE_BUF_INIT_CAP);
41             }
42              
43 3297           pdfmake_err_t pdfmake_buf_init_cap(pdfmake_buf_t *buf, size_t cap) {
44 3297 50         if (!buf) return PDFMAKE_EINVAL;
45              
46 3297           buf->data = NULL;
47 3297           buf->len = 0;
48 3297           buf->cap = 0;
49              
50 3297 50         if (cap > 0) {
51 3297           buf->data = malloc(cap);
52 3297 50         if (!buf->data) return PDFMAKE_ENOMEM;
53 3297           buf->cap = cap;
54             }
55              
56 3297           return PDFMAKE_OK;
57             }
58              
59 3282           void pdfmake_buf_free(pdfmake_buf_t *buf) {
60 3282 50         if (!buf) return;
61 3282           free(buf->data);
62 3282           buf->data = NULL;
63 3282           buf->len = 0;
64 3282           buf->cap = 0;
65             }
66              
67 53           void pdfmake_buf_clear(pdfmake_buf_t *buf) {
68 53 50         if (buf) buf->len = 0;
69 53           }
70              
71             /*----------------------------------------------------------------------------
72             * Writing
73             *--------------------------------------------------------------------------*/
74              
75 0           pdfmake_err_t pdfmake_buf_reserve(pdfmake_buf_t *buf, size_t extra) {
76 0 0         if (!buf) return PDFMAKE_EINVAL;
77 0           return buf_grow(buf, buf->len + extra);
78             }
79              
80 4800235           pdfmake_err_t pdfmake_buf_append(pdfmake_buf_t *buf, const void *data, size_t len) {
81             pdfmake_err_t err;
82              
83 4800235 50         if (!buf) return PDFMAKE_EINVAL;
84 4800235 100         if (len == 0) return PDFMAKE_OK;
85 4800231 50         if (!data) return PDFMAKE_EINVAL;
86              
87 4800231           err = buf_grow(buf, buf->len + len);
88 4800231 50         if (err != PDFMAKE_OK) return err;
89              
90 4800231           memcpy(buf->data + buf->len, data, len);
91 4800231           buf->len += len;
92 4800231           return PDFMAKE_OK;
93             }
94              
95 17792           pdfmake_err_t pdfmake_buf_append_cstr(pdfmake_buf_t *buf, const char *s) {
96 17792 50         if (!s) return PDFMAKE_OK;
97 17792           return pdfmake_buf_append(buf, s, strlen(s));
98             }
99              
100 4736673           pdfmake_err_t pdfmake_buf_append_byte(pdfmake_buf_t *buf, uint8_t byte) {
101 4736673           return pdfmake_buf_append(buf, &byte, 1);
102             }
103              
104 8912           pdfmake_err_t pdfmake_buf_vappendf(pdfmake_buf_t *buf, const char *fmt, va_list ap) {
105             va_list ap_copy;
106             size_t avail;
107             int needed;
108             pdfmake_err_t err;
109              
110 8912 50         if (!buf || !fmt) return PDFMAKE_EINVAL;
    50          
111              
112             /* First, try to format directly into remaining space. */
113 8912           PDFMAKE_VA_COPY(ap_copy, ap);
114              
115 8912           avail = buf->cap - buf->len;
116 8912           needed = vsnprintf((char *)(buf->data + buf->len), avail, fmt, ap_copy);
117 8912           va_end(ap_copy);
118              
119 8912 50         if (needed < 0) return PDFMAKE_EINVAL; /* Encoding error. */
120              
121 8912 100         if ((size_t)needed < avail) {
122             /* Fit in existing space. */
123 8911           buf->len += (size_t)needed;
124 8911           return PDFMAKE_OK;
125             }
126              
127             /* Need more space. Grow and retry. */
128 1           err = buf_grow(buf, buf->len + (size_t)needed + 1);
129 1 50         if (err != PDFMAKE_OK) return err;
130              
131 1           avail = buf->cap - buf->len;
132 1           needed = vsnprintf((char *)(buf->data + buf->len), avail, fmt, ap);
133 1 50         if (needed < 0) return PDFMAKE_EINVAL;
134              
135 1           buf->len += (size_t)needed;
136 1           return PDFMAKE_OK;
137             }
138              
139 8912           pdfmake_err_t pdfmake_buf_appendf(pdfmake_buf_t *buf, const char *fmt, ...) {
140             va_list ap;
141             pdfmake_err_t err;
142              
143 8912           va_start(ap, fmt);
144 8912           err = pdfmake_buf_vappendf(buf, fmt, ap);
145 8912           va_end(ap);
146 8912           return err;
147             }
148              
149             /*----------------------------------------------------------------------------
150             * Output
151             *--------------------------------------------------------------------------*/
152              
153 0           uint8_t *pdfmake_buf_take(pdfmake_buf_t *buf, size_t *len_out) {
154             uint8_t *data;
155             size_t len;
156              
157 0 0         if (!buf) {
158 0 0         if (len_out) *len_out = 0;
159 0           return NULL;
160             }
161              
162 0           data = buf->data;
163 0           len = buf->len;
164              
165 0           buf->data = NULL;
166 0           buf->len = 0;
167 0           buf->cap = 0;
168              
169 0 0         if (len_out) *len_out = len;
170 0           return data;
171             }