Branch data Line data Source code
1 : : /*
2 : : * gnome-keyring
3 : : *
4 : : * Copyright (C) 2011 Collabora Ltd.
5 : : *
6 : : * This program is free software; you can redistribute it and/or modify
7 : : * it under the terms of the GNU Lesser General Public License as
8 : : * published by the Free Software Foundation; either version 2.1 of
9 : : * the License, or (at your option) any later version.
10 : : *
11 : : * This program is distributed in the hope that it will be useful, but
12 : : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : * Lesser General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU Lesser General Public
17 : : * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : : *
19 : : * Author: Stef Walter <stefw@collabora.co.uk>
20 : : */
21 : :
22 : : #include "config.h"
23 : :
24 : : #include "gcr-record.h"
25 : :
26 : : #include <stdlib.h>
27 : : #include <string.h>
28 : : #include <time.h>
29 : :
30 : : #define MAX_COLUMNS 32
31 : :
32 : : typedef struct {
33 : : gpointer next;
34 : : gsize n_value;
35 : : gchar value[1];
36 : : /* Hangs off the end */
37 : : } GcrRecordBlock;
38 : :
39 : : struct _GcrRecord {
40 : : GcrRecordBlock *block;
41 : : const gchar *columns[MAX_COLUMNS];
42 : : guint n_columns;
43 : : gchar delimiter;
44 : : };
45 : :
46 [ + + + - : 5 : G_DEFINE_BOXED_TYPE (GcrRecord, _gcr_record, _gcr_record_copy, _gcr_record_free);
+ + ]
47 : :
48 : : static GcrRecordBlock *
49 : 531 : record_block_new (const gchar *value,
50 : : gsize length)
51 : : {
52 : : GcrRecordBlock *block;
53 : :
54 : 531 : block = g_malloc (sizeof (GcrRecordBlock) + length);
55 : 531 : block->next = NULL;
56 : 531 : block->n_value = length;
57 : :
58 [ + + ]: 531 : if (value != NULL) {
59 : 519 : memcpy (block->value, value, length);
60 : 519 : block->value[length] = 0;
61 : : } else {
62 : 12 : block->value[0] = 0;
63 : : }
64 : :
65 : 531 : return block;
66 : : }
67 : :
68 : : static GcrRecordBlock *
69 : 1171 : record_block_take (gchar *value,
70 : : gsize length)
71 : : {
72 : : GcrRecordBlock *block;
73 : :
74 [ - + ]: 1171 : g_assert (value);
75 : :
76 : 1171 : block = g_realloc (value, sizeof (GcrRecordBlock) + length);
77 : 1171 : memmove (((gchar*)block) + G_STRUCT_OFFSET (GcrRecordBlock, value),
78 : : block, length);
79 : 1171 : block->next = NULL;
80 : 1171 : block->n_value = length;
81 : 1171 : block->value[length] = 0;
82 : :
83 : 1171 : return block;
84 : : }
85 : :
86 : : static GcrRecord *
87 : 6 : record_flatten (GcrRecord *record)
88 : : {
89 : : GcrRecord *result;
90 : : GcrRecordBlock *block;
91 : : gsize total;
92 : : gsize at;
93 : : gsize len;
94 : : guint i;
95 : :
96 : : /* Calculate the length of what we need */
97 : 6 : total = 0;
98 [ + + ]: 40 : for (i = 0; i < record->n_columns; i++)
99 : 34 : total += strlen (record->columns[i]) + 1;
100 : :
101 : : /* Allocate a new GcrRecordData which will hold all that */
102 : 6 : result = g_slice_new0 (GcrRecord);
103 : 6 : result->block = block = record_block_new (NULL, total);
104 : :
105 : 6 : at = 0;
106 [ + + ]: 40 : for (i = 0; i < record->n_columns; i++) {
107 : 34 : len = strlen (record->columns[i]);
108 : 34 : result->columns[i] = block->value + at;
109 : 34 : memcpy ((gchar *)result->columns[i], record->columns[i], len + 1);
110 : 34 : at += len + 1;
111 : : }
112 : :
113 : 6 : result->n_columns = record->n_columns;
114 : 6 : result->delimiter = record->delimiter;
115 [ - + ]: 6 : g_assert (at == total);
116 : :
117 : 6 : return result;
118 : : }
119 : :
120 : : static void
121 : 308 : print_record_to_string (GcrRecord *record,
122 : : GString *string)
123 : : {
124 : : guint i;
125 : :
126 [ + + ]: 3690 : for (i = 0; i < record->n_columns; i++) {
127 : 3382 : g_string_append (string, record->columns[i]);
128 : 3382 : g_string_append_c (string, record->delimiter);
129 : : }
130 : 308 : }
131 : :
132 : : gchar *
133 : 90 : _gcr_record_format (GcrRecord *record)
134 : : {
135 : : GString *string;
136 : :
137 [ - + ]: 90 : g_return_val_if_fail (record, NULL);
138 : :
139 : 90 : string = g_string_new ("");
140 : 90 : print_record_to_string (record, string);
141 : 90 : return g_string_free (string, FALSE);
142 : : }
143 : :
144 : : GcrRecord *
145 : 348 : _gcr_record_new (GQuark schema,
146 : : guint n_columns,
147 : : gchar delimiter)
148 : : {
149 : : GcrRecord *result;
150 : : guint i;
151 : :
152 : 348 : result = g_slice_new0 (GcrRecord);
153 : 348 : result->block = NULL;
154 : 348 : result->delimiter = delimiter;
155 : :
156 [ + + ]: 4170 : for (i = 0; i < n_columns; i++)
157 : 3822 : result->columns[i] = "";
158 : 348 : result->columns[0] = g_quark_to_string (schema);
159 : 348 : result->n_columns = n_columns;
160 : :
161 : 348 : return result;
162 : : }
163 : :
164 : : GcrRecord *
165 : 6 : _gcr_record_copy (GcrRecord *record)
166 : : {
167 : 6 : return record_flatten (record);
168 : : }
169 : :
170 : : static GcrRecord *
171 : 180 : take_and_parse_internal (GcrRecordBlock *block,
172 : : gchar delimiter,
173 : : gboolean allow_empty)
174 : : {
175 : : GcrRecord *result;
176 : : gchar *at, *beg, *end;
177 : :
178 [ - + ]: 180 : g_assert (block);
179 : :
180 : 180 : result = g_slice_new0 (GcrRecord);
181 : 180 : result->block = block;
182 : 180 : result->delimiter = delimiter;
183 : :
184 : 180 : g_debug ("parsing line %s", block->value);
185 : :
186 : 180 : at = block->value;
187 : : for (;;) {
188 [ + + ]: 2110 : if (result->n_columns >= MAX_COLUMNS) {
189 : 1 : g_debug ("too many record (%d) in gnupg line", MAX_COLUMNS);
190 : 1 : _gcr_record_free (result);
191 : 1 : return NULL;
192 : : }
193 : :
194 : 2109 : beg = at;
195 : 2109 : result->columns[result->n_columns] = beg;
196 : :
197 : 2109 : at = strchr (beg, delimiter);
198 [ + + ]: 2109 : if (at == NULL) {
199 : 179 : end = (block->value + block->n_value) - 1;
200 : : } else {
201 : 1930 : at[0] = '\0';
202 : 1930 : end = at;
203 : 1930 : at++;
204 : : }
205 : :
206 [ + + + + ]: 2109 : if (allow_empty || end > beg)
207 : 2102 : result->n_columns++;
208 : :
209 [ + + ]: 2109 : if (at == NULL)
210 : 179 : break;
211 : : }
212 : :
213 : 179 : return result;
214 : : }
215 : :
216 : : GcrRecord*
217 : 177 : _gcr_record_parse_colons (const gchar *line, gssize n_line)
218 : : {
219 [ - + ]: 177 : g_return_val_if_fail (line, NULL);
220 [ + + ]: 177 : if (n_line < 0)
221 : 176 : n_line = strlen (line);
222 : 177 : return take_and_parse_internal (record_block_new (line, n_line), ':', TRUE);
223 : : }
224 : :
225 : : GcrRecord*
226 : 3 : _gcr_record_parse_spaces (const gchar *line, gssize n_line)
227 : : {
228 [ - + ]: 3 : g_return_val_if_fail (line, NULL);
229 [ + - ]: 3 : if (n_line < 0)
230 : 3 : n_line = strlen (line);
231 : 3 : return take_and_parse_internal (record_block_new (line, n_line), ' ', FALSE);
232 : : }
233 : :
234 : : guint
235 : 6 : _gcr_record_get_count (GcrRecord *record)
236 : : {
237 [ - + ]: 6 : g_return_val_if_fail (record, 0);
238 : 6 : return record->n_columns;
239 : : }
240 : :
241 : : static void
242 : 1516 : record_take_column (GcrRecord *record,
243 : : guint column,
244 : : GcrRecordBlock *block)
245 : : {
246 [ - + ]: 1516 : g_assert (block->next == NULL);
247 : 1516 : block->next = record->block;
248 : 1516 : record->block = block;
249 : :
250 [ - + ]: 1516 : g_assert (column < record->n_columns);
251 : 1516 : record->columns[column] = block->value;
252 : 1516 : }
253 : :
254 : : static const char HEXC_LOWER[] = "0123456789abcdef";
255 : :
256 : : /* Will return NULL if unescaping failed or not needed */
257 : : static gchar *
258 : 4 : c_colons_unescape (const gchar *source,
259 : : gsize *length)
260 : : {
261 : 4 : const gchar *p = source, *octal, *hex;
262 : 4 : gchar *dest = NULL;
263 : 4 : gchar *q = dest;
264 : : gchar *pos;
265 : :
266 [ + + ]: 72 : while (*p) {
267 [ + + ]: 68 : if (*p == '\\') {
268 [ + - ]: 1 : if (dest == NULL) {
269 : 1 : dest = g_malloc (strlen (source) + 1);
270 : 1 : memcpy (dest, source, (p - source));
271 : 1 : q = dest + (p - source);
272 : : }
273 : :
274 : 1 : p++;
275 [ - - - - : 1 : switch (*p) {
- - - +
- ]
276 : 0 : case '\0': /* invalid trailing backslash */
277 : 0 : g_free (dest);
278 : 0 : return NULL;
279 : 0 : case '0': case '1': case '2': case '3': case '4':
280 : : case '5': case '6': case '7':
281 : 0 : *q = 0;
282 : 0 : octal = p;
283 [ # # # # : 0 : while ((p < octal + 3) && (*p >= '0') && (*p <= '7')) {
# # ]
284 : 0 : *q = (*q * 8) + (*p - '0');
285 : 0 : p++;
286 : : }
287 : 0 : q++;
288 : 0 : p--;
289 : 0 : break;
290 : 0 : case 'x':
291 : 0 : *q = 0;
292 : 0 : hex = p;
293 [ # # ]: 0 : while (p < hex + 2) {
294 : 0 : pos = strchr (HEXC_LOWER, g_ascii_tolower (*p));
295 [ # # ]: 0 : if (pos == 0) { /* invalid bad hex character */
296 : 0 : g_free (dest);
297 : 0 : return NULL;
298 : : }
299 : 0 : *q = (*q * 16) + (pos - HEXC_LOWER);
300 : 0 : p++;
301 : : }
302 : 0 : q++;
303 : 0 : p--;
304 : 0 : break;
305 : 0 : case 'b':
306 : 0 : *q++ = '\b';
307 : 0 : break;
308 : 0 : case 'f':
309 : 0 : *q++ = '\f';
310 : 0 : break;
311 : 0 : case 'n':
312 : 0 : *q++ = '\n';
313 : 0 : break;
314 : 0 : case 'r':
315 : 0 : *q++ = '\r';
316 : 0 : break;
317 : 1 : case 't':
318 : 1 : *q++ = '\t';
319 : 1 : break;
320 : 0 : default: /* Also handles \" and \\ */
321 : 0 : *q++ = *p;
322 : 0 : break;
323 : : }
324 [ + + ]: 67 : } else if (q != NULL) {
325 : 4 : *q++ = *p;
326 : : }
327 : 68 : p++;
328 : : }
329 : :
330 [ + + ]: 4 : if (q != NULL) {
331 : 1 : *q = 0;
332 [ - + ]: 1 : if (length)
333 : 0 : *length = q - dest;
334 : : }
335 : :
336 : 4 : return dest;
337 : : }
338 : :
339 : : /* Will return NULL if no escaping needed */
340 : : static gchar *
341 : 75 : c_colons_escape (const gchar *source,
342 : : const gchar extra,
343 : : gsize *length)
344 : : {
345 : : const guchar *p;
346 : 75 : gchar *dest = NULL;
347 : 75 : gchar *q = NULL;
348 : : gchar escape;
349 : : gsize off;
350 : :
351 [ - + ]: 75 : g_return_val_if_fail (source != NULL, NULL);
352 : :
353 : 75 : p = (guchar *) source;
354 : :
355 [ + + ]: 2703 : while (*p) {
356 : 2628 : escape = 0;
357 [ - - - - : 2628 : switch (*p) {
- - - + ]
358 : 0 : case '\b':
359 : 0 : escape = 'b';
360 : 0 : break;
361 : 0 : case '\f':
362 : 0 : escape = 'f';
363 : 0 : break;
364 : 0 : case '\n':
365 : 0 : escape = 'n';
366 : 0 : break;
367 : 0 : case '\r':
368 : 0 : escape = 'r';
369 : 0 : break;
370 : 0 : case '\t':
371 : 0 : escape = 't';
372 : 0 : break;
373 : 0 : case '\\':
374 : 0 : escape = '\\';
375 : 0 : break;
376 : 0 : case '"':
377 : 0 : escape = '"';
378 : 0 : break;
379 : : }
380 : :
381 [ + - + - : 2628 : if (escape != 0 || *p < ' ' || *p >= 0x127 || *p == extra) {
- + ]
382 [ # # ]: 0 : if (dest == NULL) {
383 : : /* Each source byte needs maximally four destination chars (\xff) */
384 : 0 : dest = g_malloc (strlen (source) * 4 + 1);
385 : 0 : off = (gchar *)p - source;
386 : 0 : memcpy (dest, source, off);
387 : 0 : q = dest + off;
388 : : }
389 : :
390 [ # # ]: 0 : if (escape) {
391 : 0 : *q++ = '\\';
392 : 0 : *q++ = escape;
393 : : } else {
394 : 0 : *q++ = '\\';
395 : 0 : *q++ = 'x';
396 : 0 : *q++ = HEXC_LOWER[*p >> 4 & 0xf];
397 : 0 : *q++ = HEXC_LOWER[*p & 0xf];
398 : : }
399 [ - + ]: 2628 : } else if (q != NULL) {
400 : 0 : *q++ = *p;
401 : : }
402 : 2628 : p++;
403 : : }
404 : :
405 [ - + ]: 75 : if (q != NULL) {
406 : 0 : *q = 0;
407 [ # # ]: 0 : if (length)
408 : 0 : *length = q - dest;
409 : : }
410 : :
411 : 75 : return dest;
412 : : }
413 : :
414 : : gchar*
415 : 5 : _gcr_record_get_string (GcrRecord *record, guint column)
416 : : {
417 : : const gchar *value;
418 : 5 : gchar *text = NULL;
419 : :
420 [ - + ]: 5 : g_return_val_if_fail (record, NULL);
421 : :
422 : 5 : value = _gcr_record_get_raw (record, column);
423 [ + + ]: 5 : if (!value)
424 : 1 : return NULL;
425 : :
426 : 4 : text = c_colons_unescape (value, NULL);
427 [ + + ]: 4 : if (text != NULL)
428 : 1 : value = text;
429 : :
430 : : /* If it's not UTF-8, we guess that it's latin1 */
431 [ + + ]: 4 : if (!g_utf8_validate (value, -1, NULL)) {
432 : 1 : gchar *conv = g_convert (value, -1, "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
433 : 1 : g_free (text);
434 : 1 : value = text = conv;
435 : : }
436 : :
437 : : /*
438 : : * latin1 to utf-8 conversion can't really fail, just produce
439 : : * garbage... so there's no need to check here.
440 : : */
441 : :
442 [ + + ]: 4 : return (text == value) ? text : g_strdup (value);
443 : : }
444 : :
445 : : void
446 : 75 : _gcr_record_set_string (GcrRecord *record,
447 : : guint column,
448 : : const gchar *string)
449 : : {
450 : : GcrRecordBlock *block;
451 : : gchar *escaped;
452 : :
453 [ - + ]: 75 : g_return_if_fail (record != NULL);
454 [ - + ]: 75 : g_return_if_fail (string != NULL);
455 [ - + ]: 75 : g_return_if_fail (column < record->n_columns);
456 : :
457 : 75 : escaped = c_colons_escape (string, record->delimiter, NULL);
458 [ - + ]: 75 : if (escaped != NULL)
459 : 0 : block = record_block_take (escaped, strlen (escaped));
460 : : else
461 : 75 : block = record_block_new (string, strlen (string));
462 : :
463 : 75 : record_take_column (record, column, block);
464 : : }
465 : :
466 : : gchar
467 : 0 : _gcr_record_get_char (GcrRecord *record,
468 : : guint column)
469 : : {
470 : : const gchar *value;
471 : :
472 [ # # ]: 0 : g_return_val_if_fail (record, 0);
473 : :
474 : 0 : value = _gcr_record_get_raw (record, column);
475 [ # # ]: 0 : if (!value)
476 : 0 : return 0;
477 : :
478 [ # # # # ]: 0 : if (value[0] != 0 && value[1] == 0)
479 : 0 : return value[0];
480 : :
481 : 0 : return 0;
482 : : }
483 : :
484 : : void
485 : 192 : _gcr_record_set_char (GcrRecord *record,
486 : : guint column,
487 : : gchar value)
488 : : {
489 [ - + ]: 192 : g_return_if_fail (record != NULL);
490 [ - + ]: 192 : g_return_if_fail (column < record->n_columns);
491 [ - + ]: 192 : g_return_if_fail (value != 0);
492 : :
493 : 192 : record_take_column (record, column, record_block_new (&value, 1));
494 : : }
495 : :
496 : : gboolean
497 : 3 : _gcr_record_get_uint (GcrRecord *record, guint column, guint *value)
498 : : {
499 : : const gchar *raw;
500 : : gint64 result;
501 : 3 : gchar *end = NULL;
502 : :
503 [ - + ]: 3 : g_return_val_if_fail (record, FALSE);
504 : :
505 : 3 : raw = _gcr_record_get_raw (record, column);
506 [ - + ]: 3 : if (raw == NULL)
507 : 0 : return FALSE;
508 : :
509 : 3 : result = g_ascii_strtoll (raw, &end, 10);
510 [ + - + + ]: 3 : if (!end || end[0]) {
511 : 1 : g_debug ("invalid unsigned integer value: %s", raw);
512 : 1 : return FALSE;
513 : : }
514 : :
515 [ + + - + ]: 2 : if (result < 0 || result > G_MAXUINT32) {
516 : 1 : g_debug ("unsigned integer value is out of range: %s", raw);
517 : 1 : return FALSE;
518 : : }
519 : :
520 [ + - ]: 1 : if (value)
521 : 1 : *value = (guint)result;
522 : 1 : return TRUE;
523 : : }
524 : :
525 : : void
526 : 272 : _gcr_record_set_uint (GcrRecord *record,
527 : : guint column,
528 : : guint value)
529 : : {
530 : : gchar *escaped;
531 : :
532 [ - + ]: 272 : g_return_if_fail (record != NULL);
533 [ - + ]: 272 : g_return_if_fail (column < record->n_columns);
534 : :
535 : 272 : escaped = g_strdup_printf ("%u", value);
536 : 272 : record_take_column (record, column,
537 : : record_block_take (escaped, strlen (escaped)));
538 : : }
539 : :
540 : : gboolean
541 : 189 : _gcr_record_get_ulong (GcrRecord *record,
542 : : guint column,
543 : : gulong *value)
544 : : {
545 : : const gchar *raw;
546 : : gint64 result;
547 : 189 : gchar *end = NULL;
548 : :
549 [ - + ]: 189 : g_return_val_if_fail (record, FALSE);
550 : :
551 : 189 : raw = _gcr_record_get_raw (record, column);
552 [ - + ]: 189 : if (raw == NULL)
553 : 0 : return FALSE;
554 : :
555 : 189 : result = g_ascii_strtoull (raw, &end, 10);
556 [ + - - + ]: 189 : if (!end || end[0]) {
557 : 0 : g_debug ("invalid unsigned long value: %s", raw);
558 : 0 : return FALSE;
559 : : }
560 : :
561 [ - + ]: 189 : if (result < 0 || result > G_MAXULONG) {
562 : 0 : g_debug ("unsigned long value is out of range: %s", raw);
563 : 0 : return FALSE;
564 : : }
565 : :
566 [ + - ]: 189 : if (value)
567 : 189 : *value = (guint)result;
568 : 189 : return TRUE;
569 : :
570 : : }
571 : :
572 : : void
573 : 366 : _gcr_record_set_ulong (GcrRecord *record,
574 : : guint column,
575 : : gulong value)
576 : : {
577 : : gchar *escaped;
578 : :
579 [ - + ]: 366 : g_return_if_fail (record != NULL);
580 [ - + ]: 366 : g_return_if_fail (column < record->n_columns);
581 : :
582 : 366 : escaped = g_strdup_printf ("%lu", value);
583 : 366 : record_take_column (record, column,
584 : : record_block_take (escaped, strlen (escaped)));
585 : : }
586 : :
587 : : GDateTime *
588 : 0 : _gcr_record_get_date (GcrRecord *record,
589 : : guint column)
590 : : {
591 : : const char *raw;
592 : : guint64 result;
593 : 0 : char *end = NULL;
594 : : GTimeZone *tz;
595 : : GDateTime *ret;
596 : :
597 [ # # ]: 0 : g_return_val_if_fail (record, NULL);
598 : :
599 : 0 : raw = _gcr_record_get_raw (record, column);
600 [ # # ]: 0 : if (raw == NULL)
601 : 0 : return NULL;
602 : :
603 : : /* Try to parse as a number */
604 : 0 : result = g_ascii_strtoull (raw, &end, 10);
605 [ # # # # ]: 0 : if (end != NULL && end[0] == '\0') {
606 [ # # ]: 0 : if (result == 0)
607 : 0 : return NULL;
608 : : else
609 : 0 : return g_date_time_new_from_unix_utc (result);
610 : : }
611 : :
612 : : /* Try to parse as a date */
613 : 0 : tz = g_time_zone_new_utc ();
614 : 0 : ret = g_date_time_new_from_iso8601 (raw, tz);
615 : 0 : g_time_zone_unref (tz);
616 : :
617 : 0 : return ret;
618 : : }
619 : :
620 : : /**
621 : : * _gcr_record_get_base64:
622 : : * @record: The record
623 : : * @column: The column to decode.
624 : : * @n_data: Location to return size of returned data.
625 : : *
626 : : * Decode a column of a record as base64 data.
627 : : *
628 : : * Returns: (transfer full): The decoded value, or %NULL if not found.
629 : : */
630 : : gpointer
631 : 1 : _gcr_record_get_base64 (GcrRecord *record, guint column, gsize *n_data)
632 : : {
633 : : const gchar *raw;
634 : :
635 [ - + ]: 1 : g_return_val_if_fail (record, NULL);
636 : :
637 : 1 : raw = _gcr_record_get_raw (record, column);
638 [ - + ]: 1 : if (raw == NULL)
639 : 0 : return NULL;
640 : :
641 : 1 : return g_base64_decode (raw, n_data);
642 : : }
643 : :
644 : : void
645 : 6 : _gcr_record_set_base64 (GcrRecord *record,
646 : : guint column,
647 : : gconstpointer data,
648 : : gsize n_data)
649 : : {
650 : : GcrRecordBlock *block;
651 : : gint state, save;
652 : : gsize estimate;
653 : : gsize length;
654 : :
655 [ - + ]: 6 : g_return_if_fail (record != NULL);
656 [ - + ]: 6 : g_return_if_fail (column < record->n_columns);
657 : :
658 : 6 : estimate = n_data * 4 / 3 + n_data * 4 / (3 * 65) + 7;
659 : 6 : block = record_block_new (NULL, estimate);
660 : :
661 : : /* The actual base64 data, without line breaks */
662 : 6 : state = save = 0;
663 : 6 : length = g_base64_encode_step ((guchar *)data, n_data, FALSE,
664 : 6 : block->value, &state, &save);
665 : 6 : length += g_base64_encode_close (TRUE, block->value + length,
666 : : &state, &save);
667 : 6 : block->value[length] = 0;
668 [ - + ]: 6 : g_assert (length < estimate);
669 : :
670 : 6 : g_strchomp (block->value);
671 : 6 : record_take_column (record, column, block);
672 : : }
673 : :
674 : : const gchar*
675 : 1812 : _gcr_record_get_raw (GcrRecord *record, guint column)
676 : : {
677 [ - + ]: 1812 : g_return_val_if_fail (record, NULL);
678 : :
679 [ + + ]: 1812 : if (column >= record->n_columns) {
680 : 8 : g_debug ("only %d columns exist, tried to access %d",
681 : : record->n_columns, column);
682 : 8 : return NULL;
683 : : }
684 : :
685 : 1804 : return record->columns[column];
686 : : }
687 : :
688 : : void
689 : 72 : _gcr_record_set_raw (GcrRecord *record,
690 : : guint column,
691 : : const gchar *value)
692 : : {
693 [ - + ]: 72 : g_return_if_fail (record != NULL);
694 [ - + ]: 72 : g_return_if_fail (value != NULL);
695 [ - + ]: 72 : g_return_if_fail (column < record->n_columns);
696 : :
697 : 72 : record_take_column (record, column,
698 : : record_block_new (value, strlen (value)));
699 : : }
700 : :
701 : : void
702 : 533 : _gcr_record_take_raw (GcrRecord *record,
703 : : guint column,
704 : : gchar *value)
705 : : {
706 [ - + ]: 533 : g_return_if_fail (record != NULL);
707 [ - + ]: 533 : g_return_if_fail (value != NULL);
708 [ - + ]: 533 : g_return_if_fail (column < record->n_columns);
709 : :
710 : 533 : record_take_column (record, column,
711 : : record_block_take (value, strlen (value)));
712 : : }
713 : :
714 : : void
715 : 549 : _gcr_record_free (gpointer record)
716 : : {
717 : : GcrRecordBlock *block, *next;
718 : 549 : GcrRecord *rec = record;
719 : :
720 [ + + ]: 549 : if (!record)
721 : 15 : return;
722 : :
723 [ + + ]: 2236 : for (block = rec->block; block != NULL; block = next) {
724 : 1702 : next = block->next;
725 : 1702 : g_free (block);
726 : : }
727 : :
728 : 534 : g_slice_free (GcrRecord, record);
729 : : }
730 : :
731 : : GQuark
732 : 1192 : _gcr_record_get_schema (GcrRecord *record)
733 : : {
734 : : const gchar *value;
735 : :
736 : 1192 : value = _gcr_record_get_raw (record, GCR_RECORD_SCHEMA);
737 [ + - ]: 1192 : if (value != NULL)
738 : 1192 : return g_quark_try_string (value);
739 : 0 : return 0;
740 : : }
741 : :
742 : : GcrRecord *
743 : 16 : _gcr_records_find (GPtrArray *records,
744 : : GQuark schema)
745 : : {
746 : : guint i;
747 : :
748 [ - + ]: 16 : g_return_val_if_fail (records, NULL);
749 [ - + ]: 16 : g_return_val_if_fail (schema, NULL);
750 : :
751 [ + + ]: 31 : for (i = 0; i < records->len; i++) {
752 [ + + ]: 29 : if (schema == _gcr_record_get_schema (records->pdata[i]))
753 : 14 : return records->pdata[i];
754 : : }
755 : :
756 : 2 : return NULL;
757 : : }
758 : :
759 : : gchar *
760 : 26 : _gcr_records_format (GPtrArray *records)
761 : : {
762 : : GString *string;
763 : : guint i;
764 : :
765 [ - + ]: 26 : g_return_val_if_fail (records, NULL);
766 : :
767 : 26 : string = g_string_new ("");
768 [ + + ]: 244 : for (i = 0; i < records->len; i++) {
769 : 218 : print_record_to_string (records->pdata[i], string);
770 : 218 : g_string_append_c (string, '\n');
771 : : }
772 : 26 : return g_string_free (string, FALSE);
773 : : }
774 : :
775 : : static gchar **
776 : 0 : strnsplit (const gchar *string,
777 : : gsize length,
778 : : gchar delimiter)
779 : : {
780 : 0 : GSList *string_list = NULL, *slist;
781 : : gchar **str_array, *s;
782 : 0 : guint n = 0;
783 : : const gchar *remainder;
784 : : const gchar *end;
785 : :
786 [ # # ]: 0 : g_return_val_if_fail (string != NULL, NULL);
787 [ # # ]: 0 : g_return_val_if_fail (delimiter != '\0', NULL);
788 : :
789 : 0 : end = string + length;
790 : 0 : remainder = string;
791 : 0 : s = memchr (remainder, delimiter, end - remainder);
792 [ # # ]: 0 : if (s)
793 : : {
794 [ # # ]: 0 : while (s)
795 : : {
796 : : gsize len;
797 : :
798 : 0 : len = s - remainder;
799 : 0 : string_list = g_slist_prepend (string_list,
800 : 0 : g_strndup (remainder, len));
801 : 0 : n++;
802 : 0 : remainder = s + 1;
803 : 0 : s = memchr (remainder, delimiter, end - remainder);
804 : : }
805 : : }
806 [ # # ]: 0 : if (*string)
807 : : {
808 : 0 : n++;
809 : 0 : string_list = g_slist_prepend (string_list, g_strndup (remainder, end - remainder));
810 : : }
811 : :
812 : 0 : str_array = g_new (gchar*, n + 1);
813 : :
814 : 0 : str_array[n--] = NULL;
815 [ # # ]: 0 : for (slist = string_list; slist; slist = slist->next)
816 : 0 : str_array[n--] = slist->data;
817 : :
818 : 0 : g_slist_free (string_list);
819 : :
820 : 0 : return str_array;
821 : : }
822 : :
823 : : GPtrArray *
824 : 0 : _gcr_records_parse_colons (gconstpointer data,
825 : : gssize n_data)
826 : : {
827 : 0 : GPtrArray *result = NULL;
828 : : GcrRecordBlock *block;
829 : : GcrRecord *record;
830 : : gchar **lines;
831 : : guint i;
832 : :
833 : 0 : lines = strnsplit (data, n_data, '\n');
834 : 0 : result = g_ptr_array_new_with_free_func (_gcr_record_free);
835 : :
836 [ # # ]: 0 : for (i = 0; lines[i] != NULL; i++) {
837 : 0 : block = record_block_take (lines[i], strlen (lines[i]));
838 : 0 : record = take_and_parse_internal (block, ':', TRUE);
839 [ # # ]: 0 : if (record == NULL) {
840 : 0 : g_ptr_array_unref (result);
841 : 0 : result = NULL;
842 : 0 : break;
843 : : }
844 : 0 : g_ptr_array_add (result, record);
845 : : }
846 : :
847 : : /* Free any not done */
848 [ # # ]: 0 : for (; lines[i] != NULL; i++)
849 : 0 : g_free (lines[i]);
850 : :
851 : : /* Individual lines already freed */
852 : 0 : g_free (lines);
853 : :
854 : 0 : return result;
855 : : }
|