1/*
2 * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
3 *
4 * Jansson is free software; you can redistribute it and/or modify
5 * it under the terms of the MIT license. See LICENSE for details.
6 */
7
8#ifndef _GNU_SOURCE
9#define _GNU_SOURCE
10#endif
11
12#include <stdlib.h>
13#include <string.h>
14#include "jansson_private.h"
15#include "strbuffer.h"
16
17#define STRBUFFER_MIN_SIZE  16
18#define STRBUFFER_FACTOR    2
19#define STRBUFFER_SIZE_MAX  ((size_t)-1)
20
21int strbuffer_init(strbuffer_t *strbuff)
22{
23    strbuff->size = STRBUFFER_MIN_SIZE;
24    strbuff->length = 0;
25
26    strbuff->value = jsonp_malloc(strbuff->size);
27    if(!strbuff->value)
28        return -1;
29
30    /* initialize to empty */
31    strbuff->value[0] = '\0';
32    return 0;
33}
34
35void strbuffer_close(strbuffer_t *strbuff)
36{
37    if(strbuff->value)
38        jsonp_free(strbuff->value);
39
40    strbuff->size = 0;
41    strbuff->length = 0;
42    strbuff->value = NULL;
43}
44
45void strbuffer_clear(strbuffer_t *strbuff)
46{
47    strbuff->length = 0;
48    strbuff->value[0] = '\0';
49}
50
51const char *strbuffer_value(const strbuffer_t *strbuff)
52{
53    return strbuff->value;
54}
55
56char *strbuffer_steal_value(strbuffer_t *strbuff)
57{
58    char *result = strbuff->value;
59    strbuff->value = NULL;
60    return result;
61}
62
63int strbuffer_append(strbuffer_t *strbuff, const char *string)
64{
65    return strbuffer_append_bytes(strbuff, string, strlen(string));
66}
67
68int strbuffer_append_byte(strbuffer_t *strbuff, char byte)
69{
70    return strbuffer_append_bytes(strbuff, &byte, 1);
71}
72
73int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size)
74{
75    if(size >= strbuff->size - strbuff->length)
76    {
77        size_t new_size;
78        char *new_value;
79
80        /* avoid integer overflow */
81        if (strbuff->size > STRBUFFER_SIZE_MAX / STRBUFFER_FACTOR
82            || size > STRBUFFER_SIZE_MAX - 1
83            || strbuff->length > STRBUFFER_SIZE_MAX - 1 - size)
84            return -1;
85
86        new_size = max(strbuff->size * STRBUFFER_FACTOR,
87                       strbuff->length + size + 1);
88
89        new_value = jsonp_malloc(new_size);
90        if(!new_value)
91            return -1;
92
93        memcpy(new_value, strbuff->value, strbuff->length);
94
95        jsonp_free(strbuff->value);
96        strbuff->value = new_value;
97        strbuff->size = new_size;
98    }
99
100    memcpy(strbuff->value + strbuff->length, data, size);
101    strbuff->length += size;
102    strbuff->value[strbuff->length] = '\0';
103
104    return 0;
105}
106
107char strbuffer_pop(strbuffer_t *strbuff)
108{
109    if(strbuff->length > 0) {
110        char c = strbuff->value[--strbuff->length];
111        strbuff->value[strbuff->length] = '\0';
112        return c;
113    }
114    else
115        return '\0';
116}
117