2 Provides a serialize/unserialize functionality for INI-like formats.
5 The 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/>.
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
;
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_value
== 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 /* --------------------------------------------------------------------------------------------- */