xref: /reactos/sdk/lib/3rdparty/libmpg123/stringbuf.c (revision cc7cf826)
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 
17 mpg123_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 
27 void 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 
35 void 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 
43 void 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 
51 int 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 
59 int 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 
93 int 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 
122 int 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 
135 int 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 
141 int 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 
170 int 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 
178 int 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 
186 size_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 
218 int 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 
241 int 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 }
251