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