File Coverage

inc/matrixssl-3-9-3-open/core/psbuf.c
Criterion Covered Total %
statement 0 494 0.0
branch 0 230 0.0
condition n/a
subroutine n/a
pod n/a
total 0 724 0.0


line stmt bran cond sub pod time code
1             /**
2             * @file psbuf.c
3             * @version 950bba4 (HEAD -> master)
4             *
5             * Implementation of API for handling buffers containing binary data.
6             */
7             /*
8             * Copyright (c) 2017 INSIDE Secure Corporation
9             * All Rights Reserved
10             *
11             * The latest version of this code is available at http://www.matrixssl.org
12             *
13             * This software is open source; you can redistribute it and/or modify
14             * it under the terms of the GNU General Public License as published by
15             * the Free Software Foundation; either version 2 of the License, or
16             * (at your option) any later version.
17             *
18             * This General Public License does NOT permit incorporating this software
19             * into proprietary programs. If you are unable to comply with the GPL, a
20             * commercial license for this software may be purchased from INSIDE at
21             * http://www.insidesecure.com/
22             *
23             * This program is distributed in WITHOUT ANY WARRANTY; without even the
24             * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
25             * See the GNU General Public License for more details.
26             *
27             * You should have received a copy of the GNU General Public License
28             * along with this program; if not, write to the Free Software
29             * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30             * http://www.gnu.org/copyleft/gpl.html
31             */
32             /******************************************************************************/
33              
34             #include
35             #include
36             #include
37             #include
38             #include
39             #include "coreApi.h"
40             #include "osdep.h"
41              
42             /* Omit debug printouts. */
43             #define debugf(...) do { } while (0)
44              
45             /* This address is indicator for static allocations pool, and does not
46             need to point to any valid pool. The pool cannot be NULL, because
47             NULL is reserved for "default memory pool". */
48             psPool_t * const psStaticAllocationsPool =
49             (psPool_t *) &psStaticAllocationsPool;
50              
51 0           void *psBufInit(psPool_t *pool, psBuf_t *buf, size_t capacity)
52             {
53 0           buf->buf = psMalloc(pool, capacity);
54 0           buf->start = buf->buf;
55 0           buf->end = buf->start;
56 0 0         buf->size = buf->buf ? capacity : 0;
57 0           return buf->buf;
58             }
59              
60 0           void psBufUninit(psPool_t *pool, psBuf_t *buf)
61             {
62 0 0         if (pool != psStaticAllocationsPool)
63             {
64 0           psFree(buf->buf, pool);
65             }
66 0           buf->buf = NULL;
67 0           buf->start = NULL;
68 0           buf->end = NULL;
69 0           buf->size = 0;
70 0           }
71              
72 0           void *psBufDetach(psPool_t *pool, psBuf_t *buf, size_t *len_p)
73             {
74             void *new;
75 0           size_t len = buf->end - buf->start;
76              
77 0 0         new = psMalloc(pool, len ? len : 1);
78 0 0         if (new)
79             {
80 0           memcpy(new, buf->start, len);
81 0           *len_p = len;
82             }
83 0           psBufUninit(pool, buf);
84 0           return new;
85             }
86              
87 0           int32_t psBufFromData(psPool_t *pool, psBuf_t *buf, const void *data, size_t len)
88             {
89 0           void *new = NULL;
90              
91 0           buf->buf = buf->start = buf->end = NULL;
92 0           buf->size = 0;
93              
94 0 0         if (data != NULL)
95             {
96 0 0         new = psMalloc(pool, len ? len : 1);
97 0 0         if (new != NULL)
98             {
99 0           buf->buf = buf->start = buf->end = new;
100 0           buf->size = len;
101 0           buf->end += len;
102 0           memcpy(new, data, len);
103             }
104             }
105 0 0         return new ? PS_SUCCESS : PS_MEM_FAIL;
106             }
107              
108 0           int32_t psBufFromStaticData(psBuf_t *buf, const void *data, size_t len)
109             {
110 0 0         if (!data)
111             {
112 0           len = 0;
113             }
114 0           buf->buf = buf->start = buf->end = (void *) data;
115 0           buf->size = len;
116 0           buf->end += len;
117 0 0         return data ? PS_SUCCESS : PS_ARG_FAIL;
118             }
119              
120 0           int32_t psBufEmptyFromPointerSize(psBuf_t *buf, void *data, size_t len)
121             {
122 0 0         if (!data)
123             {
124 0           len = 0;
125             }
126 0           buf->buf = buf->start = buf->end = (void *) data;
127 0           buf->size = len;
128 0 0         return data ? PS_SUCCESS : PS_ARG_FAIL;
129             }
130              
131 0           char *psBufAsHex(psPool_t *pool, const psBuf_t *buf)
132             {
133             char *hexstr;
134 0           size_t len = buf->end - buf->start;
135              
136 0           hexstr = psMalloc(pool, len * 2 + 1);
137 0 0         if (hexstr)
138             {
139             size_t i;
140 0           hexstr[0] = 0;
141 0 0         for (i = 0; i < len; i++)
142             {
143 0           sprintf(hexstr + i * 2, "%02x", buf->start[i]);
144             }
145             }
146 0           return hexstr;
147             }
148              
149 0           size_t psBufGetMaxAppendSize(const psBuf_t *buf)
150             {
151 0           const unsigned char *loc = buf->end;
152 0           const unsigned char *bufend = buf->buf + buf->size;
153              
154 0           return bufend - loc;
155             }
156              
157 0           void *psBufAppendSize(psBuf_t *buf, size_t sz)
158             {
159 0           unsigned char *loc = buf->end;
160 0           unsigned char *bufend = buf->buf + buf->size;
161              
162 0 0         if (loc + sz <= bufend)
163             {
164 0           buf->end += sz;
165             }
166             else
167             {
168 0           loc = NULL;
169             }
170 0           return loc;
171             }
172              
173 0           void psBufReservePrepend(psBuf_t *buf, size_t sz)
174             {
175 0           unsigned char *bufend = buf->buf + buf->size;
176 0           unsigned char *loc = buf->end;
177              
178 0 0         assert(buf->start == buf->end); /* Must be done at the beginning. */
179              
180 0 0         if (loc + sz <= bufend)
181             {
182 0           buf->start += sz;
183 0           buf->end += sz;
184             }
185 0           }
186              
187 0           size_t psBufGetMaxPrependSize(const psBuf_t *buf)
188             {
189 0           return buf->start - buf->buf;
190             }
191              
192 0           void *psBufGetData(psBuf_t *buf)
193             {
194 0           return buf->start;
195             }
196              
197 0           size_t psBufGetDataSize(const psBuf_t *buf)
198             {
199 0           return buf->end - buf->start;
200             }
201              
202 0           void *psBufPrependSize(psBuf_t *buf, size_t sz)
203             {
204 0 0         if (buf->buf <= buf->start && buf->buf + sz <= buf->start)
    0          
205             {
206 0           buf->start -= sz;
207 0           return buf->start;
208             }
209              
210 0           return NULL;
211             }
212              
213 0           void psBufNormalize(psBuf_t *buf)
214             {
215 0           size_t sz = psBufGetMaxPrependSize(buf);
216              
217 0 0         if (sz > 0)
218             {
219             /* There is some prepend size. Delete it via memmove() that
220             moves data to the beginning of the buffer. */
221 0           memmove(buf->buf, buf->start, buf->end - buf->start);
222 0           buf->start = buf->buf;
223 0           buf->end -= sz;
224             }
225 0           }
226              
227 0           int32_t psBufCopyDataN(psBuf_t *buf, size_t reqLen,
228             unsigned char *target, size_t *targetlen)
229             {
230             size_t len;
231              
232             /* Compute actual processing size (the smaller of [data avail, reqLen]) */
233 0           len = psBufGetDataSize(buf);
234 0 0         if (reqLen < len)
235             {
236 0           len = reqLen;
237             }
238              
239             /* Check there will be no overflow. */
240 0 0         if (len > *targetlen)
241             {
242 0           *targetlen = len;
243 0           return PS_OUTPUT_LENGTH;
244             }
245              
246             /* Process copy operation + move buffer pointer. */
247 0           memcpy(target, psBufGetData(buf), len);
248 0           buf->start += len;
249 0           *targetlen = len;
250 0           return PS_SUCCESS;
251             }
252              
253 0           void *psDynBufInit(psPool_t *pool, psDynBuf_t *db, size_t capacity)
254             {
255 0           void *mem = psBufInit(pool, &db->buf, capacity);
256              
257 0           db->pool = pool;
258 0           db->err = (mem == NULL);
259 0           db->master = NULL;
260 0           return mem;
261             }
262              
263 0           void psDynBufUninit(psDynBuf_t *db)
264             {
265 0           psBufUninit(db->pool, &db->buf);
266 0           db->err = 0;
267 0           db->pool = NULL;
268 0           db->master = NULL;
269 0           }
270              
271 0           void *psDynBufDetach(psDynBuf_t *db, size_t *len_p)
272             {
273             void *new;
274              
275 0 0         if (db->err)
276             {
277 0           psDynBufUninit(db);
278 0           return NULL;
279             }
280              
281 0           new = psBufDetach(db->pool, &db->buf, len_p);
282 0           db->pool = NULL;
283 0           return new;
284             }
285              
286             static
287 0           void assert_subbuf(psDynBuf_t *sub)
288             {
289             const psDynBuf_t *db;
290              
291             /* Has master. */
292 0 0         assert(sub->master != NULL);
293              
294 0           db = sub->master;
295              
296             /* Does not have pool */
297 0 0         assert(sub->pool == NULL);
298              
299             /* The buf begin and is within master allocated data area. */
300 0 0         assert(sub->buf.buf >= db->buf.start && sub->buf.buf <= db->buf.end);
    0          
301 0 0         assert(sub->buf.buf + sub->buf.size >= db->buf.start &&
    0          
302             sub->buf.buf + sub->buf.size <= db->buf.end);
303              
304             #ifdef PSBUF_DEBUG_WITH_MEMSET
305             /* For debugging: Mark head and tail visually. */
306             memset(sub->buf.buf, '(', sub->buf.start - sub->buf.buf);
307             memset(sub->buf.end, ')', sub->buf.buf + sub->buf.size - sub->buf.end);
308             #endif /* PSBUF_DEBUG_WITH_MEMSET */
309 0           }
310              
311 0           static void *psDynBufGrow(psDynBuf_t *db, size_t head_sz, size_t tail_sz)
312             {
313             void *alloc;
314             void *loc;
315             psBuf_t new;
316 0           size_t headroom = db->buf.start - db->buf.buf;
317 0           size_t tailroom = (db->buf.buf + db->buf.size) - db->buf.end;
318 0           size_t filled = db->buf.end - db->buf.start;
319             size_t offset;
320             size_t offset_tail;
321              
322 0 0         if (db->err)
323             {
324 0           return NULL;
325             }
326              
327 0 0         if (head_sz != 0 && head_sz < PS_DYNBUF_GROW)
    0          
328             {
329 0           head_sz = PS_DYNBUF_GROW;
330             }
331 0 0         if (tail_sz < PS_DYNBUF_GROW)
332             {
333 0           tail_sz = PS_DYNBUF_GROW;
334             }
335              
336 0 0         if (db->master)
337             {
338 0           offset = db->buf.buf - db->master->buf.start;
339 0           offset_tail = db->master->buf.end - (db->buf.buf + db->buf.size);
340             debugf("Sub Grow: %zu+%zu+%zu => %zu+%zu+%zu; sub @ pos=%zd...-%zd\n",
341             headroom, filled, tailroom, headroom + head_sz, filled, tailroom + tail_sz, offset, offset_tail);
342 0           assert_subbuf(db);
343              
344             #ifdef PSBUF_DEBUG_WITH_MEMSET
345             /* For debugging: */
346             memset(db->buf.buf, '{', headroom);
347             memset(db->buf.end, '}', tailroom);
348             #endif /* PSBUF_DEBUG_WITH_MEMSET */
349              
350 0           loc = psDynBufGrow(db->master, 0, head_sz + tail_sz);
351 0 0         if (loc)
352             {
353 0           db->master->buf.end += head_sz + tail_sz;
354 0 0         if (offset_tail)
355             {
356 0           memmove(db->master->buf.end - offset_tail,
357 0           db->master->buf.end - offset_tail - head_sz - tail_sz,
358             offset_tail);
359             }
360              
361 0           db->buf.buf = db->master->buf.start + offset;
362 0           db->buf.start = db->buf.buf + headroom + head_sz;
363 0 0         if (head_sz > 0)
364             {
365 0           memmove(db->buf.start,
366 0           db->buf.start - head_sz,
367             filled);
368             }
369 0           db->buf.end = db->buf.start + filled;
370 0           db->buf.size = head_sz + headroom + filled +
371             tailroom + tail_sz;
372              
373             debugf("Sub Grown: sub @ pos=%d, %zd bytes (%zd+%zd+%zd)\n",
374             (int) (db->buf.buf - db->master->buf.start),
375             db->buf.size, db->buf.start - db->buf.buf,
376             db->buf.end - db->buf.start, db->buf.buf + db->buf.size - db->buf.end);
377              
378             #ifdef PSBUF_DEBUG_WITH_MEMSET
379             /* For debugging: */
380             memset(db->buf.buf, '<', head_sz + headroom);
381             memset(db->buf.end, '>', tail_sz + tailroom);
382             #endif /* PSBUF_DEBUG_WITH_MEMSET */
383             }
384             else
385             {
386 0           db->err++;
387             }
388 0           assert_subbuf(db);
389              
390 0           return loc;
391             }
392              
393 0           head_sz += headroom;
394 0           tail_sz += tailroom;
395              
396             debugf("Grow: %zu+%zu+%zu => %zu+%zu+%zu\n",
397             headroom, filled, tailroom, head_sz, filled, tail_sz);
398              
399 0           alloc = psBufInit(db->pool, &new, head_sz + filled + tail_sz);
400 0 0         if (alloc)
401             {
402 0           psBufReservePrepend(&new, head_sz);
403 0           loc = psBufAppendSize(&new, filled);
404             /* Just allocated so there is space. */
405 0 0         assert(loc != NULL);
406 0           memcpy(loc, db->buf.start, filled);
407 0           psBufUninit(db->pool, &db->buf);
408 0           db->buf.buf = new.buf;
409 0           db->buf.start = new.start;
410 0           db->buf.end = new.end;
411 0           db->buf.size = new.size;
412             }
413             else
414             {
415 0           db->err++;
416 0           loc = NULL;
417             }
418              
419 0           return loc;
420             }
421              
422 0           void *psDynBufAppendSize(psDynBuf_t *db, size_t sz)
423             {
424 0           unsigned char *loc = psBufAppendSize(&db->buf, sz);
425              
426 0 0         if (loc == NULL)
427             {
428 0 0         if (psDynBufGrow(db, 0, sz))
429             {
430 0           loc = psBufAppendSize(&db->buf, sz);
431 0 0         assert(loc != NULL);
432             }
433             }
434 0           return loc;
435             }
436              
437 0           void *psDynBufAppendUtf8(psDynBuf_t *db, int chr)
438             {
439             unsigned char *enc;
440 0           unsigned int ch = (unsigned int) chr;
441              
442             /* Do not encode characters outside valid UTF-8 range. */
443 0 0         if (ch > 0x1FFFF)
444             {
445 0           db->err++;
446 0           return NULL;
447             }
448 0 0         if (ch < 128)
449             {
450 0           enc = psDynBufAppendSize(db, 1);
451 0 0         if (enc)
452             {
453 0           *enc = (unsigned char) ch;
454             }
455             }
456 0 0         else if (ch <= 0x7FF)
457             {
458             /* Two byte encoding. */
459 0           enc = psDynBufAppendSize(db, 2);
460 0 0         if (enc)
461             {
462 0           enc[0] = (unsigned char) (0xC0 | (ch >> 6));
463 0           enc[1] = (unsigned char) (0x80 | (ch & 63));
464             }
465             }
466 0 0         else if (ch <= 0xffff)
467             {
468             /* Three byte encoding. */
469 0           enc = psDynBufAppendSize(db, 3);
470 0 0         if (enc)
471             {
472 0           enc[0] = (unsigned char) (0xE0 | (ch >> 12));
473 0           enc[1] = (unsigned char) (0x80 | ((ch >> 6) & 63));
474 0           enc[2] = (unsigned char) (0x80 | (ch & 63));
475             }
476             }
477             else
478             {
479             /* Four byte encoding. */
480 0           enc = psDynBufAppendSize(db, 4);
481 0 0         if (enc)
482             {
483 0           enc[0] = (unsigned char) (0xF0 | (ch >> 18));
484 0           enc[1] = (unsigned char) (0x80 | ((ch >> 12) & 63));
485 0           enc[2] = (unsigned char) (0x80 | ((ch >> 6) & 63));
486 0           enc[3] = (unsigned char) (0x80 | (ch & 63));
487             }
488             }
489 0           return enc;
490             }
491              
492              
493 0           void psDynBufReservePrepend(psDynBuf_t *db, size_t sz)
494             {
495             /* This function only performs action if nothing has been pushed.
496             The logic for prepending will make sure prepend succeeds even
497             if there is no head room. */
498 0 0         if (db->buf.start == db->buf.end)
499             {
500 0           psBufReservePrepend(&db->buf, sz);
501             }
502 0           }
503              
504 0           void *psDynBufPrependSize(psDynBuf_t *db, size_t sz)
505             {
506 0           unsigned char *loc = psBufPrependSize(&db->buf, sz);
507              
508 0 0         if (loc == NULL)
509             {
510 0 0         if (psDynBufGrow(db, sz, 0))
511             {
512 0           loc = psBufPrependSize(&db->buf, sz);
513 0 0         assert(loc != NULL);
514             }
515             }
516 0           return loc;
517             }
518              
519 0           void *psDynBufSubInit(psDynBuf_t *db, psDynBuf_t *sub, size_t capacity)
520             {
521 0           void *mem = psDynBufAppendSize(db, capacity);
522              
523 0 0         if (mem)
524             {
525 0           sub->buf.buf = db->buf.end - capacity;
526 0           sub->buf.start = sub->buf.buf;
527 0           sub->buf.end = sub->buf.buf;
528 0           sub->buf.size = capacity;
529 0           sub->pool = NULL;
530 0           sub->master = db;
531 0           sub->err = 0;
532             #ifdef PSBUF_DEBUG_WITH_MEMSET
533             memset(sub->buf.buf, '#', capacity);
534             #endif /* PSBUF_DEBUG_WITH_MEMSET */
535 0           assert_subbuf(sub);
536             }
537             else
538             {
539 0           sub->buf.buf = sub->buf.start = sub->buf.end = NULL;
540 0           sub->buf.size = 0;
541 0           sub->pool = NULL;
542 0           sub->err = 1;
543 0           db->err++;
544 0           sub->master = db;
545             }
546              
547 0           return mem;
548             }
549              
550 0           void *psDynBufSubInitAt(psDynBuf_t *db, psDynBuf_t *sub, size_t at,
551             size_t length)
552             {
553 0           size_t len = db->buf.end - db->buf.start;
554              
555 0 0         if (db->err == 0 && at + length <= len)
    0          
556             {
557 0           sub->buf.buf = db->buf.start + at;
558 0           sub->buf.start = sub->buf.buf;
559 0           sub->buf.end = sub->buf.buf;
560 0           sub->buf.size = length;
561 0           sub->pool = NULL;
562 0           sub->master = db;
563 0           sub->err = 0;
564             #ifdef PSBUF_DEBUG_WITH_MEMSET
565             memset(sub->buf.buf, '#', length);
566             #endif /* PSBUF_DEBUG_WITH_MEMSET */
567 0           assert_subbuf(sub);
568             }
569             else
570             {
571 0           sub->buf.buf = sub->buf.start = sub->buf.end = NULL;
572 0           sub->buf.size = 0;
573 0           sub->pool = NULL;
574 0           sub->err++;
575 0           db->err++;
576 0           sub->master = db;
577             }
578              
579 0           return sub->buf.buf;
580             }
581              
582 0           void *psDynBufSubFinish(psDynBuf_t *sub)
583             {
584 0           void *loc = NULL;
585 0           psDynBuf_t *db = sub->master;
586              
587 0 0         if (sub->err)
588             {
589 0           db->err += sub->err;
590             }
591             else
592             {
593 0           size_t total = sub->buf.size;
594 0           size_t filled = sub->buf.end - sub->buf.start;
595             size_t offset_tail;
596              
597 0           offset_tail = db->buf.end - (sub->buf.buf + sub->buf.size);
598              
599 0           assert_subbuf(sub);
600 0 0         if (sub->buf.buf != sub->buf.start && filled > 0)
    0          
601             {
602 0           memmove(sub->buf.buf, sub->buf.start, filled);
603             }
604 0 0         if (offset_tail > 0)
605             {
606 0           memmove(db->buf.end - total + filled - offset_tail,
607 0           db->buf.end - offset_tail, offset_tail);
608             }
609 0           db->buf.end -= total;
610 0           db->buf.end += filled;
611 0           loc = sub->buf.buf;
612             }
613 0           sub->buf.buf = NULL;
614 0           psDynBufUninit(sub);
615 0           return loc;
616             }
617              
618 0           static size_t len_of_tag_and_len(size_t len)
619             {
620             size_t lentaglen;
621              
622 0 0         if (len < 128)
623             {
624 0           lentaglen = 2;
625             }
626 0 0         else if (len < 256)
627             {
628 0           lentaglen = 3;
629             }
630 0 0         else if (len < 65536)
631             {
632 0           lentaglen = 4;
633             }
634 0 0         else if (len < 16777216)
635             {
636 0           lentaglen = 5;
637             }
638             else
639             {
640 0           lentaglen = 6; /* Supports up-to 32-bit sizes. */
641             }
642 0           return lentaglen;
643             }
644              
645 0           static void output_len(size_t len, unsigned char *target)
646             {
647 0 0         if (len < 128)
648             {
649 0           target[1] = (unsigned char) len;
650             }
651 0 0         else if (len < 256)
652             {
653 0           target[1] = 0x81;
654 0           target[2] = (unsigned char) len;
655             }
656 0 0         else if (len < 65536)
657             {
658 0           target[1] = 0x82;
659 0           target[2] = (unsigned char) (len >> 8);
660 0           target[3] = (unsigned char) len;
661             }
662 0 0         else if (len < 16777216)
663             {
664 0           target[1] = 0x83;
665 0           target[2] = (unsigned char) (len >> 16);
666 0           target[3] = (unsigned char) (len >> 8);
667 0           target[4] = (unsigned char) len;
668             }
669             else
670             {
671 0           target[1] = 0x84;
672 0           target[2] = (unsigned char) (len >> 24);
673 0           target[3] = (unsigned char) (len >> 16);
674 0           target[4] = (unsigned char) (len >> 8);
675 0           target[5] = (unsigned char) len;
676             }
677 0           }
678              
679 0           char *psDynBufAppendAsn1TagGen(psDynBuf_t *db, unsigned char tag,
680             const unsigned char *bytes, size_t len)
681             {
682 0           size_t extralen = len_of_tag_and_len(len);
683 0           unsigned char *target = psDynBufAppendSize(db, len + extralen);
684              
685 0 0         if (target)
686             {
687 0           target[0] = tag;
688 0           output_len(len, target);
689 0           memcpy(target + extralen, bytes, len);
690             }
691 0           return (char *) target;
692             }
693              
694 0           char *psDynBufBeginConstructedTag(psDynBuf_t *db, psDynBuf_t *sub)
695             {
696 0           char *target = psDynBufSubInit(db, sub, 20);
697              
698 0 0         if (target)
699             {
700 0           psDynBufReservePrepend(sub, 4);
701             }
702 0           return target;
703             }
704              
705 0           char *psDynBufEndConstructedTag(psDynBuf_t *sub, unsigned char tag)
706             {
707 0           size_t len = sub->buf.end - sub->buf.start;
708 0           size_t extralen = len_of_tag_and_len(len);
709 0           unsigned char *target = psDynBufPrependSize(sub, extralen);
710              
711 0 0         if (target)
712             {
713 0           target[0] = tag;
714 0           output_len(len, target);
715             }
716 0           psDynBufSubFinish(sub);
717 0           return (char *) target;
718             }
719              
720 0           int32_t psParseBufFromStaticData(psParseBuf_t *pb, const void *data, size_t len)
721             {
722 0           int32_t rc = psBufFromStaticData(&pb->buf, data, len);
723              
724 0           pb->pool = psStaticAllocationsPool;
725 0           pb->err = rc != PS_SUCCESS;
726 0           pb->master = NULL;
727 0           return rc;
728             }
729              
730             /* The maximum supported PS_PARSE_MAXIMUM_TAG_CONTENT: */
731             #define PS_PARSE_MAXIMUM_TAG_CONTENT 0x40000000U /* 1 gigabyte. */
732             /* Note: If the value needs to be extended, the limit for function
733             psParseBufGetTagLen() on 32-bit hosts is 0xFFFFFFFFU - 5. */
734 0           size_t psParseBufGetTagLen(const psParseBuf_t *pb,
735             unsigned char tag,
736             size_t *hdrLen_p)
737             {
738             unsigned char lenlen;
739 0           size_t len_at = 1;
740 0           size_t len_hdr = 2;
741             size_t len_content;
742             size_t len_out;
743 0           const unsigned char *ptr = pb->buf.start;
744 0           size_t bytes = pb->buf.end - pb->buf.start;
745              
746 0 0         if (bytes < 2)
747             {
748 0           return 0;
749             }
750 0 0         if (tag != 0 && ptr[0] != tag)
    0          
751             {
752 0           return 0;
753             }
754              
755             /* Check size tag: long input lengths. */
756 0           lenlen = ptr[1]; /* Use lenlen temporarily to parse length field. */
757 0 0         if (lenlen >= 0x80)
758             {
759 0 0         if (bytes < 0x83)
760             {
761 0           return 0;
762             }
763              
764 0 0         if (lenlen == 0x81 && ptr[2] < 0x80)
    0          
765             {
766 0           return 0;
767             }
768              
769 0 0         if (lenlen == 0x82 && ptr[2] == 0x00)
    0          
770             {
771 0           return 0;
772             }
773              
774 0 0         if (lenlen == 0x83 && ptr[2] == 0x00)
    0          
775             {
776 0           return 0;
777             }
778              
779 0 0         if (lenlen == 0x84 && ptr[2] == 0x00)
    0          
780             {
781 0           return 0;
782             }
783              
784 0 0         if (lenlen == 0x80 || lenlen > 0x84)
    0          
785             {
786 0           return 0; /* Too large or indefinite len. */
787             }
788 0           len_at++;
789 0           lenlen -= 0x80;
790 0           len_hdr += lenlen;
791             }
792             else
793             {
794 0           lenlen = 1;
795             }
796              
797             /* len_at and lenlen now express length and of the len. */
798             /* additionally, its known that all the length bytes are accessible. */
799 0           len_content = 0;
800 0 0         while (lenlen)
801             {
802 0           len_content <<= 8;
803 0           len_content += ptr[len_at];
804 0           len_at++;
805 0           lenlen--;
806             }
807              
808 0 0         if (len_content > PS_PARSE_MAXIMUM_TAG_CONTENT)
809             {
810 0           return 0;
811             }
812              
813 0           len_out = len_content + len_hdr;
814              
815 0 0         if (len_out > bytes)
816             {
817 0           return 0;
818             }
819              
820 0 0         if (hdrLen_p)
821             {
822 0           *hdrLen_p = len_hdr;
823             }
824              
825 0           return len_out;
826             }
827              
828 0           int psParseBufCanGetTag(const psParseBuf_t *pb, unsigned char tag)
829             {
830 0           return psParseBufGetTagLen(pb, tag, NULL) > 0;
831             }
832              
833 0           size_t psParseBufTrySkipBytes(psParseBuf_t *pb,
834             const unsigned char *bytes,
835             size_t numbytes)
836             {
837 0           size_t skip_bytes = 0;
838              
839 0 0         if (psParseCanRead(pb, numbytes) &&
    0          
840 0           memcmp(bytes, pb->buf.start, numbytes) == 0)
841             {
842 0           skip_bytes = numbytes;
843             }
844 0           pb->buf.start += skip_bytes;
845 0           return skip_bytes;
846             }
847              
848 0           size_t psParseBufSkipBytes(psParseBuf_t *pb, const unsigned char *bytes,
849             size_t numbytes)
850             {
851 0           size_t sz = psParseBufTrySkipBytes(pb, bytes, numbytes);
852              
853 0 0         if (sz == 0)
854             {
855 0           pb->err++;
856             }
857 0           return sz;
858             }
859              
860 0           size_t psParseBufTryReadTagSub(const psParseBuf_t *pb,
861             psParseBuf_t *content, unsigned char tag)
862             {
863             size_t hdrlen;
864 0           size_t len = psParseBufGetTagLen(pb, tag, &hdrlen);
865             size_t len_content;
866             psParseBuf_t content_tmp; /* Allows calling the function with
867             content == NULL to skip the tag. */
868              
869 0 0         if (!content)
870             {
871 0           content = &content_tmp;
872             }
873 0 0         if (!len)
874             {
875 0           content->buf.buf = content->buf.start = content->buf.end = NULL;
876 0           content->buf.size = 0;
877 0           content->pool = NULL;
878             /* Mark state of content as error. */
879 0           content->err = 1;
880             /* Do not raise error status of main pb. */
881 0           content->master = (psParseBuf_t *) pb;
882 0           return 0;
883             }
884              
885 0           len_content = len - hdrlen;
886 0           content->buf.start = content->buf.buf = pb->buf.start + hdrlen;
887 0           content->buf.size = len_content;
888 0           content->buf.end = content->buf.start + len_content;
889 0           content->pool = NULL;
890 0           content->master = (psParseBuf_t *) pb;
891 0           content->err = 0;
892              
893 0           return len;
894             }
895              
896 0           size_t psParseBufReadTagSub(psParseBuf_t *pb,
897             psParseBuf_t *content, unsigned char tag)
898             {
899 0           size_t len = psParseBufTryReadTagSub(pb, content, tag);
900              
901 0 0         if (len == 0)
902             {
903             /* Mark this also as an error in main parse buffer. */
904 0           pb->err++;
905              
906             /* Initialize sub as the same memory than main parse buffer,
907             to allow parsing using it (typically unsuccessfully)
908             in following parsing operations. */
909 0           memcpy(&(content->buf), &(pb->buf), sizeof content->buf);
910             }
911 0           return len;
912             }
913              
914 0           size_t psParseBufReadTagRef(psParseBuf_t *pb,
915             psBuf_t *ref, unsigned char tag)
916             {
917             psParseBuf_t content;
918 0           size_t len = psParseBufReadTagSub(pb, &content, tag);
919              
920 0 0         if (len)
921             {
922 0           memcpy(ref, &content.buf, sizeof(psBuf_t));
923 0           pb->buf.start += len;
924             }
925 0           return len;
926             }
927              
928 0           size_t psParseBufTrySkipTag(psParseBuf_t *pb, unsigned char tag)
929             {
930             psParseBuf_t sub;
931 0           size_t sz = psParseBufTryReadTagSub(pb, &sub, tag);
932              
933 0 0         if (sz)
934             {
935 0           (void) psParseBufFinish(&sub);
936             }
937 0           return sz;
938             }
939              
940 0           size_t psParseBufSkipTag(psParseBuf_t *pb, unsigned char tag)
941             {
942             psParseBuf_t sub;
943 0           size_t sz = psParseBufReadTagSub(pb, &sub, tag);
944              
945 0 0         if (sz)
946             {
947 0           (void) psParseBufFinish(&sub);
948             }
949 0           return sz;
950             }
951              
952 0           int32_t psParseBufCopyAll(const psParseBuf_t *pb, unsigned char *target,
953             size_t *targetlen)
954             {
955 0           size_t len = pb->buf.end - pb->buf.start;
956              
957 0 0         if (pb->err != 0)
958             {
959 0           return PS_FAILURE;
960             }
961              
962 0 0         if (target == NULL)
963             {
964 0           *targetlen = len;
965 0           return PS_OUTPUT_LENGTH;
966             }
967              
968 0 0         if (len > *targetlen)
969             {
970 0           *targetlen = len;
971 0           return PS_OUTPUT_LENGTH;
972             }
973              
974 0           memcpy(target, pb->buf.start, len);
975 0           *targetlen = len;
976 0           return PS_SUCCESS;
977             }
978              
979 0           int32_t psParseBufCopyN(const psParseBuf_t *pb, size_t reqLen,
980             unsigned char *target, size_t *targetlen)
981             {
982 0           size_t len = pb->buf.end - pb->buf.start;
983              
984 0 0         if (pb->err != 0)
985             {
986 0           return PS_FAILURE;
987             }
988              
989 0 0         if (reqLen > len)
990             {
991 0           reqLen = len;
992             }
993              
994 0 0         if (target == NULL)
995             {
996 0           *targetlen = reqLen;
997 0           return PS_OUTPUT_LENGTH;
998             }
999              
1000 0 0         if (reqLen > *targetlen)
1001             {
1002 0           *targetlen = reqLen;
1003 0           return PS_OUTPUT_LENGTH;
1004             }
1005              
1006 0           memcpy(target, pb->buf.start, reqLen);
1007 0           *targetlen = reqLen;
1008 0           return PS_SUCCESS;
1009             }
1010              
1011 0           int32_t psParseBufCopyUntilByte(psParseBuf_t *pb, unsigned char stopbyte,
1012             unsigned char *target, size_t *targetlen)
1013             {
1014             const unsigned char *end;
1015             size_t len;
1016              
1017 0 0         if (pb->err != 0)
1018             {
1019 0           return PS_FAILURE;
1020             }
1021              
1022 0           end = memchr(pb->buf.start, stopbyte, pb->buf.end - pb->buf.start);
1023              
1024 0 0         if (end == NULL)
1025             {
1026 0           return PS_FAILURE;
1027             }
1028              
1029 0           len = (end - pb->buf.start) + 1;
1030 0           return psParseBufCopyN(pb, len, target, targetlen);
1031             }
1032              
1033 0           int psParseBufEq(const psParseBuf_t *pb1, const psParseBuf_t *pb2)
1034             {
1035 0 0         if (pb1->err || pb2->err)
    0          
1036             {
1037 0           return 0;
1038             }
1039              
1040 0           return psBufEq(&pb1->buf, &pb2->buf);
1041             }
1042              
1043 0           int32_t psParseBufCheckState(const psParseBuf_t *pb)
1044             {
1045 0 0         return pb->err == 0 ? PS_SUCCESS : PS_FAILURE;
1046             }
1047              
1048 0           int32_t psParseBufFinish(psParseBuf_t *pb)
1049             {
1050             int32_t rc;
1051              
1052 0 0         if (pb->master)
1053             {
1054 0 0         if (pb->err)
1055             {
1056             /* Signal master on error. */
1057 0           pb->master->err++;
1058             }
1059             else
1060             {
1061             /* Advance master. */
1062 0           pb->master->buf.start = pb->buf.buf + pb->buf.size;
1063             }
1064              
1065 0           pb->buf.buf = NULL; /* Do not free any data. */
1066             }
1067              
1068             /* Free state. */
1069 0           rc = psParseBufCheckState(pb);
1070 0           psBufUninit(pb->pool, &pb->buf);
1071 0           pb->master = NULL;
1072 0           pb->err = 0;
1073 0           pb->pool = NULL;
1074 0           return rc;
1075             }
1076              
1077 0           void psParseBufCancel(psParseBuf_t *pb)
1078             {
1079             /* Free state. */
1080 0 0         if (pb->master)
1081             {
1082 0           pb->buf.buf = NULL; /* Do not free any data. */
1083             }
1084 0           psBufUninit(pb->pool, &pb->buf);
1085 0           pb->master = NULL;
1086 0           pb->err = 0;
1087 0           pb->pool = NULL;
1088 0           }
1089              
1090             /* end of file psbuf.c */