1 /*
2  * Copyright (c) 2002-2010 Balabit
3  * Copyright (c) 1998-2010 Balázs Scheidler
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  * As an additional exemption you are allowed to compile & link against the
20  * OpenSSL libraries as published by the OpenSSL project. See the file
21  * COPYING for details.
22  *
23  */
24 
25 #ifndef SERIALIZE_H_INCLUDED
26 #define SERIALIZE_H_INCLUDED
27 
28 #include "syslog-ng.h"
29 
30 #include <stdio.h>
31 #include <string.h>
32 
33 typedef struct _SerializeArchive SerializeArchive;
34 
35 struct _SerializeArchive
36 {
37   GError *error;
38   guint16 len;
39   guint16 silent:1;
40 
41   gboolean (*read_bytes)(SerializeArchive *archive, gchar *buf, gsize count, GError **error);
42   gboolean (*write_bytes)(SerializeArchive *archive, const gchar *buf, gsize count, GError **error);
43 };
44 
45 /* this is private and is only published so that the inline functions below can invoke it */
46 void _serialize_handle_errors(SerializeArchive *self, const gchar *error_desc, GError *error);
47 
48 static inline gboolean
serialize_archive_read_bytes(SerializeArchive * self,gchar * buf,gsize buflen)49 serialize_archive_read_bytes(SerializeArchive *self, gchar *buf, gsize buflen)
50 {
51   GError *error = NULL;
52 
53   if ((self->error == NULL) && !self->read_bytes(self, buf, buflen, &error))
54     _serialize_handle_errors(self, "Error reading serialized data", error);
55   return self->error == NULL;
56 }
57 
58 static inline gboolean
serialize_archive_write_bytes(SerializeArchive * self,const gchar * buf,gsize buflen)59 serialize_archive_write_bytes(SerializeArchive *self, const gchar *buf, gsize buflen)
60 {
61   GError *error = NULL;
62 
63   if ((self->error == NULL) && !self->write_bytes(self, buf, buflen, &error))
64     _serialize_handle_errors(self, "Error writing serialized data", error);
65   return self->error == NULL;
66 }
67 
68 static inline gboolean
serialize_write_uint32(SerializeArchive * archive,guint32 value)69 serialize_write_uint32(SerializeArchive *archive, guint32 value)
70 {
71   guint32 n;
72 
73   n = GUINT32_TO_BE(value);
74   return serialize_archive_write_bytes(archive, (gchar *) &n, sizeof(n));
75 }
76 
77 static inline gboolean
serialize_read_uint32(SerializeArchive * archive,guint32 * value)78 serialize_read_uint32(SerializeArchive *archive, guint32 *value)
79 {
80   guint32 n;
81 
82   if (serialize_archive_read_bytes(archive, (gchar *) &n, sizeof(n)))
83     {
84       *value = GUINT32_FROM_BE(n);
85       return TRUE;
86     }
87   return FALSE;
88 }
89 
90 /* NOTE: this function writes to the array to convert it to big endian. It
91  * is converted back to native byte order before returning */
92 static inline gboolean
serialize_write_uint32_array(SerializeArchive * archive,guint32 * values,gsize elements)93 serialize_write_uint32_array(SerializeArchive *archive, guint32 *values, gsize elements)
94 {
95   const int buffer_size = 128;
96   guint32 converted_values[buffer_size];
97   gint converted_ndx;
98 
99   while (elements > 0)
100     {
101       for (converted_ndx = 0;
102            converted_ndx < buffer_size && converted_ndx < elements;
103            converted_ndx++)
104         converted_values[converted_ndx] = GUINT32_TO_BE(values[converted_ndx]);
105 
106       if (!serialize_archive_write_bytes(archive, (void *) converted_values, converted_ndx * sizeof(guint32)))
107         return FALSE;
108 
109       values += converted_ndx;
110       elements -= converted_ndx;
111     }
112   return TRUE;
113 }
114 
115 static inline gboolean
serialize_read_uint32_array(SerializeArchive * archive,guint32 * values,gsize elements)116 serialize_read_uint32_array(SerializeArchive *archive, guint32 *values, gsize elements)
117 {
118   if (serialize_archive_read_bytes(archive, (void *) values, elements * sizeof(guint32)))
119     {
120       for (int i = 0; i < elements; i++)
121         values[i] = GUINT32_FROM_BE(values[i]);
122       return TRUE;
123     }
124   return FALSE;
125 }
126 
127 static inline gboolean
serialize_read_uint16_array(SerializeArchive * archive,guint32 * values,gsize elements)128 serialize_read_uint16_array(SerializeArchive *archive, guint32 *values, gsize elements)
129 {
130   guint16 buffer[elements];
131 
132   if (serialize_archive_read_bytes(archive, (void *) &buffer, elements * sizeof(guint16)))
133     {
134       for (int i = 0; i < elements; i++)
135         values[i] = GUINT16_FROM_BE(buffer[i]);
136       return TRUE;
137     }
138   return FALSE;
139 }
140 
141 static inline gboolean
serialize_write_uint64(SerializeArchive * archive,guint64 value)142 serialize_write_uint64(SerializeArchive *archive, guint64 value)
143 {
144   guint64 n;
145 
146   n = GUINT64_TO_BE(value);
147   return serialize_archive_write_bytes(archive, (gchar *) &n, sizeof(n));
148 }
149 
150 static inline gboolean
serialize_read_uint64(SerializeArchive * archive,guint64 * value)151 serialize_read_uint64(SerializeArchive *archive, guint64 *value)
152 {
153   guint64 n;
154 
155   if (serialize_archive_read_bytes(archive, (gchar *) &n, sizeof(n)))
156     {
157       *value = GUINT64_FROM_BE(n);
158       return TRUE;
159     }
160   return FALSE;
161 }
162 
163 static inline gboolean
serialize_write_uint16(SerializeArchive * archive,guint16 value)164 serialize_write_uint16(SerializeArchive *archive, guint16 value)
165 {
166   guint16 n;
167 
168   n = GUINT16_TO_BE(value);
169   return serialize_archive_write_bytes(archive, (gchar *) &n, sizeof(n));
170 }
171 
172 static inline gboolean
serialize_read_uint16(SerializeArchive * archive,guint16 * value)173 serialize_read_uint16(SerializeArchive *archive, guint16 *value)
174 {
175   guint16 n;
176 
177   if (serialize_archive_read_bytes(archive, (gchar *) &n, sizeof(n)))
178     {
179       *value = GUINT16_FROM_BE(n);
180       return TRUE;
181     }
182   return FALSE;
183 }
184 
185 static inline gboolean
serialize_write_uint8(SerializeArchive * archive,guint8 value)186 serialize_write_uint8(SerializeArchive *archive, guint8 value)
187 {
188   guint8 n;
189 
190   n = value;
191   return serialize_archive_write_bytes(archive, (gchar *) &n, sizeof(n));
192 }
193 
194 static inline gboolean
serialize_read_uint8(SerializeArchive * archive,guint8 * value)195 serialize_read_uint8(SerializeArchive *archive, guint8 *value)
196 {
197   guint8 n;
198 
199   if (serialize_archive_read_bytes(archive, (gchar *) &n, sizeof(n)))
200     {
201       *value = n;
202       return TRUE;
203     }
204   return FALSE;
205 }
206 
207 
208 static inline gboolean
serialize_write_blob(SerializeArchive * archive,const void * blob,gsize len)209 serialize_write_blob(SerializeArchive *archive, const void *blob, gsize len)
210 {
211   return serialize_archive_write_bytes(archive, blob, len);
212 }
213 
214 static inline gboolean
serialize_read_blob(SerializeArchive * archive,void * blob,gsize len)215 serialize_read_blob(SerializeArchive *archive, void *blob, gsize len)
216 {
217   return serialize_archive_read_bytes(archive, blob, len);
218 }
219 
220 static inline gboolean
serialize_write_string(SerializeArchive * archive,GString * str)221 serialize_write_string(SerializeArchive *archive, GString *str)
222 {
223   return serialize_write_uint32(archive, str->len) &&
224          serialize_archive_write_bytes(archive, str->str, str->len);
225 }
226 
227 static inline gboolean
serialize_read_string(SerializeArchive * archive,GString * str)228 serialize_read_string(SerializeArchive *archive, GString *str)
229 {
230   guint32 len;
231 
232   if (serialize_read_uint32(archive, &len))
233     {
234       if (len > str->allocated_len)
235         {
236           gchar *p;
237 
238           p = g_try_realloc(str->str, len + 1);
239           if (!p)
240             return FALSE;
241           str->str = p;
242           str->str[len] = 0;
243           str->len = len;
244         }
245       else
246         g_string_set_size(str, len);
247 
248       return serialize_archive_read_bytes(archive, str->str, len);
249     }
250   return FALSE;
251 }
252 
253 static inline gboolean
serialize_write_cstring(SerializeArchive * archive,const gchar * str,gssize len)254 serialize_write_cstring(SerializeArchive *archive, const gchar *str, gssize len)
255 {
256   if (len < 0)
257     len = strlen(str);
258 
259   return serialize_write_uint32(archive, len) &&
260          (len == 0 || serialize_archive_write_bytes(archive, str, len));
261 }
262 
263 static inline gboolean
serialize_read_cstring(SerializeArchive * archive,gchar ** str,gsize * str_len)264 serialize_read_cstring(SerializeArchive *archive, gchar **str, gsize *str_len)
265 {
266   guint32 len;
267 
268   if (serialize_read_uint32(archive, &len))
269     {
270       *str = g_try_malloc(len + 1);
271 
272       if (!(*str))
273         return FALSE;
274       (*str)[len] = 0;
275       if (str_len)
276         *str_len = len;
277       return serialize_archive_read_bytes(archive, *str, len);
278     }
279   return FALSE;
280 }
281 
282 
283 SerializeArchive *serialize_file_archive_new(FILE *f);
284 SerializeArchive *serialize_string_archive_new(GString *str);
285 void serialize_string_archive_reset(SerializeArchive *sa);
286 SerializeArchive *serialize_buffer_archive_new(gchar *buff, gsize len);
287 gsize serialize_buffer_archive_get_pos(SerializeArchive *self);
288 void serialize_archive_free(SerializeArchive *self);
289 
290 #endif
291