gimpscanner.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086
  1. /* LIBGIMP - The GIMP Library
  2. * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3. *
  4. * gimpscanner.c
  5. * Copyright (C) 2002 Sven Neumann <sven@gimp.org>
  6. * Michael Natterer <mitch@gimp.org>
  7. *
  8. * This library is free software: you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 3 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Library General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library. If not, see
  20. * <https://www.gnu.org/licenses/>.
  21. */
  22. #include "config.h"
  23. #include <string.h>
  24. #include <errno.h>
  25. #include <cairo.h>
  26. #include <gegl.h>
  27. #include <gdk-pixbuf/gdk-pixbuf.h>
  28. #include "libgimpbase/gimpbase.h"
  29. #include "libgimpcolor/gimpcolor.h"
  30. #include "libgimpmath/gimpmath.h"
  31. #include "gimpconfig-error.h"
  32. #include "gimpscanner.h"
  33. #include "libgimp/libgimp-intl.h"
  34. /**
  35. * SECTION: gimpscanner
  36. * @title: GimpScanner
  37. * @short_description: A wrapper around #GScanner with some convenience API.
  38. *
  39. * A wrapper around #GScanner with some convenience API.
  40. **/
  41. typedef struct
  42. {
  43. gint ref_count;
  44. gchar *name;
  45. GMappedFile *mapped;
  46. gchar *text;
  47. GError **error;
  48. } GimpScannerData;
  49. G_DEFINE_BOXED_TYPE (GimpScanner, gimp_scanner,
  50. gimp_scanner_ref, gimp_scanner_unref)
  51. /* local function prototypes */
  52. static GimpScanner * gimp_scanner_new (const gchar *name,
  53. GMappedFile *mapped,
  54. gchar *text,
  55. GError **error);
  56. static void gimp_scanner_message (GimpScanner *scanner,
  57. gchar *message,
  58. gboolean is_error);
  59. static GTokenType gimp_scanner_parse_deprecated_color (GimpScanner *scanner,
  60. GeglColor **color);
  61. /* public functions */
  62. /**
  63. * gimp_scanner_new_file:
  64. * @file: a #GFile
  65. * @error: return location for #GError, or %NULL
  66. *
  67. * Returns: (transfer full): The new #GimpScanner.
  68. *
  69. * Since: 2.10
  70. **/
  71. GimpScanner *
  72. gimp_scanner_new_file (GFile *file,
  73. GError **error)
  74. {
  75. GimpScanner *scanner;
  76. gchar *path;
  77. g_return_val_if_fail (G_IS_FILE (file), NULL);
  78. g_return_val_if_fail (error == NULL || *error == NULL, NULL);
  79. path = g_file_get_path (file);
  80. if (path)
  81. {
  82. GMappedFile *mapped;
  83. mapped = g_mapped_file_new (path, FALSE, error);
  84. g_free (path);
  85. if (! mapped)
  86. {
  87. if (error)
  88. {
  89. (*error)->domain = GIMP_CONFIG_ERROR;
  90. (*error)->code = ((*error)->code == G_FILE_ERROR_NOENT ?
  91. GIMP_CONFIG_ERROR_OPEN_ENOENT :
  92. GIMP_CONFIG_ERROR_OPEN);
  93. }
  94. return NULL;
  95. }
  96. /* gimp_scanner_new() takes a "name" for the scanner, not a filename */
  97. scanner = gimp_scanner_new (gimp_file_get_utf8_name (file),
  98. mapped, NULL, error);
  99. g_scanner_input_text (scanner,
  100. g_mapped_file_get_contents (mapped),
  101. g_mapped_file_get_length (mapped));
  102. }
  103. else
  104. {
  105. GInputStream *input;
  106. input = G_INPUT_STREAM (g_file_read (file, NULL, error));
  107. if (! input)
  108. {
  109. if (error)
  110. {
  111. (*error)->domain = GIMP_CONFIG_ERROR;
  112. (*error)->code = ((*error)->code == G_IO_ERROR_NOT_FOUND ?
  113. GIMP_CONFIG_ERROR_OPEN_ENOENT :
  114. GIMP_CONFIG_ERROR_OPEN);
  115. }
  116. return NULL;
  117. }
  118. g_object_set_data (G_OBJECT (input), "gimp-data", file);
  119. scanner = gimp_scanner_new_stream (input, error);
  120. g_object_unref (input);
  121. }
  122. return scanner;
  123. }
  124. /**
  125. * gimp_scanner_new_stream:
  126. * @input: a #GInputStream
  127. * @error: return location for #GError, or %NULL
  128. *
  129. * Returns: (transfer full): The new #GimpScanner.
  130. *
  131. * Since: 2.10
  132. **/
  133. GimpScanner *
  134. gimp_scanner_new_stream (GInputStream *input,
  135. GError **error)
  136. {
  137. GimpScanner *scanner;
  138. GFile *file;
  139. const gchar *path;
  140. GString *string;
  141. gchar buffer[4096];
  142. gsize bytes_read;
  143. g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL);
  144. g_return_val_if_fail (error == NULL || *error == NULL, NULL);
  145. file = g_object_get_data (G_OBJECT (input), "gimp-file");
  146. if (file)
  147. path = gimp_file_get_utf8_name (file);
  148. else
  149. path = "stream";
  150. string = g_string_new (NULL);
  151. do
  152. {
  153. GError *my_error = NULL;
  154. gboolean success;
  155. success = g_input_stream_read_all (input, buffer, sizeof (buffer),
  156. &bytes_read, NULL, &my_error);
  157. if (bytes_read > 0)
  158. g_string_append_len (string, buffer, bytes_read);
  159. if (! success)
  160. {
  161. if (string->len > 0)
  162. {
  163. g_printerr ("%s: read error in '%s', trying to scan "
  164. "partial content: %s",
  165. G_STRFUNC, path, my_error->message);
  166. g_clear_error (&my_error);
  167. break;
  168. }
  169. g_string_free (string, TRUE);
  170. g_propagate_error (error, my_error);
  171. return NULL;
  172. }
  173. }
  174. while (bytes_read == sizeof (buffer));
  175. /* gimp_scanner_new() takes a "name" for the scanner, not a filename */
  176. scanner = gimp_scanner_new (path, NULL, string->str, error);
  177. bytes_read = string->len;
  178. g_scanner_input_text (scanner, g_string_free (string, FALSE), bytes_read);
  179. return scanner;
  180. }
  181. /**
  182. * gimp_scanner_new_string:
  183. * @text: (array length=text_len):
  184. * @text_len: The length of @text, or -1 if NULL-terminated
  185. * @error: return location for #GError, or %NULL
  186. *
  187. * Returns: (transfer full): The new #GimpScanner.
  188. *
  189. * Since: 2.4
  190. **/
  191. GimpScanner *
  192. gimp_scanner_new_string (const gchar *text,
  193. gint text_len,
  194. GError **error)
  195. {
  196. GimpScanner *scanner;
  197. g_return_val_if_fail (text != NULL || text_len <= 0, NULL);
  198. g_return_val_if_fail (error == NULL || *error == NULL, NULL);
  199. if (text_len < 0)
  200. text_len = text ? strlen (text) : 0;
  201. scanner = gimp_scanner_new (NULL, NULL, NULL, error);
  202. g_scanner_input_text (scanner, text, text_len);
  203. return scanner;
  204. }
  205. static GimpScanner *
  206. gimp_scanner_new (const gchar *name,
  207. GMappedFile *mapped,
  208. gchar *text,
  209. GError **error)
  210. {
  211. GimpScanner *scanner;
  212. GimpScannerData *data;
  213. scanner = g_scanner_new (NULL);
  214. data = g_slice_new0 (GimpScannerData);
  215. data->ref_count = 1;
  216. data->name = g_strdup (name);
  217. data->mapped = mapped;
  218. data->text = text;
  219. data->error = error;
  220. scanner->user_data = data;
  221. scanner->msg_handler = gimp_scanner_message;
  222. scanner->config->cset_identifier_first = ( G_CSET_a_2_z G_CSET_A_2_Z );
  223. scanner->config->cset_identifier_nth = ( G_CSET_a_2_z G_CSET_A_2_Z
  224. G_CSET_DIGITS "-_" );
  225. scanner->config->scan_identifier_1char = TRUE;
  226. scanner->config->store_int64 = TRUE;
  227. return scanner;
  228. }
  229. /**
  230. * gimp_scanner_ref:
  231. * @scanner: #GimpScanner to ref
  232. *
  233. * Adds a reference to a #GimpScanner.
  234. *
  235. * Returns: the same @scanner.
  236. *
  237. * Since: 3.0
  238. */
  239. GimpScanner *
  240. gimp_scanner_ref (GimpScanner *scanner)
  241. {
  242. GimpScannerData *data;
  243. g_return_val_if_fail (scanner != NULL, NULL);
  244. data = scanner->user_data;
  245. data->ref_count++;
  246. return scanner;
  247. }
  248. /**
  249. * gimp_scanner_unref:
  250. * @scanner: A #GimpScanner created by gimp_scanner_new_file() or
  251. * gimp_scanner_new_string()
  252. *
  253. * Unref a #GimpScanner. If the reference count drops to zero, the
  254. * scanner is freed.
  255. *
  256. * Since: 3.0
  257. **/
  258. void
  259. gimp_scanner_unref (GimpScanner *scanner)
  260. {
  261. GimpScannerData *data;
  262. g_return_if_fail (scanner != NULL);
  263. data = scanner->user_data;
  264. data->ref_count--;
  265. if (data->ref_count < 1)
  266. {
  267. if (data->mapped)
  268. g_mapped_file_unref (data->mapped);
  269. if (data->text)
  270. g_free (data->text);
  271. g_free (data->name);
  272. g_slice_free (GimpScannerData, data);
  273. g_scanner_destroy (scanner);
  274. }
  275. }
  276. /**
  277. * gimp_scanner_parse_token:
  278. * @scanner: A #GimpScanner created by gimp_scanner_new_file() or
  279. * gimp_scanner_new_string()
  280. * @token: the #GTokenType expected as next token.
  281. *
  282. * Returns: %TRUE if the next token is @token, %FALSE otherwise.
  283. *
  284. * Since: 2.4
  285. **/
  286. gboolean
  287. gimp_scanner_parse_token (GimpScanner *scanner,
  288. GTokenType token)
  289. {
  290. if (g_scanner_peek_next_token (scanner) != token)
  291. return FALSE;
  292. g_scanner_get_next_token (scanner);
  293. return TRUE;
  294. }
  295. /**
  296. * gimp_scanner_parse_identifier:
  297. * @scanner: A #GimpScanner created by gimp_scanner_new_file() or
  298. * gimp_scanner_new_string()
  299. * @identifier: (out): the expected identifier.
  300. *
  301. * Returns: %TRUE if the next token is an identifier and if its
  302. * value matches @identifier.
  303. *
  304. * Since: 2.4
  305. **/
  306. gboolean
  307. gimp_scanner_parse_identifier (GimpScanner *scanner,
  308. const gchar *identifier)
  309. {
  310. if (g_scanner_peek_next_token (scanner) != G_TOKEN_IDENTIFIER)
  311. return FALSE;
  312. g_scanner_get_next_token (scanner);
  313. if (strcmp (scanner->value.v_identifier, identifier))
  314. return FALSE;
  315. return TRUE;
  316. }
  317. /**
  318. * gimp_scanner_parse_string:
  319. * @scanner: A #GimpScanner created by gimp_scanner_new_file() or
  320. * gimp_scanner_new_string()
  321. * @dest: (out): Return location for the parsed string
  322. *
  323. * Returns: %TRUE on success
  324. *
  325. * Since: 2.4
  326. **/
  327. gboolean
  328. gimp_scanner_parse_string (GimpScanner *scanner,
  329. gchar **dest)
  330. {
  331. if (g_scanner_peek_next_token (scanner) != G_TOKEN_STRING)
  332. return FALSE;
  333. g_scanner_get_next_token (scanner);
  334. if (*scanner->value.v_string)
  335. {
  336. if (! g_utf8_validate (scanner->value.v_string, -1, NULL))
  337. {
  338. g_scanner_warn (scanner, _("invalid UTF-8 string"));
  339. return FALSE;
  340. }
  341. *dest = g_strdup (scanner->value.v_string);
  342. }
  343. else
  344. {
  345. *dest = NULL;
  346. }
  347. return TRUE;
  348. }
  349. /**
  350. * gimp_scanner_parse_string_no_validate:
  351. * @scanner: A #GimpScanner created by gimp_scanner_new_file() or
  352. * gimp_scanner_new_string()
  353. * @dest: (out): Return location for the parsed string
  354. *
  355. * Returns: %TRUE on success
  356. *
  357. * Since: 2.4
  358. **/
  359. gboolean
  360. gimp_scanner_parse_string_no_validate (GimpScanner *scanner,
  361. gchar **dest)
  362. {
  363. if (g_scanner_peek_next_token (scanner) != G_TOKEN_STRING)
  364. return FALSE;
  365. g_scanner_get_next_token (scanner);
  366. if (*scanner->value.v_string)
  367. *dest = g_strdup (scanner->value.v_string);
  368. else
  369. *dest = NULL;
  370. return TRUE;
  371. }
  372. /**
  373. * gimp_scanner_parse_data:
  374. * @scanner: A #GimpScanner created by gimp_scanner_new_file() or
  375. * gimp_scanner_new_string()
  376. * @length: Length of the data to parse
  377. * @dest: (out) (array length=length): Return location for the parsed data
  378. *
  379. * Returns: %TRUE on success
  380. *
  381. * Since: 2.4
  382. **/
  383. gboolean
  384. gimp_scanner_parse_data (GimpScanner *scanner,
  385. gint length,
  386. guint8 **dest)
  387. {
  388. if (g_scanner_peek_next_token (scanner) != G_TOKEN_STRING)
  389. return FALSE;
  390. g_scanner_get_next_token (scanner);
  391. if (scanner->value.v_string)
  392. *dest = g_memdup2 (scanner->value.v_string, length);
  393. else
  394. *dest = NULL;
  395. return TRUE;
  396. }
  397. /**
  398. * gimp_scanner_parse_int:
  399. * @scanner: A #GimpScanner created by gimp_scanner_new_file() or
  400. * gimp_scanner_new_string()
  401. * @dest: (out): Return location for the parsed integer
  402. *
  403. * Returns: %TRUE on success
  404. *
  405. * Since: 2.4
  406. **/
  407. gboolean
  408. gimp_scanner_parse_int (GimpScanner *scanner,
  409. gint *dest)
  410. {
  411. gboolean negate = FALSE;
  412. if (g_scanner_peek_next_token (scanner) == '-')
  413. {
  414. negate = TRUE;
  415. g_scanner_get_next_token (scanner);
  416. }
  417. if (g_scanner_peek_next_token (scanner) != G_TOKEN_INT)
  418. return FALSE;
  419. g_scanner_get_next_token (scanner);
  420. if (negate)
  421. *dest = -scanner->value.v_int64;
  422. else
  423. *dest = scanner->value.v_int64;
  424. return TRUE;
  425. }
  426. /**
  427. * gimp_scanner_parse_int64:
  428. * @scanner: A #GimpScanner created by gimp_scanner_new_file() or
  429. * gimp_scanner_new_string()
  430. * @dest: (out): Return location for the parsed integer
  431. *
  432. * Returns: %TRUE on success
  433. *
  434. * Since: 2.8
  435. **/
  436. gboolean
  437. gimp_scanner_parse_int64 (GimpScanner *scanner,
  438. gint64 *dest)
  439. {
  440. gboolean negate = FALSE;
  441. if (g_scanner_peek_next_token (scanner) == '-')
  442. {
  443. negate = TRUE;
  444. g_scanner_get_next_token (scanner);
  445. }
  446. if (g_scanner_peek_next_token (scanner) != G_TOKEN_INT)
  447. return FALSE;
  448. g_scanner_get_next_token (scanner);
  449. if (negate)
  450. *dest = -scanner->value.v_int64;
  451. else
  452. *dest = scanner->value.v_int64;
  453. return TRUE;
  454. }
  455. /**
  456. * gimp_scanner_parse_float:
  457. * @scanner: A #GimpScanner created by gimp_scanner_new_file() or
  458. * gimp_scanner_new_string()
  459. * @dest: (out): Return location for the parsed float
  460. *
  461. * Returns: %TRUE on success
  462. *
  463. * Since: 2.4
  464. **/
  465. gboolean
  466. gimp_scanner_parse_float (GimpScanner *scanner,
  467. gdouble *dest)
  468. {
  469. gboolean negate = FALSE;
  470. if (g_scanner_peek_next_token (scanner) == '-')
  471. {
  472. negate = TRUE;
  473. g_scanner_get_next_token (scanner);
  474. }
  475. if (g_scanner_peek_next_token (scanner) == G_TOKEN_FLOAT)
  476. {
  477. g_scanner_get_next_token (scanner);
  478. if (negate)
  479. *dest = -scanner->value.v_float;
  480. else
  481. *dest = scanner->value.v_float;
  482. return TRUE;
  483. }
  484. else if (g_scanner_peek_next_token (scanner) == G_TOKEN_INT)
  485. {
  486. /* v_int is unsigned so we need to cast to
  487. *
  488. * gint64 first for negative values.
  489. */
  490. g_scanner_get_next_token (scanner);
  491. if (negate)
  492. *dest = - (gint64) scanner->value.v_int;
  493. else
  494. *dest = scanner->value.v_int;
  495. return TRUE;
  496. }
  497. return FALSE;
  498. }
  499. /**
  500. * gimp_scanner_parse_boolean:
  501. * @scanner: A #GimpScanner created by gimp_scanner_new_file() or
  502. * gimp_scanner_new_string()
  503. * @dest: (out): Return location for the parsed boolean
  504. *
  505. * Returns: %TRUE on success
  506. *
  507. * Since: 2.4
  508. **/
  509. gboolean
  510. gimp_scanner_parse_boolean (GimpScanner *scanner,
  511. gboolean *dest)
  512. {
  513. if (g_scanner_peek_next_token (scanner) != G_TOKEN_IDENTIFIER)
  514. return FALSE;
  515. g_scanner_get_next_token (scanner);
  516. if (! g_ascii_strcasecmp (scanner->value.v_identifier, "yes") ||
  517. ! g_ascii_strcasecmp (scanner->value.v_identifier, "true"))
  518. {
  519. *dest = TRUE;
  520. }
  521. else if (! g_ascii_strcasecmp (scanner->value.v_identifier, "no") ||
  522. ! g_ascii_strcasecmp (scanner->value.v_identifier, "false"))
  523. {
  524. *dest = FALSE;
  525. }
  526. else
  527. {
  528. g_scanner_error
  529. (scanner,
  530. /* please don't translate 'yes' and 'no' */
  531. _("expected 'yes' or 'no' for boolean token, got '%s'"),
  532. scanner->value.v_identifier);
  533. return FALSE;
  534. }
  535. return TRUE;
  536. }
  537. enum
  538. {
  539. COLOR_RGB = 1,
  540. COLOR_RGBA,
  541. COLOR_HSV,
  542. COLOR_HSVA,
  543. COLOR
  544. };
  545. /**
  546. * gimp_scanner_parse_color:
  547. * @scanner: A #GimpScanner created by gimp_scanner_new_file() or
  548. * gimp_scanner_new_string()
  549. * @color: (out callee-allocates): Pointer to a color to store the result
  550. *
  551. * Returns: %TRUE on success
  552. *
  553. * Since: 2.4
  554. **/
  555. gboolean
  556. gimp_scanner_parse_color (GimpScanner *scanner,
  557. GeglColor **color)
  558. {
  559. guint scope_id;
  560. guint old_scope_id;
  561. GTokenType token;
  562. gboolean success = TRUE;
  563. scope_id = g_quark_from_static_string ("gimp_scanner_parse_color");
  564. old_scope_id = g_scanner_set_scope (scanner, scope_id);
  565. if (! g_scanner_scope_lookup_symbol (scanner, scope_id, "color"))
  566. {
  567. g_scanner_scope_add_symbol (scanner, scope_id,
  568. "color", GINT_TO_POINTER (COLOR));
  569. /* Deprecated. Kept for backward compatibility. */
  570. g_scanner_scope_add_symbol (scanner, scope_id,
  571. "color-rgb", GINT_TO_POINTER (COLOR_RGB));
  572. g_scanner_scope_add_symbol (scanner, scope_id,
  573. "color-rgba", GINT_TO_POINTER (COLOR_RGBA));
  574. g_scanner_scope_add_symbol (scanner, scope_id,
  575. "color-hsv", GINT_TO_POINTER (COLOR_HSV));
  576. g_scanner_scope_add_symbol (scanner, scope_id,
  577. "color-hsva", GINT_TO_POINTER (COLOR_HSVA));
  578. }
  579. token = g_scanner_peek_next_token (scanner);
  580. if (token == G_TOKEN_IDENTIFIER)
  581. {
  582. g_scanner_get_next_token (scanner);
  583. if (g_ascii_strcasecmp (scanner->value.v_identifier, "null") != 0)
  584. /* Do not fail the whole color parsing. Just output to stderr and assume
  585. * a NULL color property.
  586. */
  587. g_printerr ("%s: expected NULL identifier for serialized color, got '%s'. "
  588. "Assuming NULL instead.\n",
  589. G_STRFUNC, scanner->value.v_identifier);
  590. *color = NULL;
  591. token = g_scanner_peek_next_token (scanner);
  592. if (token == G_TOKEN_RIGHT_PAREN)
  593. token = G_TOKEN_NONE;
  594. else
  595. token = G_TOKEN_RIGHT_PAREN;
  596. }
  597. else if (token == G_TOKEN_LEFT_PAREN)
  598. {
  599. g_scanner_get_next_token (scanner);
  600. token = g_scanner_peek_next_token (scanner);
  601. if (token == G_TOKEN_SYMBOL)
  602. {
  603. if (GPOINTER_TO_INT (scanner->next_value.v_symbol) != COLOR)
  604. {
  605. /* Support historical GimpRGB format which may be stored in various config
  606. * files, but even some data (such as GTP tool presets which contains
  607. * tool-options which are GimpContext).
  608. */
  609. if (gimp_scanner_parse_deprecated_color (scanner, color))
  610. token = G_TOKEN_RIGHT_PAREN;
  611. else
  612. success = FALSE;
  613. }
  614. else
  615. {
  616. const Babl *format;
  617. gchar *encoding;
  618. guint8 *data;
  619. gint data_length;
  620. gint profile_data_length;
  621. g_scanner_get_next_token (scanner);
  622. if (! gimp_scanner_parse_string (scanner, &encoding))
  623. {
  624. token = G_TOKEN_STRING;
  625. goto color_parsed;
  626. }
  627. if (! babl_format_exists (encoding))
  628. {
  629. g_scanner_error (scanner,
  630. "%s: format \"%s\" for serialized color is not a valid babl format.",
  631. G_STRFUNC, encoding);
  632. g_free (encoding);
  633. success = FALSE;
  634. goto color_parsed;
  635. }
  636. format = babl_format (encoding);
  637. g_free (encoding);
  638. if (! gimp_scanner_parse_int (scanner, &data_length))
  639. {
  640. token = G_TOKEN_INT;
  641. goto color_parsed;
  642. }
  643. if (data_length != babl_format_get_bytes_per_pixel (format))
  644. {
  645. g_scanner_error (scanner,
  646. "%s: format \"%s\" expects %d bpp but color was serialized with %d bpp.",
  647. G_STRFUNC, babl_get_name (format),
  648. babl_format_get_bytes_per_pixel (format),
  649. data_length);
  650. success = FALSE;
  651. goto color_parsed;
  652. }
  653. if (! gimp_scanner_parse_data (scanner, data_length, &data))
  654. {
  655. token = G_TOKEN_STRING;
  656. goto color_parsed;
  657. }
  658. if (! gimp_scanner_parse_int (scanner, &profile_data_length))
  659. {
  660. g_free (data);
  661. token = G_TOKEN_INT;
  662. goto color_parsed;
  663. }
  664. if (profile_data_length > 0)
  665. {
  666. const Babl *space = NULL;
  667. GimpColorProfile *profile;
  668. guint8 *profile_data;
  669. GError *error = NULL;
  670. if (! gimp_scanner_parse_data (scanner, profile_data_length, &profile_data))
  671. {
  672. g_free (data);
  673. token = G_TOKEN_STRING;
  674. goto color_parsed;
  675. }
  676. profile = gimp_color_profile_new_from_icc_profile (profile_data, profile_data_length, &error);
  677. if (profile)
  678. {
  679. space = gimp_color_profile_get_space (profile,
  680. GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
  681. &error);
  682. if (! space)
  683. {
  684. g_scanner_error (scanner,
  685. "%s: failed to create Babl space for serialized color from profile: %s\n",
  686. G_STRFUNC, error->message);
  687. g_clear_error (&error);
  688. }
  689. g_object_unref (profile);
  690. }
  691. else
  692. {
  693. g_scanner_error (scanner,
  694. "%s: invalid profile data for serialized color: %s",
  695. G_STRFUNC, error->message);
  696. g_error_free (error);
  697. }
  698. format = babl_format_with_space (babl_format_get_encoding (format), space);
  699. g_free (profile_data);
  700. }
  701. *color = gegl_color_new (NULL);
  702. gegl_color_set_pixel (*color, format, data);
  703. token = G_TOKEN_RIGHT_PAREN;
  704. g_free (data);
  705. }
  706. }
  707. else
  708. {
  709. token = G_TOKEN_SYMBOL;
  710. }
  711. if (success && token == G_TOKEN_RIGHT_PAREN)
  712. {
  713. token = g_scanner_peek_next_token (scanner);
  714. if (token == G_TOKEN_RIGHT_PAREN)
  715. {
  716. g_scanner_get_next_token (scanner);
  717. token = G_TOKEN_NONE;
  718. }
  719. else
  720. {
  721. g_clear_object (color);
  722. token = G_TOKEN_RIGHT_PAREN;
  723. }
  724. }
  725. }
  726. else
  727. {
  728. token = G_TOKEN_LEFT_PAREN;
  729. }
  730. color_parsed:
  731. if (success && token != G_TOKEN_NONE)
  732. {
  733. g_scanner_get_next_token (scanner);
  734. g_scanner_unexp_token (scanner, token, NULL, NULL, NULL,
  735. _("fatal parse error"), TRUE);
  736. }
  737. g_scanner_set_scope (scanner, old_scope_id);
  738. return (success && token == G_TOKEN_NONE);
  739. }
  740. /**
  741. * gimp_scanner_parse_matrix2:
  742. * @scanner: A #GimpScanner created by gimp_scanner_new_file() or
  743. * gimp_scanner_new_string()
  744. * @dest: (out caller-allocates): Pointer to a matrix to store the result
  745. *
  746. * Returns: %TRUE on success
  747. *
  748. * Since: 2.4
  749. **/
  750. gboolean
  751. gimp_scanner_parse_matrix2 (GimpScanner *scanner,
  752. GimpMatrix2 *dest)
  753. {
  754. guint scope_id;
  755. guint old_scope_id;
  756. GTokenType token;
  757. GimpMatrix2 matrix;
  758. scope_id = g_quark_from_static_string ("gimp_scanner_parse_matrix");
  759. old_scope_id = g_scanner_set_scope (scanner, scope_id);
  760. if (! g_scanner_scope_lookup_symbol (scanner, scope_id, "matrix"))
  761. g_scanner_scope_add_symbol (scanner, scope_id,
  762. "matrix", GINT_TO_POINTER (0));
  763. token = G_TOKEN_LEFT_PAREN;
  764. while (g_scanner_peek_next_token (scanner) == token)
  765. {
  766. token = g_scanner_get_next_token (scanner);
  767. switch (token)
  768. {
  769. case G_TOKEN_LEFT_PAREN:
  770. token = G_TOKEN_SYMBOL;
  771. break;
  772. case G_TOKEN_SYMBOL:
  773. {
  774. token = G_TOKEN_FLOAT;
  775. if (! gimp_scanner_parse_float (scanner, &matrix.coeff[0][0]))
  776. goto finish;
  777. if (! gimp_scanner_parse_float (scanner, &matrix.coeff[0][1]))
  778. goto finish;
  779. if (! gimp_scanner_parse_float (scanner, &matrix.coeff[1][0]))
  780. goto finish;
  781. if (! gimp_scanner_parse_float (scanner, &matrix.coeff[1][1]))
  782. goto finish;
  783. token = G_TOKEN_RIGHT_PAREN;
  784. }
  785. break;
  786. case G_TOKEN_RIGHT_PAREN:
  787. token = G_TOKEN_NONE; /* indicates success */
  788. goto finish;
  789. default: /* do nothing */
  790. break;
  791. }
  792. }
  793. finish:
  794. if (token != G_TOKEN_NONE)
  795. {
  796. g_scanner_get_next_token (scanner);
  797. g_scanner_unexp_token (scanner, token, NULL, NULL, NULL,
  798. _("fatal parse error"), TRUE);
  799. }
  800. else
  801. {
  802. *dest = matrix;
  803. }
  804. g_scanner_set_scope (scanner, old_scope_id);
  805. return (token == G_TOKEN_NONE);
  806. }
  807. /* private functions */
  808. static void
  809. gimp_scanner_message (GimpScanner *scanner,
  810. gchar *message,
  811. gboolean is_error)
  812. {
  813. GimpScannerData *data = scanner->user_data;
  814. /* we don't expect warnings */
  815. g_return_if_fail (is_error);
  816. if (data->name)
  817. g_set_error (data->error, GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_PARSE,
  818. _("Error while parsing '%s' in line %d: %s"),
  819. data->name, scanner->line, message);
  820. else
  821. /* should never happen, thus not marked for translation */
  822. g_set_error (data->error, GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_PARSE,
  823. "Error parsing internal buffer: %s", message);
  824. }
  825. static GTokenType
  826. gimp_scanner_parse_deprecated_color (GimpScanner *scanner,
  827. GeglColor **color)
  828. {
  829. guint scope_id;
  830. guint old_scope_id;
  831. GTokenType token;
  832. scope_id = g_quark_from_static_string ("gimp_scanner_parse_deprecated_color");
  833. old_scope_id = g_scanner_set_scope (scanner, scope_id);
  834. if (! g_scanner_scope_lookup_symbol (scanner, scope_id, "color-rgb"))
  835. {
  836. g_scanner_scope_add_symbol (scanner, scope_id,
  837. "color-rgb", GINT_TO_POINTER (COLOR_RGB));
  838. g_scanner_scope_add_symbol (scanner, scope_id,
  839. "color-rgba", GINT_TO_POINTER (COLOR_RGBA));
  840. g_scanner_scope_add_symbol (scanner, scope_id,
  841. "color-hsv", GINT_TO_POINTER (COLOR_HSV));
  842. g_scanner_scope_add_symbol (scanner, scope_id,
  843. "color-hsva", GINT_TO_POINTER (COLOR_HSVA));
  844. }
  845. token = G_TOKEN_SYMBOL;
  846. while (g_scanner_peek_next_token (scanner) == token)
  847. {
  848. token = g_scanner_get_next_token (scanner);
  849. switch (token)
  850. {
  851. case G_TOKEN_SYMBOL:
  852. {
  853. gdouble col[4] = { 0.0, 0.0, 0.0, 1.0 };
  854. gdouble col_f[4] = { 0.0, 0.0, 0.0, 1.0 };
  855. gint n_channels = 4;
  856. gboolean is_hsv = FALSE;
  857. gint i;
  858. switch (GPOINTER_TO_INT (scanner->value.v_symbol))
  859. {
  860. case COLOR_RGB:
  861. n_channels = 3;
  862. /* fallthrough */
  863. case COLOR_RGBA:
  864. break;
  865. case COLOR_HSV:
  866. n_channels = 3;
  867. /* fallthrough */
  868. case COLOR_HSVA:
  869. is_hsv = TRUE;
  870. break;
  871. }
  872. token = G_TOKEN_FLOAT;
  873. for (i = 0; i < n_channels; i++)
  874. {
  875. if (! gimp_scanner_parse_float (scanner, &col[i]))
  876. goto finish;
  877. col_f[i] = (gfloat) col[i];
  878. }
  879. *color = gegl_color_new (NULL);
  880. if (is_hsv)
  881. gegl_color_set_pixel (*color, babl_format ("HSVA float"), col_f);
  882. else
  883. gegl_color_set_pixel (*color, babl_format ("R'G'B'A double"), col);
  884. /* Indicates success. */
  885. token = G_TOKEN_NONE;
  886. }
  887. break;
  888. default: /* do nothing */
  889. break;
  890. }
  891. }
  892. finish:
  893. g_scanner_set_scope (scanner, old_scope_id);
  894. return token;
  895. }