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