Coverage Report

Created: 2026-02-11 06:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mpg123/src/libmpg123/stringbuf.c
Line
Count
Source
1
/*
2
  stringbuf: mimicking a bit of C++ to more safely handle strings
3
4
  copyright 2006-20 by the mpg123 project
5
      - free software under the terms of the LGPL 2.1
6
  see COPYING and AUTHORS files in distribution or http://mpg123.org
7
  initially written by Thomas Orgis
8
*/
9
10
#include "mpg123lib_intern.h"
11
#include "config.h"
12
#include "mpg123.h"
13
#include "../compat/compat.h"
14
#include <string.h>
15
#include "../common/debug.h"
16
17
mpg123_string* attribute_align_arg mpg123_new_string(const char *val)
18
0
{
19
0
  mpg123_string *sb = malloc(sizeof(mpg123_string));
20
0
  if(!sb)
21
0
    return NULL;
22
0
  mpg123_init_string(sb);
23
0
  mpg123_set_string(sb, val);
24
0
  return sb;
25
0
}
26
27
void attribute_align_arg mpg123_delete_string(mpg123_string* sb)
28
0
{
29
0
  if(!sb)
30
0
    return;
31
0
  mpg123_free_string(sb);
32
0
  free(sb);
33
0
}
34
35
void attribute_align_arg mpg123_init_string(mpg123_string* sb)
36
169k
{
37
  /* Handing in NULL here is a fatal mistake and rightfully so. */
38
169k
  sb->p = NULL;
39
169k
  sb->size = 0;
40
169k
  sb->fill = 0;
41
169k
}
42
43
void attribute_align_arg mpg123_free_string(mpg123_string* sb)
44
75.7k
{
45
75.7k
  if(!sb)
46
0
    return;
47
75.7k
  if(sb->p != NULL) free(sb->p);
48
75.7k
  mpg123_init_string(sb);
49
75.7k
}
50
51
int attribute_align_arg mpg123_grow_string(mpg123_string* sb, size_t new)
52
49.4k
{
53
49.4k
  if(!sb)
54
0
    return 0;
55
49.4k
  if(sb->size < new) return mpg123_resize_string(sb, new);
56
286
  else return 1;
57
49.4k
}
58
59
int attribute_align_arg mpg123_resize_string(mpg123_string* sb, size_t new)
60
49.1k
{
61
49.1k
  if(!sb)
62
0
    return 0;
63
49.1k
  debug3("resizing string pointer %p from %lu to %lu", (void*) sb->p, (unsigned long)sb->size, (unsigned long)new);
64
49.1k
  if(new == 0)
65
0
  {
66
0
    if(sb->size && sb->p != NULL) free(sb->p);
67
0
    mpg123_init_string(sb);
68
0
    return 1;
69
0
  }
70
49.1k
  if(sb->size != new)
71
49.1k
  {
72
49.1k
    char* t;
73
49.1k
    debug("really!");
74
49.1k
    t = (char*) INT123_safe_realloc(sb->p, new*sizeof(char));
75
49.1k
    debug1("INT123_safe_realloc returned %p", (void*) t); 
76
49.1k
    if(t != NULL)
77
49.1k
    {
78
49.1k
      sb->p = t;
79
49.1k
      sb->size = new;
80
49.1k
      if(sb->size < sb->fill)
81
0
      {
82
        // Cut short the existing data, properly.
83
0
        sb->fill = sb->size;
84
0
        sb->p[sb->fill-1] = 0;
85
0
      }
86
49.1k
      return 1;
87
49.1k
    }
88
0
    else return 0;
89
49.1k
  }
90
0
  else return 1; /* success */
91
49.1k
}
92
93
int attribute_align_arg mpg123_copy_string(mpg123_string* from, mpg123_string* to)
94
0
{
95
0
  size_t fill;
96
0
  char  *text;
97
98
0
  debug2("called copy_string with %p -> %p", (void*)from, (void*)to);
99
0
  if(to == NULL)
100
0
    return 0;
101
0
  if(from == NULL)
102
0
  {
103
0
    fill = 0;
104
0
    text = NULL;
105
0
  }
106
0
  else
107
0
  {
108
0
    fill = from->fill;
109
0
    text = from->p;
110
0
  }
111
112
0
  if(mpg123_resize_string(to, fill))
113
0
  {
114
0
    if(fill) /* Avoid memcpy(NULL, NULL, 0) */
115
0
      memcpy(to->p, text, fill);
116
0
    to->fill = fill;
117
0
    return 1;
118
0
  }
119
0
  else return 0;
120
0
}
121
122
int attribute_align_arg mpg123_move_string(mpg123_string *from, mpg123_string *to)
123
14.7k
{
124
14.7k
  if(to)
125
14.7k
    mpg123_free_string(to);
126
0
  else
127
0
    mpg123_free_string(from);
128
14.7k
  if(from && to)
129
14.7k
    *to = *from;
130
14.7k
  if(from)
131
14.7k
    mpg123_init_string(from);
132
14.7k
  return (from && to) ? 1 : 0;
133
14.7k
}
134
135
int attribute_align_arg mpg123_add_string(mpg123_string* sb, const char* stuff)
136
0
{
137
0
  debug1("adding %s", stuff);
138
0
  return mpg123_add_substring(sb, stuff, 0, stuff ? strlen(stuff) : 0);
139
0
}
140
141
int attribute_align_arg mpg123_add_substring(mpg123_string *sb, const char *stuff, size_t from, size_t count)
142
0
{
143
0
  debug("adding a substring");
144
0
  if(!sb || !stuff)
145
0
    return 0;
146
0
  if(sb->fill) /* includes zero byte... */
147
0
  {
148
0
    if( (SIZE_MAX - sb->fill >= count) /* Avoid overflow. */
149
0
        && (sb->size >= sb->fill+count || mpg123_grow_string(sb, sb->fill+count)) )
150
0
    {
151
0
      memcpy(sb->p+sb->fill-1, stuff+from, count);
152
0
      sb->fill += count;
153
0
      sb->p[sb->fill-1] = 0; /* Terminate! */
154
0
    }
155
0
    else return 0;
156
0
  }
157
0
  else
158
0
  {
159
0
    if( count < SIZE_MAX && mpg123_grow_string(sb, count+1) )
160
0
    {
161
0
      memcpy(sb->p, stuff+from, count);
162
0
      sb->fill = count+1;
163
0
      sb->p[sb->fill-1] = 0; /* Terminate! */
164
0
    }
165
0
    else return 0;
166
0
  }
167
0
  return 1;
168
0
}
169
170
int attribute_align_arg mpg123_set_substring(mpg123_string* sb, const char* stuff, size_t from, size_t count)
171
0
{
172
0
  if(!sb)
173
0
    return 0;
174
0
  sb->fill = 0;
175
0
  return mpg123_add_substring(sb, stuff, from, count);
176
0
}
177
178
int attribute_align_arg mpg123_set_string(mpg123_string* sb, const char* stuff)
179
0
{
180
0
  if(!sb)
181
0
    return 0;
182
0
  sb->fill = 0;
183
0
  return mpg123_add_string(sb, stuff);
184
0
}
185
186
size_t attribute_align_arg mpg123_strlen(mpg123_string *sb, int utf8)
187
0
{
188
0
  size_t i;
189
0
  size_t bytelen;
190
191
  /* Notions of empty string. If there's only a single character, it has to be the trailing zero, and if the first is the trailing zero anyway, we got empty. */
192
0
  if(!sb || sb->fill < 2 || sb->p[0] == 0) return 0;
193
194
  /* Find the first non-null character from the back.
195
     We already established that the first character is non-null
196
     That at fill-2 has to be null, though. */
197
0
  for(i=sb->fill-2; i>0; --i)
198
0
  if(sb->p[i] != 0) break;
199
200
  /* For simple byte strings, we are done now. */
201
0
  bytelen = i+1;
202
203
0
  if(!utf8) return bytelen;
204
0
  else
205
0
  {
206
    /* Work out the actual count of UTF8 bytes.
207
       This employs no particular encoding error checking. */
208
0
    size_t len = 0;
209
0
    for(i=0; i<bytelen; ++i)
210
0
    {
211
      /* Every byte that is not a continuation byte ( 0xc0 == 10xx xxxx ) stands for a character. */
212
0
      if((sb->p[i] & 0xc0) != 0x80) len++;
213
0
    }
214
0
    return len;
215
0
  }
216
0
}
217
218
int attribute_align_arg mpg123_chomp_string(mpg123_string *sb)
219
0
{
220
0
  if(!sb || !sb->fill) return 0;
221
222
  /* Ensure that it is zero-terminated. */
223
0
  char *c = sb->p+sb->fill-1;
224
0
  *c = 0;
225
0
  for(; c >= sb->p; --c)
226
0
  {
227
    /* Stop at the first proper character. */
228
0
    if(*c && *c != '\r' && *c != '\n') break;
229
0
    else *c = 0;
230
0
  }
231
  // We at least got a trailing zero. 
232
0
  sb->fill = (size_t)(c - sb->p + 1) + 1;
233
234
0
  return 1;
235
0
}
236
237
int attribute_align_arg mpg123_same_string(mpg123_string *a, mpg123_string *b)
238
3.13k
{
239
3.13k
  if(!a || !b)
240
0
    return 0;
241
3.13k
  if(a->fill != b->fill)
242
1.12k
    return 0;
243
2.00k
  if(memcmp(a->p, b->p, a->fill))
244
1.04k
    return 0;
245
956
  return 1;
246
2.00k
}