1 /*
2  * libwbxml, the WBXML Library.
3  * Copyright (C) 2002-2008 Aymerick Jehanne <aymerick@jehanne.org>
4  * Copyright (C) 2011 Michael Bell <michael.bell@opensync.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * LGPL v2.1: http://www.gnu.org/copyleft/lesser.txt
21  *
22  * Contact: aymerick@jehanne.org
23  * Home: http://libwbxml.aymerick.com
24  */
25 
26 /**
27  * @file wbxml_buffers.c
28  * @ingroup wbxml_buffers
29  *
30  * @author Aymerick Jehanne <aymerick@jehanne.org>
31  * @date 02/03/12
32  *
33  * @brief Generic Buffers Functions
34  *
35  * @note Original idea: Kannel Project (http://www.kannel.org/)
36  */
37 
38 #include <limits.h>
39 #include <ctype.h>
40 
41 #include "wbxml_buffers.h"
42 #include "wbxml_base64.h"
43 
44 
45 /* Memory management define */
46 #define WBXML_BUFFER_SPLIT_BLOCK 20
47 
48 /**
49  * The Generic Buffer type
50  */
51 struct WBXMLBuffer_s
52 {
53     WB_UTINY *data;             /**< The data */
54     WB_ULONG  len;              /**< Length of data in buffer */
55     WB_ULONG  malloced;         /**< Length of buffer */
56     WB_BOOL   is_static;        /**< Is it a static buffer ?  */
57 };
58 
59 
60 static WB_BOOL grow_buff(WBXMLBuffer *buffer, WB_ULONG size);
61 static WB_BOOL insert_data(WBXMLBuffer *buffer, WB_ULONG pos, const WB_UTINY *data, WB_ULONG len);
62 
63 
64 
65 /**********************************
66  *    Public functions
67  */
68 
69 
wbxml_buffer_create_real(const WB_UTINY * data,WB_ULONG len,WB_ULONG malloc_block)70 WBXML_DECLARE(WBXMLBuffer *) wbxml_buffer_create_real(const WB_UTINY *data, WB_ULONG len, WB_ULONG malloc_block)
71 {
72     WBXMLBuffer *buffer = NULL;
73 
74     buffer = wbxml_malloc(sizeof(WBXMLBuffer));
75     if (buffer == NULL)
76         return NULL;
77 
78     buffer->is_static    = FALSE;
79 
80     if ((len <= 0) || (data == NULL)) {
81         buffer->malloced = 0;
82         buffer->len = 0;
83         buffer->data = NULL;
84     }
85     else {
86         if (len + 1 > malloc_block + 1)
87             buffer->malloced = len + 1 + malloc_block;
88         else
89             buffer->malloced = malloc_block + 1;
90 
91         buffer->data = wbxml_malloc(buffer->malloced * sizeof(WB_UTINY));
92         if (buffer->data == NULL) {
93             wbxml_free(buffer);
94             return NULL;
95         }
96 
97         buffer->len = len;
98         memcpy(buffer->data, data, len);
99         buffer->data[len] = '\0';
100     }
101 
102     return buffer;
103 }
104 
105 
wbxml_buffer_sta_create_real(const WB_UTINY * data,WB_ULONG len)106 WBXML_DECLARE(WBXMLBuffer *) wbxml_buffer_sta_create_real(const WB_UTINY *data, WB_ULONG len)
107 {
108     WBXMLBuffer *buffer = NULL;
109 
110     buffer = wbxml_malloc(sizeof(WBXMLBuffer));
111     if (buffer == NULL) {
112         return NULL;
113     }
114 
115     buffer->is_static    = TRUE;
116     buffer->data         = (WB_UTINY *) data;
117     buffer->len          = len;
118 
119     return buffer;
120 }
121 
122 
wbxml_buffer_destroy(WBXMLBuffer * buffer)123 WBXML_DECLARE(void) wbxml_buffer_destroy(WBXMLBuffer *buffer)
124 {
125     if (buffer != NULL) {
126         if (!buffer->is_static) {
127             /* Free dynamic data */
128             wbxml_free(buffer->data);
129         }
130 
131         /* Free structure */
132         wbxml_free(buffer);
133     }
134 }
135 
136 
wbxml_buffer_destroy_item(void * buff)137 WBXML_DECLARE_NONSTD(void) wbxml_buffer_destroy_item(void *buff)
138 {
139     wbxml_buffer_destroy((WBXMLBuffer *) buff);
140 }
141 
142 
wbxml_buffer_duplicate(WBXMLBuffer * buff)143 WBXML_DECLARE(WBXMLBuffer *) wbxml_buffer_duplicate(WBXMLBuffer *buff)
144 {
145     WBXMLBuffer *result = NULL;
146 
147     if (buff == NULL)
148         return NULL;
149 
150     result = wbxml_buffer_create_real(wbxml_buffer_get_cstr(buff),
151                                       wbxml_buffer_len(buff),
152                                       wbxml_buffer_len(buff));
153 
154     return result;
155 }
156 
157 
wbxml_buffer_len(WBXMLBuffer * buffer)158 WBXML_DECLARE(WB_ULONG) wbxml_buffer_len(WBXMLBuffer *buffer)
159 {
160     if (buffer == NULL)
161         return 0;
162 
163     return buffer->len;
164 }
165 
166 
wbxml_buffer_get_char(WBXMLBuffer * buffer,WB_ULONG pos,WB_UTINY * result)167 WBXML_DECLARE(WB_BOOL) wbxml_buffer_get_char(WBXMLBuffer *buffer, WB_ULONG pos, WB_UTINY *result)
168 {
169     if ((buffer == NULL) || (pos >= buffer->len) || (result == NULL))
170         return FALSE;
171 
172     *result = buffer->data[pos];
173     return TRUE;
174 }
175 
176 
wbxml_buffer_set_char(WBXMLBuffer * buffer,WB_ULONG pos,WB_UTINY ch)177 WBXML_DECLARE(WB_BOOL) wbxml_buffer_set_char(WBXMLBuffer *buffer, WB_ULONG pos, WB_UTINY ch)
178 {
179     if ((buffer == NULL) || (buffer->is_static) || (pos >= buffer->len))
180         return FALSE;
181 
182     buffer->data[pos] = ch;
183 
184     return TRUE;
185 }
186 
187 
wbxml_buffer_get_cstr(WBXMLBuffer * buffer)188 WBXML_DECLARE(WB_UTINY *) wbxml_buffer_get_cstr(WBXMLBuffer *buffer)
189 {
190     if ((buffer == NULL) || (buffer->len == 0))
191         return WBXML_UTINY_NULL_STRING;
192 
193     return buffer->data;
194 }
195 
196 
wbxml_buffer_insert(WBXMLBuffer * to,WBXMLBuffer * buffer,WB_ULONG pos)197 WBXML_DECLARE(WB_BOOL) wbxml_buffer_insert(WBXMLBuffer *to, WBXMLBuffer *buffer, WB_ULONG pos)
198 {
199     if ((to != NULL) && (buffer != NULL) && !to->is_static)
200         return insert_data(to, pos, buffer->data, buffer->len);
201 
202     return FALSE;
203 }
204 
205 
wbxml_buffer_insert_cstr(WBXMLBuffer * to,const WB_UTINY * str,WB_ULONG pos)206 WBXML_DECLARE(WB_BOOL) wbxml_buffer_insert_cstr(WBXMLBuffer *to, const WB_UTINY *str, WB_ULONG pos)
207 {
208     if ((to != NULL) && (str != NULL) && !to->is_static)
209         return insert_data(to, pos, str, WBXML_STRLEN(str));
210 
211     return FALSE;
212 }
213 
214 
wbxml_buffer_append(WBXMLBuffer * dest,WBXMLBuffer * buff)215 WBXML_DECLARE(WB_BOOL) wbxml_buffer_append(WBXMLBuffer *dest, WBXMLBuffer *buff)
216 {
217     if ((dest == NULL) || dest->is_static)
218         return FALSE;
219 
220     if (buff == NULL)
221         return TRUE;
222 
223     return wbxml_buffer_append_data(dest, wbxml_buffer_get_cstr(buff), wbxml_buffer_len(buff));
224 }
225 
226 
wbxml_buffer_append_data_real(WBXMLBuffer * buffer,const WB_UTINY * data,WB_ULONG len)227 WBXML_DECLARE(WB_BOOL) wbxml_buffer_append_data_real(WBXMLBuffer *buffer, const WB_UTINY *data, WB_ULONG len)
228 {
229     if ((buffer == NULL) || buffer->is_static)
230         return FALSE;
231 
232     if ((data == NULL) || (len == 0))
233         return TRUE;
234 
235     return insert_data(buffer, buffer->len, data, len);
236 }
237 
wbxml_buffer_append_cstr_real(WBXMLBuffer * buffer,const WB_UTINY * data)238 WBXML_DECLARE(WB_BOOL) wbxml_buffer_append_cstr_real(WBXMLBuffer *buffer, const WB_UTINY *data)
239 {
240     if ((buffer == NULL) || buffer->is_static) {
241         return FALSE;
242     }
243 
244     if (data == NULL)
245         return TRUE;
246 
247     return wbxml_buffer_append_data(buffer, data, WBXML_STRLEN(data));
248 }
249 
250 
wbxml_buffer_append_char(WBXMLBuffer * buffer,WB_UTINY ch)251 WBXML_DECLARE(WB_BOOL) wbxml_buffer_append_char(WBXMLBuffer *buffer, WB_UTINY ch)
252 {
253     WB_UTINY c = ch;
254 
255     if ((buffer == NULL) || buffer->is_static)
256         return FALSE;
257 
258     return insert_data(buffer, buffer->len, &c, 1);
259 }
260 
261 
wbxml_buffer_append_mb_uint_32(WBXMLBuffer * buffer,WB_ULONG value)262 WBXML_DECLARE(WB_BOOL) wbxml_buffer_append_mb_uint_32(WBXMLBuffer *buffer, WB_ULONG value)
263 {
264     /**
265      * A uintvar is defined to be up to 32 bits large
266      * so it will fit in 5 octets (to handle continuation bits)
267      */
268     WB_UTINY octets[5];
269     WB_LONG i = 0, start = 0;
270 
271     if ((buffer == NULL) || buffer->is_static)
272         return FALSE;
273 
274     /**
275      * Handle last byte separately; it has no continuation bit,
276      * and must be encoded even if value is 0.
277      */
278     octets[4] = (WB_UTINY) (value & 0x7f);
279     value >>= 7;
280 
281     for (i = 3; value > 0 && i >= 0; i--) {
282         octets[i] = (WB_UTINY) (0x80 | (value & 0x7f));
283         value >>= 7;
284     }
285     start = i + 1;
286 
287     return wbxml_buffer_append_data(buffer, octets + start, 5 - start);
288 }
289 
290 
wbxml_buffer_delete(WBXMLBuffer * buffer,WB_ULONG pos,WB_ULONG len)291 WBXML_DECLARE(WB_BOOL) wbxml_buffer_delete(WBXMLBuffer *buffer, WB_ULONG pos, WB_ULONG len)
292 {
293     if ((buffer == NULL) || (buffer->is_static))
294         return FALSE;
295 
296     if ((pos >= buffer->len) || (len <= 0))
297         return FALSE;
298 
299     memmove(buffer->data + pos, buffer->data + pos + len,
300             buffer->len - pos - len);
301 
302     buffer->len -= len;
303     buffer->data[buffer->len] = '\0';
304 
305     return TRUE;
306 }
307 
308 
wbxml_buffer_shrink_blanks(WBXMLBuffer * buffer)309 WBXML_DECLARE(WB_BOOL) wbxml_buffer_shrink_blanks(WBXMLBuffer *buffer)
310 {
311     WB_ULONG i = 0, j = 0, end = 0;
312     WB_UTINY ch = 0;
313 
314     if ((buffer == NULL) || buffer->is_static)
315         return FALSE;
316 
317     end = wbxml_buffer_len(buffer);
318 
319     for (i = 0; i < end; i++)
320     {
321         if (wbxml_buffer_get_char(buffer, i, &ch) && isspace(ch))
322         {
323             /* Replace space by a whitespace */
324             if (ch != ' ')
325                 wbxml_buffer_set_char(buffer, i, ' ');
326 
327             /* Remove all following spaces */
328             j = i = i + 1;
329             while (wbxml_buffer_get_char(buffer, j, &ch) && isspace(ch))
330                 j++;
331 
332             if (j - i > 1)
333                 wbxml_buffer_delete(buffer, i, j - i);
334         }
335     }
336 
337     return TRUE;
338 }
339 
340 
wbxml_buffer_strip_blanks(WBXMLBuffer * buffer)341 WBXML_DECLARE(WB_BOOL) wbxml_buffer_strip_blanks(WBXMLBuffer *buffer)
342 {
343     WB_ULONG start = 0, end = 0, len = 0;
344     WB_UTINY ch = 0;
345 
346     if ((buffer == NULL) || buffer->is_static)
347         return FALSE;
348 
349     /* Remove whitespaces at beginning of buffer... */
350     while (wbxml_buffer_get_char(buffer, start, &ch) &&
351            isspace(ch) &&
352            start <= wbxml_buffer_len(buffer))
353     {
354         start ++;
355     }
356 
357     if (start > 0)
358         wbxml_buffer_delete(buffer, 0, start);
359 
360     /* ... and at the end */
361     if ((len = wbxml_buffer_len(buffer)) > 0) {
362         end = len = len - 1;
363         while (wbxml_buffer_get_char(buffer, end, &ch) &&
364             isspace(ch))
365         {
366             end--;
367         }
368         wbxml_buffer_delete(buffer, end + 1, len - end);
369     }
370 
371     return TRUE;
372 }
373 
wbxml_buffer_no_spaces(WBXMLBuffer * buffer)374 WBXML_DECLARE(void) wbxml_buffer_no_spaces(WBXMLBuffer *buffer)
375 {
376     WB_ULONG i = 0, j = 0, end = 0;
377     WB_UTINY ch = 0;
378 
379     if ((buffer == NULL) || buffer->is_static)
380         return;
381 
382     while (i < wbxml_buffer_len(buffer))
383     {
384         if (wbxml_buffer_get_char(buffer, i, &ch) && isspace(ch))
385         {
386              wbxml_buffer_delete(buffer, i, 1);
387         } else {
388              i++;
389         }
390     }
391 }
392 
wbxml_buffer_compare(WBXMLBuffer * buff1,WBXMLBuffer * buff2)393 WBXML_DECLARE(WB_LONG) wbxml_buffer_compare(WBXMLBuffer *buff1, WBXMLBuffer *buff2)
394 {
395     WB_LONG ret = 0, len = 0;
396 
397     if ((buff1 == NULL) || (buff2 == NULL)) {
398         if ((buff1 == NULL) && (buff2 == NULL))
399             return 0;
400 
401         if (buff1 == NULL)
402             return -1;
403         else
404             return 1;
405     }
406 
407     if (buff1->len < buff2->len)
408         len = buff1->len;
409     else
410         len = buff2->len;
411 
412     if (len == 0)
413     {
414         if (buff1->len == 0 && buff2->len > 0)
415             return -1;
416         if (buff1->len > 0 && buff2->len == 0)
417             return 1;
418         return 0;
419     }
420 
421     if ((ret = memcmp(buff1->data, buff2->data, len)) == 0)
422     {
423         if (buff1->len < buff2->len)
424             ret = -1;
425         else {
426             if (buff1->len > buff2->len)
427                 ret = 1;
428         }
429     }
430 
431     return ret;
432 }
433 
434 
wbxml_buffer_compare_cstr(WBXMLBuffer * buff,const WB_TINY * str)435 WBXML_DECLARE(WB_LONG) wbxml_buffer_compare_cstr(WBXMLBuffer *buff, const WB_TINY *str)
436 {
437     WB_LONG ret = 0, len = 0;
438 
439     if ((buff == NULL) || (str == NULL)) {
440         if ((buff == NULL) && (str == NULL))
441             return 0;
442 
443         if (buff == NULL)
444             return -1;
445         else
446             return 1;
447     }
448 
449     if (buff->len < WBXML_STRLEN(str))
450         len = buff->len;
451     else
452         len = WBXML_STRLEN(str);
453 
454     if (len == 0)
455     {
456         if (buff->len == 0 && WBXML_STRLEN(str) > 0)
457             return -1;
458         if (buff->len > 0 && WBXML_STRLEN(str) == 0)
459             return 1;
460         return 0;
461     }
462 
463     if ((ret = memcmp(buff->data, str, len)) == 0)
464     {
465         if (buff->len < WBXML_STRLEN(str))
466             ret = -1;
467         else {
468             if (buff->len > WBXML_STRLEN(str))
469                 ret = 1;
470         }
471     }
472 
473     return ret;
474 }
475 
476 
wbxml_buffer_split_words_real(WBXMLBuffer * buff)477 WBXML_DECLARE(WBXMLList *) wbxml_buffer_split_words_real(WBXMLBuffer *buff)
478 {
479     WB_UTINY *p = NULL;
480     WBXMLList *list = NULL;
481     WBXMLBuffer *word = NULL;
482     WB_ULONG i = 0, start = 0, end = 0;
483 
484     if (buff == NULL)
485         return NULL;
486 
487     if ((list = wbxml_list_create()) == NULL)
488         return NULL;
489 
490     p = buff->data;
491     i = 0;
492     while (TRUE)
493     {
494         while (i < buff->len && isspace(*p)) {
495             ++p;
496             ++i;
497         }
498         start = i;
499 
500         while (i < buff->len && !isspace(*p)) {
501             ++p;
502             ++i;
503         }
504         end = i;
505 
506         if (start == end)
507             break;
508 
509         if((word = wbxml_buffer_create(buff->data + start, end - start, WBXML_BUFFER_SPLIT_BLOCK)) == NULL) {
510             wbxml_list_destroy(list, wbxml_buffer_destroy_item);
511             return NULL;
512         }
513 
514         wbxml_list_append(list, word);
515     }
516 
517     return list;
518 }
519 
520 
wbxml_buffer_search_char(WBXMLBuffer * to,const WB_UTINY ch,WB_ULONG pos,WB_ULONG * result)521 WBXML_DECLARE(WB_BOOL) wbxml_buffer_search_char(WBXMLBuffer *to, const WB_UTINY ch, WB_ULONG pos, WB_ULONG *result)
522 {
523     WB_UTINY *p = NULL;
524 
525     if (to == NULL)
526         return FALSE;
527 
528     if (pos >= to->len)
529         return FALSE;
530 
531     if ((p = (WB_UTINY *) memchr(to->data + pos, ch, to->len - pos)) == NULL)
532         return FALSE;
533 
534     if (result != NULL)
535         *result = p - to->data;
536 
537     return TRUE;
538 }
539 
540 
wbxml_buffer_search(WBXMLBuffer * to,WBXMLBuffer * search,WB_ULONG pos,WB_ULONG * result)541 WBXML_DECLARE(WB_BOOL) wbxml_buffer_search(WBXMLBuffer *to, WBXMLBuffer *search, WB_ULONG pos, WB_ULONG *result)
542 {
543     WB_UTINY first = 0;
544 
545     if ((to == NULL) || (search == NULL))
546         return FALSE;
547 
548     if (result != NULL)
549         *result = 0;
550 
551     /* Always "find" an empty string */
552     if (search->len == 0)
553         return TRUE;
554 
555     /* Check if 'search' is greater than 'to' */
556     if (search->len > to->len)
557         return FALSE;
558 
559     /* We are searching for one char */
560     if (search->len == 1)
561         return wbxml_buffer_search_char(to, search->data[0], pos, result);
562 
563     /* For each occurrence of search's first character in to, then check if the rest of needle follows.
564      * Stop if there are no more occurrences, or if the rest of 'search' can't possibly fit in 'to'. */
565     first = search->data[0];
566     while ((wbxml_buffer_search_char(to, first, pos, &pos)) &&
567            (to->len - pos >= search->len))
568     {
569         if (memcmp(to->data + pos, search->data, search->len) == 0) {
570             if (result != NULL)
571                 *result = pos;
572             return TRUE;
573         }
574         pos++;
575     }
576 
577     return FALSE;
578 }
579 
580 
wbxml_buffer_search_cstr(WBXMLBuffer * to,const WB_UTINY * search,WB_ULONG pos,WB_ULONG * result)581 WBXML_DECLARE(WB_BOOL) wbxml_buffer_search_cstr(WBXMLBuffer *to, const WB_UTINY *search, WB_ULONG pos, WB_ULONG *result)
582 {
583     WB_UTINY first = 0;
584 
585     if ((to == NULL) || (search == NULL))
586         return FALSE;
587 
588     if (result != NULL)
589         *result = 0;
590 
591     /* Always "find" an empty string */
592     if (WBXML_STRLEN(search) == 0)
593         return TRUE;
594 
595     /* Check if 'search' is greater than 'to' */
596     if (WBXML_STRLEN(search) > to->len)
597         return FALSE;
598 
599     /* We are searching for one char */
600     if (WBXML_STRLEN(search) == 1)
601         return wbxml_buffer_search_char(to, search[0], pos, result);
602 
603     /* For each occurrence of search's first character in to, then check if the rest of needle follows.
604      * Stop if there are no more occurrences, or if the rest of 'search' can't possibly fit in 'to'. */
605     first = search[0];
606     while ((wbxml_buffer_search_char(to, first, pos, &pos)) &&
607            (to->len - pos >= WBXML_STRLEN(search)))
608     {
609         if (memcmp(to->data + pos, search, WBXML_STRLEN(search)) == 0) {
610             if (result != NULL)
611                 *result = pos;
612             return TRUE;
613         }
614         pos++;
615     }
616 
617     return FALSE;
618 }
619 
620 
wbxml_buffer_contains_only_whitespaces(WBXMLBuffer * buffer)621 WBXML_DECLARE(WB_BOOL) wbxml_buffer_contains_only_whitespaces(WBXMLBuffer *buffer)
622 {
623     WB_ULONG i = 0;
624 
625     if (buffer == NULL)
626         return FALSE;
627 
628     for (i=0; i<buffer->len; i++) {
629         if (!isspace(*(buffer->data + i)))
630             return FALSE;
631     }
632 
633     return TRUE;
634 }
635 
636 
wbxml_buffer_hex_to_binary(WBXMLBuffer * buffer)637 WBXML_DECLARE(WB_BOOL) wbxml_buffer_hex_to_binary(WBXMLBuffer *buffer)
638 {
639     WB_UTINY *p = NULL;
640     WB_ULONG i = 0, len = 0;
641 
642     if ((buffer == NULL) || buffer->is_static)
643         return FALSE;
644 
645     p = buffer->data;
646     len = wbxml_buffer_len(buffer);
647 
648     /* Convert ascii data to binary values */
649     for (i = 0; i < len; i++, p++) {
650         if (*p >= '0' && *p <= '9')
651             *p -= '0';
652         else if (*p >= 'a' && *p <= 'f')
653             *p = (WB_UTINY) (*p - 'a' + 10);
654         else if (*p >= 'A' && *p <= 'F')
655             *p = (WB_UTINY) (*p - 'A' + 10);
656         else {
657             /* Bad Bad ! There should be only digits in the buffer ! */
658             *p = 0;
659         }
660     }
661 
662     /* De-hexing will compress data by factor of 2 */
663     len = buffer->len / 2;
664 
665     for (i = 0; i < len; i++)
666         buffer->data[i] = (WB_UTINY) (buffer->data[i * 2] * 16 | buffer->data[i * 2 + 1]);
667 
668     buffer->len = len;
669     buffer->data[len] = '\0';
670 
671     return TRUE;
672 }
673 
674 
wbxml_buffer_binary_to_hex(WBXMLBuffer * buffer,WB_BOOL uppercase)675 WBXML_DECLARE(WB_BOOL) wbxml_buffer_binary_to_hex(WBXMLBuffer *buffer, WB_BOOL uppercase)
676 {
677     WB_UTINY *hexits = NULL;
678     WB_LONG i = 0;
679 
680     if ((buffer == NULL) || buffer->is_static)
681         return FALSE;
682 
683     if (wbxml_buffer_len(buffer) == 0)
684         return TRUE;
685 
686     hexits = (WB_UTINY *)(uppercase ? "0123456789ABCDEF" : "0123456789abcdef");
687 
688     /* Grows the Buffer size by 2 */
689     grow_buff(buffer, buffer->len * 2);
690 
691     /* In-place modification must be done back-to-front to avoid
692      * overwriting the data while we read it.  Even the order of
693      * the two assignments is important, to get i == 0 right.
694      */
695     for (i = buffer->len - 1; i >= 0; i--) {
696         buffer->data[i * 2 + 1] = hexits[buffer->data[i] % 16];
697         buffer->data[i * 2] = hexits[(buffer->data[i] / 16) & 0xf];
698     }
699 
700     buffer->len = buffer->len * 2;
701     buffer->data[buffer->len] = '\0';
702 
703     return TRUE;
704 }
705 
wbxml_buffer_decode_base64(WBXMLBuffer * buffer)706 WBXML_DECLARE(WBXMLError) wbxml_buffer_decode_base64(WBXMLBuffer *buffer)
707 {
708     WB_UTINY   *result = NULL;
709     WB_LONG     len    = 0;
710     WBXMLError  ret    = WBXML_OK;
711 
712     if ( (buffer == NULL) || (buffer->is_static) ) {
713         return WBXML_ERROR_INTERNAL;
714     }
715 
716     wbxml_buffer_no_spaces(buffer);
717 
718     if ((len = wbxml_base64_decode((const WB_UTINY *) wbxml_buffer_get_cstr(buffer),
719                                    wbxml_buffer_len(buffer), &result)) <= 0)
720     {
721         return WBXML_ERROR_B64_DEC;
722     }
723 
724     /* Reset buffer */
725     wbxml_buffer_delete(buffer, 0, wbxml_buffer_len(buffer));
726 
727     /* Set binary data */
728     if (!wbxml_buffer_append_data(buffer, result, len)) {
729         ret = WBXML_ERROR_NOT_ENOUGH_MEMORY;
730     }
731 
732     wbxml_free(result);
733 
734     return ret;
735 }
736 
wbxml_buffer_encode_base64(WBXMLBuffer * buffer)737 WBXML_DECLARE(WBXMLError) wbxml_buffer_encode_base64(WBXMLBuffer *buffer)
738 {
739     WB_UTINY   *result = NULL;
740     WBXMLError  ret    = WBXML_OK;
741 
742     if ( (buffer == NULL) || (buffer->is_static) ) {
743         return WBXML_ERROR_INTERNAL;
744     }
745 
746     if ((result = wbxml_base64_encode((const WB_UTINY *) wbxml_buffer_get_cstr(buffer),
747                                       wbxml_buffer_len(buffer))) == NULL)
748     {
749         return WBXML_ERROR_B64_ENC;
750     }
751 
752     /* Reset buffer */
753     wbxml_buffer_delete(buffer, 0, wbxml_buffer_len(buffer));
754 
755     /* Set data */
756     if (!wbxml_buffer_append_cstr(buffer, result)) {
757         ret = WBXML_ERROR_NOT_ENOUGH_MEMORY;
758     }
759 
760     wbxml_free(result);
761 
762     return ret;
763 }
764 
wbxml_buffer_remove_trailing_zeros(WBXMLBuffer * buffer)765 WBXML_DECLARE(WB_BOOL) wbxml_buffer_remove_trailing_zeros(WBXMLBuffer *buffer)
766 {
767     WB_UTINY ch = 0;
768 
769     if ((buffer == NULL) || (buffer->is_static))
770         return FALSE;
771 
772     while (buffer->len > 0) {
773         if (wbxml_buffer_get_char(buffer, wbxml_buffer_len(buffer) - 1, &ch) && (ch == '\0'))
774             wbxml_buffer_delete(buffer, wbxml_buffer_len(buffer) - 1, 1);
775         else
776             return TRUE;
777     }
778 
779     return TRUE;
780 }
781 
782 
783 /**********************************
784  *    Private functions
785  */
786 
787 /**
788  * @brief Add space for at least 'size' octets
789  * @param buffer The buffer
790  * @param size The size to add
791  * @return TRUE is space successfully reserved, FALSE is size was negative, buffer was NULL or if not enough memory
792  */
grow_buff(WBXMLBuffer * buffer,WB_ULONG size)793 static WB_BOOL grow_buff(WBXMLBuffer *buffer, WB_ULONG size)
794 {
795     if ((buffer == NULL) || buffer->is_static)
796         return FALSE;
797 
798     /* Make room for the invisible terminating NUL */
799     size++;
800 
801     if ((buffer->len + size) > buffer->malloced) {
802         if ((buffer->malloced * 2) < (buffer->len + size))
803             buffer->malloced = buffer->len + size;
804         else
805             buffer->malloced *= 2;
806 
807         buffer->data = wbxml_realloc(buffer->data, buffer->malloced);
808         if (buffer->data == NULL)
809             return FALSE;
810     }
811 
812     return TRUE;
813 }
814 
815 
816 /**
817  * @brief Insert data into a Generic Buffer
818  * @param buffer The Generic Buffer
819  * @param pos Position in Generic Buffer where to insert data
820  * @param data Data to insert
821  * @param len Data length
822  * @return TRUE is data inserted, FALSE if not
823  */
insert_data(WBXMLBuffer * buffer,WB_ULONG pos,const WB_UTINY * data,WB_ULONG len)824 static WB_BOOL insert_data(WBXMLBuffer *buffer, WB_ULONG pos, const WB_UTINY *data, WB_ULONG len)
825 {
826     if ((buffer == NULL) || buffer->is_static || (len == 0) || (pos > buffer->len))
827         return FALSE;
828 
829     if (!grow_buff(buffer, len))
830         return FALSE;
831 
832     if (buffer->len > pos) {
833         /* Only if neccessary */
834         memmove(buffer->data + pos + len, buffer->data + pos, buffer->len - pos);
835     }
836 
837     memcpy(buffer->data + pos, data, len);
838     buffer->len += len;
839     buffer->data[buffer->len] = '\0';
840 
841     return TRUE;
842 }
843