2 Provides a serialize/unserialize functionality for INI-like formats.
4 Copyright (C) 2011 Free Software Foundation, Inc.
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,
28 * \brief Source: serialize/unserialize functionality for INI-like formats.
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 /* --------------------------------------------------------------------------------------------- */
56 prepend_error_message (GError
** error
, const char *format
, ...)
62 if ((error
== NULL
) || (*error
== NULL
))
65 va_start (ap
, format
);
66 prepend_str
= g_strdup_vprintf (format
, ap
);
69 split_str
= g_strdup_printf ("%s: %s", prepend_str
, (*error
)->message
);
71 g_free ((*error
)->message
);
72 (*error
)->message
= split_str
;
75 /* --------------------------------------------------------------------------------------------- */
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
))
88 non_serialized_data
+= calculated_offset
;
89 *offset
+= calculated_offset
;
91 return non_serialized_data
;
94 /* --------------------------------------------------------------------------------------------- */
95 /*** public functions ****************************************************************************/
96 /* --------------------------------------------------------------------------------------------- */
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
109 mc_serialize_str (const char prefix
, const char *data
, GError
** error
)
113 g_set_error (error
, MC_ERROR
, -1, "mc_serialize_str(): Input data is 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()"
132 mc_deserialize_str (const char prefix
, const char *data
, GError
** error
)
136 if ((data
== NULL
) || (strlen (data
) == 0))
138 g_set_error (error
, MC_ERROR
, -1, FUNC_NAME
": Input data is NULL or empty.");
144 g_set_error (error
, MC_ERROR
, -2, FUNC_NAME
": String prefix doesn't equal to '%c'",
150 char buffer
[BUF_TINY
];
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
);
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");
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
));
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
;
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
;
211 serialized_str
= mc_serialize_str ('g', *group_iterator
, error
);
212 if (serialized_str
== NULL
)
214 g_string_free (buffer
, TRUE
);
218 g_string_append (buffer
, serialized_str
);
219 g_free (serialized_str
);
221 param_iterator
= params
= mc_config_get_keys (data
, *group_iterator
, ¶m_count
);
223 while (param_count
-- != 0)
226 serialized_str
= mc_serialize_str ('p', *param_iterator
, error
);
227 if (serialized_str
== NULL
)
229 g_string_free (buffer
, TRUE
);
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
);
241 if (serialized_str
== NULL
)
243 g_string_free (buffer
, TRUE
);
249 g_string_append (buffer
, serialized_str
);
250 g_free (serialized_str
);
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); \
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
);
290 } current_status
= WAIT_GROUP
;
294 if ((current_status
== WAIT_GROUP
) && (*data
== 'p') && (current_group
!= NULL
))
295 current_status
= WAIT_PARAM
;
297 switch (current_status
)
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
, ¤t_position
);
307 current_status
= 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
, ¤t_position
);
320 current_status
= 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
, ¤t_position
);
333 g_free (current_value
);
334 current_status
= WAIT_GROUP
;
338 g_free (current_group
);
339 g_free (current_param
);
346 /* --------------------------------------------------------------------------------------------- */