xref: /reactos/sdk/lib/3rdparty/libmpg123/stringbuf.c (revision c2c66aff)
1 /*
2 	stringbuf: mimicking a bit of C++ to more safely handle strings
3 
4 	copyright 2006-17 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 void attribute_align_arg mpg123_init_string(mpg123_string* sb)
18 {
19 	/* Handing in NULL here is a fatal mistake and rightfully so. */
20 	sb->p = NULL;
21 	sb->size = 0;
22 	sb->fill = 0;
23 }
24 
25 void attribute_align_arg mpg123_free_string(mpg123_string* sb)
26 {
27 	if(!sb)
28 		return;
29 	if(sb->p != NULL) free(sb->p);
30 	mpg123_init_string(sb);
31 }
32 
33 int attribute_align_arg mpg123_grow_string(mpg123_string* sb, size_t new)
34 {
35 	if(!sb)
36 		return 0;
37 	if(sb->size < new) return mpg123_resize_string(sb, new);
38 	else return 1;
39 }
40 
41 int attribute_align_arg mpg123_resize_string(mpg123_string* sb, size_t new)
42 {
43 	if(!sb)
44 		return 0;
45 	debug3("resizing string pointer %p from %lu to %lu", (void*) sb->p, (unsigned long)sb->size, (unsigned long)new);
46 	if(new == 0)
47 	{
48 		if(sb->size && sb->p != NULL) free(sb->p);
49 		mpg123_init_string(sb);
50 		return 1;
51 	}
52 	if(sb->size != new)
53 	{
54 		char* t;
55 		debug("really!");
56 		t = (char*) safe_realloc(sb->p, new*sizeof(char));
57 		debug1("safe_realloc returned %p", (void*) t);
58 		if(t != NULL)
59 		{
60 			sb->p = t;
61 			sb->size = new;
62 			return 1;
63 		}
64 		else return 0;
65 	}
66 	else return 1; /* success */
67 }
68 
69 int attribute_align_arg mpg123_copy_string(mpg123_string* from, mpg123_string* to)
70 {
71 	size_t fill;
72 	char  *text;
73 
74 	debug2("called copy_string with %p -> %p", (void*)from, (void*)to);
75 	if(to == NULL)
76 		return 0;
77 	if(from == NULL)
78 	{
79 		fill = 0;
80 		text = NULL;
81 	}
82 	else
83 	{
84 		fill = from->fill;
85 		text = from->p;
86 	}
87 
88 	if(mpg123_resize_string(to, fill))
89 	{
90 		if(fill) /* Avoid memcpy(NULL, NULL, 0) */
91 			memcpy(to->p, text, fill);
92 		to->fill = fill;
93 		return 1;
94 	}
95 	else return 0;
96 }
97 
98 int attribute_align_arg mpg123_add_string(mpg123_string* sb, const char* stuff)
99 {
100 	debug1("adding %s", stuff);
101 	return mpg123_add_substring(sb, stuff, 0, stuff ? strlen(stuff) : 0);
102 }
103 
104 int attribute_align_arg mpg123_add_substring(mpg123_string *sb, const char *stuff, size_t from, size_t count)
105 {
106 	debug("adding a substring");
107 	if(!sb || !stuff)
108 		return 0;
109 	if(sb->fill) /* includes zero byte... */
110 	{
111 		if( (SIZE_MAX - sb->fill >= count) /* Avoid overflow. */
112 		    && (sb->size >= sb->fill+count || mpg123_grow_string(sb, sb->fill+count)) )
113 		{
114 			memcpy(sb->p+sb->fill-1, stuff+from, count);
115 			sb->fill += count;
116 			sb->p[sb->fill-1] = 0; /* Terminate! */
117 		}
118 		else return 0;
119 	}
120 	else
121 	{
122 		if( count < SIZE_MAX && mpg123_grow_string(sb, count+1) )
123 		{
124 			memcpy(sb->p, stuff+from, count);
125 			sb->fill = count+1;
126 			sb->p[sb->fill-1] = 0; /* Terminate! */
127 		}
128 		else return 0;
129 	}
130 	return 1;
131 }
132 
133 int attribute_align_arg mpg123_set_substring(mpg123_string* sb, const char* stuff, size_t from, size_t count)
134 {
135 	if(!sb)
136 		return 0;
137 	sb->fill = 0;
138 	return mpg123_add_substring(sb, stuff, from, count);
139 }
140 
141 int attribute_align_arg mpg123_set_string(mpg123_string* sb, const char* stuff)
142 {
143 	if(!sb)
144 		return 0;
145 	sb->fill = 0;
146 	return mpg123_add_string(sb, stuff);
147 }
148 
149 size_t attribute_align_arg mpg123_strlen(mpg123_string *sb, int utf8)
150 {
151 	size_t i;
152 	size_t bytelen;
153 
154 	/* 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. */
155 	if(!sb || sb->fill < 2 || sb->p[0] == 0) return 0;
156 
157 	/* Find the first non-null character from the back.
158 	   We already established that the first character is non-null
159 	   That at fill-2 has to be null, though. */
160 	for(i=sb->fill-2; i>0; --i)
161 	if(sb->p[i] != 0) break;
162 
163 	/* For simple byte strings, we are done now. */
164 	bytelen = i+1;
165 
166 	if(!utf8) return bytelen;
167 	else
168 	{
169 		/* Work out the actual count of UTF8 bytes.
170 		   This employs no particular encoding error checking. */
171 		size_t len = 0;
172 		for(i=0; i<bytelen; ++i)
173 		{
174 			/* Every byte that is not a continuation byte ( 0xc0 == 10xx xxxx ) stands for a character. */
175 			if((sb->p[i] & 0xc0) != 0x80) len++;
176 		}
177 		return len;
178 	}
179 }
180 
181 int attribute_align_arg mpg123_chomp_string(mpg123_string *sb)
182 {
183 	ssize_t i;
184 	if(!sb || !sb->fill) return 0;
185 
186 	/* Ensure that it is zero-terminated. */
187 	sb->p[sb->fill-1] = 0;
188 	for(i=sb->fill-2; i>=0; --i)
189 	{
190 		char *c = sb->p+i;
191 		/* Stop at the first proper character. */
192 		if(*c && *c != '\r' && *c != '\n') break;
193 		else *c = 0;
194 	}
195 	/* initial fill at least 1, so i at least -1,
196 	   +2 means nothing happened for fill=1 .
197 	   With i=0, we got one non-null character, fill shall be 2
198 	   to accomodate the trailing zero. */
199 	sb->fill = (size_t)i+2;
200 
201 	return 1;
202 }
203