Reactos
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.h"
14#include <string.h>
15#include "debug.h"
16
17mpg123_string* attribute_align_arg mpg123_new_string(const char *val)
18{
19 mpg123_string *sb = malloc(sizeof(mpg123_string));
20 if(!sb)
21 return NULL;
22 mpg123_init_string(sb);
23 mpg123_set_string(sb, val);
24 return sb;
25}
26
27void attribute_align_arg mpg123_delete_string(mpg123_string* sb)
28{
29 if(!sb)
30 return;
31 mpg123_free_string(sb);
32 free(sb);
33}
34
35void attribute_align_arg mpg123_init_string(mpg123_string* sb)
36{
37 /* Handing in NULL here is a fatal mistake and rightfully so. */
38 sb->p = NULL;
39 sb->size = 0;
40 sb->fill = 0;
41}
42
43void attribute_align_arg mpg123_free_string(mpg123_string* sb)
44{
45 if(!sb)
46 return;
47 if(sb->p != NULL) free(sb->p);
48 mpg123_init_string(sb);
49}
50
51int attribute_align_arg mpg123_grow_string(mpg123_string* sb, size_t new)
52{
53 if(!sb)
54 return 0;
55 if(sb->size < new) return mpg123_resize_string(sb, new);
56 else return 1;
57}
58
59int attribute_align_arg mpg123_resize_string(mpg123_string* sb, size_t new)
60{
61 if(!sb)
62 return 0;
63 debug3("resizing string pointer %p from %lu to %lu", (void*) sb->p, (unsigned long)sb->size, (unsigned long)new);
64 if(new == 0)
65 {
66 if(sb->size && sb->p != NULL) free(sb->p);
67 mpg123_init_string(sb);
68 return 1;
69 }
70 if(sb->size != new)
71 {
72 char* t;
73 debug("really!");
74 t = (char*) safe_realloc(sb->p, new*sizeof(char));
75 debug1("safe_realloc returned %p", (void*) t);
76 if(t != NULL)
77 {
78 sb->p = t;
79 sb->size = new;
80 if(sb->size < sb->fill)
81 {
82 // Cut short the existing data, properly.
83 sb->fill = sb->size;
84 sb->p[sb->fill-1] = 0;
85 }
86 return 1;
87 }
88 else return 0;
89 }
90 else return 1; /* success */
91}
92
93int attribute_align_arg mpg123_copy_string(mpg123_string* from, mpg123_string* to)
94{
95 size_t fill;
96 char *text;
97
98 debug2("called copy_string with %p -> %p", (void*)from, (void*)to);
99 if(to == NULL)
100 return 0;
101 if(from == NULL)
102 {
103 fill = 0;
104 text = NULL;
105 }
106 else
107 {
108 fill = from->fill;
109 text = from->p;
110 }
111
112 if(mpg123_resize_string(to, fill))
113 {
114 if(fill) /* Avoid memcpy(NULL, NULL, 0) */
115 memcpy(to->p, text, fill);
116 to->fill = fill;
117 return 1;
118 }
119 else return 0;
120}
121
122int attribute_align_arg mpg123_move_string(mpg123_string *from, mpg123_string *to)
123{
124 if(to)
125 mpg123_free_string(to);
126 else
127 mpg123_free_string(from);
128 if(from && to)
129 *to = *from;
130 if(from)
131 mpg123_init_string(from);
132 return (from && to) ? 1 : 0;
133}
134
135int attribute_align_arg mpg123_add_string(mpg123_string* sb, const char* stuff)
136{
137 debug1("adding %s", stuff);
138 return mpg123_add_substring(sb, stuff, 0, stuff ? strlen(stuff) : 0);
139}
140
141int attribute_align_arg mpg123_add_substring(mpg123_string *sb, const char *stuff, size_t from, size_t count)
142{
143 debug("adding a substring");
144 if(!sb || !stuff)
145 return 0;
146 if(sb->fill) /* includes zero byte... */
147 {
148 if( (SIZE_MAX - sb->fill >= count) /* Avoid overflow. */
149 && (sb->size >= sb->fill+count || mpg123_grow_string(sb, sb->fill+count)) )
150 {
151 memcpy(sb->p+sb->fill-1, stuff+from, count);
152 sb->fill += count;
153 sb->p[sb->fill-1] = 0; /* Terminate! */
154 }
155 else return 0;
156 }
157 else
158 {
159 if( count < SIZE_MAX && mpg123_grow_string(sb, count+1) )
160 {
161 memcpy(sb->p, stuff+from, count);
162 sb->fill = count+1;
163 sb->p[sb->fill-1] = 0; /* Terminate! */
164 }
165 else return 0;
166 }
167 return 1;
168}
169
170int attribute_align_arg mpg123_set_substring(mpg123_string* sb, const char* stuff, size_t from, size_t count)
171{
172 if(!sb)
173 return 0;
174 sb->fill = 0;
175 return mpg123_add_substring(sb, stuff, from, count);
176}
177
178int attribute_align_arg mpg123_set_string(mpg123_string* sb, const char* stuff)
179{
180 if(!sb)
181 return 0;
182 sb->fill = 0;
183 return mpg123_add_string(sb, stuff);
184}
185
186size_t attribute_align_arg mpg123_strlen(mpg123_string *sb, int utf8)
187{
188 size_t i;
189 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 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 for(i=sb->fill-2; i>0; --i)
198 if(sb->p[i] != 0) break;
199
200 /* For simple byte strings, we are done now. */
201 bytelen = i+1;
202
203 if(!utf8) return bytelen;
204 else
205 {
206 /* Work out the actual count of UTF8 bytes.
207 This employs no particular encoding error checking. */
208 size_t len = 0;
209 for(i=0; i<bytelen; ++i)
210 {
211 /* Every byte that is not a continuation byte ( 0xc0 == 10xx xxxx ) stands for a character. */
212 if((sb->p[i] & 0xc0) != 0x80) len++;
213 }
214 return len;
215 }
216}
217
218int attribute_align_arg mpg123_chomp_string(mpg123_string *sb)
219{
220 ssize_t i;
221 if(!sb || !sb->fill) return 0;
222
223 /* Ensure that it is zero-terminated. */
224 sb->p[sb->fill-1] = 0;
225 for(i=sb->fill-2; i>=0; --i)
226 {
227 char *c = sb->p+i;
228 /* Stop at the first proper character. */
229 if(*c && *c != '\r' && *c != '\n') break;
230 else *c = 0;
231 }
232 /* initial fill at least 1, so i at least -1,
233 +2 means nothing happened for fill=1 .
234 With i=0, we got one non-null character, fill shall be 2
235 to accomodate the trailing zero. */
236 sb->fill = (size_t)i+2;
237
238 return 1;
239}
240
241int attribute_align_arg mpg123_same_string(mpg123_string *a, mpg123_string *b)
242{
243 if(!a || !b)
244 return 0;
245 if(a->fill != b->fill)
246 return 0;
247 if(memcmp(a->p, b->p, a->fill))
248 return 0;
249 return 1;
250}