16a16f4bd8c3a1fb9108cddf3b452c9394ac2247
[strongswan.git] / src / libstrongswan / bio / bio_writer.c
1 /*
2 * Copyright (C) 2012 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * Copyright (C) 2010 Martin Willi
6 * Copyright (C) 2010 revosec AG
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 */
18
19 #include "bio_writer.h"
20
21 typedef struct private_bio_writer_t private_bio_writer_t;
22
23 /**
24 * Private data of an bio_writer_t object.
25 */
26 struct private_bio_writer_t {
27
28 /**
29 * Public bio_writer_t interface.
30 */
31 bio_writer_t public;
32
33 /**
34 * Allocated buffer
35 */
36 chunk_t buf;
37
38 /**
39 * Used bytes in buffer
40 */
41 size_t used;
42
43 /**
44 * Number of bytes to increase buffer size
45 */
46 size_t increase;
47 };
48
49 /**
50 * Increase buffer size
51 */
52 static void increase(private_bio_writer_t *this)
53 {
54 this->buf.len += this->increase;
55 this->buf.ptr = realloc(this->buf.ptr, this->buf.len);
56 }
57
58 METHOD(bio_writer_t, write_uint8, void,
59 private_bio_writer_t *this, u_int8_t value)
60 {
61 if (this->used + 1 > this->buf.len)
62 {
63 increase(this);
64 }
65 this->buf.ptr[this->used] = value;
66 this->used += 1;
67 }
68
69 METHOD(bio_writer_t, write_uint16, void,
70 private_bio_writer_t *this, u_int16_t value)
71 {
72 if (this->used + 2 > this->buf.len)
73 {
74 increase(this);
75 }
76 htoun16(this->buf.ptr + this->used, value);
77 this->used += 2;
78 }
79
80 METHOD(bio_writer_t, write_uint24, void,
81 private_bio_writer_t *this, u_int32_t value)
82 {
83 if (this->used + 3 > this->buf.len)
84 {
85 increase(this);
86 }
87 value = htonl(value);
88 memcpy(this->buf.ptr + this->used, ((char*)&value) + 1, 3);
89 this->used += 3;
90 }
91
92 METHOD(bio_writer_t, write_uint32, void,
93 private_bio_writer_t *this, u_int32_t value)
94 {
95 if (this->used + 4 > this->buf.len)
96 {
97 increase(this);
98 }
99 htoun32(this->buf.ptr + this->used, value);
100 this->used += 4;
101 }
102
103 METHOD(bio_writer_t, write_uint64, void,
104 private_bio_writer_t *this, u_int64_t value)
105 {
106 if (this->used + 8 > this->buf.len)
107 {
108 increase(this);
109 }
110 htoun64(this->buf.ptr + this->used, value);
111 this->used += 8;
112 }
113
114 METHOD(bio_writer_t, write_data, void,
115 private_bio_writer_t *this, chunk_t value)
116 {
117 while (this->used + value.len > this->buf.len)
118 {
119 increase(this);
120 }
121 memcpy(this->buf.ptr + this->used, value.ptr, value.len);
122 this->used += value.len;
123 }
124
125 METHOD(bio_writer_t, write_data8, void,
126 private_bio_writer_t *this, chunk_t value)
127 {
128 write_uint8(this, value.len);
129 write_data(this, value);
130 }
131
132 METHOD(bio_writer_t, write_data16, void,
133 private_bio_writer_t *this, chunk_t value)
134 {
135 write_uint16(this, value.len);
136 write_data(this, value);
137 }
138
139 METHOD(bio_writer_t, write_data24, void,
140 private_bio_writer_t *this, chunk_t value)
141 {
142 write_uint24(this, value.len);
143 write_data(this, value);
144 }
145
146 METHOD(bio_writer_t, write_data32, void,
147 private_bio_writer_t *this, chunk_t value)
148 {
149 write_uint32(this, value.len);
150 write_data(this, value);
151 }
152
153 METHOD(bio_writer_t, wrap8, void,
154 private_bio_writer_t *this)
155 {
156 if (this->used + 1 > this->buf.len)
157 {
158 increase(this);
159 }
160 memmove(this->buf.ptr + 1, this->buf.ptr, this->used);
161 this->buf.ptr[0] = this->used;
162 this->used += 1;
163 }
164
165 METHOD(bio_writer_t, wrap16, void,
166 private_bio_writer_t *this)
167 {
168 if (this->used + 2 > this->buf.len)
169 {
170 increase(this);
171 }
172 memmove(this->buf.ptr + 2, this->buf.ptr, this->used);
173 htoun16(this->buf.ptr, this->used);
174 this->used += 2;
175 }
176
177 METHOD(bio_writer_t, wrap24, void,
178 private_bio_writer_t *this)
179 {
180 u_int32_t len;
181
182 if (this->used + 3 > this->buf.len)
183 {
184 increase(this);
185 }
186 memmove(this->buf.ptr + 3, this->buf.ptr, this->used);
187
188 len = htonl(this->used);
189 memcpy(this->buf.ptr, ((char*)&len) + 1, 3);
190 this->used += 3;
191 }
192
193 METHOD(bio_writer_t, wrap32, void,
194 private_bio_writer_t *this)
195 {
196 if (this->used + 4 > this->buf.len)
197 {
198 increase(this);
199 }
200 memmove(this->buf.ptr + 4, this->buf.ptr, this->used);
201 htoun32(this->buf.ptr, this->used);
202 this->used += 4;
203 }
204
205 METHOD(bio_writer_t, get_buf, chunk_t,
206 private_bio_writer_t *this)
207 {
208 return chunk_create(this->buf.ptr, this->used);
209 }
210
211 METHOD(bio_writer_t, extract_buf, chunk_t,
212 private_bio_writer_t *this)
213 {
214 chunk_t buf = get_buf(this);
215 this->buf = chunk_empty;
216 this->used = 0;
217 return buf;
218 }
219
220 METHOD(bio_writer_t, destroy, void,
221 private_bio_writer_t *this)
222 {
223 free(this->buf.ptr);
224 free(this);
225 }
226
227 /**
228 * See header
229 */
230 bio_writer_t *bio_writer_create(u_int32_t bufsize)
231 {
232 private_bio_writer_t *this;
233
234 INIT(this,
235 .public = {
236 .write_uint8 = _write_uint8,
237 .write_uint16 = _write_uint16,
238 .write_uint24 = _write_uint24,
239 .write_uint32 = _write_uint32,
240 .write_uint64 = _write_uint64,
241 .write_data = _write_data,
242 .write_data8 = _write_data8,
243 .write_data16 = _write_data16,
244 .write_data24 = _write_data24,
245 .write_data32 = _write_data32,
246 .wrap8 = _wrap8,
247 .wrap16 = _wrap16,
248 .wrap24 = _wrap24,
249 .wrap32 = _wrap32,
250 .get_buf = _get_buf,
251 .extract_buf = _extract_buf,
252 .destroy = _destroy,
253 },
254 .increase = bufsize ? max(bufsize, 4) : 32,
255 );
256 if (bufsize)
257 {
258 this->buf = chunk_alloc(bufsize);
259 }
260
261 return &this->public;
262 }