2 Provides a serialize/unserialize functionality for INI-like formats.
4 Copyright (C) 2011-2014
5 Free Software Foundation, Inc.
8 Slava Zanko <slavazanko@gmail.com>, 2011
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 /** \file lib/serialize.c
27 * \brief Source: serialize/unserialize functionality for INI-like formats.
36 #include "lib/global.h"
38 #include "lib/serialize.h"
40 /*** global variables ****************************************************************************/
42 /*** file scope macro definitions ****************************************************************/
44 #define SRLZ_DELIM_C ':'
45 #define SRLZ_DELIM_S ":"
47 /*** file scope type declarations ****************************************************************/
49 /*** file scope variables ************************************************************************/
51 /*** file scope functions ************************************************************************/
52 /* --------------------------------------------------------------------------------------------- */
55 prepend_error_message (GError
** error
, const char *format
, ...)
61 if ((error
== NULL
) || (*error
== NULL
))
64 va_start (ap
, format
);
65 prepend_str
= g_strdup_vprintf (format
, ap
);
68 split_str
= g_strdup_printf ("%s: %s", prepend_str
, (*error
)->message
);
70 g_free ((*error
)->message
);
71 (*error
)->message
= split_str
;
74 /* --------------------------------------------------------------------------------------------- */
77 go_to_end_of_serialized_string (const char *non_serialized_data
,
78 const char *already_serialized_part
, size_t * offset
)
80 size_t calculated_offset
;
81 const char *semi_ptr
= strchr (non_serialized_data
+ 1, SRLZ_DELIM_C
);
83 calculated_offset
= (semi_ptr
- non_serialized_data
) + 1 + strlen (already_serialized_part
);
84 if (calculated_offset
>= strlen (non_serialized_data
))
87 non_serialized_data
+= calculated_offset
;
88 *offset
+= calculated_offset
;
90 return non_serialized_data
;
93 /* --------------------------------------------------------------------------------------------- */
94 /*** public functions ****************************************************************************/
95 /* --------------------------------------------------------------------------------------------- */
98 * Serialize some string object to string
100 * @param prefix prefix for serailization
101 * @param data data for serialization
102 * @param error contain pointer to object for handle error code and message
104 * @return serialized data as newly allocated string
108 mc_serialize_str (const char prefix
, const char *data
, GError
** error
)
112 g_set_error (error
, MC_ERROR
, -1, "mc_serialize_str(): Input data is NULL.");
115 return g_strdup_printf ("%c%zd" SRLZ_DELIM_S
"%s", prefix
, strlen (data
), data
);
118 /* --------------------------------------------------------------------------------------------- */
120 * Deserialize string to string object
122 * @param prefix prefix for deserailization
123 * @param data data for deserialization
124 * @param error contain pointer to object for handle error code and message
126 * @return newly allocated string
129 #define FUNC_NAME "mc_serialize_str()"
131 mc_deserialize_str (const char prefix
, const char *data
, GError
** error
)
135 if ((data
== NULL
) || (strlen (data
) == 0))
137 g_set_error (error
, MC_ERROR
, -1, FUNC_NAME
": Input data is NULL or empty.");
143 g_set_error (error
, MC_ERROR
, -2, FUNC_NAME
": String prefix doesn't equal to '%c'",
149 char buffer
[BUF_TINY
];
153 semi_ptr
= strchr (data
+ 1, SRLZ_DELIM_C
);
154 if (semi_ptr
== NULL
)
156 g_set_error (error
, MC_ERROR
, -3,
157 FUNC_NAME
": Length delimiter '%c' doesn't exists", SRLZ_DELIM_C
);
160 semi_offset
= semi_ptr
- (data
+ 1);
161 if (semi_offset
>= BUF_TINY
)
163 g_set_error (error
, MC_ERROR
, -3, FUNC_NAME
": Too big string length");
166 strncpy (buffer
, data
+ 1, semi_offset
);
167 buffer
[semi_offset
] = '\0';
168 data_len
= atol (buffer
);
169 data
+= semi_offset
+ 2;
172 if (data_len
> strlen (data
))
174 g_set_error (error
, MC_ERROR
, -3,
176 ": Specified data length (%zd) is greater than actual data length (%zd)",
177 data_len
, strlen (data
));
180 return g_strndup (data
, data_len
);
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
196 mc_serialize_config (const mc_config_t
* data
, GError
** error
)
198 gchar
**groups
, **group_iterator
;
201 buffer
= g_string_new ("");
202 groups
= mc_config_get_groups (data
, NULL
);
204 for (group_iterator
= groups
; *group_iterator
!= NULL
; group_iterator
++)
206 char *serialized_str
;
207 gchar
**params
, **param_iterator
;
209 serialized_str
= mc_serialize_str ('g', *group_iterator
, error
);
210 if (serialized_str
== NULL
)
212 g_string_free (buffer
, TRUE
);
216 g_string_append (buffer
, serialized_str
);
217 g_free (serialized_str
);
219 params
= mc_config_get_keys (data
, *group_iterator
, NULL
);
221 for (param_iterator
= params
; *param_iterator
!= NULL
; param_iterator
++)
225 serialized_str
= mc_serialize_str ('p', *param_iterator
, error
);
226 if (serialized_str
== NULL
)
228 g_string_free (buffer
, TRUE
);
233 g_string_append (buffer
, serialized_str
);
234 g_free (serialized_str
);
236 value
= mc_config_get_string_raw (data
, *group_iterator
, *param_iterator
, "");
237 serialized_str
= mc_serialize_str ('v', value
, error
);
240 if (serialized_str
== NULL
)
242 g_string_free (buffer
, TRUE
);
248 g_string_append (buffer
, serialized_str
);
249 g_free (serialized_str
);
254 return g_string_free (buffer
, FALSE
);
257 /* --------------------------------------------------------------------------------------------- */
259 * Deserialize string to mc_config_t object
261 * @param data data for serialization
262 * @param error contain pointer to object for handle error code and message
264 * @return newly allocated mc_config_t object
267 #define FUNC_NAME "mc_deserialize_config()"
268 #define prepend_error_and_exit() { \
269 prepend_error_message (error, FUNC_NAME " at %lu", current_position + 1); \
270 mc_config_deinit (ret_data); \
275 mc_deserialize_config (const char *data
, GError
** error
)
277 char *current_group
= NULL
, *current_param
= NULL
, *current_value
= NULL
;
278 size_t current_position
= 0;
279 mc_config_t
*ret_data
;
285 } current_status
= WAIT_GROUP
;
287 ret_data
= mc_config_init (NULL
, FALSE
);
291 if ((current_status
== WAIT_GROUP
) && (*data
== 'p') && (current_group
!= NULL
))
292 current_status
= WAIT_PARAM
;
294 switch (current_status
)
297 g_free (current_group
);
299 current_group
= mc_deserialize_str ('g', data
, error
);
300 if (current_group
== NULL
)
301 prepend_error_and_exit ();
303 data
= go_to_end_of_serialized_string (data
, current_group
, ¤t_position
);
304 current_status
= WAIT_PARAM
;
307 g_free (current_param
);
309 current_param
= mc_deserialize_str ('p', data
, error
);
310 if (current_param
== NULL
)
312 g_free (current_group
);
313 prepend_error_and_exit ();
316 data
= go_to_end_of_serialized_string (data
, current_param
, ¤t_position
);
317 current_status
= WAIT_VALUE
;
320 current_value
= mc_deserialize_str ('v', data
, error
);
321 if (current_value
== NULL
)
323 g_free (current_group
);
324 g_free (current_param
);
325 prepend_error_and_exit ();
327 mc_config_set_string (ret_data
, current_group
, current_param
, current_value
);
329 data
= go_to_end_of_serialized_string (data
, current_value
, ¤t_position
);
330 g_free (current_value
);
331 current_status
= WAIT_GROUP
;
335 g_free (current_group
);
336 g_free (current_param
);
343 /* --------------------------------------------------------------------------------------------- */