| File: | ctk/ctktextbufferserialize.c |
| Warning: | line 453, column 22 Access to field 'data' results in a dereference of a null pointer (loaded from variable 'active_tags') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* ctktextbufferserialize.c | |||
| 2 | * | |||
| 3 | * Copyright (C) 2001 Havoc Pennington | |||
| 4 | * Copyright (C) 2004 Nokia Corporation | |||
| 5 | * | |||
| 6 | * This library is free software; you can redistribute it and/or | |||
| 7 | * modify it under the terms of the GNU Library General Public | |||
| 8 | * License as published by the Free Software Foundation; either | |||
| 9 | * version 2 of the License, or (at your option) any later version. | |||
| 10 | * | |||
| 11 | * This library is distributed in the hope that it will be useful, | |||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| 14 | * Library General Public License for more details. | |||
| 15 | * | |||
| 16 | * You should have received a copy of the GNU Library General Public | |||
| 17 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
| 18 | */ | |||
| 19 | ||||
| 20 | /* FIXME: We should use other error codes for the | |||
| 21 | * parts that deal with the format errors | |||
| 22 | */ | |||
| 23 | ||||
| 24 | #include "config.h" | |||
| 25 | ||||
| 26 | #include <stdio.h> | |||
| 27 | #include <string.h> | |||
| 28 | #include <stdlib.h> | |||
| 29 | #include <errno(*__errno_location ()).h> | |||
| 30 | ||||
| 31 | #include "gdk-pixbuf/gdk-pixdata.h" | |||
| 32 | #include "ctktextbufferserialize.h" | |||
| 33 | #include "ctktexttagprivate.h" | |||
| 34 | #include "ctkintl.h" | |||
| 35 | ||||
| 36 | ||||
| 37 | typedef struct | |||
| 38 | { | |||
| 39 | GString *tag_table_str; | |||
| 40 | GString *text_str; | |||
| 41 | GHashTable *tags; | |||
| 42 | CtkTextIter start, end; | |||
| 43 | ||||
| 44 | gint n_pixbufs; | |||
| 45 | GList *pixbufs; | |||
| 46 | gint tag_id; | |||
| 47 | GHashTable *tag_id_tags; | |||
| 48 | } SerializationContext; | |||
| 49 | ||||
| 50 | static gchar * | |||
| 51 | serialize_value (GValue *value) | |||
| 52 | { | |||
| 53 | G_GNUC_BEGIN_IGNORE_DEPRECATIONSclang diagnostic push
clang diagnostic ignored "-Wdeprecated-declarations" | |||
| 54 | if (g_value_type_transformable (value->g_type, G_TYPE_STRING((GType) ((16) << (2))))) | |||
| 55 | { | |||
| 56 | GValue text_value = G_VALUE_INIT{ 0, { { 0 } } }; | |||
| 57 | gchar *tmp; | |||
| 58 | ||||
| 59 | g_value_init (&text_value, G_TYPE_STRING((GType) ((16) << (2)))); | |||
| 60 | g_value_transform (value, &text_value); | |||
| 61 | ||||
| 62 | tmp = g_markup_escape_text (g_value_get_string (&text_value), -1); | |||
| 63 | g_value_unset (&text_value); | |||
| 64 | ||||
| 65 | return tmp; | |||
| 66 | } | |||
| 67 | else if (value->g_type == CDK_TYPE_COLOR(cdk_color_get_type ())) | |||
| 68 | { | |||
| 69 | CdkColor *color = g_value_get_boxed (value); | |||
| 70 | ||||
| 71 | return g_strdup_printf ("%x:%x:%x", color->red, color->green, color->blue); | |||
| 72 | } | |||
| 73 | else | |||
| 74 | { | |||
| 75 | g_warning ("Type %s is not serializable", g_type_name (value->g_type)); | |||
| 76 | } | |||
| 77 | G_GNUC_END_IGNORE_DEPRECATIONSclang diagnostic pop | |||
| 78 | ||||
| 79 | return NULL((void*)0); | |||
| 80 | } | |||
| 81 | ||||
| 82 | static gboolean | |||
| 83 | deserialize_value (const gchar *str, | |||
| 84 | GValue *value) | |||
| 85 | { | |||
| 86 | G_GNUC_BEGIN_IGNORE_DEPRECATIONSclang diagnostic push
clang diagnostic ignored "-Wdeprecated-declarations" | |||
| 87 | if (g_value_type_transformable (G_TYPE_STRING((GType) ((16) << (2))), value->g_type)) | |||
| 88 | { | |||
| 89 | GValue text_value = G_VALUE_INIT{ 0, { { 0 } } }; | |||
| 90 | gboolean retval; | |||
| 91 | ||||
| 92 | g_value_init (&text_value, G_TYPE_STRING((GType) ((16) << (2)))); | |||
| 93 | g_value_set_static_string (&text_value, str); | |||
| 94 | ||||
| 95 | retval = g_value_transform (&text_value, value); | |||
| 96 | g_value_unset (&text_value); | |||
| 97 | ||||
| 98 | return retval; | |||
| 99 | } | |||
| 100 | else if (value->g_type == G_TYPE_BOOLEAN((GType) ((5) << (2)))) | |||
| 101 | { | |||
| 102 | gboolean v; | |||
| 103 | ||||
| 104 | v = strcmp (str, "TRUE") == 0; | |||
| 105 | ||||
| 106 | g_value_set_boolean (value, v); | |||
| 107 | ||||
| 108 | return TRUE(!(0)); | |||
| 109 | } | |||
| 110 | else if (value->g_type == G_TYPE_INT((GType) ((6) << (2)))) | |||
| 111 | { | |||
| 112 | gchar *tmp; | |||
| 113 | int v; | |||
| 114 | ||||
| 115 | errno(*__errno_location ()) = 0; | |||
| 116 | v = g_ascii_strtoll (str, &tmp, 10); | |||
| 117 | ||||
| 118 | if (errno(*__errno_location ()) || tmp == NULL((void*)0) || tmp == str) | |||
| 119 | return FALSE(0); | |||
| 120 | ||||
| 121 | g_value_set_int (value, v); | |||
| 122 | ||||
| 123 | return TRUE(!(0)); | |||
| 124 | } | |||
| 125 | else if (value->g_type == G_TYPE_DOUBLE((GType) ((15) << (2)))) | |||
| 126 | { | |||
| 127 | gchar *tmp; | |||
| 128 | gdouble v; | |||
| 129 | ||||
| 130 | v = g_ascii_strtod (str, &tmp); | |||
| 131 | ||||
| 132 | if (tmp == NULL((void*)0) || tmp == str) | |||
| 133 | return FALSE(0); | |||
| 134 | ||||
| 135 | g_value_set_double (value, v); | |||
| 136 | ||||
| 137 | return TRUE(!(0)); | |||
| 138 | } | |||
| 139 | else if (value->g_type == CDK_TYPE_COLOR(cdk_color_get_type ())) | |||
| 140 | { | |||
| 141 | CdkColor color; | |||
| 142 | const gchar *old; | |||
| 143 | gchar *tmp; | |||
| 144 | ||||
| 145 | old = str; | |||
| 146 | tmp = NULL((void*)0); | |||
| 147 | errno(*__errno_location ()) = 0; | |||
| 148 | color.red = g_ascii_strtoll (old, &tmp, 16); | |||
| 149 | ||||
| 150 | if (errno(*__errno_location ()) || tmp == old) | |||
| 151 | return FALSE(0); | |||
| 152 | ||||
| 153 | old = tmp; | |||
| 154 | if (*old++ != ':') | |||
| 155 | return FALSE(0); | |||
| 156 | ||||
| 157 | tmp = NULL((void*)0); | |||
| 158 | errno(*__errno_location ()) = 0; | |||
| 159 | color.green = g_ascii_strtoll (old, &tmp, 16); | |||
| 160 | if (errno(*__errno_location ()) || tmp == old) | |||
| 161 | return FALSE(0); | |||
| 162 | ||||
| 163 | old = tmp; | |||
| 164 | if (*old++ != ':') | |||
| 165 | return FALSE(0); | |||
| 166 | ||||
| 167 | tmp = NULL((void*)0); | |||
| 168 | errno(*__errno_location ()) = 0; | |||
| 169 | color.blue = g_ascii_strtoll (old, &tmp, 16); | |||
| 170 | ||||
| 171 | if (errno(*__errno_location ()) || tmp == old || *tmp != '\0') | |||
| 172 | return FALSE(0); | |||
| 173 | ||||
| 174 | g_value_set_boxed (value, &color); | |||
| 175 | ||||
| 176 | return TRUE(!(0)); | |||
| 177 | } | |||
| 178 | else if (G_VALUE_HOLDS_ENUM (value)(((__extension__ ({ const GValue *__val = (const GValue*) ((value )); GType __t = (((GType) ((12) << (2)))); gboolean __r ; if (!__val) __r = (0); else if (__val->g_type == __t) __r = (!(0)); else __r = g_type_check_value_holds (__val, __t); __r ; }))))) | |||
| 179 | { | |||
| 180 | GEnumClass *class = G_ENUM_CLASS (g_type_class_peek (value->g_type))((((GEnumClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((g_type_class_peek (value->g_type))), (((GType) ((12) << (2)))))))); | |||
| 181 | GEnumValue *enum_value; | |||
| 182 | ||||
| 183 | enum_value = g_enum_get_value_by_name (class, str); | |||
| 184 | ||||
| 185 | if (enum_value) | |||
| 186 | { | |||
| 187 | g_value_set_enum (value, enum_value->value); | |||
| 188 | return TRUE(!(0)); | |||
| 189 | } | |||
| 190 | ||||
| 191 | return FALSE(0); | |||
| 192 | } | |||
| 193 | else | |||
| 194 | { | |||
| 195 | g_warning ("Type %s can not be deserialized", g_type_name (value->g_type)); | |||
| 196 | } | |||
| 197 | G_GNUC_END_IGNORE_DEPRECATIONSclang diagnostic pop | |||
| 198 | ||||
| 199 | return FALSE(0); | |||
| 200 | } | |||
| 201 | ||||
| 202 | /* Checks if a param is set, or if it's the default value */ | |||
| 203 | static gboolean | |||
| 204 | is_param_set (GObject *object, | |||
| 205 | GParamSpec *pspec, | |||
| 206 | GValue *value) | |||
| 207 | { | |||
| 208 | /* We need to special case some attributes here */ | |||
| 209 | if (strcmp (pspec->name, "background-cdk") == 0) | |||
| 210 | { | |||
| 211 | gboolean is_set; | |||
| 212 | ||||
| 213 | g_object_get (object, "background-set", &is_set, NULL((void*)0)); | |||
| 214 | ||||
| 215 | if (is_set) | |||
| 216 | { | |||
| 217 | g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec)(((((GParamSpec*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((pspec)), (((GType) ((19) << (2))))))))->value_type )); | |||
| 218 | ||||
| 219 | g_object_get_property (object, pspec->name, value); | |||
| 220 | ||||
| 221 | return TRUE(!(0)); | |||
| 222 | } | |||
| 223 | ||||
| 224 | return FALSE(0); | |||
| 225 | } | |||
| 226 | else if (strcmp (pspec->name, "foreground-cdk") == 0) | |||
| 227 | { | |||
| 228 | gboolean is_set; | |||
| 229 | ||||
| 230 | g_object_get (object, "foreground-set", &is_set, NULL((void*)0)); | |||
| 231 | ||||
| 232 | if (is_set) | |||
| 233 | { | |||
| 234 | g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec)(((((GParamSpec*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((pspec)), (((GType) ((19) << (2))))))))->value_type )); | |||
| 235 | ||||
| 236 | g_object_get_property (object, pspec->name, value); | |||
| 237 | ||||
| 238 | return TRUE(!(0)); | |||
| 239 | } | |||
| 240 | ||||
| 241 | return FALSE(0); | |||
| 242 | } | |||
| 243 | else | |||
| 244 | { | |||
| 245 | gboolean is_set; | |||
| 246 | gchar *is_set_name; | |||
| 247 | ||||
| 248 | is_set_name = g_strdup_printf ("%s-set", pspec->name); | |||
| 249 | ||||
| 250 | if (g_object_class_find_property (G_OBJECT_GET_CLASS (object)((((GObjectClass*) (((GTypeInstance*) ((object)))->g_class )))), is_set_name) == NULL((void*)0)) | |||
| 251 | { | |||
| 252 | g_free (is_set_name); | |||
| 253 | return FALSE(0); | |||
| 254 | } | |||
| 255 | else | |||
| 256 | { | |||
| 257 | g_object_get (object, is_set_name, &is_set, NULL((void*)0)); | |||
| 258 | ||||
| 259 | if (!is_set) | |||
| 260 | { | |||
| 261 | g_free (is_set_name); | |||
| 262 | return FALSE(0); | |||
| 263 | } | |||
| 264 | ||||
| 265 | g_free (is_set_name); | |||
| 266 | ||||
| 267 | g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec)(((((GParamSpec*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((pspec)), (((GType) ((19) << (2))))))))->value_type )); | |||
| 268 | ||||
| 269 | g_object_get_property (object, pspec->name, value); | |||
| 270 | ||||
| 271 | if (g_param_value_defaults (pspec, value)) | |||
| 272 | { | |||
| 273 | g_value_unset (value); | |||
| 274 | ||||
| 275 | return FALSE(0); | |||
| 276 | } | |||
| 277 | } | |||
| 278 | return TRUE(!(0)); | |||
| 279 | } | |||
| 280 | } | |||
| 281 | ||||
| 282 | static void | |||
| 283 | serialize_tag (gpointer key G_GNUC_UNUSED__attribute__ ((__unused__)), | |||
| 284 | gpointer data, | |||
| 285 | gpointer user_data) | |||
| 286 | { | |||
| 287 | SerializationContext *context = user_data; | |||
| 288 | CtkTextTag *tag = data; | |||
| 289 | gchar *tag_name; | |||
| 290 | gint tag_id; | |||
| 291 | GParamSpec **pspecs; | |||
| 292 | guint n_pspecs; | |||
| 293 | int i; | |||
| 294 | ||||
| 295 | g_string_append (context->tag_table_str, " <tag ")(__builtin_constant_p (" <tag ") ? __extension__ ({ const char * const __val = (" <tag "); g_string_append_len_inline (context->tag_table_str, __val, (__val != ((void*)0)) ? ( gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (context->tag_table_str, " <tag ", (gssize) -1)); | |||
| 296 | ||||
| 297 | /* Handle anonymous tags */ | |||
| 298 | if (tag->priv->name) | |||
| 299 | { | |||
| 300 | tag_name = g_markup_escape_text (tag->priv->name, -1); | |||
| 301 | g_string_append_printf (context->tag_table_str, "name=\"%s\"", tag_name); | |||
| 302 | g_free (tag_name); | |||
| 303 | } | |||
| 304 | else | |||
| 305 | { | |||
| 306 | tag_id = GPOINTER_TO_INT (g_hash_table_lookup (context->tag_id_tags, tag))((gint) (glong) (g_hash_table_lookup (context->tag_id_tags , tag))); | |||
| 307 | ||||
| 308 | g_string_append_printf (context->tag_table_str, "id=\"%d\"", tag_id); | |||
| 309 | } | |||
| 310 | ||||
| 311 | g_string_append_printf (context->tag_table_str, " priority=\"%d\">\n", tag->priv->priority); | |||
| 312 | ||||
| 313 | /* Serialize properties */ | |||
| 314 | pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (tag)((((GObjectClass*) (((GTypeInstance*) ((tag)))->g_class))) ), &n_pspecs); | |||
| 315 | ||||
| 316 | for (i = 0; i < n_pspecs; i++) | |||
| 317 | { | |||
| 318 | GValue value = G_VALUE_INIT{ 0, { { 0 } } }; | |||
| 319 | gchar *tmp, *tmp2; | |||
| 320 | ||||
| 321 | if (!(pspecs[i]->flags & G_PARAM_READABLE) || | |||
| 322 | !(pspecs[i]->flags & G_PARAM_WRITABLE)) | |||
| 323 | continue; | |||
| 324 | ||||
| 325 | if (!is_param_set (G_OBJECT (tag)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((tag)), (((GType) ((20) << (2)))))))), pspecs[i], &value)) | |||
| 326 | continue; | |||
| 327 | ||||
| 328 | /* Now serialize the attr */ | |||
| 329 | tmp2 = serialize_value (&value); | |||
| 330 | ||||
| 331 | if (tmp2) | |||
| 332 | { | |||
| 333 | tmp = g_markup_escape_text (pspecs[i]->name, -1); | |||
| 334 | g_string_append_printf (context->tag_table_str, " <attr name=\"%s\" ", tmp); | |||
| 335 | g_free (tmp); | |||
| 336 | ||||
| 337 | tmp = g_markup_escape_text (g_type_name (pspecs[i]->value_type), -1); | |||
| 338 | g_string_append_printf (context->tag_table_str, "type=\"%s\" value=\"%s\" />\n", tmp, tmp2); | |||
| 339 | ||||
| 340 | g_free (tmp); | |||
| 341 | g_free (tmp2); | |||
| 342 | } | |||
| 343 | ||||
| 344 | g_value_unset (&value); | |||
| 345 | } | |||
| 346 | ||||
| 347 | g_free (pspecs); | |||
| 348 | ||||
| 349 | g_string_append (context->tag_table_str, " </tag>\n")(__builtin_constant_p (" </tag>\n") ? __extension__ ({ const char * const __val = (" </tag>\n"); g_string_append_len_inline (context->tag_table_str, __val, (__val != ((void*)0)) ? ( gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (context->tag_table_str, " </tag>\n", (gssize) -1) ); | |||
| 350 | } | |||
| 351 | ||||
| 352 | static void | |||
| 353 | serialize_tags (SerializationContext *context) | |||
| 354 | { | |||
| 355 | g_string_append (context->tag_table_str, " <text_view_markup>\n")(__builtin_constant_p (" <text_view_markup>\n") ? __extension__ ({ const char * const __val = (" <text_view_markup>\n" ); g_string_append_len_inline (context->tag_table_str, __val , (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val ))) : (gssize) -1); }) : g_string_append_len_inline (context-> tag_table_str, " <text_view_markup>\n", (gssize) -1)); | |||
| 356 | g_string_append (context->tag_table_str, " <tags>\n")(__builtin_constant_p (" <tags>\n") ? __extension__ ({ const char * const __val = (" <tags>\n"); g_string_append_len_inline (context->tag_table_str, __val, (__val != ((void*)0)) ? ( gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (context->tag_table_str, " <tags>\n", (gssize) -1)); | |||
| 357 | g_hash_table_foreach (context->tags, serialize_tag, context); | |||
| 358 | g_string_append (context->tag_table_str, " </tags>\n")(__builtin_constant_p (" </tags>\n") ? __extension__ ({ const char * const __val = (" </tags>\n"); g_string_append_len_inline (context->tag_table_str, __val, (__val != ((void*)0)) ? ( gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (context->tag_table_str, " </tags>\n", (gssize) -1) ); | |||
| 359 | } | |||
| 360 | ||||
| 361 | static void | |||
| 362 | find_list_delta (GSList *old_list, | |||
| 363 | GSList *new_list, | |||
| 364 | GList **added, | |||
| 365 | GList **removed) | |||
| 366 | { | |||
| 367 | GSList *tmp; | |||
| 368 | GList *tmp_added, *tmp_removed; | |||
| 369 | ||||
| 370 | tmp_added = NULL((void*)0); | |||
| 371 | tmp_removed = NULL((void*)0); | |||
| 372 | ||||
| 373 | /* Find added tags */ | |||
| 374 | tmp = new_list; | |||
| 375 | while (tmp) | |||
| 376 | { | |||
| 377 | if (!g_slist_find (old_list, tmp->data)) | |||
| 378 | tmp_added = g_list_prepend (tmp_added, tmp->data); | |||
| 379 | ||||
| 380 | tmp = tmp->next; | |||
| 381 | } | |||
| 382 | ||||
| 383 | *added = tmp_added; | |||
| 384 | ||||
| 385 | /* Find removed tags */ | |||
| 386 | tmp = old_list; | |||
| 387 | while (tmp) | |||
| 388 | { | |||
| 389 | if (!g_slist_find (new_list, tmp->data)) | |||
| 390 | tmp_removed = g_list_prepend (tmp_removed, tmp->data); | |||
| 391 | ||||
| 392 | tmp = tmp->next; | |||
| 393 | } | |||
| 394 | ||||
| 395 | /* We reverse the list here to match the xml semantics */ | |||
| 396 | *removed = g_list_reverse (tmp_removed); | |||
| 397 | } | |||
| 398 | ||||
| 399 | static void | |||
| 400 | serialize_section_header (GString *str, | |||
| 401 | const gchar *name, | |||
| 402 | gint length) | |||
| 403 | { | |||
| 404 | g_return_if_fail (strlen (name) == 26)do { if ((strlen (name) == 26)) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "strlen (name) == 26"); return ; } } while (0); | |||
| 405 | ||||
| 406 | g_string_append (str, name)(__builtin_constant_p (name) ? __extension__ ({ const char * const __val = (name); g_string_append_len_inline (str, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize ) -1); }) : g_string_append_len_inline (str, name, (gssize) - 1)); | |||
| 407 | ||||
| 408 | g_string_append_c (str, length >> 24)g_string_append_c_inline (str, length >> 24); | |||
| 409 | ||||
| 410 | g_string_append_c (str, (length >> 16) & 0xff)g_string_append_c_inline (str, (length >> 16) & 0xff ); | |||
| 411 | g_string_append_c (str, (length >> 8) & 0xff)g_string_append_c_inline (str, (length >> 8) & 0xff ); | |||
| 412 | g_string_append_c (str, length & 0xff)g_string_append_c_inline (str, length & 0xff); | |||
| 413 | } | |||
| 414 | ||||
| 415 | static void | |||
| 416 | serialize_text (CtkTextBuffer *buffer G_GNUC_UNUSED__attribute__ ((__unused__)), | |||
| 417 | SerializationContext *context) | |||
| 418 | { | |||
| 419 | CtkTextIter iter, old_iter; | |||
| 420 | GSList *tag_list, *new_tag_list; | |||
| 421 | GSList *active_tags; | |||
| 422 | ||||
| 423 | g_string_append (context->text_str, "<text>")(__builtin_constant_p ("<text>") ? __extension__ ({ const char * const __val = ("<text>"); g_string_append_len_inline (context->text_str, __val, (__val != ((void*)0)) ? (gssize ) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (context->text_str, "<text>", (gssize) -1)); | |||
| 424 | ||||
| 425 | iter = context->start; | |||
| 426 | tag_list = NULL((void*)0); | |||
| 427 | active_tags = NULL((void*)0); | |||
| 428 | ||||
| 429 | do | |||
| 430 | { | |||
| 431 | GList *added, *removed; | |||
| 432 | GList *tmp; | |||
| 433 | gchar *tmp_text, *escaped_text; | |||
| 434 | ||||
| 435 | new_tag_list = ctk_text_iter_get_tags (&iter); | |||
| 436 | find_list_delta (tag_list, new_tag_list, &added, &removed); | |||
| 437 | ||||
| 438 | /* Handle removed tags */ | |||
| 439 | for (tmp = removed; tmp; tmp = tmp->next) | |||
| 440 | { | |||
| 441 | CtkTextTag *tag = tmp->data; | |||
| 442 | ||||
| 443 | /* Only close the tag if we didn't close it before (by using | |||
| 444 | * the stack logic in the while() loop below) | |||
| 445 | */ | |||
| 446 | if (g_slist_find (active_tags, tag)) | |||
| 447 | { | |||
| 448 | g_string_append (context->text_str, "</apply_tag>")(__builtin_constant_p ("</apply_tag>") ? __extension__ ( { const char * const __val = ("</apply_tag>"); g_string_append_len_inline (context->text_str, __val, (__val != ((void*)0)) ? (gssize ) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (context->text_str, "</apply_tag>", (gssize) -1)); | |||
| 449 | ||||
| 450 | /* Drop all tags that were opened after this one (which are | |||
| 451 | * above this on in the stack) | |||
| 452 | */ | |||
| 453 | while (active_tags->data != tag) | |||
| ||||
| 454 | { | |||
| 455 | added = g_list_prepend (added, active_tags->data); | |||
| 456 | active_tags = g_slist_remove (active_tags, active_tags->data); | |||
| 457 | g_string_append_printf (context->text_str, "</apply_tag>"); | |||
| 458 | } | |||
| 459 | ||||
| 460 | active_tags = g_slist_remove (active_tags, active_tags->data); | |||
| 461 | } | |||
| 462 | } | |||
| 463 | ||||
| 464 | /* Handle added tags */ | |||
| 465 | for (tmp = added; tmp; tmp = tmp->next) | |||
| 466 | { | |||
| 467 | CtkTextTag *tag = tmp->data; | |||
| 468 | gchar *tag_name; | |||
| 469 | ||||
| 470 | /* Add it to the tag hash table */ | |||
| 471 | g_hash_table_insert (context->tags, tag, tag); | |||
| 472 | ||||
| 473 | if (tag->priv->name) | |||
| 474 | { | |||
| 475 | tag_name = g_markup_escape_text (tag->priv->name, -1); | |||
| 476 | ||||
| 477 | g_string_append_printf (context->text_str, "<apply_tag name=\"%s\">", tag_name); | |||
| 478 | g_free (tag_name); | |||
| 479 | } | |||
| 480 | else | |||
| 481 | { | |||
| 482 | gpointer tag_id; | |||
| 483 | ||||
| 484 | /* We've got an anonymous tag, find out if it's been | |||
| 485 | used before */ | |||
| 486 | if (!g_hash_table_lookup_extended (context->tag_id_tags, tag, NULL((void*)0), &tag_id)) | |||
| 487 | { | |||
| 488 | tag_id = GINT_TO_POINTER (context->tag_id++)((gpointer) (glong) (context->tag_id++)); | |||
| 489 | ||||
| 490 | g_hash_table_insert (context->tag_id_tags, tag, tag_id); | |||
| 491 | } | |||
| 492 | ||||
| 493 | g_string_append_printf (context->text_str, "<apply_tag id=\"%d\">", GPOINTER_TO_INT (tag_id)((gint) (glong) (tag_id))); | |||
| 494 | } | |||
| 495 | ||||
| 496 | active_tags = g_slist_prepend (active_tags, tag); | |||
| 497 | } | |||
| 498 | ||||
| 499 | g_slist_free (tag_list); | |||
| 500 | tag_list = new_tag_list; | |||
| 501 | ||||
| 502 | g_list_free (added); | |||
| 503 | g_list_free (removed); | |||
| 504 | ||||
| 505 | old_iter = iter; | |||
| 506 | ||||
| 507 | /* Now try to go to either the next tag toggle, or if a pixbuf appears */ | |||
| 508 | while (TRUE(!(0))) | |||
| 509 | { | |||
| 510 | gunichar ch = ctk_text_iter_get_char (&iter); | |||
| 511 | ||||
| 512 | if (ch == 0xFFFC) | |||
| 513 | { | |||
| 514 | GdkPixbuf *pixbuf = ctk_text_iter_get_pixbuf (&iter); | |||
| 515 | ||||
| 516 | if (pixbuf) | |||
| 517 | { | |||
| 518 | /* Append the text before the pixbuf */ | |||
| 519 | tmp_text = ctk_text_iter_get_slice (&old_iter, &iter); | |||
| 520 | escaped_text = g_markup_escape_text (tmp_text, -1); | |||
| 521 | g_free (tmp_text); | |||
| 522 | ||||
| 523 | /* Forward so we don't get the 0xfffc char */ | |||
| 524 | ctk_text_iter_forward_char (&iter); | |||
| 525 | old_iter = iter; | |||
| 526 | ||||
| 527 | g_string_append (context->text_str, escaped_text)(__builtin_constant_p (escaped_text) ? __extension__ ({ const char * const __val = (escaped_text); g_string_append_len_inline (context->text_str, __val, (__val != ((void*)0)) ? (gssize ) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (context->text_str, escaped_text, (gssize) -1)); | |||
| 528 | g_free (escaped_text); | |||
| 529 | ||||
| 530 | g_string_append_printf (context->text_str, "<pixbuf index=\"%d\" />", context->n_pixbufs); | |||
| 531 | ||||
| 532 | context->n_pixbufs++; | |||
| 533 | context->pixbufs = g_list_prepend (context->pixbufs, pixbuf); | |||
| 534 | } | |||
| 535 | } | |||
| 536 | else if (ch == 0) | |||
| 537 | { | |||
| 538 | break; | |||
| 539 | } | |||
| 540 | else | |||
| 541 | ctk_text_iter_forward_char (&iter); | |||
| 542 | ||||
| 543 | if (ctk_text_iter_toggles_tag (&iter, NULL((void*)0))) | |||
| 544 | break; | |||
| 545 | } | |||
| 546 | ||||
| 547 | /* We might have moved too far */ | |||
| 548 | if (ctk_text_iter_compare (&iter, &context->end) > 0) | |||
| 549 | iter = context->end; | |||
| 550 | ||||
| 551 | /* Append the text */ | |||
| 552 | tmp_text = ctk_text_iter_get_slice (&old_iter, &iter); | |||
| 553 | escaped_text = g_markup_escape_text (tmp_text, -1); | |||
| 554 | g_free (tmp_text); | |||
| 555 | ||||
| 556 | g_string_append (context->text_str, escaped_text)(__builtin_constant_p (escaped_text) ? __extension__ ({ const char * const __val = (escaped_text); g_string_append_len_inline (context->text_str, __val, (__val != ((void*)0)) ? (gssize ) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (context->text_str, escaped_text, (gssize) -1)); | |||
| 557 | g_free (escaped_text); | |||
| 558 | } | |||
| 559 | while (!ctk_text_iter_equal (&iter, &context->end)); | |||
| 560 | ||||
| 561 | g_slist_free (tag_list); | |||
| 562 | ||||
| 563 | /* Close any open tags */ | |||
| 564 | for (tag_list = active_tags; tag_list; tag_list = tag_list->next) | |||
| 565 | g_string_append (context->text_str, "</apply_tag>")(__builtin_constant_p ("</apply_tag>") ? __extension__ ( { const char * const __val = ("</apply_tag>"); g_string_append_len_inline (context->text_str, __val, (__val != ((void*)0)) ? (gssize ) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (context->text_str, "</apply_tag>", (gssize) -1)); | |||
| 566 | ||||
| 567 | g_slist_free (active_tags); | |||
| 568 | g_string_append (context->text_str, "</text>\n</text_view_markup>\n")(__builtin_constant_p ("</text>\n</text_view_markup>\n" ) ? __extension__ ({ const char * const __val = ("</text>\n</text_view_markup>\n" ); g_string_append_len_inline (context->text_str, __val, ( __val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (context-> text_str, "</text>\n</text_view_markup>\n", (gssize ) -1)); | |||
| 569 | } | |||
| 570 | ||||
| 571 | G_GNUC_BEGIN_IGNORE_DEPRECATIONSclang diagnostic push
clang diagnostic ignored "-Wdeprecated-declarations" | |||
| 572 | static void | |||
| 573 | serialize_pixbufs (SerializationContext *context, | |||
| 574 | GString *text) | |||
| 575 | { | |||
| 576 | GList *list; | |||
| 577 | ||||
| 578 | for (list = context->pixbufs; list != NULL((void*)0); list = list->next) | |||
| 579 | { | |||
| 580 | GdkPixbuf *pixbuf = list->data; | |||
| 581 | GdkPixdata pixdata; | |||
| 582 | guint8 *tmp; | |||
| 583 | guint len; | |||
| 584 | ||||
| 585 | gdk_pixdata_from_pixbuf (&pixdata, pixbuf, FALSE(0)); | |||
| 586 | tmp = gdk_pixdata_serialize (&pixdata, &len); | |||
| 587 | ||||
| 588 | serialize_section_header (text, "CTKTEXTBUFFERPIXBDATA-0001", len); | |||
| 589 | g_string_append_len (text, (gchar *) tmp, len)g_string_append_len_inline (text, (gchar *) tmp, len); | |||
| 590 | g_free (tmp); | |||
| 591 | } | |||
| 592 | } | |||
| 593 | G_GNUC_END_IGNORE_DEPRECATIONSclang diagnostic pop | |||
| 594 | ||||
| 595 | guint8 * | |||
| 596 | _ctk_text_buffer_serialize_rich_text (CtkTextBuffer *register_buffer G_GNUC_UNUSED__attribute__ ((__unused__)), | |||
| 597 | CtkTextBuffer *content_buffer, | |||
| 598 | const CtkTextIter *start, | |||
| 599 | const CtkTextIter *end, | |||
| 600 | gsize *length, | |||
| 601 | gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__))) | |||
| 602 | { | |||
| 603 | SerializationContext context; | |||
| 604 | GString *text; | |||
| 605 | ||||
| 606 | context.tags = g_hash_table_new (NULL((void*)0), NULL((void*)0)); | |||
| 607 | context.text_str = g_string_new (NULL((void*)0)); | |||
| 608 | context.tag_table_str = g_string_new (NULL((void*)0)); | |||
| 609 | context.start = *start; | |||
| 610 | context.end = *end; | |||
| 611 | context.n_pixbufs = 0; | |||
| 612 | context.pixbufs = NULL((void*)0); | |||
| 613 | context.tag_id = 0; | |||
| 614 | context.tag_id_tags = g_hash_table_new (NULL((void*)0), NULL((void*)0)); | |||
| 615 | ||||
| 616 | /* We need to serialize the text before the tag table so we know | |||
| 617 | what tags are used */ | |||
| 618 | serialize_text (content_buffer, &context); | |||
| ||||
| 619 | serialize_tags (&context); | |||
| 620 | ||||
| 621 | text = g_string_new (NULL((void*)0)); | |||
| 622 | serialize_section_header (text, "CTKTEXTBUFFERCONTENTS-0001", | |||
| 623 | context.tag_table_str->len + context.text_str->len); | |||
| 624 | ||||
| 625 | g_string_append_len (text, context.tag_table_str->str, context.tag_table_str->len)g_string_append_len_inline (text, context.tag_table_str->str , context.tag_table_str->len); | |||
| 626 | g_string_append_len (text, context.text_str->str, context.text_str->len)g_string_append_len_inline (text, context.text_str->str, context .text_str->len); | |||
| 627 | ||||
| 628 | context.pixbufs = g_list_reverse (context.pixbufs); | |||
| 629 | serialize_pixbufs (&context, text); | |||
| 630 | ||||
| 631 | g_hash_table_destroy (context.tags); | |||
| 632 | g_list_free (context.pixbufs); | |||
| 633 | g_string_free (context.text_str, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) ( (context.text_str), ((!(0)))) : g_string_free_and_steal (context .text_str)) : (g_string_free) ((context.text_str), ((!(0))))); | |||
| 634 | g_string_free (context.tag_table_str, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) ( (context.tag_table_str), ((!(0)))) : g_string_free_and_steal ( context.tag_table_str)) : (g_string_free) ((context.tag_table_str ), ((!(0))))); | |||
| 635 | g_hash_table_destroy (context.tag_id_tags); | |||
| 636 | ||||
| 637 | *length = text->len; | |||
| 638 | ||||
| 639 | return (guint8 *) g_string_free (text, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((text ), ((0))) : g_string_free_and_steal (text)) : (g_string_free) ((text), ((0)))); | |||
| 640 | } | |||
| 641 | ||||
| 642 | typedef enum | |||
| 643 | { | |||
| 644 | STATE_START, | |||
| 645 | STATE_TEXT_VIEW_MARKUP, | |||
| 646 | STATE_TAGS, | |||
| 647 | STATE_TAG, | |||
| 648 | STATE_ATTR, | |||
| 649 | STATE_TEXT, | |||
| 650 | STATE_APPLY_TAG, | |||
| 651 | STATE_PIXBUF | |||
| 652 | } ParseState; | |||
| 653 | ||||
| 654 | typedef struct | |||
| 655 | { | |||
| 656 | gchar *text; | |||
| 657 | GdkPixbuf *pixbuf; | |||
| 658 | GSList *tags; | |||
| 659 | } TextSpan; | |||
| 660 | ||||
| 661 | typedef struct | |||
| 662 | { | |||
| 663 | CtkTextTag *tag; | |||
| 664 | gint prio; | |||
| 665 | } TextTagPrio; | |||
| 666 | ||||
| 667 | typedef struct | |||
| 668 | { | |||
| 669 | GSList *states; | |||
| 670 | ||||
| 671 | GList *headers; | |||
| 672 | ||||
| 673 | CtkTextBuffer *buffer; | |||
| 674 | ||||
| 675 | /* Tags that are defined in <tag> elements */ | |||
| 676 | GHashTable *defined_tags; | |||
| 677 | ||||
| 678 | /* Tags that are anonymous */ | |||
| 679 | GHashTable *anonymous_tags; | |||
| 680 | ||||
| 681 | /* Tag name substitutions */ | |||
| 682 | GHashTable *substitutions; | |||
| 683 | ||||
| 684 | /* Current tag */ | |||
| 685 | CtkTextTag *current_tag; | |||
| 686 | ||||
| 687 | /* Priority of current tag */ | |||
| 688 | gint current_tag_prio; | |||
| 689 | ||||
| 690 | /* Id of current tag */ | |||
| 691 | gint current_tag_id; | |||
| 692 | ||||
| 693 | /* Tags and their priorities */ | |||
| 694 | GList *tag_priorities; | |||
| 695 | ||||
| 696 | GSList *tag_stack; | |||
| 697 | ||||
| 698 | GList *spans; | |||
| 699 | ||||
| 700 | gboolean create_tags; | |||
| 701 | ||||
| 702 | gboolean parsed_text; | |||
| 703 | gboolean parsed_tags; | |||
| 704 | } ParseInfo; | |||
| 705 | ||||
| 706 | static void | |||
| 707 | set_error (GError **err, | |||
| 708 | GMarkupParseContext *context, | |||
| 709 | int error_domain, | |||
| 710 | int error_code, | |||
| 711 | const char *format, | |||
| 712 | ...) G_GNUC_PRINTF(5, 6)__attribute__((__format__ (__printf__, 5, 6))); | |||
| 713 | ||||
| 714 | static void | |||
| 715 | set_error (GError **err, | |||
| 716 | GMarkupParseContext *context, | |||
| 717 | int error_domain, | |||
| 718 | int error_code, | |||
| 719 | const char *format, | |||
| 720 | ...) | |||
| 721 | { | |||
| 722 | int line, ch; | |||
| 723 | va_list args; | |||
| 724 | char *str; | |||
| 725 | ||||
| 726 | g_markup_parse_context_get_position (context, &line, &ch); | |||
| 727 | ||||
| 728 | va_start (args, format)__builtin_va_start(args, format); | |||
| 729 | str = g_strdup_vprintf (format, args); | |||
| 730 | va_end (args)__builtin_va_end(args); | |||
| 731 | ||||
| 732 | g_set_error (err, error_domain, error_code, | |||
| 733 | ("Line %d character %d: %s"), | |||
| 734 | line, ch, str); | |||
| 735 | ||||
| 736 | g_free (str); | |||
| 737 | } | |||
| 738 | ||||
| 739 | static void | |||
| 740 | push_state (ParseInfo *info, | |||
| 741 | ParseState state) | |||
| 742 | { | |||
| 743 | info->states = g_slist_prepend (info->states, GINT_TO_POINTER (state)((gpointer) (glong) (state))); | |||
| 744 | } | |||
| 745 | ||||
| 746 | static void | |||
| 747 | pop_state (ParseInfo *info) | |||
| 748 | { | |||
| 749 | g_return_if_fail (info->states != NULL)do { if ((info->states != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "info->states != NULL" ); return; } } while (0); | |||
| 750 | ||||
| 751 | info->states = g_slist_remove (info->states, info->states->data); | |||
| 752 | } | |||
| 753 | ||||
| 754 | static ParseState | |||
| 755 | peek_state (ParseInfo *info) | |||
| 756 | { | |||
| 757 | g_return_val_if_fail (info->states != NULL, STATE_START)do { if ((info->states != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "info->states != NULL" ); return (STATE_START); } } while (0); | |||
| 758 | ||||
| 759 | return GPOINTER_TO_INT (info->states->data)((gint) (glong) (info->states->data)); | |||
| 760 | } | |||
| 761 | ||||
| 762 | #define ELEMENT_IS(name)(strcmp (element_name, (name)) == 0) (strcmp (element_name, (name)) == 0) | |||
| 763 | ||||
| 764 | ||||
| 765 | static gboolean | |||
| 766 | check_id_or_name (GMarkupParseContext *context, | |||
| 767 | const gchar *element_name, | |||
| 768 | const gchar **attribute_names, | |||
| 769 | const gchar **attribute_values, | |||
| 770 | gint *id, | |||
| 771 | const gchar **name, | |||
| 772 | GError **error) | |||
| 773 | { | |||
| 774 | gboolean has_id = FALSE(0); | |||
| 775 | gboolean has_name = FALSE(0); | |||
| 776 | int i; | |||
| 777 | ||||
| 778 | *id = 0; | |||
| 779 | *name = NULL((void*)0); | |||
| 780 | ||||
| 781 | for (i = 0; attribute_names[i] != NULL((void*)0); i++) | |||
| 782 | { | |||
| 783 | if (strcmp (attribute_names[i], "name") == 0) | |||
| 784 | { | |||
| 785 | *name = attribute_values[i]; | |||
| 786 | ||||
| 787 | if (has_id) | |||
| 788 | { | |||
| 789 | set_error (error, context, | |||
| 790 | G_MARKUP_ERRORg_markup_error_quark (), | |||
| 791 | G_MARKUP_ERROR_PARSE, | |||
| 792 | _("Both \"id\" and \"name\" were found on the <%s> element")((char *) g_dgettext ("ctk30", "Both \"id\" and \"name\" were found on the <%s> element" )), | |||
| 793 | element_name); | |||
| 794 | return FALSE(0); | |||
| 795 | } | |||
| 796 | ||||
| 797 | if (has_name) | |||
| 798 | { | |||
| 799 | set_error (error, context, | |||
| 800 | G_MARKUP_ERRORg_markup_error_quark (), | |||
| 801 | G_MARKUP_ERROR_PARSE, | |||
| 802 | _("The attribute \"%s\" was found twice on the <%s> element")((char *) g_dgettext ("ctk30", "The attribute \"%s\" was found twice on the <%s> element" )), | |||
| 803 | "name", element_name); | |||
| 804 | return FALSE(0); | |||
| 805 | } | |||
| 806 | ||||
| 807 | has_name = TRUE(!(0)); | |||
| 808 | } | |||
| 809 | else if (strcmp (attribute_names[i], "id") == 0) | |||
| 810 | { | |||
| 811 | gchar *tmp; | |||
| 812 | ||||
| 813 | if (has_name) | |||
| 814 | { | |||
| 815 | set_error (error, context, | |||
| 816 | G_MARKUP_ERRORg_markup_error_quark (), | |||
| 817 | G_MARKUP_ERROR_PARSE, | |||
| 818 | _("Both \"id\" and \"name\" were found on the <%s> element")((char *) g_dgettext ("ctk30", "Both \"id\" and \"name\" were found on the <%s> element" )), | |||
| 819 | element_name); | |||
| 820 | return FALSE(0); | |||
| 821 | } | |||
| 822 | ||||
| 823 | if (has_id) | |||
| 824 | { | |||
| 825 | set_error (error, context, | |||
| 826 | G_MARKUP_ERRORg_markup_error_quark (), | |||
| 827 | G_MARKUP_ERROR_PARSE, | |||
| 828 | _("The attribute \"%s\" was found twice on the <%s> element")((char *) g_dgettext ("ctk30", "The attribute \"%s\" was found twice on the <%s> element" )), | |||
| 829 | "id", element_name); | |||
| 830 | return FALSE(0); | |||
| 831 | } | |||
| 832 | ||||
| 833 | has_id = TRUE(!(0)); | |||
| 834 | ||||
| 835 | /* Try parsing the integer */ | |||
| 836 | tmp = NULL((void*)0); | |||
| 837 | errno(*__errno_location ()) = 0; | |||
| 838 | *id = g_ascii_strtoll (attribute_values[i], &tmp, 10); | |||
| 839 | ||||
| 840 | if (errno(*__errno_location ()) || tmp == attribute_values[i]) | |||
| 841 | { | |||
| 842 | set_error (error, context, | |||
| 843 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, | |||
| 844 | _("<%s> element has invalid ID \"%s\"")((char *) g_dgettext ("ctk30", "<%s> element has invalid ID \"%s\"" )), | |||
| 845 | element_name, attribute_values[i]); | |||
| 846 | return FALSE(0); | |||
| 847 | } | |||
| 848 | } | |||
| 849 | } | |||
| 850 | ||||
| 851 | if (!has_id && !has_name) | |||
| 852 | { | |||
| 853 | set_error (error, context, | |||
| 854 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, | |||
| 855 | _("<%s> element has neither a \"name\" nor an \"id\" attribute")((char *) g_dgettext ("ctk30", "<%s> element has neither a \"name\" nor an \"id\" attribute" )), element_name); | |||
| 856 | return FALSE(0); | |||
| 857 | } | |||
| 858 | ||||
| 859 | return TRUE(!(0)); | |||
| 860 | } | |||
| 861 | ||||
| 862 | typedef struct | |||
| 863 | { | |||
| 864 | const char *name; | |||
| 865 | const char **retloc; | |||
| 866 | } LocateAttr; | |||
| 867 | ||||
| 868 | static gboolean | |||
| 869 | locate_attributes (GMarkupParseContext *context, | |||
| 870 | const char *element_name, | |||
| 871 | const char **attribute_names, | |||
| 872 | const char **attribute_values, | |||
| 873 | gboolean allow_unknown_attrs, | |||
| 874 | GError **error, | |||
| 875 | const char *first_attribute_name, | |||
| 876 | const char **first_attribute_retloc, | |||
| 877 | ...) | |||
| 878 | { | |||
| 879 | va_list args; | |||
| 880 | const char *name; | |||
| 881 | const char **retloc; | |||
| 882 | int n_attrs; | |||
| 883 | #define MAX_ATTRS24 24 | |||
| 884 | LocateAttr attrs[MAX_ATTRS24]; | |||
| 885 | gboolean retval; | |||
| 886 | int i; | |||
| 887 | ||||
| 888 | g_return_val_if_fail (first_attribute_name != NULL, FALSE)do { if ((first_attribute_name != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "first_attribute_name != NULL" ); return ((0)); } } while (0); | |||
| 889 | g_return_val_if_fail (first_attribute_retloc != NULL, FALSE)do { if ((first_attribute_retloc != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "first_attribute_retloc != NULL" ); return ((0)); } } while (0); | |||
| 890 | ||||
| 891 | retval = TRUE(!(0)); | |||
| 892 | ||||
| 893 | n_attrs = 1; | |||
| 894 | attrs[0].name = first_attribute_name; | |||
| 895 | attrs[0].retloc = first_attribute_retloc; | |||
| 896 | *first_attribute_retloc = NULL((void*)0); | |||
| 897 | ||||
| 898 | va_start (args, first_attribute_retloc)__builtin_va_start(args, first_attribute_retloc); | |||
| 899 | ||||
| 900 | name = va_arg (args, const char*)__builtin_va_arg(args, const char*); | |||
| 901 | retloc = va_arg (args, const char**)__builtin_va_arg(args, const char**); | |||
| 902 | ||||
| 903 | while (name != NULL((void*)0)) | |||
| 904 | { | |||
| 905 | g_return_val_if_fail (retloc != NULL, FALSE)do { if ((retloc != ((void*)0))) { } else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__)), "retloc != NULL"); return ((0)); } } while (0); | |||
| 906 | ||||
| 907 | g_assert (n_attrs < MAX_ATTRS)do { if (n_attrs < 24) ; else g_assertion_message_expr ("Ctk" , "ctktextbufferserialize.c", 907, ((const char*) (__func__)) , "n_attrs < MAX_ATTRS"); } while (0); | |||
| 908 | ||||
| 909 | attrs[n_attrs].name = name; | |||
| 910 | attrs[n_attrs].retloc = retloc; | |||
| 911 | n_attrs += 1; | |||
| 912 | *retloc = NULL((void*)0); | |||
| 913 | ||||
| 914 | name = va_arg (args, const char*)__builtin_va_arg(args, const char*); | |||
| 915 | retloc = va_arg (args, const char**)__builtin_va_arg(args, const char**); | |||
| 916 | } | |||
| 917 | ||||
| 918 | va_end (args)__builtin_va_end(args); | |||
| 919 | ||||
| 920 | if (!retval) | |||
| 921 | return retval; | |||
| 922 | ||||
| 923 | i = 0; | |||
| 924 | while (attribute_names[i]) | |||
| 925 | { | |||
| 926 | int j; | |||
| 927 | gboolean found; | |||
| 928 | ||||
| 929 | found = FALSE(0); | |||
| 930 | j = 0; | |||
| 931 | while (j < n_attrs) | |||
| 932 | { | |||
| 933 | if (strcmp (attrs[j].name, attribute_names[i]) == 0) | |||
| 934 | { | |||
| 935 | retloc = attrs[j].retloc; | |||
| 936 | ||||
| 937 | if (*retloc != NULL((void*)0)) | |||
| 938 | { | |||
| 939 | set_error (error, context, | |||
| 940 | G_MARKUP_ERRORg_markup_error_quark (), | |||
| 941 | G_MARKUP_ERROR_PARSE, | |||
| 942 | _("Attribute \"%s\" repeated twice on the same <%s> element")((char *) g_dgettext ("ctk30", "Attribute \"%s\" repeated twice on the same <%s> element" )), | |||
| 943 | attrs[j].name, element_name); | |||
| 944 | retval = FALSE(0); | |||
| 945 | goto out; | |||
| 946 | } | |||
| 947 | ||||
| 948 | *retloc = attribute_values[i]; | |||
| 949 | found = TRUE(!(0)); | |||
| 950 | } | |||
| 951 | ||||
| 952 | ++j; | |||
| 953 | } | |||
| 954 | ||||
| 955 | if (!found && !allow_unknown_attrs) | |||
| 956 | { | |||
| 957 | set_error (error, context, | |||
| 958 | G_MARKUP_ERRORg_markup_error_quark (), | |||
| 959 | G_MARKUP_ERROR_PARSE, | |||
| 960 | _("Attribute \"%s\" is invalid on <%s> element in this context")((char *) g_dgettext ("ctk30", "Attribute \"%s\" is invalid on <%s> element in this context" )), | |||
| 961 | attribute_names[i], element_name); | |||
| 962 | retval = FALSE(0); | |||
| 963 | goto out; | |||
| 964 | } | |||
| 965 | ||||
| 966 | ++i; | |||
| 967 | } | |||
| 968 | ||||
| 969 | out: | |||
| 970 | return retval; | |||
| 971 | } | |||
| 972 | ||||
| 973 | static gboolean | |||
| 974 | check_no_attributes (GMarkupParseContext *context, | |||
| 975 | const char *element_name, | |||
| 976 | const char **attribute_names, | |||
| 977 | const char **attribute_values G_GNUC_UNUSED__attribute__ ((__unused__)), | |||
| 978 | GError **error) | |||
| 979 | { | |||
| 980 | if (attribute_names[0] != NULL((void*)0)) | |||
| 981 | { | |||
| 982 | set_error (error, context, | |||
| 983 | G_MARKUP_ERRORg_markup_error_quark (), | |||
| 984 | G_MARKUP_ERROR_PARSE, | |||
| 985 | _("Attribute \"%s\" is invalid on <%s> element in this context")((char *) g_dgettext ("ctk30", "Attribute \"%s\" is invalid on <%s> element in this context" )), | |||
| 986 | attribute_names[0], element_name); | |||
| 987 | return FALSE(0); | |||
| 988 | } | |||
| 989 | ||||
| 990 | return TRUE(!(0)); | |||
| 991 | } | |||
| 992 | ||||
| 993 | static CtkTextTag * | |||
| 994 | tag_exists (GMarkupParseContext *context, | |||
| 995 | const gchar *name, | |||
| 996 | gint id, | |||
| 997 | ParseInfo *info, | |||
| 998 | GError **error) | |||
| 999 | { | |||
| 1000 | CtkTextTagTable *tag_table; | |||
| 1001 | const gchar *real_name; | |||
| 1002 | ||||
| 1003 | tag_table = ctk_text_buffer_get_tag_table (info->buffer); | |||
| 1004 | ||||
| 1005 | if (info->create_tags) | |||
| 1006 | { | |||
| 1007 | /* If we have an anonymous tag, just return it directly */ | |||
| 1008 | if (!name) | |||
| 1009 | return g_hash_table_lookup (info->anonymous_tags, | |||
| 1010 | GINT_TO_POINTER (id)((gpointer) (glong) (id))); | |||
| 1011 | ||||
| 1012 | /* First, try the substitutions */ | |||
| 1013 | real_name = g_hash_table_lookup (info->substitutions, name); | |||
| 1014 | ||||
| 1015 | if (real_name) | |||
| 1016 | return ctk_text_tag_table_lookup (tag_table, real_name); | |||
| 1017 | ||||
| 1018 | /* Next, try the list of defined tags */ | |||
| 1019 | if (g_hash_table_lookup (info->defined_tags, name) != NULL((void*)0)) | |||
| 1020 | return ctk_text_tag_table_lookup (tag_table, name); | |||
| 1021 | ||||
| 1022 | set_error (error, context, | |||
| 1023 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, | |||
| 1024 | _("Tag \"%s\" has not been defined.")((char *) g_dgettext ("ctk30", "Tag \"%s\" has not been defined." )), name); | |||
| 1025 | ||||
| 1026 | return NULL((void*)0); | |||
| 1027 | } | |||
| 1028 | else | |||
| 1029 | { | |||
| 1030 | CtkTextTag *tag; | |||
| 1031 | ||||
| 1032 | if (!name) | |||
| 1033 | { | |||
| 1034 | set_error (error, context, | |||
| 1035 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, | |||
| 1036 | _("Anonymous tag found and tags can not be created.")((char *) g_dgettext ("ctk30", "Anonymous tag found and tags can not be created." ))); | |||
| 1037 | return NULL((void*)0); | |||
| 1038 | } | |||
| 1039 | ||||
| 1040 | tag = ctk_text_tag_table_lookup (tag_table, name); | |||
| 1041 | ||||
| 1042 | if (tag) | |||
| 1043 | return tag; | |||
| 1044 | ||||
| 1045 | set_error (error, context, | |||
| 1046 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, | |||
| 1047 | _("Tag \"%s\" does not exist in buffer and tags can not be created.")((char *) g_dgettext ("ctk30", "Tag \"%s\" does not exist in buffer and tags can not be created." )), name); | |||
| 1048 | ||||
| 1049 | return NULL((void*)0); | |||
| 1050 | } | |||
| 1051 | } | |||
| 1052 | ||||
| 1053 | typedef struct | |||
| 1054 | { | |||
| 1055 | const gchar *id; | |||
| 1056 | gint length; | |||
| 1057 | const gchar *start; | |||
| 1058 | } Header; | |||
| 1059 | ||||
| 1060 | G_GNUC_BEGIN_IGNORE_DEPRECATIONSclang diagnostic push
clang diagnostic ignored "-Wdeprecated-declarations" | |||
| 1061 | static GdkPixbuf * | |||
| 1062 | get_pixbuf_from_headers (GList *headers, | |||
| 1063 | int id, | |||
| 1064 | GError **error) | |||
| 1065 | { | |||
| 1066 | Header *header; | |||
| 1067 | GdkPixdata pixdata; | |||
| 1068 | GdkPixbuf *pixbuf; | |||
| 1069 | ||||
| 1070 | header = g_list_nth_data (headers, id); | |||
| 1071 | ||||
| 1072 | if (!header) | |||
| 1073 | return NULL((void*)0); | |||
| 1074 | ||||
| 1075 | if (!gdk_pixdata_deserialize (&pixdata, header->length, | |||
| 1076 | (const guint8 *) header->start, error)) | |||
| 1077 | return NULL((void*)0); | |||
| 1078 | ||||
| 1079 | pixbuf = gdk_pixbuf_from_pixdata (&pixdata, TRUE(!(0)), error); | |||
| 1080 | ||||
| 1081 | return pixbuf; | |||
| 1082 | } | |||
| 1083 | G_GNUC_END_IGNORE_DEPRECATIONSclang diagnostic pop | |||
| 1084 | ||||
| 1085 | static void | |||
| 1086 | parse_apply_tag_element (GMarkupParseContext *context, | |||
| 1087 | const gchar *element_name, | |||
| 1088 | const gchar **attribute_names, | |||
| 1089 | const gchar **attribute_values, | |||
| 1090 | ParseInfo *info, | |||
| 1091 | GError **error) | |||
| 1092 | { | |||
| 1093 | const gchar *name, *priority; | |||
| 1094 | gint id; | |||
| 1095 | CtkTextTag *tag; | |||
| 1096 | ||||
| 1097 | g_assert (peek_state (info) == STATE_TEXT ||do { if (peek_state (info) == STATE_TEXT || peek_state (info) == STATE_APPLY_TAG) ; else g_assertion_message_expr ("Ctk", "ctktextbufferserialize.c" , 1098, ((const char*) (__func__)), "peek_state (info) == STATE_TEXT || peek_state (info) == STATE_APPLY_TAG" ); } while (0) | |||
| 1098 | peek_state (info) == STATE_APPLY_TAG)do { if (peek_state (info) == STATE_TEXT || peek_state (info) == STATE_APPLY_TAG) ; else g_assertion_message_expr ("Ctk", "ctktextbufferserialize.c" , 1098, ((const char*) (__func__)), "peek_state (info) == STATE_TEXT || peek_state (info) == STATE_APPLY_TAG" ); } while (0); | |||
| 1099 | ||||
| 1100 | if (ELEMENT_IS ("apply_tag")(strcmp (element_name, ("apply_tag")) == 0)) | |||
| 1101 | { | |||
| 1102 | if (!locate_attributes (context, element_name, attribute_names, attribute_values, TRUE(!(0)), error, | |||
| 1103 | "priority", &priority, NULL((void*)0))) | |||
| 1104 | return; | |||
| 1105 | ||||
| 1106 | if (!check_id_or_name (context, element_name, attribute_names, attribute_values, | |||
| 1107 | &id, &name, error)) | |||
| 1108 | return; | |||
| 1109 | ||||
| 1110 | ||||
| 1111 | tag = tag_exists (context, name, id, info, error); | |||
| 1112 | ||||
| 1113 | if (!tag) | |||
| 1114 | return; | |||
| 1115 | ||||
| 1116 | info->tag_stack = g_slist_prepend (info->tag_stack, tag); | |||
| 1117 | ||||
| 1118 | push_state (info, STATE_APPLY_TAG); | |||
| 1119 | } | |||
| 1120 | else if (ELEMENT_IS ("pixbuf")(strcmp (element_name, ("pixbuf")) == 0)) | |||
| 1121 | { | |||
| 1122 | int int_id; | |||
| 1123 | GdkPixbuf *pixbuf; | |||
| 1124 | TextSpan *span; | |||
| 1125 | const gchar *pixbuf_id; | |||
| 1126 | ||||
| 1127 | if (!locate_attributes (context, element_name, attribute_names, attribute_values, FALSE(0), error, | |||
| 1128 | "index", &pixbuf_id, NULL((void*)0))) | |||
| 1129 | return; | |||
| 1130 | ||||
| 1131 | int_id = atoi (pixbuf_id); | |||
| 1132 | pixbuf = get_pixbuf_from_headers (info->headers, int_id, error); | |||
| 1133 | ||||
| 1134 | span = g_slice_new0 (TextSpan)((TextSpan*) g_slice_alloc0 (sizeof (TextSpan))); | |||
| 1135 | span->pixbuf = pixbuf; | |||
| 1136 | span->tags = NULL((void*)0); | |||
| 1137 | ||||
| 1138 | info->spans = g_list_prepend (info->spans, span); | |||
| 1139 | ||||
| 1140 | if (!pixbuf) | |||
| 1141 | return; | |||
| 1142 | ||||
| 1143 | push_state (info, STATE_PIXBUF); | |||
| 1144 | } | |||
| 1145 | else | |||
| 1146 | set_error (error, context, | |||
| 1147 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, | |||
| 1148 | _("Element <%s> is not allowed below <%s>")((char *) g_dgettext ("ctk30", "Element <%s> is not allowed below <%s>" )), | |||
| 1149 | element_name, peek_state(info) == STATE_TEXT ? "text" : "apply_tag"); | |||
| 1150 | } | |||
| 1151 | ||||
| 1152 | static void | |||
| 1153 | parse_attr_element (GMarkupParseContext *context, | |||
| 1154 | const gchar *element_name, | |||
| 1155 | const gchar **attribute_names, | |||
| 1156 | const gchar **attribute_values, | |||
| 1157 | ParseInfo *info, | |||
| 1158 | GError **error) | |||
| 1159 | { | |||
| 1160 | const gchar *name, *type, *value; | |||
| 1161 | GType gtype; | |||
| 1162 | GValue gvalue = G_VALUE_INIT{ 0, { { 0 } } }; | |||
| 1163 | GParamSpec *pspec; | |||
| 1164 | ||||
| 1165 | g_assert (peek_state (info) == STATE_TAG)do { if (peek_state (info) == STATE_TAG) ; else g_assertion_message_expr ("Ctk", "ctktextbufferserialize.c", 1165, ((const char*) (__func__ )), "peek_state (info) == STATE_TAG"); } while (0); | |||
| 1166 | ||||
| 1167 | if (ELEMENT_IS ("attr")(strcmp (element_name, ("attr")) == 0)) | |||
| 1168 | { | |||
| 1169 | if (!locate_attributes (context, element_name, attribute_names, attribute_values, FALSE(0), error, | |||
| 1170 | "name", &name, "type", &type, "value", &value, NULL((void*)0))) | |||
| 1171 | return; | |||
| 1172 | ||||
| 1173 | gtype = g_type_from_name (type); | |||
| 1174 | ||||
| 1175 | if (gtype == G_TYPE_INVALID((GType) ((0) << (2)))) | |||
| 1176 | { | |||
| 1177 | set_error (error, context, | |||
| 1178 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, | |||
| 1179 | _("\"%s\" is not a valid attribute type")((char *) g_dgettext ("ctk30", "\"%s\" is not a valid attribute type" )), type); | |||
| 1180 | return; | |||
| 1181 | } | |||
| 1182 | ||||
| 1183 | if (!(pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (info->current_tag)((((GObjectClass*) (((GTypeInstance*) ((info->current_tag) ))->g_class)))), name))) | |||
| 1184 | { | |||
| 1185 | set_error (error, context, | |||
| 1186 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, | |||
| 1187 | _("\"%s\" is not a valid attribute name")((char *) g_dgettext ("ctk30", "\"%s\" is not a valid attribute name" )), name); | |||
| 1188 | return; | |||
| 1189 | } | |||
| 1190 | ||||
| 1191 | g_value_init (&gvalue, gtype); | |||
| 1192 | ||||
| 1193 | if (!deserialize_value (value, &gvalue)) | |||
| 1194 | { | |||
| 1195 | set_error (error, context, | |||
| 1196 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, | |||
| 1197 | _("\"%s\" could not be converted to a value of type \"%s\" for attribute \"%s\"")((char *) g_dgettext ("ctk30", "\"%s\" could not be converted to a value of type \"%s\" for attribute \"%s\"" )), | |||
| 1198 | value, type, name); | |||
| 1199 | return; | |||
| 1200 | } | |||
| 1201 | ||||
| 1202 | if (g_param_value_validate (pspec, &gvalue)) | |||
| 1203 | { | |||
| 1204 | set_error (error, context, | |||
| 1205 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, | |||
| 1206 | _("\"%s\" is not a valid value for attribute \"%s\"")((char *) g_dgettext ("ctk30", "\"%s\" is not a valid value for attribute \"%s\"" )), | |||
| 1207 | value, name); | |||
| 1208 | g_value_unset (&gvalue); | |||
| 1209 | return; | |||
| 1210 | } | |||
| 1211 | ||||
| 1212 | g_object_set_property (G_OBJECT (info->current_tag)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((info->current_tag)), (((GType) ((20) << (2))))) ))), | |||
| 1213 | name, &gvalue); | |||
| 1214 | ||||
| 1215 | g_value_unset (&gvalue); | |||
| 1216 | ||||
| 1217 | push_state (info, STATE_ATTR); | |||
| 1218 | } | |||
| 1219 | else | |||
| 1220 | { | |||
| 1221 | set_error (error, context, | |||
| 1222 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, | |||
| 1223 | _("Element <%s> is not allowed below <%s>")((char *) g_dgettext ("ctk30", "Element <%s> is not allowed below <%s>" )), | |||
| 1224 | element_name, "tag"); | |||
| 1225 | } | |||
| 1226 | } | |||
| 1227 | ||||
| 1228 | ||||
| 1229 | static gchar * | |||
| 1230 | get_tag_name (ParseInfo *info, | |||
| 1231 | const gchar *tag_name) | |||
| 1232 | { | |||
| 1233 | CtkTextTagTable *tag_table; | |||
| 1234 | gchar *name; | |||
| 1235 | gint i; | |||
| 1236 | ||||
| 1237 | name = g_strdup (tag_name)g_strdup_inline (tag_name); | |||
| 1238 | ||||
| 1239 | if (!info->create_tags) | |||
| 1240 | return name; | |||
| 1241 | ||||
| 1242 | i = 0; | |||
| 1243 | tag_table = ctk_text_buffer_get_tag_table (info->buffer); | |||
| 1244 | ||||
| 1245 | while (ctk_text_tag_table_lookup (tag_table, name) != NULL((void*)0)) | |||
| 1246 | { | |||
| 1247 | g_free (name); | |||
| 1248 | name = g_strdup_printf ("%s-%d", tag_name, ++i); | |||
| 1249 | } | |||
| 1250 | ||||
| 1251 | if (i != 0) | |||
| 1252 | { | |||
| 1253 | g_hash_table_insert (info->substitutions, g_strdup (tag_name)g_strdup_inline (tag_name), g_strdup (name)g_strdup_inline (name)); | |||
| 1254 | } | |||
| 1255 | ||||
| 1256 | return name; | |||
| 1257 | } | |||
| 1258 | ||||
| 1259 | static void | |||
| 1260 | parse_tag_element (GMarkupParseContext *context, | |||
| 1261 | const gchar *element_name, | |||
| 1262 | const gchar **attribute_names, | |||
| 1263 | const gchar **attribute_values, | |||
| 1264 | ParseInfo *info, | |||
| 1265 | GError **error) | |||
| 1266 | { | |||
| 1267 | const gchar *name, *priority; | |||
| 1268 | gchar *tag_name; | |||
| 1269 | gint id; | |||
| 1270 | gint prio; | |||
| 1271 | gchar *tmp; | |||
| 1272 | ||||
| 1273 | g_assert (peek_state (info) == STATE_TAGS)do { if (peek_state (info) == STATE_TAGS) ; else g_assertion_message_expr ("Ctk", "ctktextbufferserialize.c", 1273, ((const char*) (__func__ )), "peek_state (info) == STATE_TAGS"); } while (0); | |||
| 1274 | ||||
| 1275 | if (ELEMENT_IS ("tag")(strcmp (element_name, ("tag")) == 0)) | |||
| 1276 | { | |||
| 1277 | if (!locate_attributes (context, element_name, attribute_names, attribute_values, TRUE(!(0)), error, | |||
| 1278 | "priority", &priority, NULL((void*)0))) | |||
| 1279 | return; | |||
| 1280 | ||||
| 1281 | if (!check_id_or_name (context, element_name, attribute_names, attribute_values, | |||
| 1282 | &id, &name, error)) | |||
| 1283 | return; | |||
| 1284 | ||||
| 1285 | if (name) | |||
| 1286 | { | |||
| 1287 | if (g_hash_table_lookup (info->defined_tags, name) != NULL((void*)0)) | |||
| 1288 | { | |||
| 1289 | set_error (error, context, | |||
| 1290 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, | |||
| 1291 | _("Tag \"%s\" already defined")((char *) g_dgettext ("ctk30", "Tag \"%s\" already defined")), name); | |||
| 1292 | return; | |||
| 1293 | } | |||
| 1294 | } | |||
| 1295 | ||||
| 1296 | tmp = NULL((void*)0); | |||
| 1297 | errno(*__errno_location ()) = 0; | |||
| 1298 | prio = g_ascii_strtoll (priority, &tmp, 10); | |||
| 1299 | ||||
| 1300 | if (errno(*__errno_location ()) || tmp == priority) | |||
| 1301 | { | |||
| 1302 | set_error (error, context, | |||
| 1303 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, | |||
| 1304 | _("Tag \"%s\" has invalid priority \"%s\"")((char *) g_dgettext ("ctk30", "Tag \"%s\" has invalid priority \"%s\"" )), name, priority); | |||
| 1305 | return; | |||
| 1306 | } | |||
| 1307 | ||||
| 1308 | if (name) | |||
| 1309 | { | |||
| 1310 | tag_name = get_tag_name (info, name); | |||
| 1311 | info->current_tag = ctk_text_tag_new (tag_name); | |||
| 1312 | g_free (tag_name); | |||
| 1313 | } | |||
| 1314 | else | |||
| 1315 | { | |||
| 1316 | info->current_tag = ctk_text_tag_new (NULL((void*)0)); | |||
| 1317 | info->current_tag_id = id; | |||
| 1318 | } | |||
| 1319 | ||||
| 1320 | info->current_tag_prio = prio; | |||
| 1321 | ||||
| 1322 | push_state (info, STATE_TAG); | |||
| 1323 | } | |||
| 1324 | else | |||
| 1325 | { | |||
| 1326 | set_error (error, context, | |||
| 1327 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, | |||
| 1328 | _("Element <%s> is not allowed below <%s>")((char *) g_dgettext ("ctk30", "Element <%s> is not allowed below <%s>" )), | |||
| 1329 | element_name, "tags"); | |||
| 1330 | } | |||
| 1331 | } | |||
| 1332 | ||||
| 1333 | static void | |||
| 1334 | start_element_handler (GMarkupParseContext *context, | |||
| 1335 | const gchar *element_name, | |||
| 1336 | const gchar **attribute_names, | |||
| 1337 | const gchar **attribute_values, | |||
| 1338 | gpointer user_data, | |||
| 1339 | GError **error) | |||
| 1340 | { | |||
| 1341 | ParseInfo *info = user_data; | |||
| 1342 | ||||
| 1343 | switch (peek_state (info)) | |||
| 1344 | { | |||
| 1345 | case STATE_START: | |||
| 1346 | if (ELEMENT_IS ("text_view_markup")(strcmp (element_name, ("text_view_markup")) == 0)) | |||
| 1347 | { | |||
| 1348 | if (!check_no_attributes (context, element_name, | |||
| 1349 | attribute_names, attribute_values, error)) | |||
| 1350 | return; | |||
| 1351 | ||||
| 1352 | push_state (info, STATE_TEXT_VIEW_MARKUP); | |||
| 1353 | break; | |||
| 1354 | } | |||
| 1355 | else | |||
| 1356 | set_error (error, context, G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, | |||
| 1357 | _("Outermost element in text must be <text_view_markup> not <%s>")((char *) g_dgettext ("ctk30", "Outermost element in text must be <text_view_markup> not <%s>" )), | |||
| 1358 | element_name); | |||
| 1359 | break; | |||
| 1360 | case STATE_TEXT_VIEW_MARKUP: | |||
| 1361 | if (ELEMENT_IS ("tags")(strcmp (element_name, ("tags")) == 0)) | |||
| 1362 | { | |||
| 1363 | if (info->parsed_tags) | |||
| 1364 | { | |||
| 1365 | set_error (error, context, G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, | |||
| 1366 | _("A <%s> element has already been specified")((char *) g_dgettext ("ctk30", "A <%s> element has already been specified" )), "tags"); | |||
| 1367 | return; | |||
| 1368 | } | |||
| 1369 | ||||
| 1370 | if (!check_no_attributes (context, element_name, | |||
| 1371 | attribute_names, attribute_values, error)) | |||
| 1372 | return; | |||
| 1373 | ||||
| 1374 | push_state (info, STATE_TAGS); | |||
| 1375 | break; | |||
| 1376 | } | |||
| 1377 | else if (ELEMENT_IS ("text")(strcmp (element_name, ("text")) == 0)) | |||
| 1378 | { | |||
| 1379 | if (info->parsed_text) | |||
| 1380 | { | |||
| 1381 | set_error (error, context, G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, | |||
| 1382 | _("A <%s> element has already been specified")((char *) g_dgettext ("ctk30", "A <%s> element has already been specified" )), "text"); | |||
| 1383 | return; | |||
| 1384 | } | |||
| 1385 | else if (!info->parsed_tags) | |||
| 1386 | { | |||
| 1387 | set_error (error, context, G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, | |||
| 1388 | _("A <text> element can't occur before a <tags> element")((char *) g_dgettext ("ctk30", "A <text> element can't occur before a <tags> element" ))); | |||
| 1389 | return; | |||
| 1390 | } | |||
| 1391 | ||||
| 1392 | if (!check_no_attributes (context, element_name, | |||
| 1393 | attribute_names, attribute_values, error)) | |||
| 1394 | return; | |||
| 1395 | ||||
| 1396 | push_state (info, STATE_TEXT); | |||
| 1397 | break; | |||
| 1398 | } | |||
| 1399 | else | |||
| 1400 | set_error (error, context, | |||
| 1401 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, | |||
| 1402 | _("Element <%s> is not allowed below <%s>")((char *) g_dgettext ("ctk30", "Element <%s> is not allowed below <%s>" )), | |||
| 1403 | element_name, "text_view_markup"); | |||
| 1404 | break; | |||
| 1405 | case STATE_TAGS: | |||
| 1406 | parse_tag_element (context, element_name, | |||
| 1407 | attribute_names, attribute_values, | |||
| 1408 | info, error); | |||
| 1409 | break; | |||
| 1410 | case STATE_TAG: | |||
| 1411 | parse_attr_element (context, element_name, | |||
| 1412 | attribute_names, attribute_values, | |||
| 1413 | info, error); | |||
| 1414 | break; | |||
| 1415 | case STATE_TEXT: | |||
| 1416 | case STATE_APPLY_TAG: | |||
| 1417 | parse_apply_tag_element (context, element_name, | |||
| 1418 | attribute_names, attribute_values, | |||
| 1419 | info, error); | |||
| 1420 | break; | |||
| 1421 | default: | |||
| 1422 | g_assert_not_reached ()do { g_assertion_message_expr ("Ctk", "ctktextbufferserialize.c" , 1422, ((const char*) (__func__)), ((void*)0)); } while (0); | |||
| 1423 | break; | |||
| 1424 | } | |||
| 1425 | } | |||
| 1426 | ||||
| 1427 | static gint | |||
| 1428 | sort_tag_prio (TextTagPrio *a, | |||
| 1429 | TextTagPrio *b) | |||
| 1430 | { | |||
| 1431 | if (a->prio < b->prio) | |||
| 1432 | return -1; | |||
| 1433 | else if (a->prio > b->prio) | |||
| 1434 | return 1; | |||
| 1435 | else | |||
| 1436 | return 0; | |||
| 1437 | } | |||
| 1438 | ||||
| 1439 | static void | |||
| 1440 | end_element_handler (GMarkupParseContext *context G_GNUC_UNUSED__attribute__ ((__unused__)), | |||
| 1441 | const gchar *element_name G_GNUC_UNUSED__attribute__ ((__unused__)), | |||
| 1442 | gpointer user_data, | |||
| 1443 | GError **error G_GNUC_UNUSED__attribute__ ((__unused__))) | |||
| 1444 | { | |||
| 1445 | ParseInfo *info = user_data; | |||
| 1446 | gchar *tmp; | |||
| 1447 | GList *list; | |||
| 1448 | ||||
| 1449 | switch (peek_state (info)) | |||
| 1450 | { | |||
| 1451 | case STATE_TAGS: | |||
| 1452 | pop_state (info); | |||
| 1453 | g_assert (peek_state (info) == STATE_TEXT_VIEW_MARKUP)do { if (peek_state (info) == STATE_TEXT_VIEW_MARKUP) ; else g_assertion_message_expr ("Ctk", "ctktextbufferserialize.c", 1453, ((const char*) (__func__ )), "peek_state (info) == STATE_TEXT_VIEW_MARKUP"); } while ( 0); | |||
| 1454 | ||||
| 1455 | info->parsed_tags = TRUE(!(0)); | |||
| 1456 | ||||
| 1457 | /* Sort list and add the tags */ | |||
| 1458 | info->tag_priorities = g_list_sort (info->tag_priorities, | |||
| 1459 | (GCompareFunc)sort_tag_prio); | |||
| 1460 | list = info->tag_priorities; | |||
| 1461 | while (list) | |||
| 1462 | { | |||
| 1463 | TextTagPrio *prio = list->data; | |||
| 1464 | ||||
| 1465 | if (info->create_tags) | |||
| 1466 | ctk_text_tag_table_add (ctk_text_buffer_get_tag_table (info->buffer), | |||
| 1467 | prio->tag); | |||
| 1468 | ||||
| 1469 | g_object_unref (prio->tag); | |||
| 1470 | prio->tag = NULL((void*)0); | |||
| 1471 | ||||
| 1472 | list = list->next; | |||
| 1473 | } | |||
| 1474 | ||||
| 1475 | break; | |||
| 1476 | case STATE_TAG: | |||
| 1477 | pop_state (info); | |||
| 1478 | g_assert (peek_state (info) == STATE_TAGS)do { if (peek_state (info) == STATE_TAGS) ; else g_assertion_message_expr ("Ctk", "ctktextbufferserialize.c", 1478, ((const char*) (__func__ )), "peek_state (info) == STATE_TAGS"); } while (0); | |||
| 1479 | ||||
| 1480 | if (info->current_tag->priv->name) | |||
| 1481 | { | |||
| 1482 | /* Add tag to defined tags hash */ | |||
| 1483 | tmp = g_strdup (info->current_tag->priv->name)g_strdup_inline (info->current_tag->priv->name); | |||
| 1484 | g_hash_table_insert (info->defined_tags, | |||
| 1485 | tmp, tmp); | |||
| 1486 | } | |||
| 1487 | else | |||
| 1488 | { | |||
| 1489 | g_hash_table_insert (info->anonymous_tags, | |||
| 1490 | GINT_TO_POINTER (info->current_tag_id)((gpointer) (glong) (info->current_tag_id)), | |||
| 1491 | info->current_tag); | |||
| 1492 | } | |||
| 1493 | ||||
| 1494 | if (info->create_tags) | |||
| 1495 | { | |||
| 1496 | TextTagPrio *prio; | |||
| 1497 | ||||
| 1498 | /* add the tag to the list */ | |||
| 1499 | prio = g_slice_new0 (TextTagPrio)((TextTagPrio*) g_slice_alloc0 (sizeof (TextTagPrio))); | |||
| 1500 | prio->prio = info->current_tag_prio; | |||
| 1501 | prio->tag = info->current_tag; | |||
| 1502 | ||||
| 1503 | info->tag_priorities = g_list_prepend (info->tag_priorities, prio); | |||
| 1504 | } | |||
| 1505 | ||||
| 1506 | info->current_tag = NULL((void*)0); | |||
| 1507 | break; | |||
| 1508 | case STATE_ATTR: | |||
| 1509 | pop_state (info); | |||
| 1510 | g_assert (peek_state (info) == STATE_TAG)do { if (peek_state (info) == STATE_TAG) ; else g_assertion_message_expr ("Ctk", "ctktextbufferserialize.c", 1510, ((const char*) (__func__ )), "peek_state (info) == STATE_TAG"); } while (0); | |||
| 1511 | break; | |||
| 1512 | case STATE_APPLY_TAG: | |||
| 1513 | pop_state (info); | |||
| 1514 | g_assert (peek_state (info) == STATE_APPLY_TAG ||do { if (peek_state (info) == STATE_APPLY_TAG || peek_state ( info) == STATE_TEXT) ; else g_assertion_message_expr ("Ctk", "ctktextbufferserialize.c" , 1515, ((const char*) (__func__)), "peek_state (info) == STATE_APPLY_TAG || peek_state (info) == STATE_TEXT" ); } while (0) | |||
| 1515 | peek_state (info) == STATE_TEXT)do { if (peek_state (info) == STATE_APPLY_TAG || peek_state ( info) == STATE_TEXT) ; else g_assertion_message_expr ("Ctk", "ctktextbufferserialize.c" , 1515, ((const char*) (__func__)), "peek_state (info) == STATE_APPLY_TAG || peek_state (info) == STATE_TEXT" ); } while (0); | |||
| 1516 | ||||
| 1517 | /* Pop tag */ | |||
| 1518 | info->tag_stack = g_slist_delete_link (info->tag_stack, | |||
| 1519 | info->tag_stack); | |||
| 1520 | ||||
| 1521 | break; | |||
| 1522 | case STATE_TEXT: | |||
| 1523 | pop_state (info); | |||
| 1524 | g_assert (peek_state (info) == STATE_TEXT_VIEW_MARKUP)do { if (peek_state (info) == STATE_TEXT_VIEW_MARKUP) ; else g_assertion_message_expr ("Ctk", "ctktextbufferserialize.c", 1524, ((const char*) (__func__ )), "peek_state (info) == STATE_TEXT_VIEW_MARKUP"); } while ( 0); | |||
| 1525 | ||||
| 1526 | info->spans = g_list_reverse (info->spans); | |||
| 1527 | info->parsed_text = TRUE(!(0)); | |||
| 1528 | break; | |||
| 1529 | case STATE_TEXT_VIEW_MARKUP: | |||
| 1530 | pop_state (info); | |||
| 1531 | g_assert (peek_state (info) == STATE_START)do { if (peek_state (info) == STATE_START) ; else g_assertion_message_expr ("Ctk", "ctktextbufferserialize.c", 1531, ((const char*) (__func__ )), "peek_state (info) == STATE_START"); } while (0); | |||
| 1532 | break; | |||
| 1533 | case STATE_PIXBUF: | |||
| 1534 | pop_state (info); | |||
| 1535 | g_assert (peek_state (info) == STATE_APPLY_TAG ||do { if (peek_state (info) == STATE_APPLY_TAG || peek_state ( info) == STATE_TEXT) ; else g_assertion_message_expr ("Ctk", "ctktextbufferserialize.c" , 1536, ((const char*) (__func__)), "peek_state (info) == STATE_APPLY_TAG || peek_state (info) == STATE_TEXT" ); } while (0) | |||
| 1536 | peek_state (info) == STATE_TEXT)do { if (peek_state (info) == STATE_APPLY_TAG || peek_state ( info) == STATE_TEXT) ; else g_assertion_message_expr ("Ctk", "ctktextbufferserialize.c" , 1536, ((const char*) (__func__)), "peek_state (info) == STATE_APPLY_TAG || peek_state (info) == STATE_TEXT" ); } while (0); | |||
| 1537 | break; | |||
| 1538 | default: | |||
| 1539 | g_assert_not_reached ()do { g_assertion_message_expr ("Ctk", "ctktextbufferserialize.c" , 1539, ((const char*) (__func__)), ((void*)0)); } while (0); | |||
| 1540 | break; | |||
| 1541 | } | |||
| 1542 | } | |||
| 1543 | ||||
| 1544 | static gboolean | |||
| 1545 | all_whitespace (const char *text, | |||
| 1546 | int text_len) | |||
| 1547 | { | |||
| 1548 | const char *p; | |||
| 1549 | const char *end; | |||
| 1550 | ||||
| 1551 | p = text; | |||
| 1552 | end = text + text_len; | |||
| 1553 | ||||
| 1554 | while (p != end) | |||
| 1555 | { | |||
| 1556 | if (!g_ascii_isspace (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0)) | |||
| 1557 | return FALSE(0); | |||
| 1558 | ||||
| 1559 | p = g_utf8_next_char (p)((p) + g_utf8_skip[*(const guchar *)(p)]); | |||
| 1560 | } | |||
| 1561 | ||||
| 1562 | return TRUE(!(0)); | |||
| 1563 | } | |||
| 1564 | ||||
| 1565 | static void | |||
| 1566 | text_handler (GMarkupParseContext *context G_GNUC_UNUSED__attribute__ ((__unused__)), | |||
| 1567 | const gchar *text, | |||
| 1568 | gsize text_len, | |||
| 1569 | gpointer user_data, | |||
| 1570 | GError **error G_GNUC_UNUSED__attribute__ ((__unused__))) | |||
| 1571 | { | |||
| 1572 | ParseInfo *info = user_data; | |||
| 1573 | TextSpan *span; | |||
| 1574 | ||||
| 1575 | if (all_whitespace (text, text_len) && | |||
| 1576 | peek_state (info) != STATE_TEXT && | |||
| 1577 | peek_state (info) != STATE_APPLY_TAG) | |||
| 1578 | return; | |||
| 1579 | ||||
| 1580 | switch (peek_state (info)) | |||
| 1581 | { | |||
| 1582 | case STATE_START: | |||
| 1583 | g_assert_not_reached ()do { g_assertion_message_expr ("Ctk", "ctktextbufferserialize.c" , 1583, ((const char*) (__func__)), ((void*)0)); } while (0); /* gmarkup shouldn't do this */ | |||
| 1584 | break; | |||
| 1585 | case STATE_TEXT: | |||
| 1586 | case STATE_APPLY_TAG: | |||
| 1587 | if (text_len == 0) | |||
| 1588 | return; | |||
| 1589 | ||||
| 1590 | span = g_slice_new0 (TextSpan)((TextSpan*) g_slice_alloc0 (sizeof (TextSpan))); | |||
| 1591 | span->text = g_strndup (text, text_len); | |||
| 1592 | span->tags = g_slist_copy (info->tag_stack); | |||
| 1593 | ||||
| 1594 | info->spans = g_list_prepend (info->spans, span); | |||
| 1595 | break; | |||
| 1596 | default: | |||
| 1597 | g_assert_not_reached ()do { g_assertion_message_expr ("Ctk", "ctktextbufferserialize.c" , 1597, ((const char*) (__func__)), ((void*)0)); } while (0); | |||
| 1598 | break; | |||
| 1599 | } | |||
| 1600 | } | |||
| 1601 | ||||
| 1602 | static void | |||
| 1603 | parse_info_init (ParseInfo *info, | |||
| 1604 | CtkTextBuffer *buffer, | |||
| 1605 | gboolean create_tags, | |||
| 1606 | GList *headers) | |||
| 1607 | { | |||
| 1608 | info->states = g_slist_prepend (NULL((void*)0), GINT_TO_POINTER (STATE_START)((gpointer) (glong) (STATE_START))); | |||
| 1609 | ||||
| 1610 | info->create_tags = create_tags; | |||
| 1611 | info->headers = headers; | |||
| 1612 | info->defined_tags = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0)); | |||
| 1613 | info->substitutions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); | |||
| 1614 | info->anonymous_tags = g_hash_table_new_full (NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)); | |||
| 1615 | info->tag_stack = NULL((void*)0); | |||
| 1616 | info->spans = NULL((void*)0); | |||
| 1617 | info->parsed_text = FALSE(0); | |||
| 1618 | info->parsed_tags = FALSE(0); | |||
| 1619 | info->current_tag = NULL((void*)0); | |||
| 1620 | info->current_tag_prio = -1; | |||
| 1621 | info->tag_priorities = NULL((void*)0); | |||
| 1622 | ||||
| 1623 | info->buffer = buffer; | |||
| 1624 | } | |||
| 1625 | ||||
| 1626 | static void | |||
| 1627 | text_span_free (TextSpan *span) | |||
| 1628 | { | |||
| 1629 | g_free (span->text); | |||
| 1630 | g_slist_free (span->tags); | |||
| 1631 | g_slice_free (TextSpan, span)do { if (1) g_slice_free1 (sizeof (TextSpan), (span)); else ( void) ((TextSpan*) 0 == (span)); } while (0); | |||
| 1632 | } | |||
| 1633 | ||||
| 1634 | static void | |||
| 1635 | parse_info_free (ParseInfo *info) | |||
| 1636 | { | |||
| 1637 | GList *list; | |||
| 1638 | ||||
| 1639 | g_slist_free (info->tag_stack); | |||
| 1640 | g_slist_free (info->states); | |||
| 1641 | ||||
| 1642 | g_hash_table_destroy (info->substitutions); | |||
| 1643 | g_hash_table_destroy (info->defined_tags); | |||
| 1644 | ||||
| 1645 | if (info->current_tag) | |||
| 1646 | g_object_unref (info->current_tag); | |||
| 1647 | ||||
| 1648 | list = info->spans; | |||
| 1649 | while (list) | |||
| 1650 | { | |||
| 1651 | text_span_free (list->data); | |||
| 1652 | ||||
| 1653 | list = list->next; | |||
| 1654 | } | |||
| 1655 | g_list_free (info->spans); | |||
| 1656 | ||||
| 1657 | list = info->tag_priorities; | |||
| 1658 | while (list) | |||
| 1659 | { | |||
| 1660 | TextTagPrio *prio = list->data; | |||
| 1661 | ||||
| 1662 | if (prio->tag) | |||
| 1663 | g_object_unref (prio->tag); | |||
| 1664 | g_slice_free (TextTagPrio, prio)do { if (1) g_slice_free1 (sizeof (TextTagPrio), (prio)); else (void) ((TextTagPrio*) 0 == (prio)); } while (0); | |||
| 1665 | ||||
| 1666 | list = list->next; | |||
| 1667 | } | |||
| 1668 | g_list_free (info->tag_priorities); | |||
| 1669 | ||||
| 1670 | } | |||
| 1671 | ||||
| 1672 | static void | |||
| 1673 | insert_text (ParseInfo *info, | |||
| 1674 | CtkTextIter *iter) | |||
| 1675 | { | |||
| 1676 | CtkTextIter start_iter; | |||
| 1677 | CtkTextMark *mark; | |||
| 1678 | GList *tmp; | |||
| 1679 | GSList *tags; | |||
| 1680 | ||||
| 1681 | start_iter = *iter; | |||
| 1682 | ||||
| 1683 | mark = ctk_text_buffer_create_mark (info->buffer, "deserialize_insert_point", | |||
| 1684 | &start_iter, TRUE(!(0))); | |||
| 1685 | ||||
| 1686 | tmp = info->spans; | |||
| 1687 | while (tmp) | |||
| 1688 | { | |||
| 1689 | TextSpan *span = tmp->data; | |||
| 1690 | ||||
| 1691 | if (span->text) | |||
| 1692 | ctk_text_buffer_insert (info->buffer, iter, span->text, -1); | |||
| 1693 | else | |||
| 1694 | { | |||
| 1695 | ctk_text_buffer_insert_pixbuf (info->buffer, iter, span->pixbuf); | |||
| 1696 | g_object_unref (span->pixbuf); | |||
| 1697 | } | |||
| 1698 | ctk_text_buffer_get_iter_at_mark (info->buffer, &start_iter, mark); | |||
| 1699 | ||||
| 1700 | /* Apply tags */ | |||
| 1701 | tags = span->tags; | |||
| 1702 | while (tags) | |||
| 1703 | { | |||
| 1704 | CtkTextTag *tag = tags->data; | |||
| 1705 | ||||
| 1706 | ctk_text_buffer_apply_tag (info->buffer, tag, | |||
| 1707 | &start_iter, iter); | |||
| 1708 | ||||
| 1709 | tags = tags->next; | |||
| 1710 | } | |||
| 1711 | ||||
| 1712 | ctk_text_buffer_move_mark (info->buffer, mark, iter); | |||
| 1713 | ||||
| 1714 | tmp = tmp->next; | |||
| 1715 | } | |||
| 1716 | ||||
| 1717 | ctk_text_buffer_delete_mark (info->buffer, mark); | |||
| 1718 | } | |||
| 1719 | ||||
| 1720 | ||||
| 1721 | ||||
| 1722 | static int | |||
| 1723 | read_int (const guchar *start) | |||
| 1724 | { | |||
| 1725 | int result; | |||
| 1726 | ||||
| 1727 | result = | |||
| 1728 | start[0] << 24 | | |||
| 1729 | start[1] << 16 | | |||
| 1730 | start[2] << 8 | | |||
| 1731 | start[3]; | |||
| 1732 | ||||
| 1733 | return result; | |||
| 1734 | } | |||
| 1735 | ||||
| 1736 | static gboolean | |||
| 1737 | header_is (Header *header, | |||
| 1738 | const gchar *id) | |||
| 1739 | { | |||
| 1740 | return (strncmp (header->id, id, strlen (id)) == 0); | |||
| 1741 | } | |||
| 1742 | ||||
| 1743 | static GList * | |||
| 1744 | read_headers (const gchar *start, | |||
| 1745 | gint len, | |||
| 1746 | GError **error) | |||
| 1747 | { | |||
| 1748 | int i = 0; | |||
| 1749 | int section_len; | |||
| 1750 | Header *header; | |||
| 1751 | GList *headers = NULL((void*)0); | |||
| 1752 | GList *l; | |||
| 1753 | ||||
| 1754 | while (i < len) | |||
| 1755 | { | |||
| 1756 | if (i + 30 >= len) | |||
| 1757 | goto error; | |||
| 1758 | ||||
| 1759 | if (strncmp (start + i, "CTKTEXTBUFFERCONTENTS-0001", 26) == 0 || | |||
| 1760 | strncmp (start + i, "CTKTEXTBUFFERPIXBDATA-0001", 26) == 0) | |||
| 1761 | { | |||
| 1762 | section_len = read_int ((const guchar *) start + i + 26); | |||
| 1763 | ||||
| 1764 | if (i + 30 + section_len > len) | |||
| 1765 | goto error; | |||
| 1766 | ||||
| 1767 | header = g_slice_new0 (Header)((Header*) g_slice_alloc0 (sizeof (Header))); | |||
| 1768 | header->id = start + i; | |||
| 1769 | header->length = section_len; | |||
| 1770 | header->start = start + i + 30; | |||
| 1771 | ||||
| 1772 | i += 30 + section_len; | |||
| 1773 | ||||
| 1774 | headers = g_list_prepend (headers, header); | |||
| 1775 | } | |||
| 1776 | else | |||
| 1777 | break; | |||
| 1778 | } | |||
| 1779 | ||||
| 1780 | return g_list_reverse (headers); | |||
| 1781 | ||||
| 1782 | error: | |||
| 1783 | for (l = headers; l != NULL((void*)0); l = l->next) | |||
| 1784 | { | |||
| 1785 | header = l->data; | |||
| 1786 | g_slice_free (Header, header)do { if (1) g_slice_free1 (sizeof (Header), (header)); else ( void) ((Header*) 0 == (header)); } while (0); | |||
| 1787 | } | |||
| 1788 | ||||
| 1789 | g_list_free (headers); | |||
| 1790 | ||||
| 1791 | g_set_error_literal (error, | |||
| 1792 | G_MARKUP_ERRORg_markup_error_quark (), | |||
| 1793 | G_MARKUP_ERROR_PARSE, | |||
| 1794 | _("Serialized data is malformed")((char *) g_dgettext ("ctk30", "Serialized data is malformed" ))); | |||
| 1795 | ||||
| 1796 | return NULL((void*)0); | |||
| 1797 | } | |||
| 1798 | ||||
| 1799 | static gboolean | |||
| 1800 | deserialize_text (CtkTextBuffer *buffer, | |||
| 1801 | CtkTextIter *iter, | |||
| 1802 | const gchar *text, | |||
| 1803 | gint len, | |||
| 1804 | gboolean create_tags, | |||
| 1805 | GError **error, | |||
| 1806 | GList *headers) | |||
| 1807 | { | |||
| 1808 | GMarkupParseContext *context; | |||
| 1809 | ParseInfo info; | |||
| 1810 | gboolean retval = FALSE(0); | |||
| 1811 | ||||
| 1812 | static const GMarkupParser rich_text_parser = { | |||
| 1813 | start_element_handler, | |||
| 1814 | end_element_handler, | |||
| 1815 | text_handler, | |||
| 1816 | NULL((void*)0), | |||
| 1817 | NULL((void*)0) | |||
| 1818 | }; | |||
| 1819 | ||||
| 1820 | parse_info_init (&info, buffer, create_tags, headers); | |||
| 1821 | ||||
| 1822 | context = g_markup_parse_context_new (&rich_text_parser, | |||
| 1823 | 0, &info, NULL((void*)0)); | |||
| 1824 | ||||
| 1825 | if (!g_markup_parse_context_parse (context, | |||
| 1826 | text, | |||
| 1827 | len, | |||
| 1828 | error)) | |||
| 1829 | goto out; | |||
| 1830 | ||||
| 1831 | if (!g_markup_parse_context_end_parse (context, error)) | |||
| 1832 | goto out; | |||
| 1833 | ||||
| 1834 | retval = TRUE(!(0)); | |||
| 1835 | ||||
| 1836 | /* Now insert the text */ | |||
| 1837 | insert_text (&info, iter); | |||
| 1838 | ||||
| 1839 | out: | |||
| 1840 | parse_info_free (&info); | |||
| 1841 | ||||
| 1842 | g_markup_parse_context_free (context); | |||
| 1843 | ||||
| 1844 | return retval; | |||
| 1845 | } | |||
| 1846 | ||||
| 1847 | gboolean | |||
| 1848 | _ctk_text_buffer_deserialize_rich_text (CtkTextBuffer *register_buffer G_GNUC_UNUSED__attribute__ ((__unused__)), | |||
| 1849 | CtkTextBuffer *content_buffer, | |||
| 1850 | CtkTextIter *iter, | |||
| 1851 | const guint8 *text, | |||
| 1852 | gsize length, | |||
| 1853 | gboolean create_tags, | |||
| 1854 | gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)), | |||
| 1855 | GError **error) | |||
| 1856 | { | |||
| 1857 | GList *headers; | |||
| 1858 | GList *l; | |||
| 1859 | Header *header; | |||
| 1860 | gboolean retval; | |||
| 1861 | ||||
| 1862 | headers = read_headers ((gchar *) text, length, error); | |||
| 1863 | ||||
| 1864 | if (!headers) | |||
| 1865 | return FALSE(0); | |||
| 1866 | ||||
| 1867 | header = headers->data; | |||
| 1868 | if (!header_is (header, "CTKTEXTBUFFERCONTENTS-0001")) | |||
| 1869 | { | |||
| 1870 | g_set_error_literal (error, | |||
| 1871 | G_MARKUP_ERRORg_markup_error_quark (), | |||
| 1872 | G_MARKUP_ERROR_PARSE, | |||
| 1873 | _("Serialized data is malformed. First section isn't CTKTEXTBUFFERCONTENTS-0001")((char *) g_dgettext ("ctk30", "Serialized data is malformed. First section isn't CTKTEXTBUFFERCONTENTS-0001" ))); | |||
| 1874 | ||||
| 1875 | retval = FALSE(0); | |||
| 1876 | goto out; | |||
| 1877 | } | |||
| 1878 | ||||
| 1879 | retval = deserialize_text (content_buffer, iter, | |||
| 1880 | header->start, header->length, | |||
| 1881 | create_tags, error, headers->next); | |||
| 1882 | ||||
| 1883 | out: | |||
| 1884 | for (l = headers; l != NULL((void*)0); l = l->next) | |||
| 1885 | { | |||
| 1886 | header = l->data; | |||
| 1887 | g_slice_free (Header, header)do { if (1) g_slice_free1 (sizeof (Header), (header)); else ( void) ((Header*) 0 == (header)); } while (0); | |||
| 1888 | } | |||
| 1889 | ||||
| 1890 | g_list_free (headers); | |||
| 1891 | ||||
| 1892 | return retval; | |||
| 1893 | } |