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