LCOV - code coverage report
Current view: top level - egg - egg-buffer.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 55.7 % 305 170
Test Date: 2024-12-15 20:37:51 Functions: 70.6 % 34 24

            Line data    Source code
       1              : /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
       2              : /* egg-buffer.c - Generic data buffer, used by openssh, gnome-keyring
       3              : 
       4              :    Copyright (C) 2007 Stefan Walter
       5              : 
       6              :    The Gnome Keyring Library is free software; you can redistribute it and/or
       7              :    modify it under the terms of the GNU Library General Public License as
       8              :    published by the Free Software Foundation; either version 2 of the
       9              :    License, or (at your option) any later version.
      10              : 
      11              :    The Gnome Keyring Library is distributed in the hope that it will be useful,
      12              :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14              :    Library General Public License for more details.
      15              : 
      16              :    You should have received a copy of the GNU Library General Public
      17              :    License along with the Gnome Library; see the file COPYING.LIB.  If not,
      18              :    <http://www.gnu.org/licenses/>.
      19              : 
      20              :    Author: Stef Walter <stef@memberwebs.com>
      21              : */
      22              : #include "config.h"
      23              : 
      24              : #include <string.h>
      25              : #include <stdarg.h>
      26              : 
      27              : #include "egg-buffer.h"
      28              : 
      29              : #define DEFAULT_ALLOCATOR  ((EggBufferAllocator)realloc)
      30              : 
      31              : int
      32            0 : egg_buffer_init (EggBuffer *buffer, size_t reserve)
      33              : {
      34            0 :         return egg_buffer_init_full (buffer, reserve, NULL);
      35              : }
      36              : 
      37              : int
      38          155 : egg_buffer_init_full (EggBuffer *buffer, size_t reserve, EggBufferAllocator allocator)
      39              : {
      40          155 :         memset (buffer, 0, sizeof (*buffer));
      41              :         
      42          155 :         if (!allocator) 
      43            0 :                 allocator = DEFAULT_ALLOCATOR;
      44          155 :         if (reserve == 0)
      45            0 :                 reserve = 64;
      46              : 
      47          155 :         buffer->buf = (allocator) (NULL, reserve);
      48          155 :         if (!buffer->buf) {
      49            0 :                 buffer->failures++;
      50            0 :                 return 0;
      51              :         }
      52              : 
      53          155 :         buffer->len = 0;
      54          155 :         buffer->allocated_len = reserve;
      55          155 :         buffer->failures = 0;
      56          155 :         buffer->allocator = allocator;
      57              : 
      58          155 :         return 1;
      59              : }
      60              : 
      61              : void
      62          121 : egg_buffer_init_static (EggBuffer* buffer, const unsigned char *buf, size_t len)
      63              : {
      64          121 :         memset (buffer, 0, sizeof (*buffer));
      65              : 
      66          121 :         buffer->buf = (unsigned char*)buf;
      67          121 :         buffer->len = len;
      68          121 :         buffer->allocated_len = len;
      69          121 :         buffer->failures = 0;
      70              : 
      71              :         /* A null allocator, and the buffer can't change in size */
      72          121 :         buffer->allocator = NULL;    
      73          121 : }
      74              : 
      75              : void
      76            0 : egg_buffer_init_allocated (EggBuffer *buffer, unsigned char *buf, size_t len,
      77              :                            EggBufferAllocator allocator)
      78              : {
      79            0 :         memset (buffer, 0, sizeof (*buffer));
      80              :         
      81            0 :         if (!allocator) 
      82            0 :                 allocator = DEFAULT_ALLOCATOR;
      83              : 
      84            0 :         buffer->buf = buf;
      85            0 :         buffer->len = len;
      86            0 :         buffer->allocated_len = len;
      87            0 :         buffer->failures = 0;
      88            0 :         buffer->allocator = allocator;
      89            0 : }
      90              : 
      91              : void 
      92          211 : egg_buffer_reset (EggBuffer *buffer)
      93              : {
      94          211 :         memset (buffer->buf, 0, buffer->allocated_len);
      95          211 :         buffer->len = 0;
      96          211 :         buffer->failures = 0;
      97          211 : }
      98              : 
      99              : void
     100          246 : egg_buffer_uninit (EggBuffer *buffer)
     101              : {
     102          246 :         if (!buffer)
     103            0 :                 return;
     104              : 
     105              :         /* 
     106              :          * Free the memory block using allocator. If no allocator, 
     107              :          * then this memory is ownerd elsewhere and not to be freed. 
     108              :          */
     109          246 :         if (buffer->buf && buffer->allocator)
     110          225 :                 (buffer->allocator) (buffer->buf, 0);
     111              :                 
     112          246 :         memset (buffer, 0, sizeof (*buffer));
     113              : }
     114              : 
     115              : unsigned char*
     116           16 : egg_buffer_uninit_steal (EggBuffer *buffer, size_t *n_result)
     117              : {
     118              :         unsigned char *result;
     119              : 
     120           16 :         if (n_result)
     121           16 :                 *n_result = buffer->len;
     122           16 :         result = buffer->buf;
     123              : 
     124           16 :         memset (buffer, 0, sizeof (*buffer));
     125              : 
     126           16 :         return result;
     127              : }
     128              : 
     129              : int
     130          102 : egg_buffer_set_allocator (EggBuffer *buffer, EggBufferAllocator allocator)
     131              : {
     132          102 :         unsigned char *buf = NULL;
     133              :         
     134          102 :         if (!allocator)
     135            0 :                 allocator = DEFAULT_ALLOCATOR;
     136          102 :         if (buffer->allocator == allocator)
     137           16 :                 return 1;
     138              :         
     139           86 :         if (buffer->allocated_len) {
     140              :                 /* Reallocate memory block using new allocator */
     141            0 :                 buf = (allocator) (NULL, buffer->allocated_len);
     142            0 :                 if (buf == NULL)
     143            0 :                         return 0;
     144              :                 
     145              :                 /* Copy stuff into new memory */
     146            0 :                 memcpy (buf, buffer->buf, buffer->allocated_len);
     147              :         }
     148              :                 
     149              :         /* If old wasn't static, then free it */
     150           86 :         if (buffer->allocator && buffer->buf)
     151            0 :                 (buffer->allocator) (buffer->buf, 0);
     152              :                 
     153           86 :         buffer->buf = buf;
     154           86 :         buffer->allocator = allocator;
     155              :         
     156           86 :         return 1;
     157              : }
     158              : 
     159              : int
     160            0 : egg_buffer_equal (EggBuffer *b1, EggBuffer *b2)
     161              : {
     162            0 :         if (b1->len != b2->len)
     163            0 :                 return 0;
     164            0 :         return memcmp (b1->buf, b2->buf, b1->len) == 0;
     165              : }
     166              : 
     167              : int
     168         1794 : egg_buffer_reserve (EggBuffer *buffer, size_t len)
     169              : {
     170              :         unsigned char *newbuf;
     171              :         size_t newlen;
     172              : 
     173         1794 :         if (len < buffer->allocated_len)
     174         1660 :                 return 1;
     175              :                 
     176              :         /* Calculate a new length, minimize number of buffer allocations */
     177          134 :         newlen = buffer->allocated_len * 2;
     178          134 :         if (len > newlen)
     179           86 :                 newlen += len;
     180              :         
     181              :         /* Memory owned elsewhere can't be reallocated */       
     182          134 :         if (!buffer->allocator) {
     183            0 :                 buffer->failures++;
     184            0 :                 return 0;
     185              :         }
     186              : 
     187              :         /* Reallocate built in buffer using allocator */
     188          134 :         newbuf = (buffer->allocator) (buffer->buf, newlen);
     189          134 :         if (!newbuf) {
     190            0 :                 buffer->failures++;
     191            0 :                 return 0;
     192              :         }
     193              : 
     194          134 :         buffer->buf = newbuf;
     195          134 :         buffer->allocated_len = newlen;
     196              : 
     197          134 :         return 1;
     198              : }
     199              : 
     200              : int
     201          211 : egg_buffer_resize (EggBuffer *buffer, size_t len)
     202              : {
     203          211 :         if (!egg_buffer_reserve (buffer, len))
     204            0 :                 return 0;
     205              :                 
     206          211 :         buffer->len = len;
     207          211 :         return 1;
     208              : }
     209              : 
     210              : unsigned char*
     211           39 : egg_buffer_add_empty (EggBuffer *buffer, size_t len)
     212              : {
     213           39 :         size_t pos = buffer->len;
     214           39 :         if (!egg_buffer_reserve (buffer, buffer->len + len))
     215            0 :                 return NULL;
     216           39 :         buffer->len += len;
     217           39 :         return buffer->buf + pos;
     218              : }
     219              : 
     220              : int 
     221          277 : egg_buffer_append (EggBuffer *buffer, const unsigned char *val,
     222              :                              size_t len)
     223              : {
     224          277 :         if (!egg_buffer_reserve (buffer, buffer->len + len))
     225            0 :                 return 0; /* failures already incremented */
     226          277 :         memcpy (buffer->buf + buffer->len, val, len);
     227          277 :         buffer->len += len;
     228          277 :         return 1;
     229              : }
     230              : 
     231              : int
     232          178 : egg_buffer_add_byte (EggBuffer *buffer, unsigned char val)
     233              : {
     234          178 :         if (!egg_buffer_reserve (buffer, buffer->len + 1))
     235            0 :                 return 0; /* failures already incremented */
     236          178 :         buffer->buf[buffer->len] = val;
     237          178 :         buffer->len++;
     238          178 :         return 1;
     239              : }
     240              : 
     241              : int
     242           10 : egg_buffer_get_byte (EggBuffer *buffer, size_t offset,
     243              :                                size_t *next_offset, unsigned char *val)
     244              : {
     245              :         unsigned char *ptr;
     246           10 :         if (buffer->len < 1 || offset > buffer->len - 1) {
     247            0 :                 buffer->failures++;
     248            0 :                 return 0;
     249              :         }
     250           10 :         ptr = (unsigned char*)buffer->buf + offset;
     251           10 :         if (val != NULL)
     252           10 :                 *val = *ptr;
     253           10 :         if (next_offset != NULL)
     254           10 :                 *next_offset = offset + 1;
     255           10 :         return 1;
     256              : }
     257              : 
     258              : void
     259            0 : egg_buffer_encode_uint16 (unsigned char* buf, uint16_t val)
     260              : {
     261            0 :         buf[0] = (val >> 8) & 0xff;
     262            0 :         buf[1] = (val >> 0) & 0xff;   
     263            0 : }
     264              : 
     265              : uint16_t
     266            0 : egg_buffer_decode_uint16 (unsigned char* buf)
     267              : {
     268            0 :         uint16_t val = buf[0] << 8 | buf[1];
     269            0 :         return val;
     270              : }
     271              : 
     272              : int
     273            0 : egg_buffer_add_uint16 (EggBuffer *buffer, uint16_t val)
     274              : {
     275            0 :         if (!egg_buffer_reserve (buffer, buffer->len + 2))
     276            0 :                 return 0; /* failures already incremented */
     277            0 :         buffer->len += 2;
     278            0 :         egg_buffer_set_uint16 (buffer, buffer->len - 2, val);
     279            0 :         return 1;       
     280              : }
     281              : 
     282              : int
     283            0 : egg_buffer_set_uint16 (EggBuffer *buffer, size_t offset, uint16_t val)
     284              : {
     285              :         unsigned char *ptr;
     286            0 :         if (buffer->len < 2 || offset > buffer->len - 2) {
     287            0 :                 buffer->failures++;
     288            0 :                 return 0;
     289              :         }
     290            0 :         ptr = (unsigned char*)buffer->buf + offset;
     291            0 :         egg_buffer_encode_uint16 (ptr, val);
     292            0 :         return 1;
     293              : }
     294              : 
     295              : int
     296            0 : egg_buffer_get_uint16 (EggBuffer *buffer, size_t offset,
     297              :                        size_t *next_offset, uint16_t *val)
     298              : {
     299              :         unsigned char *ptr;
     300            0 :         if (buffer->len < 2 || offset > buffer->len - 2) {
     301            0 :                 buffer->failures++;
     302            0 :                 return 0;
     303              :         }
     304            0 :         ptr = (unsigned char*)buffer->buf + offset;
     305            0 :         if (val != NULL)
     306            0 :                 *val = egg_buffer_decode_uint16 (ptr);
     307            0 :         if (next_offset != NULL)
     308            0 :                 *next_offset = offset + 2;
     309            0 :         return 1;       
     310              : }
     311              : 
     312              : void 
     313         1022 : egg_buffer_encode_uint32 (unsigned char* buf, uint32_t val)
     314              : {
     315         1022 :         buf[0] = (val >> 24) & 0xff;
     316         1022 :         buf[1] = (val >> 16) & 0xff;
     317         1022 :         buf[2] = (val >> 8) & 0xff;
     318         1022 :         buf[3] = (val >> 0) & 0xff;
     319         1022 : }
     320              : 
     321              : uint32_t
     322         3889 : egg_buffer_decode_uint32 (unsigned char* ptr)
     323              : {
     324         3889 :         uint32_t val = (uint32_t) ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
     325         3889 :         return val;
     326              : }
     327              : 
     328              : int 
     329          981 : egg_buffer_add_uint32 (EggBuffer *buffer, uint32_t val)
     330              : {
     331          981 :         if (!egg_buffer_reserve (buffer, buffer->len + 4))
     332            0 :                 return 0; /* failures already incremented */
     333          981 :         buffer->len += 4;
     334          981 :         egg_buffer_set_uint32 (buffer, buffer->len - 4, val);
     335          981 :         return 1;
     336              : }
     337              : 
     338              : int
     339         1010 : egg_buffer_set_uint32 (EggBuffer *buffer, size_t offset, uint32_t val)
     340              : {
     341              :         unsigned char *ptr;
     342         1010 :         if (buffer->len < 4 || offset > buffer->len - 4) {
     343            0 :                 buffer->failures++;
     344            0 :                 return 0;
     345              :         }
     346         1010 :         ptr = (unsigned char*)buffer->buf + offset;
     347         1010 :         egg_buffer_encode_uint32 (ptr, val);
     348         1010 :         return 1;
     349              : }
     350              : 
     351              : int
     352         3858 : egg_buffer_get_uint32 (EggBuffer *buffer, size_t offset, size_t *next_offset,
     353              :                                  uint32_t *val)
     354              : {
     355              :         unsigned char *ptr;
     356         3858 :         if (buffer->len < 4 || offset > buffer->len - 4) {
     357            0 :                 buffer->failures++;
     358            0 :                 return 0;
     359              :         }
     360         3858 :         ptr = (unsigned char*)buffer->buf + offset;
     361         3858 :         if (val != NULL)
     362         3858 :                 *val = egg_buffer_decode_uint32 (ptr);
     363         3858 :         if (next_offset != NULL)
     364         3843 :                 *next_offset = offset + 4;
     365         3858 :         return 1;
     366              : }
     367              : 
     368              : int
     369           24 : egg_buffer_add_uint64 (EggBuffer *buffer, uint64_t val)
     370              : {
     371           24 :         if (!egg_buffer_add_uint32 (buffer, ((val >> 32) & 0xffffffff)))
     372            0 :                 return 0;
     373           24 :         return egg_buffer_add_uint32 (buffer, (val & 0xffffffff));
     374              : }
     375              : 
     376              : int
     377           55 : egg_buffer_get_uint64 (EggBuffer *buffer, size_t offset, 
     378              :                                            size_t *next_offset, uint64_t *val)
     379              : {
     380              :         uint32_t a, b;
     381           55 :         if (!egg_buffer_get_uint32 (buffer, offset, &offset, &a))
     382            0 :                 return 0;
     383           55 :         if (!egg_buffer_get_uint32 (buffer, offset, &offset, &b))
     384            0 :                 return 0;
     385           55 :         if (val != NULL)
     386           55 :                 *val = ((uint64_t)a) << 32 | b;
     387           55 :         if (next_offset != NULL)
     388           55 :                 *next_offset = offset;
     389           55 :         return 1;
     390              : }
     391              : 
     392              : int
     393           67 : egg_buffer_add_byte_array (EggBuffer *buffer, const unsigned char *val,
     394              :                                      size_t len)
     395              : {
     396           67 :         if (val == NULL) 
     397            2 :                 return egg_buffer_add_uint32 (buffer, 0xffffffff);
     398           65 :         if (len >= 0x7fffffff) {
     399            0 :                 buffer->failures++;
     400            0 :                 return 0; 
     401              :         }
     402           65 :         if (!egg_buffer_add_uint32 (buffer, len))
     403            0 :                 return 0;
     404           65 :         return egg_buffer_append (buffer, val, len);
     405              : }
     406              : 
     407              : unsigned char*
     408           27 : egg_buffer_add_byte_array_empty (EggBuffer *buffer, size_t vlen)
     409              : {
     410           27 :         if (vlen >= 0x7fffffff) {
     411            0 :                 buffer->failures++;
     412            0 :                 return NULL; 
     413              :         }
     414           27 :         if (!egg_buffer_add_uint32 (buffer, vlen))
     415            0 :                 return NULL;
     416           27 :         return egg_buffer_add_empty (buffer, vlen);
     417              : }
     418              : 
     419              : int
     420          205 : egg_buffer_get_byte_array (EggBuffer *buffer, size_t offset,
     421              :                            size_t *next_offset, const unsigned char **val,
     422              :                            size_t *vlen)
     423              : {
     424              :         uint32_t len;
     425          205 :         if (!egg_buffer_get_uint32 (buffer, offset, &offset, &len))
     426            0 :                 return 0;
     427          205 :         if (len == 0xffffffff) {
     428            0 :                 if (next_offset) 
     429            0 :                         *next_offset = offset;
     430            0 :                 if (val)
     431            0 :                         *val = NULL;
     432            0 :                 if (vlen)
     433            0 :                         *vlen = 0;
     434            0 :                 return 1;
     435          205 :         } else if (len >= 0x7fffffff) {
     436            0 :                 buffer->failures++;
     437            0 :                 return 0;
     438              :         }
     439              : 
     440          205 :         if (buffer->len < len || offset > buffer->len - len) {
     441            0 :                 buffer->failures++;
     442            0 :                 return 0;
     443              :         }
     444              :         
     445          205 :         if (val) 
     446          205 :                 *val = buffer->buf + offset;
     447          205 :         if (vlen)
     448          205 :                 *vlen = len;
     449          205 :         if (next_offset) 
     450          205 :                 *next_offset = offset + len;
     451              : 
     452          205 :         return 1;
     453              : }
     454              : 
     455              : int
     456          164 : egg_buffer_add_string (EggBuffer *buffer, const char *str)
     457              : {
     458          164 :         if (str == NULL) {
     459           19 :                 return egg_buffer_add_uint32 (buffer, 0xffffffff);
     460              :         } else {
     461          145 :                 size_t len = strlen (str);
     462          145 :                 if (len >= 0x7fffffff)
     463            0 :                         return 0;
     464          145 :                 if (!egg_buffer_add_uint32 (buffer, len))
     465            0 :                         return 0;
     466          145 :                 return egg_buffer_append (buffer, (unsigned char*)str, len);
     467              :         }
     468              : }
     469              : 
     470              : int
     471          866 : egg_buffer_get_string (EggBuffer *buffer, size_t offset, size_t *next_offset,
     472              :                        char **str_ret, EggBufferAllocator allocator)
     473              : {
     474              :         uint32_t len;
     475              :         
     476          866 :         if (!allocator)
     477           20 :                 allocator = buffer->allocator;
     478          866 :         if (!allocator)
     479            0 :                 allocator = DEFAULT_ALLOCATOR;
     480              :         
     481          866 :         if (!egg_buffer_get_uint32 (buffer, offset, &offset, &len)) {
     482            0 :                 return 0;
     483              :         }
     484          866 :         if (len == 0xffffffff) {
     485           55 :                 *next_offset = offset;
     486           55 :                 *str_ret = NULL;
     487           55 :                 return 1;
     488          811 :         } else if (len >= 0x7fffffff) {
     489            0 :                 return 0;
     490              :         }
     491              :         
     492          811 :         if (buffer->len < len ||
     493          811 :             offset > buffer->len - len) {
     494            0 :                 return 0;
     495              :         }
     496              :         
     497              :         /* Make sure no null characters in string */
     498          811 :         if (memchr (buffer->buf + offset, 0, len) != NULL)
     499            0 :                 return 0;
     500              :         
     501              :         /* The passed allocator may be for non-pageable memory */
     502          811 :         *str_ret = (allocator) (NULL, len + 1);
     503          811 :         if (!*str_ret)
     504            0 :                 return 0;
     505          811 :         memcpy (*str_ret, buffer->buf + offset, len);
     506              : 
     507              :         /* Always zero terminate */
     508          811 :         (*str_ret)[len] = 0;
     509          811 :         *next_offset = offset + len;
     510              :         
     511          811 :         return 1;
     512              : }
     513              : 
     514              : int
     515            0 : egg_buffer_add_stringv (EggBuffer *buffer, const char** strv)
     516              : {
     517              :         const char **v;
     518            0 :         uint32_t n = 0;
     519              :         
     520            0 :         if (!strv)
     521            0 :                 return 0;
     522              :         
     523              :         /* Add the number of strings coming */
     524            0 :         for (v = strv; *v; ++v)
     525            0 :                 ++n;
     526            0 :         if (!egg_buffer_add_uint32 (buffer, n))
     527            0 :                 return 0;
     528              :         
     529              :         /* Add the individual strings */
     530            0 :         for (v = strv; *v; ++v) {
     531            0 :                 if (!egg_buffer_add_string (buffer, *v))
     532            0 :                         return 0;
     533              :         }
     534              :         
     535            0 :         return 1;
     536              : }
     537              : 
     538              : int
     539            0 : egg_buffer_get_stringv (EggBuffer *buffer, size_t offset, size_t *next_offset,
     540              :                                 char ***strv_ret, EggBufferAllocator allocator)
     541              : {
     542              :         uint32_t n, i, j;
     543              :         size_t len;
     544              :         
     545            0 :         if (!allocator)
     546            0 :                 allocator = buffer->allocator;
     547            0 :         if (!allocator)
     548            0 :                 allocator = DEFAULT_ALLOCATOR;
     549              :         
     550              :         /* First the number of environment variable lines */
     551            0 :         if (!egg_buffer_get_uint32 (buffer, offset, &offset, &n))
     552            0 :                 return 0;
     553              :         
     554              :         /* Then that number of strings */
     555            0 :         len = (n + 1) * sizeof (char*);
     556            0 :         *strv_ret = (char**)(allocator) (NULL, len);
     557            0 :         if (!*strv_ret)
     558            0 :                 return 0;
     559              :         
     560              :         /* All null strings */
     561            0 :         memset (*strv_ret, 0, len);
     562              :         
     563            0 :         for (i = 0; i < n; ++i) {
     564            0 :                 if (!egg_buffer_get_string (buffer, offset, &offset, 
     565            0 :                                             &((*strv_ret)[i]), allocator)) {
     566              :                         
     567              :                         /* Free all the strings on failure */
     568            0 :                         for (j = 0; j < i; ++j) {
     569            0 :                                 if ((*strv_ret)[j])
     570            0 :                                         (allocator) ((*strv_ret)[j], 0);
     571              :                         }
     572              :                         
     573            0 :                         return 0;
     574              :                 }
     575              :         }
     576              :         
     577            0 :         if (next_offset != NULL)
     578            0 :                 *next_offset = offset;
     579              :         
     580            0 :         return 1;
     581              : }
        

Generated by: LCOV version 2.0-1