2 Provides a serialize/unserialize functionality for INI-like formats.
4 Copyright (C) 2011-2023
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 /*** forward declarations (file scope functions) *************************************************/
51 /*** file scope variables ************************************************************************/
53 /* --------------------------------------------------------------------------------------------- */
54 /*** file scope functions ************************************************************************/
55 /* --------------------------------------------------------------------------------------------- */
59 prepend_error_message (GError
** error
, const char *format
, ...)
65 if ((error
== NULL
) || (*error
== NULL
))
68 va_start (ap
, format
);
69 prepend_str
= g_strdup_vprintf (format
, ap
);
72 split_str
= g_strdup_printf ("%s: %s", prepend_str
, (*error
)->message
);
74 g_free ((*error
)->message
);
75 (*error
)->message
= split_str
;
78 /* --------------------------------------------------------------------------------------------- */
81 go_to_end_of_serialized_string (const char *non_serialized_data
,
82 const char *already_serialized_part
, size_t * offset
)
84 size_t calculated_offset
;
85 const char *semi_ptr
= strchr (non_serialized_data
+ 1, SRLZ_DELIM_C
);
87 calculated_offset
= (semi_ptr
- non_serialized_data
) + 1 + strlen (already_serialized_part
);
88 if (calculated_offset
>= strlen (non_serialized_data
))
91 non_serialized_data
+= calculated_offset
;
92 *offset
+= calculated_offset
;
94 return non_serialized_data
;
97 /* --------------------------------------------------------------------------------------------- */
98 /*** public functions ****************************************************************************/
99 /* --------------------------------------------------------------------------------------------- */
102 * Serialize some string object to string
104 * @param prefix prefix for serialization
105 * @param data data for serialization
106 * @param error contain pointer to object for handle error code and message
108 * @return serialized data as newly allocated string
112 mc_serialize_str (const char prefix
, const char *data
, GError
** error
)
116 g_set_error (error
, MC_ERROR
, 0, "mc_serialize_str(): Input data is NULL.");
119 return g_strdup_printf ("%c%zu" SRLZ_DELIM_S
"%s", prefix
, strlen (data
), data
);
122 /* --------------------------------------------------------------------------------------------- */
124 * Deserialize string to string object
126 * @param prefix prefix for deserailization
127 * @param data data for deserialization
128 * @param error contain pointer to object for handle error code and message
130 * @return newly allocated string
133 #define FUNC_NAME "mc_serialize_str()"
135 mc_deserialize_str (const char prefix
, const char *data
, GError
** error
)
139 if ((data
== NULL
) || (*data
== '\0'))
141 g_set_error (error
, MC_ERROR
, 0, FUNC_NAME
": Input data is NULL or empty.");
147 g_set_error (error
, MC_ERROR
, 0, FUNC_NAME
": String prefix doesn't equal to '%c'", prefix
);
152 char buffer
[BUF_TINY
];
156 semi_ptr
= strchr (data
+ 1, SRLZ_DELIM_C
);
157 if (semi_ptr
== NULL
)
159 g_set_error (error
, MC_ERROR
, 0,
160 FUNC_NAME
": Length delimiter '%c' doesn't exists", SRLZ_DELIM_C
);
163 semi_offset
= semi_ptr
- (data
+ 1);
164 if (semi_offset
>= BUF_TINY
)
166 g_set_error (error
, MC_ERROR
, 0, FUNC_NAME
": Too big string length");
169 strncpy (buffer
, data
+ 1, semi_offset
);
170 buffer
[semi_offset
] = '\0';
171 data_len
= atol (buffer
);
172 data
+= semi_offset
+ 2;
175 if (data_len
> strlen (data
))
177 g_set_error (error
, MC_ERROR
, 0,
179 ": Specified data length (%zu) is greater than actual data length (%zu)",
180 data_len
, strlen (data
));
183 return g_strndup (data
, data_len
);
188 /* --------------------------------------------------------------------------------------------- */
190 * Serialize mc_config_t object to string
192 * @param data data for serialization
193 * @param error contain pointer to object for handle error code and message
195 * @return serialized data as newly allocated string
199 mc_serialize_config (mc_config_t
* data
, GError
** error
)
201 gchar
**groups
, **group_iterator
;
204 buffer
= g_string_new ("");
205 groups
= mc_config_get_groups (data
, NULL
);
207 for (group_iterator
= groups
; *group_iterator
!= NULL
; group_iterator
++)
209 char *serialized_str
;
210 gchar
**params
, **param_iterator
;
212 serialized_str
= mc_serialize_str ('g', *group_iterator
, error
);
213 if (serialized_str
== NULL
)
215 g_string_free (buffer
, TRUE
);
219 g_string_append (buffer
, serialized_str
);
220 g_free (serialized_str
);
222 params
= mc_config_get_keys (data
, *group_iterator
, NULL
);
224 for (param_iterator
= params
; *param_iterator
!= NULL
; param_iterator
++)
228 serialized_str
= mc_serialize_str ('p', *param_iterator
, error
);
229 if (serialized_str
== NULL
)
231 g_string_free (buffer
, TRUE
);
236 g_string_append (buffer
, serialized_str
);
237 g_free (serialized_str
);
239 value
= mc_config_get_string_raw (data
, *group_iterator
, *param_iterator
, "");
240 serialized_str
= mc_serialize_str ('v', value
, error
);
243 if (serialized_str
== NULL
)
245 g_string_free (buffer
, TRUE
);
251 g_string_append (buffer
, serialized_str
);
252 g_free (serialized_str
);
260 return g_string_free (buffer
, FALSE
);
263 /* --------------------------------------------------------------------------------------------- */
265 * Deserialize string to mc_config_t object
267 * @param data data for serialization
268 * @param error contain pointer to object for handle error code and message
270 * @return newly allocated mc_config_t object
273 #define FUNC_NAME "mc_deserialize_config()"
274 #define prepend_error_and_exit() { \
275 prepend_error_message (error, FUNC_NAME " at %zu", current_position + 1); \
276 mc_config_deinit (ret_data); \
281 mc_deserialize_config (const char *data
, GError
** error
)
283 char *current_group
= NULL
, *current_param
= NULL
, *current_value
= NULL
;
284 size_t current_position
= 0;
285 mc_config_t
*ret_data
;
291 } current_status
= WAIT_GROUP
;
293 ret_data
= mc_config_init (NULL
, FALSE
);
297 if ((current_status
== WAIT_GROUP
) && (*data
== 'p') && (current_group
!= NULL
))
298 current_status
= WAIT_PARAM
;
300 switch (current_status
)
303 g_free (current_group
);
305 current_group
= mc_deserialize_str ('g', data
, error
);
306 if (current_group
== NULL
)
307 prepend_error_and_exit ();
309 data
= go_to_end_of_serialized_string (data
, current_group
, ¤t_position
);
310 current_status
= WAIT_PARAM
;
313 g_free (current_param
);
315 current_param
= mc_deserialize_str ('p', data
, error
);
316 if (current_param
== NULL
)
318 g_free (current_group
);
319 prepend_error_and_exit ();
322 data
= go_to_end_of_serialized_string (data
, current_param
, ¤t_position
);
323 current_status
= WAIT_VALUE
;
326 current_value
= mc_deserialize_str ('v', data
, error
);
327 if (current_value
== NULL
)
329 g_free (current_group
);
330 g_free (current_param
);
331 prepend_error_and_exit ();
333 mc_config_set_string (ret_data
, current_group
, current_param
, current_value
);
335 data
= go_to_end_of_serialized_string (data
, current_value
, ¤t_position
);
336 g_free (current_value
);
337 current_status
= WAIT_GROUP
;
343 g_free (current_group
);
344 g_free (current_param
);
351 /* --------------------------------------------------------------------------------------------- */