LCOV - code coverage report
Current view: top level - gcr - gcr-record.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 257 408 63.0 %
Date: 2022-09-04 10:20:22 Functions: 32 36 88.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 120 245 49.0 %

           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                 :            : }

Generated by: LCOV version 1.14