gimpconfig-deserialize.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185
  1. /* LIBGIMP - The GIMP Library
  2. * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
  3. *
  4. * Object properties deserialization routines
  5. * Copyright (C) 2001-2002 Sven Neumann <sven@gimp.org>
  6. *
  7. * This library is free software: you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 3 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Library General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library. If not, see
  19. * <https://www.gnu.org/licenses/>.
  20. */
  21. #include "config.h"
  22. #include <cairo.h>
  23. #include <gegl.h>
  24. #include <gdk-pixbuf/gdk-pixbuf.h>
  25. #include "libgimpbase/gimpbase.h"
  26. #include "libgimpcolor/gimpcolor.h"
  27. #include "libgimpmath/gimpmath.h"
  28. #include "gimpconfigtypes.h"
  29. #include "gimpconfigwriter.h"
  30. #include "gimpconfig-array.h"
  31. #include "gimpconfig-iface.h"
  32. #include "gimpconfig-deserialize.h"
  33. #include "gimpconfig-params.h"
  34. #include "gimpconfig-path.h"
  35. #include "gimpscanner.h"
  36. #include "libgimp/libgimp-intl.h"
  37. /**
  38. * SECTION: gimpconfig-deserialize
  39. * @title: GimpConfig-deserialize
  40. * @short_description: Deserializing code for libgimpconfig.
  41. *
  42. * Deserializing code for libgimpconfig.
  43. **/
  44. /*
  45. * All functions return G_TOKEN_RIGHT_PAREN on success,
  46. * the GTokenType they would have expected but didn't get
  47. * or G_TOKEN_NONE if they got the expected token but
  48. * couldn't parse it.
  49. */
  50. static GTokenType gimp_config_deserialize_value (GValue *value,
  51. GimpConfig *config,
  52. GParamSpec *prop_spec,
  53. GScanner *scanner);
  54. static GTokenType gimp_config_deserialize_fundamental (GValue *value,
  55. GParamSpec *prop_spec,
  56. GScanner *scanner);
  57. static GTokenType gimp_config_deserialize_enum (GValue *value,
  58. GParamSpec *prop_spec,
  59. GScanner *scanner);
  60. static GTokenType gimp_config_deserialize_memsize (GValue *value,
  61. GParamSpec *prop_spec,
  62. GScanner *scanner);
  63. static GTokenType gimp_config_deserialize_path (GValue *value,
  64. GParamSpec *prop_spec,
  65. GScanner *scanner);
  66. static GTokenType gimp_config_deserialize_rgb (GValue *value,
  67. GParamSpec *prop_spec,
  68. GScanner *scanner);
  69. static GTokenType gimp_config_deserialize_matrix2 (GValue *value,
  70. GParamSpec *prop_spec,
  71. GScanner *scanner);
  72. static GTokenType gimp_config_deserialize_object (GValue *value,
  73. GimpConfig *config,
  74. GParamSpec *prop_spec,
  75. GScanner *scanner,
  76. gint nest_level);
  77. static GTokenType gimp_config_deserialize_value_array (GValue *value,
  78. GimpConfig *config,
  79. GParamSpec *prop_spec,
  80. GScanner *scanner);
  81. static GTokenType gimp_config_deserialize_unit (GValue *value,
  82. GParamSpec *prop_spec,
  83. GScanner *scanner);
  84. static GTokenType gimp_config_deserialize_file_value (GValue *value,
  85. GParamSpec *prop_spec,
  86. GScanner *scanner);
  87. static GTokenType gimp_config_deserialize_parasite_value (GValue *value,
  88. GParamSpec *prop_spec,
  89. GScanner *scanner);
  90. static GTokenType gimp_config_deserialize_bytes (GValue *value,
  91. GParamSpec *prop_spec,
  92. GScanner *scanner);
  93. static GTokenType gimp_config_deserialize_color (GValue *value,
  94. GParamSpec *prop_spec,
  95. GScanner *scanner);
  96. static GTokenType gimp_config_deserialize_any (GValue *value,
  97. GParamSpec *prop_spec,
  98. GScanner *scanner);
  99. static GTokenType gimp_config_skip_unknown_property (GScanner *scanner);
  100. static inline gboolean scanner_string_utf8_valid (GScanner *scanner,
  101. const gchar *token_name);
  102. static inline gboolean
  103. scanner_string_utf8_valid (GScanner *scanner,
  104. const gchar *token_name)
  105. {
  106. if (g_utf8_validate (scanner->value.v_string, -1, NULL))
  107. return TRUE;
  108. g_scanner_error (scanner,
  109. _("value for token %s is not a valid UTF-8 string"),
  110. token_name);
  111. return FALSE;
  112. }
  113. /**
  114. * gimp_config_deserialize_properties:
  115. * @config: a #GimpConfig.
  116. * @scanner: a #GScanner.
  117. * @nest_level: the nest level
  118. *
  119. * This function uses the @scanner to configure the properties of @config.
  120. *
  121. * Returns: %TRUE on success, %FALSE otherwise.
  122. *
  123. * Since: 2.4
  124. **/
  125. gboolean
  126. gimp_config_deserialize_properties (GimpConfig *config,
  127. GScanner *scanner,
  128. gint nest_level)
  129. {
  130. GObjectClass *klass;
  131. GParamSpec **property_specs;
  132. guint n_property_specs;
  133. guint i;
  134. guint scope_id;
  135. guint old_scope_id;
  136. GTokenType token;
  137. g_return_val_if_fail (GIMP_IS_CONFIG (config), FALSE);
  138. klass = G_OBJECT_GET_CLASS (config);
  139. property_specs = g_object_class_list_properties (klass, &n_property_specs);
  140. if (! property_specs)
  141. return TRUE;
  142. scope_id = g_type_qname (G_TYPE_FROM_INSTANCE (config));
  143. old_scope_id = g_scanner_set_scope (scanner, scope_id);
  144. for (i = 0; i < n_property_specs; i++)
  145. {
  146. GParamSpec *prop_spec = property_specs[i];
  147. if (prop_spec->flags & GIMP_CONFIG_PARAM_SERIALIZE)
  148. {
  149. g_scanner_scope_add_symbol (scanner, scope_id,
  150. prop_spec->name, prop_spec);
  151. }
  152. }
  153. g_free (property_specs);
  154. g_object_freeze_notify (G_OBJECT (config));
  155. token = G_TOKEN_LEFT_PAREN;
  156. while (TRUE)
  157. {
  158. GTokenType next = g_scanner_peek_next_token (scanner);
  159. if (next == G_TOKEN_EOF)
  160. break;
  161. if (G_UNLIKELY (next != token &&
  162. ! (token == G_TOKEN_SYMBOL &&
  163. next == G_TOKEN_IDENTIFIER)))
  164. {
  165. break;
  166. }
  167. token = g_scanner_get_next_token (scanner);
  168. switch (token)
  169. {
  170. case G_TOKEN_LEFT_PAREN:
  171. token = G_TOKEN_SYMBOL;
  172. break;
  173. case G_TOKEN_IDENTIFIER:
  174. token = gimp_config_skip_unknown_property (scanner);
  175. break;
  176. case G_TOKEN_SYMBOL:
  177. token = gimp_config_deserialize_property (config,
  178. scanner, nest_level);
  179. break;
  180. case G_TOKEN_RIGHT_PAREN:
  181. token = G_TOKEN_LEFT_PAREN;
  182. break;
  183. default: /* do nothing */
  184. break;
  185. }
  186. }
  187. g_scanner_set_scope (scanner, old_scope_id);
  188. g_object_thaw_notify (G_OBJECT (config));
  189. if (token == G_TOKEN_NONE)
  190. return FALSE;
  191. return gimp_config_deserialize_return (scanner, token, nest_level);
  192. }
  193. /**
  194. * gimp_config_deserialize_property:
  195. * @config: a #GimpConfig.
  196. * @scanner: a #GScanner.
  197. * @nest_level: the nest level
  198. *
  199. * This function deserializes a single property of @config. You
  200. * shouldn't need to call this function directly. If possible, use
  201. * gimp_config_deserialize_properties() instead.
  202. *
  203. * Returns: %G_TOKEN_RIGHT_PAREN on success, otherwise the
  204. * expected #GTokenType or %G_TOKEN_NONE if the expected token was
  205. * found but couldn't be parsed.
  206. *
  207. * Since: 2.4
  208. **/
  209. GTokenType
  210. gimp_config_deserialize_property (GimpConfig *config,
  211. GScanner *scanner,
  212. gint nest_level)
  213. {
  214. GimpConfigInterface *config_iface = NULL;
  215. GimpConfigInterface *parent_iface = NULL;
  216. GParamSpec *prop_spec;
  217. GTokenType token = G_TOKEN_RIGHT_PAREN;
  218. GValue value = G_VALUE_INIT;
  219. guint old_scope_id;
  220. old_scope_id = g_scanner_set_scope (scanner, 0);
  221. prop_spec = G_PARAM_SPEC (scanner->value.v_symbol);
  222. g_value_init (&value, prop_spec->value_type);
  223. if (G_TYPE_IS_OBJECT (prop_spec->owner_type))
  224. {
  225. GTypeClass *owner_class = g_type_class_peek (prop_spec->owner_type);
  226. config_iface = g_type_interface_peek (owner_class, GIMP_TYPE_CONFIG);
  227. /* We must call deserialize_property() *only* if the *exact* class
  228. * which implements it is param_spec->owner_type's class.
  229. *
  230. * Therefore, we ask param_spec->owner_type's immediate parent class
  231. * for it's GimpConfigInterface and check if we get a different
  232. * pointer.
  233. *
  234. * (if the pointers are the same, param_spec->owner_type's
  235. * GimpConfigInterface is inherited from one of it's parent classes
  236. * and thus not able to handle param_spec->owner_type's properties).
  237. */
  238. if (config_iface)
  239. {
  240. GTypeClass *owner_parent_class;
  241. owner_parent_class = g_type_class_peek_parent (owner_class);
  242. parent_iface = g_type_interface_peek (owner_parent_class,
  243. GIMP_TYPE_CONFIG);
  244. }
  245. }
  246. if (config_iface &&
  247. config_iface != parent_iface && /* see comment above */
  248. config_iface->deserialize_property &&
  249. config_iface->deserialize_property (config,
  250. prop_spec->param_id,
  251. &value,
  252. prop_spec,
  253. scanner,
  254. &token))
  255. {
  256. /* nop */
  257. }
  258. else
  259. {
  260. if (G_VALUE_HOLDS_OBJECT (&value) &&
  261. G_VALUE_TYPE (&value) != G_TYPE_FILE &&
  262. G_VALUE_TYPE (&value) != GEGL_TYPE_COLOR)
  263. {
  264. token = gimp_config_deserialize_object (&value,
  265. config, prop_spec,
  266. scanner, nest_level);
  267. }
  268. else
  269. {
  270. token = gimp_config_deserialize_value (&value,
  271. config, prop_spec, scanner);
  272. }
  273. }
  274. if (token == G_TOKEN_RIGHT_PAREN &&
  275. g_scanner_peek_next_token (scanner) == token)
  276. {
  277. if (GIMP_VALUE_HOLDS_COLOR (&value) ||
  278. ! (G_VALUE_HOLDS_OBJECT (&value) &&
  279. (prop_spec->flags & GIMP_CONFIG_PARAM_AGGREGATE)))
  280. g_object_set_property (G_OBJECT (config), prop_spec->name, &value);
  281. }
  282. #ifdef CONFIG_DEBUG
  283. else
  284. {
  285. g_warning ("%s: couldn't deserialize property %s::%s of type %s",
  286. G_STRFUNC,
  287. g_type_name (G_TYPE_FROM_INSTANCE (config)),
  288. prop_spec->name,
  289. g_type_name (prop_spec->value_type));
  290. }
  291. #endif
  292. g_value_unset (&value);
  293. g_scanner_set_scope (scanner, old_scope_id);
  294. return token;
  295. }
  296. static GTokenType
  297. gimp_config_deserialize_value (GValue *value,
  298. GimpConfig *config,
  299. GParamSpec *prop_spec,
  300. GScanner *scanner)
  301. {
  302. if (G_TYPE_FUNDAMENTAL (prop_spec->value_type) == G_TYPE_ENUM)
  303. {
  304. return gimp_config_deserialize_enum (value, prop_spec, scanner);
  305. }
  306. else if (G_TYPE_IS_FUNDAMENTAL (prop_spec->value_type))
  307. {
  308. return gimp_config_deserialize_fundamental (value, prop_spec, scanner);
  309. }
  310. else if (prop_spec->value_type == GIMP_TYPE_MEMSIZE)
  311. {
  312. return gimp_config_deserialize_memsize (value, prop_spec, scanner);
  313. }
  314. else if (prop_spec->value_type == GIMP_TYPE_CONFIG_PATH)
  315. {
  316. return gimp_config_deserialize_path (value, prop_spec, scanner);
  317. }
  318. else if (prop_spec->value_type == GIMP_TYPE_RGB)
  319. {
  320. return gimp_config_deserialize_rgb (value, prop_spec, scanner);
  321. }
  322. else if (prop_spec->value_type == GIMP_TYPE_MATRIX2)
  323. {
  324. return gimp_config_deserialize_matrix2 (value, prop_spec, scanner);
  325. }
  326. else if (prop_spec->value_type == GIMP_TYPE_VALUE_ARRAY)
  327. {
  328. return gimp_config_deserialize_value_array (value,
  329. config, prop_spec, scanner);
  330. }
  331. else if (prop_spec->value_type == G_TYPE_STRV)
  332. {
  333. return gimp_config_deserialize_strv (value, scanner);
  334. }
  335. else if (prop_spec->value_type == GIMP_TYPE_UNIT)
  336. {
  337. return gimp_config_deserialize_unit (value, prop_spec, scanner);
  338. }
  339. else if (prop_spec->value_type == G_TYPE_FILE)
  340. {
  341. return gimp_config_deserialize_file_value (value, prop_spec, scanner);
  342. }
  343. else if (prop_spec->value_type == GIMP_TYPE_PARASITE)
  344. {
  345. return gimp_config_deserialize_parasite_value (value, prop_spec, scanner);
  346. }
  347. else if (prop_spec->value_type == G_TYPE_BYTES)
  348. {
  349. return gimp_config_deserialize_bytes (value, prop_spec, scanner);
  350. }
  351. else if (prop_spec->value_type == GEGL_TYPE_COLOR)
  352. {
  353. return gimp_config_deserialize_color (value, prop_spec, scanner);
  354. }
  355. /* This fallback will only work for value_types that
  356. * can be transformed from a string value.
  357. */
  358. return gimp_config_deserialize_any (value, prop_spec, scanner);
  359. }
  360. static GTokenType
  361. gimp_config_deserialize_fundamental (GValue *value,
  362. GParamSpec *prop_spec,
  363. GScanner *scanner)
  364. {
  365. GTokenType token;
  366. GTokenType next_token;
  367. GType value_type;
  368. gboolean negate = FALSE;
  369. value_type = G_TYPE_FUNDAMENTAL (prop_spec->value_type);
  370. switch (value_type)
  371. {
  372. case G_TYPE_STRING:
  373. token = G_TOKEN_STRING;
  374. break;
  375. case G_TYPE_BOOLEAN:
  376. token = G_TOKEN_IDENTIFIER;
  377. break;
  378. case G_TYPE_INT:
  379. case G_TYPE_LONG:
  380. case G_TYPE_INT64:
  381. if (g_scanner_peek_next_token (scanner) == '-')
  382. {
  383. negate = TRUE;
  384. g_scanner_get_next_token (scanner);
  385. }
  386. /* fallthrough */
  387. case G_TYPE_UINT:
  388. case G_TYPE_ULONG:
  389. case G_TYPE_UINT64:
  390. token = G_TOKEN_INT;
  391. break;
  392. case G_TYPE_FLOAT:
  393. case G_TYPE_DOUBLE:
  394. if (g_scanner_peek_next_token (scanner) == '-')
  395. {
  396. negate = TRUE;
  397. g_scanner_get_next_token (scanner);
  398. }
  399. token = G_TOKEN_FLOAT;
  400. break;
  401. default:
  402. g_assert_not_reached ();
  403. break;
  404. }
  405. next_token = g_scanner_peek_next_token (scanner);
  406. /* we parse integers into floats too, because g_ascii_dtostr()
  407. * serialized whole number without decimal point
  408. */
  409. if (next_token != token &&
  410. ! (token == G_TOKEN_FLOAT && next_token == G_TOKEN_INT))
  411. {
  412. return token;
  413. }
  414. g_scanner_get_next_token (scanner);
  415. switch (value_type)
  416. {
  417. case G_TYPE_STRING:
  418. if (scanner_string_utf8_valid (scanner, prop_spec->name))
  419. g_value_set_string (value, scanner->value.v_string);
  420. else
  421. return G_TOKEN_NONE;
  422. break;
  423. case G_TYPE_BOOLEAN:
  424. if (! g_ascii_strcasecmp (scanner->value.v_identifier, "yes") ||
  425. ! g_ascii_strcasecmp (scanner->value.v_identifier, "true"))
  426. g_value_set_boolean (value, TRUE);
  427. else if (! g_ascii_strcasecmp (scanner->value.v_identifier, "no") ||
  428. ! g_ascii_strcasecmp (scanner->value.v_identifier, "false"))
  429. g_value_set_boolean (value, FALSE);
  430. else
  431. {
  432. g_scanner_error
  433. (scanner,
  434. /* please don't translate 'yes' and 'no' */
  435. _("expected 'yes' or 'no' for boolean token %s, got '%s'"),
  436. prop_spec->name, scanner->value.v_identifier);
  437. return G_TOKEN_NONE;
  438. }
  439. break;
  440. case G_TYPE_INT:
  441. g_value_set_int (value, (negate ?
  442. - (gint) scanner->value.v_int64 :
  443. (gint) scanner->value.v_int64));
  444. break;
  445. case G_TYPE_UINT:
  446. g_value_set_uint (value, scanner->value.v_int64);
  447. break;
  448. case G_TYPE_LONG:
  449. g_value_set_long (value, (negate ?
  450. - (glong) scanner->value.v_int64 :
  451. (glong) scanner->value.v_int64));
  452. break;
  453. case G_TYPE_ULONG:
  454. g_value_set_ulong (value, scanner->value.v_int64);
  455. break;
  456. case G_TYPE_INT64:
  457. g_value_set_int64 (value, (negate ?
  458. - (gint64) scanner->value.v_int64 :
  459. (gint64) scanner->value.v_int64));
  460. break;
  461. case G_TYPE_UINT64:
  462. g_value_set_uint64 (value, scanner->value.v_int64);
  463. break;
  464. case G_TYPE_FLOAT:
  465. if (next_token == G_TOKEN_FLOAT)
  466. g_value_set_float (value, negate ?
  467. - scanner->value.v_float :
  468. scanner->value.v_float);
  469. else
  470. g_value_set_float (value, negate ?
  471. - (gfloat) scanner->value.v_int :
  472. (gfloat) scanner->value.v_int);
  473. break;
  474. case G_TYPE_DOUBLE:
  475. if (next_token == G_TOKEN_FLOAT)
  476. g_value_set_double (value, negate ?
  477. - scanner->value.v_float:
  478. scanner->value.v_float);
  479. else
  480. g_value_set_double (value, negate ?
  481. - (gdouble) scanner->value.v_int:
  482. (gdouble) scanner->value.v_int);
  483. break;
  484. default:
  485. g_assert_not_reached ();
  486. break;
  487. }
  488. return G_TOKEN_RIGHT_PAREN;
  489. }
  490. static GTokenType
  491. gimp_config_deserialize_enum (GValue *value,
  492. GParamSpec *prop_spec,
  493. GScanner *scanner)
  494. {
  495. GEnumClass *enum_class;
  496. GEnumValue *enum_value;
  497. enum_class = g_type_class_peek (G_VALUE_TYPE (value));
  498. switch (g_scanner_peek_next_token (scanner))
  499. {
  500. case G_TOKEN_IDENTIFIER:
  501. g_scanner_get_next_token (scanner);
  502. enum_value = g_enum_get_value_by_nick (enum_class,
  503. scanner->value.v_identifier);
  504. if (! enum_value)
  505. enum_value = g_enum_get_value_by_name (enum_class,
  506. scanner->value.v_identifier);
  507. if (! enum_value)
  508. {
  509. /* if the value was not found, check if we have a compat
  510. * enum to find the ideitifier
  511. */
  512. GQuark quark = g_quark_from_static_string ("gimp-compat-enum");
  513. GType compat_type = (GType) g_type_get_qdata (G_VALUE_TYPE (value),
  514. quark);
  515. if (compat_type)
  516. {
  517. GEnumClass *compat_class = g_type_class_ref (compat_type);
  518. enum_value = g_enum_get_value_by_nick (compat_class,
  519. scanner->value.v_identifier);
  520. if (! enum_value)
  521. enum_value = g_enum_get_value_by_name (compat_class,
  522. scanner->value.v_identifier);
  523. /* finally, if we found a compat value, make sure the
  524. * same value exists in the original enum
  525. */
  526. if (enum_value)
  527. enum_value = g_enum_get_value (enum_class, enum_value->value);
  528. g_type_class_unref (compat_class);
  529. }
  530. }
  531. if (! enum_value)
  532. {
  533. g_scanner_error (scanner,
  534. _("invalid value '%s' for token %s"),
  535. scanner->value.v_identifier, prop_spec->name);
  536. return G_TOKEN_NONE;
  537. }
  538. break;
  539. case G_TOKEN_INT:
  540. g_scanner_get_next_token (scanner);
  541. enum_value = g_enum_get_value (enum_class,
  542. (gint) scanner->value.v_int64);
  543. if (! enum_value)
  544. {
  545. g_scanner_error (scanner,
  546. _("invalid value '%ld' for token %s"),
  547. (glong) scanner->value.v_int64, prop_spec->name);
  548. return G_TOKEN_NONE;
  549. }
  550. break;
  551. default:
  552. return G_TOKEN_IDENTIFIER;
  553. }
  554. g_value_set_enum (value, enum_value->value);
  555. return G_TOKEN_RIGHT_PAREN;
  556. }
  557. static GTokenType
  558. gimp_config_deserialize_memsize (GValue *value,
  559. GParamSpec *prop_spec,
  560. GScanner *scanner)
  561. {
  562. gchar *orig_cset_first = scanner->config->cset_identifier_first;
  563. gchar *orig_cset_nth = scanner->config->cset_identifier_nth;
  564. guint64 memsize;
  565. scanner->config->cset_identifier_first = G_CSET_DIGITS;
  566. scanner->config->cset_identifier_nth = G_CSET_DIGITS "gGmMkKbB";
  567. if (g_scanner_peek_next_token (scanner) != G_TOKEN_IDENTIFIER)
  568. return G_TOKEN_IDENTIFIER;
  569. g_scanner_get_next_token (scanner);
  570. scanner->config->cset_identifier_first = orig_cset_first;
  571. scanner->config->cset_identifier_nth = orig_cset_nth;
  572. if (! gimp_memsize_deserialize (scanner->value.v_identifier, &memsize))
  573. return G_TOKEN_NONE;
  574. g_value_set_uint64 (value, memsize);
  575. return G_TOKEN_RIGHT_PAREN;
  576. }
  577. static GTokenType
  578. gimp_config_deserialize_path (GValue *value,
  579. GParamSpec *prop_spec,
  580. GScanner *scanner)
  581. {
  582. GError *error = NULL;
  583. if (g_scanner_peek_next_token (scanner) != G_TOKEN_STRING)
  584. return G_TOKEN_STRING;
  585. g_scanner_get_next_token (scanner);
  586. if (!scanner_string_utf8_valid (scanner, prop_spec->name))
  587. return G_TOKEN_NONE;
  588. if (scanner->value.v_string)
  589. {
  590. /* Check if the string can be expanded
  591. * and converted to the filesystem encoding.
  592. */
  593. gchar *expand = gimp_config_path_expand (scanner->value.v_string,
  594. TRUE, &error);
  595. if (!expand)
  596. {
  597. g_scanner_error (scanner,
  598. _("while parsing token '%s': %s"),
  599. prop_spec->name, error->message);
  600. g_error_free (error);
  601. return G_TOKEN_NONE;
  602. }
  603. g_free (expand);
  604. g_value_set_static_string (value, scanner->value.v_string);
  605. }
  606. return G_TOKEN_RIGHT_PAREN;
  607. }
  608. static GTokenType
  609. gimp_config_deserialize_rgb (GValue *value,
  610. GParamSpec *prop_spec,
  611. GScanner *scanner)
  612. {
  613. GeglColor *color = NULL;
  614. GimpRGB rgb;
  615. if (! gimp_scanner_parse_color (scanner, &color))
  616. return G_TOKEN_NONE;
  617. gegl_color_get_pixel (color, babl_format ("R'G'B'A double"), &rgb);
  618. g_value_set_boxed (value, &rgb);
  619. return G_TOKEN_RIGHT_PAREN;
  620. }
  621. static GTokenType
  622. gimp_config_deserialize_matrix2 (GValue *value,
  623. GParamSpec *prop_spec,
  624. GScanner *scanner)
  625. {
  626. GimpMatrix2 matrix;
  627. if (! gimp_scanner_parse_matrix2 (scanner, &matrix))
  628. return G_TOKEN_NONE;
  629. g_value_set_boxed (value, &matrix);
  630. return G_TOKEN_RIGHT_PAREN;
  631. }
  632. static GTokenType
  633. gimp_config_deserialize_object (GValue *value,
  634. GimpConfig *config,
  635. GParamSpec *prop_spec,
  636. GScanner *scanner,
  637. gint nest_level)
  638. {
  639. GimpConfigInterface *config_iface;
  640. GimpConfig *prop_object;
  641. GType type;
  642. g_object_get_property (G_OBJECT (config), prop_spec->name, value);
  643. prop_object = g_value_get_object (value);
  644. /* if the object property is not GIMP_CONFIG_PARAM_AGGREGATE, read
  645. * the type of the object.
  646. */
  647. if (! (prop_spec->flags & GIMP_CONFIG_PARAM_AGGREGATE))
  648. {
  649. gchar *type_name;
  650. if (! gimp_scanner_parse_string (scanner, &type_name))
  651. return G_TOKEN_STRING;
  652. if (! (type_name && *type_name))
  653. {
  654. g_scanner_error (scanner, "Type name is empty");
  655. g_free (type_name);
  656. return G_TOKEN_NONE;
  657. }
  658. type = g_type_from_name (type_name);
  659. g_free (type_name);
  660. if (! g_type_is_a (type, prop_spec->value_type))
  661. return G_TOKEN_STRING;
  662. }
  663. if (! prop_object)
  664. {
  665. /* if the object property is not GIMP_CONFIG_PARAM_AGGREGATE,
  666. * create the object.
  667. */
  668. if (! (prop_spec->flags & GIMP_CONFIG_PARAM_AGGREGATE))
  669. {
  670. prop_object = g_object_new (type, NULL);
  671. g_value_take_object (value, prop_object);
  672. }
  673. else
  674. {
  675. return G_TOKEN_RIGHT_PAREN;
  676. }
  677. }
  678. config_iface = GIMP_CONFIG_GET_IFACE (prop_object);
  679. if (! config_iface)
  680. return gimp_config_deserialize_any (value, prop_spec, scanner);
  681. if (config_iface->deserialize_create != NULL)
  682. {
  683. /* Some class may prefer to create themselves their objects, for instance
  684. * to maintain unicity of objects (in libgimp in particular, the various
  685. * GimpItem or GimpResource are managed by the lib. A single item or
  686. * resource must be represented for a single object across the whole
  687. * processus.
  688. */
  689. GimpConfig *created_object;
  690. created_object = config_iface->deserialize_create (G_TYPE_FROM_INSTANCE (prop_object),
  691. scanner, nest_level + 1, NULL);
  692. if (created_object == NULL)
  693. return G_TOKEN_NONE;
  694. else
  695. g_value_take_object (value, created_object);
  696. }
  697. else if (! config_iface->deserialize (prop_object, scanner, nest_level + 1, NULL))
  698. {
  699. return G_TOKEN_NONE;
  700. }
  701. return G_TOKEN_RIGHT_PAREN;
  702. }
  703. static GTokenType
  704. gimp_config_deserialize_value_array (GValue *value,
  705. GimpConfig *config,
  706. GParamSpec *prop_spec,
  707. GScanner *scanner)
  708. {
  709. GimpParamSpecValueArray *array_spec;
  710. GimpValueArray *array;
  711. GValue array_value = G_VALUE_INIT;
  712. gint n_values;
  713. GTokenType token;
  714. gint i;
  715. array_spec = GIMP_PARAM_SPEC_VALUE_ARRAY (prop_spec);
  716. if (! gimp_scanner_parse_int (scanner, &n_values))
  717. return G_TOKEN_INT;
  718. array = gimp_value_array_new (n_values);
  719. for (i = 0; i < n_values; i++)
  720. {
  721. g_value_init (&array_value, array_spec->element_spec->value_type);
  722. token = gimp_config_deserialize_value (&array_value,
  723. config,
  724. array_spec->element_spec,
  725. scanner);
  726. if (token == G_TOKEN_RIGHT_PAREN)
  727. gimp_value_array_append (array, &array_value);
  728. g_value_unset (&array_value);
  729. if (token != G_TOKEN_RIGHT_PAREN)
  730. {
  731. gimp_value_array_unref (array);
  732. return token;
  733. }
  734. }
  735. g_value_take_boxed (value, array);
  736. return G_TOKEN_RIGHT_PAREN;
  737. }
  738. /* This function is entirely sick, so is our method of serializing
  739. * units, which we write out as (unit foo bar) instead of
  740. * (unit "foo bar"). The assumption that caused this shit was that a
  741. * unit's "identifier" is really an identifier in the C-ish sense,
  742. * when in fact it's just a random user entered string.
  743. *
  744. * Here, we try to parse at least the default units shipped with gimp,
  745. * and we add code to parse (unit "foo bar") in order to be compatible
  746. * with future correct unit serializing.
  747. */
  748. static GTokenType
  749. gimp_config_deserialize_unit (GValue *value,
  750. GParamSpec *prop_spec,
  751. GScanner *scanner)
  752. {
  753. gchar *old_cset_skip_characters;
  754. gchar *old_cset_identifier_first;
  755. gchar *old_cset_identifier_nth;
  756. GString *buffer;
  757. GValue src = G_VALUE_INIT;
  758. GTokenType token;
  759. /* parse the next token *before* reconfiguring the scanner, so it
  760. * skips whitespace first
  761. */
  762. token = g_scanner_peek_next_token (scanner);
  763. if (token == G_TOKEN_STRING)
  764. return gimp_config_deserialize_any (value, prop_spec, scanner);
  765. old_cset_skip_characters = scanner->config->cset_skip_characters;
  766. old_cset_identifier_first = scanner->config->cset_identifier_first;
  767. old_cset_identifier_nth = scanner->config->cset_identifier_nth;
  768. scanner->config->cset_skip_characters = "";
  769. scanner->config->cset_identifier_first = ( G_CSET_a_2_z G_CSET_A_2_Z "." );
  770. scanner->config->cset_identifier_nth = ( G_CSET_a_2_z G_CSET_A_2_Z
  771. G_CSET_DIGITS "-_." );
  772. buffer = g_string_new ("");
  773. while (g_scanner_peek_next_token (scanner) != G_TOKEN_RIGHT_PAREN)
  774. {
  775. token = g_scanner_peek_next_token (scanner);
  776. if (token == G_TOKEN_IDENTIFIER)
  777. {
  778. g_scanner_get_next_token (scanner);
  779. g_string_append (buffer, scanner->value.v_identifier);
  780. }
  781. else if (token == G_TOKEN_CHAR)
  782. {
  783. g_scanner_get_next_token (scanner);
  784. g_string_append_c (buffer, scanner->value.v_char);
  785. }
  786. else if (token == ' ')
  787. {
  788. g_scanner_get_next_token (scanner);
  789. g_string_append_c (buffer, token);
  790. }
  791. else
  792. {
  793. token = G_TOKEN_IDENTIFIER;
  794. goto cleanup;
  795. }
  796. }
  797. g_value_init (&src, G_TYPE_STRING);
  798. g_value_set_static_string (&src, buffer->str);
  799. g_value_transform (&src, value);
  800. g_value_unset (&src);
  801. token = G_TOKEN_RIGHT_PAREN;
  802. cleanup:
  803. g_string_free (buffer, TRUE);
  804. scanner->config->cset_skip_characters = old_cset_skip_characters;
  805. scanner->config->cset_identifier_first = old_cset_identifier_first;
  806. scanner->config->cset_identifier_nth = old_cset_identifier_nth;
  807. return token;
  808. }
  809. static GTokenType
  810. gimp_config_deserialize_file_value (GValue *value,
  811. GParamSpec *prop_spec,
  812. GScanner *scanner)
  813. {
  814. GTokenType token;
  815. token = g_scanner_peek_next_token (scanner);
  816. if (token != G_TOKEN_IDENTIFIER &&
  817. token != G_TOKEN_STRING)
  818. {
  819. return G_TOKEN_STRING;
  820. }
  821. g_scanner_get_next_token (scanner);
  822. if (token == G_TOKEN_IDENTIFIER)
  823. {
  824. /* this is supposed to parse a literal "NULL" only, but so what... */
  825. g_value_set_object (value, NULL);
  826. }
  827. else
  828. {
  829. gchar *path = gimp_config_path_expand (scanner->value.v_string, TRUE,
  830. NULL);
  831. if (path)
  832. {
  833. GFile *file = g_file_new_for_path (path);
  834. g_value_take_object (value, file);
  835. g_free (path);
  836. }
  837. else
  838. {
  839. g_value_set_object (value, NULL);
  840. }
  841. }
  842. return G_TOKEN_RIGHT_PAREN;
  843. }
  844. /*
  845. * Note: this is different from gimp_config_deserialize_parasite()
  846. * which is a public API to deserialize random properties into a config
  847. * object from a parasite. Here we are deserializing the contents of a
  848. * parasite itself in @scanner.
  849. */
  850. static GTokenType
  851. gimp_config_deserialize_parasite_value (GValue *value,
  852. GParamSpec *prop_spec,
  853. GScanner *scanner)
  854. {
  855. GimpParasite *parasite;
  856. gchar *name;
  857. guint8 *data;
  858. gint data_length;
  859. gint64 flags;
  860. if (! gimp_scanner_parse_string (scanner, &name))
  861. return G_TOKEN_STRING;
  862. if (! (name && *name))
  863. {
  864. g_scanner_error (scanner, "Parasite name is empty");
  865. g_free (name);
  866. return G_TOKEN_NONE;
  867. }
  868. if (! gimp_scanner_parse_int64 (scanner, &flags))
  869. return G_TOKEN_INT;
  870. if (! gimp_scanner_parse_int (scanner, &data_length))
  871. return G_TOKEN_INT;
  872. if (! gimp_scanner_parse_data (scanner, data_length, &data))
  873. return G_TOKEN_STRING;
  874. parasite = gimp_parasite_new (name, flags, data_length, data);
  875. g_free (data);
  876. g_value_take_boxed (value, parasite);
  877. return G_TOKEN_RIGHT_PAREN;
  878. }
  879. static GTokenType
  880. gimp_config_deserialize_bytes (GValue *value,
  881. GParamSpec *prop_spec,
  882. GScanner *scanner)
  883. {
  884. GTokenType token;
  885. GBytes *bytes;
  886. guint8 *data;
  887. gint data_length;
  888. token = g_scanner_peek_next_token (scanner);
  889. if (token == G_TOKEN_IDENTIFIER)
  890. {
  891. g_scanner_get_next_token (scanner);
  892. if (g_ascii_strcasecmp (scanner->value.v_identifier, "null") != 0)
  893. /* Do not fail the whole file parsing. Just output to stderr and assume
  894. * a NULL bytes property.
  895. */
  896. g_printerr ("%s: expected NULL identifier for bytes token '%s', got '%s'. "
  897. "Assuming NULL instead.\n",
  898. G_STRFUNC, prop_spec->name, scanner->value.v_identifier);
  899. g_value_set_boxed (value, NULL);
  900. }
  901. else if (token == G_TOKEN_INT)
  902. {
  903. if (! gimp_scanner_parse_int (scanner, &data_length))
  904. return G_TOKEN_INT;
  905. if (! gimp_scanner_parse_data (scanner, data_length, &data))
  906. return G_TOKEN_STRING;
  907. bytes = g_bytes_new_take (data, data_length);
  908. g_value_take_boxed (value, bytes);
  909. }
  910. else
  911. {
  912. return G_TOKEN_INT;
  913. }
  914. return G_TOKEN_RIGHT_PAREN;
  915. }
  916. static GTokenType
  917. gimp_config_deserialize_color (GValue *value,
  918. GParamSpec *prop_spec,
  919. GScanner *scanner)
  920. {
  921. GeglColor *color = NULL;
  922. if (! gimp_scanner_parse_color (scanner, &color))
  923. return G_TOKEN_NONE;
  924. g_value_take_object (value, color);
  925. return G_TOKEN_RIGHT_PAREN;
  926. }
  927. static GTokenType
  928. gimp_config_deserialize_any (GValue *value,
  929. GParamSpec *prop_spec,
  930. GScanner *scanner)
  931. {
  932. GValue src = G_VALUE_INIT;
  933. GTokenType token;
  934. if (!g_value_type_transformable (G_TYPE_STRING, prop_spec->value_type))
  935. {
  936. g_scanner_error (scanner,
  937. "%s can not be transformed from a string",
  938. g_type_name (prop_spec->value_type));
  939. return G_TOKEN_NONE;
  940. }
  941. token = g_scanner_peek_next_token (scanner);
  942. if (token != G_TOKEN_IDENTIFIER &&
  943. token != G_TOKEN_STRING)
  944. {
  945. return G_TOKEN_IDENTIFIER;
  946. }
  947. g_scanner_get_next_token (scanner);
  948. g_value_init (&src, G_TYPE_STRING);
  949. if (token == G_TOKEN_IDENTIFIER)
  950. g_value_set_static_string (&src, scanner->value.v_identifier);
  951. else
  952. g_value_set_static_string (&src, scanner->value.v_string);
  953. g_value_transform (&src, value);
  954. g_value_unset (&src);
  955. return G_TOKEN_RIGHT_PAREN;
  956. }
  957. static GTokenType
  958. gimp_config_skip_unknown_property (GScanner *scanner)
  959. {
  960. gint open_paren = 0;
  961. while (TRUE)
  962. {
  963. GTokenType token = g_scanner_peek_next_token (scanner);
  964. switch (token)
  965. {
  966. case G_TOKEN_LEFT_PAREN:
  967. open_paren++;
  968. g_scanner_get_next_token (scanner);
  969. break;
  970. case G_TOKEN_RIGHT_PAREN:
  971. if (open_paren == 0)
  972. return token;
  973. open_paren--;
  974. g_scanner_get_next_token (scanner);
  975. break;
  976. case G_TOKEN_EOF:
  977. return token;
  978. default:
  979. g_scanner_get_next_token (scanner);
  980. break;
  981. }
  982. }
  983. }