Merge branch '2591_editor_bottom_line_click'
[midnight-commander.git] / lib / serialize.c
blobef0da1435af722d96eafcc6be79c33e6b6c5e2d6
1 /*
2 Provides a serialize/unserialize functionality for INI-like formats.
4 Copyright (C) 2011 Free Software Foundation, Inc.
6 Written:
7 2011 Slava Zanko <slavazanko@gmail.com>.
9 This file is part of the Midnight Commander.
11 The Midnight Commander is free software; you can redistribute it
12 and/or modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation; either version 2 of the
14 License, or (at your option) any later version.
16 The Midnight Commander is distributed in the hope that it will be
17 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
18 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
24 MA 02110-1301, USA.
27 /** \file serialize.c
28 * \brief Source: serialize/unserialize functionality for INI-like formats.
31 #include <config.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <stdarg.h>
37 #include "lib/global.h"
39 #include "lib/serialize.h"
41 /*** global variables ****************************************************************************/
43 /*** file scope macro definitions ****************************************************************/
45 #define SRLZ_DELIM_C ':'
46 #define SRLZ_DELIM_S ":"
48 /*** file scope type declarations ****************************************************************/
50 /*** file scope variables ************************************************************************/
52 /*** file scope functions ************************************************************************/
53 /* --------------------------------------------------------------------------------------------- */
55 static void
56 prepend_error_message (GError ** error, const char *format, ...)
58 char *prepend_str;
59 char *split_str;
60 va_list ap;
62 if ((error == NULL) || (*error == NULL))
63 return;
65 va_start (ap, format);
66 prepend_str = g_strdup_vprintf (format, ap);
67 va_end (ap);
69 split_str = g_strdup_printf ("%s: %s", prepend_str, (*error)->message);
70 g_free (prepend_str);
71 g_free ((*error)->message);
72 (*error)->message = split_str;
75 /* --------------------------------------------------------------------------------------------- */
77 static const char *
78 go_to_end_of_serialized_string (const char *non_serialized_data,
79 const char *already_serialized_part, size_t * offset)
81 size_t calculated_offset;
82 const char *semi_ptr = strchr (non_serialized_data + 1, SRLZ_DELIM_C);
84 calculated_offset = (semi_ptr - non_serialized_data) + 1 + strlen (already_serialized_part);
85 if (calculated_offset >= strlen (non_serialized_data))
86 return NULL;
88 non_serialized_data += calculated_offset;
89 *offset += calculated_offset;
91 return non_serialized_data;
94 /* --------------------------------------------------------------------------------------------- */
95 /*** public functions ****************************************************************************/
96 /* --------------------------------------------------------------------------------------------- */
98 /**
99 * Serialize some string object to string
101 * @param prefix prefix for serailization
102 * @param data data for serialization
103 * @param error contain pointer to object for handle error code and message
105 * @return serialized data as newly allocated string
108 char *
109 mc_serialize_str (const char prefix, const char *data, GError ** error)
111 if (data == NULL)
113 g_set_error (error, MC_ERROR, -1, "mc_serialize_str(): Input data is NULL.");
114 return NULL;
116 return g_strdup_printf ("%c%zd" SRLZ_DELIM_S "%s", prefix, strlen (data), data);
119 /* --------------------------------------------------------------------------------------------- */
121 * Deserialize string to string object
123 * @param prefix prefix for deserailization
124 * @param data data for deserialization
125 * @param error contain pointer to object for handle error code and message
127 * @return newly allocated string
130 #define FUNC_NAME "mc_serialize_str()"
131 char *
132 mc_deserialize_str (const char prefix, const char *data, GError ** error)
134 size_t data_len;
136 if ((data == NULL) || (strlen (data) == 0))
138 g_set_error (error, MC_ERROR, -1, FUNC_NAME ": Input data is NULL or empty.");
139 return NULL;
142 if (*data != prefix)
144 g_set_error (error, MC_ERROR, -2, FUNC_NAME ": String prefix doesn't equal to '%c'",
145 prefix);
146 return NULL;
150 char buffer[BUF_TINY];
151 char *semi_ptr;
152 size_t semi_offset;
154 semi_ptr = strchr (data + 1, SRLZ_DELIM_C);
155 if (semi_ptr == NULL)
157 g_set_error (error, MC_ERROR, -3,
158 FUNC_NAME ": Length delimiter '%c' doesn't exists", SRLZ_DELIM_C);
159 return NULL;
161 semi_offset = semi_ptr - (data + 1);
162 if (semi_offset >= BUF_TINY)
164 g_set_error (error, MC_ERROR, -3, FUNC_NAME ": Too big string length");
165 return NULL;
167 strncpy (buffer, data + 1, semi_offset);
168 buffer[semi_offset] = '\0';
169 data_len = atol (buffer);
170 data += semi_offset + 2;
173 if (data_len > strlen (data))
175 g_set_error (error, MC_ERROR, -3,
176 FUNC_NAME ": Specified data length (%zd) is greater than actual data length (%zd)",
177 data_len, strlen (data));
178 return NULL;
180 return g_strndup (data, data_len);
183 #undef FUNC_NAME
185 /* --------------------------------------------------------------------------------------------- */
187 * Serialize mc_config_t object to string
189 * @param data data for serialization
190 * @param error contain pointer to object for handle error code and message
192 * @return serialized data as newly allocated string
195 char *
196 mc_serialize_config (const mc_config_t * data, GError ** error)
198 gchar **groups, **group_iterator;
199 size_t group_count;
200 GString *buffer;
202 buffer = g_string_new ("");
203 group_iterator = groups = mc_config_get_groups (data, &group_count);
205 while (group_count-- != 0)
207 char *serialized_str;
208 gchar **params, **param_iterator;
209 size_t param_count;
211 serialized_str = mc_serialize_str ('g', *group_iterator, error);
212 if (serialized_str == NULL)
214 g_string_free (buffer, TRUE);
215 g_strfreev (groups);
216 return NULL;
218 g_string_append (buffer, serialized_str);
219 g_free (serialized_str);
221 param_iterator = params = mc_config_get_keys (data, *group_iterator, &param_count);
223 while (param_count-- != 0)
225 char *value;
226 serialized_str = mc_serialize_str ('p', *param_iterator, error);
227 if (serialized_str == NULL)
229 g_string_free (buffer, TRUE);
230 g_strfreev (params);
231 g_strfreev (groups);
232 return NULL;
234 g_string_append (buffer, serialized_str);
235 g_free (serialized_str);
237 value = mc_config_get_string_raw (data, *group_iterator, *param_iterator, "");
238 serialized_str = mc_serialize_str ('v', value, error);
239 g_free (value);
241 if (serialized_str == NULL)
243 g_string_free (buffer, TRUE);
244 g_strfreev (params);
245 g_strfreev (groups);
246 return NULL;
249 g_string_append (buffer, serialized_str);
250 g_free (serialized_str);
252 param_iterator++;
255 g_strfreev (params);
257 group_iterator++;
259 return g_string_free (buffer, FALSE);
262 /* --------------------------------------------------------------------------------------------- */
264 * Deserialize string to mc_config_t object
266 * @param data data for serialization
267 * @param error contain pointer to object for handle error code and message
269 * @return newly allocated mc_config_t object
272 #define FUNC_NAME "mc_deserialize_config()"
273 #define prepend_error_and_exit() { \
274 prepend_error_message (error, FUNC_NAME " at %lu", current_position + 1); \
275 mc_config_deinit (ret_data); \
276 return NULL; \
279 mc_config_t *
280 mc_deserialize_config (const char *data, GError ** error)
282 char *current_group = NULL, *current_param = NULL, *current_value = NULL;
283 size_t current_position = 0;
284 mc_config_t *ret_data = mc_config_init (NULL);
285 enum automat_status
287 WAIT_GROUP,
288 WAIT_PARAM,
289 WAIT_VALUE
290 } current_status = WAIT_GROUP;
292 while (data != NULL)
294 if ((current_status == WAIT_GROUP) && (*data == 'p') && (current_group != NULL))
295 current_status = WAIT_PARAM;
297 switch (current_status)
299 case WAIT_GROUP:
300 g_free (current_group);
302 current_group = mc_deserialize_str ('g', data, error);
303 if (current_group == NULL)
304 prepend_error_and_exit ();
306 data = go_to_end_of_serialized_string (data, current_group, &current_position);
307 current_status = WAIT_PARAM;
308 break;
309 case WAIT_PARAM:
310 g_free (current_param);
312 current_param = mc_deserialize_str ('p', data, error);
313 if (current_param == NULL)
315 g_free (current_group);
316 prepend_error_and_exit ();
319 data = go_to_end_of_serialized_string (data, current_param, &current_position);
320 current_status = WAIT_VALUE;
321 break;
322 case WAIT_VALUE:
323 current_value = mc_deserialize_str ('v', data, error);
324 if (current_param == NULL)
326 g_free (current_group);
327 g_free (current_param);
328 prepend_error_and_exit ();
330 mc_config_set_string (ret_data, current_group, current_param, current_value);
332 data = go_to_end_of_serialized_string (data, current_value, &current_position);
333 g_free (current_value);
334 current_status = WAIT_GROUP;
335 break;
338 g_free (current_group);
339 g_free (current_param);
341 return ret_data;
344 #undef FUNC_NAME
346 /* --------------------------------------------------------------------------------------------- */