Blame src/libmpg123/stringbuf.c

Packit c32a2d
/*
Packit c32a2d
	stringbuf: mimicking a bit of C++ to more safely handle strings
Packit c32a2d
Packit c32a2d
	copyright 2006-17 by the mpg123 project
Packit c32a2d
	    - free software under the terms of the LGPL 2.1
Packit c32a2d
	see COPYING and AUTHORS files in distribution or http://mpg123.org
Packit c32a2d
	initially written by Thomas Orgis
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
#include "mpg123lib_intern.h"
Packit c32a2d
#include "config.h"
Packit c32a2d
#include "mpg123.h"
Packit c32a2d
#include "compat.h"
Packit c32a2d
#include <string.h>
Packit c32a2d
#include "debug.h"
Packit c32a2d
Packit c32a2d
void attribute_align_arg mpg123_init_string(mpg123_string* sb)
Packit c32a2d
{
Packit c32a2d
	/* Handing in NULL here is a fatal mistake and rightfully so. */
Packit c32a2d
	sb->p = NULL;
Packit c32a2d
	sb->size = 0;
Packit c32a2d
	sb->fill = 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
void attribute_align_arg mpg123_free_string(mpg123_string* sb)
Packit c32a2d
{
Packit c32a2d
	if(!sb)
Packit c32a2d
		return;
Packit c32a2d
	if(sb->p != NULL) free(sb->p);
Packit c32a2d
	mpg123_init_string(sb);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int attribute_align_arg mpg123_grow_string(mpg123_string* sb, size_t new)
Packit c32a2d
{
Packit c32a2d
	if(!sb)
Packit c32a2d
		return 0;
Packit c32a2d
	if(sb->size < new) return mpg123_resize_string(sb, new);
Packit c32a2d
	else return 1;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int attribute_align_arg mpg123_resize_string(mpg123_string* sb, size_t new)
Packit c32a2d
{
Packit c32a2d
	if(!sb)
Packit c32a2d
		return 0;
Packit c32a2d
	debug3("resizing string pointer %p from %lu to %lu", (void*) sb->p, (unsigned long)sb->size, (unsigned long)new);
Packit c32a2d
	if(new == 0)
Packit c32a2d
	{
Packit c32a2d
		if(sb->size && sb->p != NULL) free(sb->p);
Packit c32a2d
		mpg123_init_string(sb);
Packit c32a2d
		return 1;
Packit c32a2d
	}
Packit c32a2d
	if(sb->size != new)
Packit c32a2d
	{
Packit c32a2d
		char* t;
Packit c32a2d
		debug("really!");
Packit c32a2d
		t = (char*) safe_realloc(sb->p, new*sizeof(char));
Packit c32a2d
		debug1("safe_realloc returned %p", (void*) t); 
Packit c32a2d
		if(t != NULL)
Packit c32a2d
		{
Packit c32a2d
			sb->p = t;
Packit c32a2d
			sb->size = new;
Packit c32a2d
			return 1;
Packit c32a2d
		}
Packit c32a2d
		else return 0;
Packit c32a2d
	}
Packit c32a2d
	else return 1; /* success */
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int attribute_align_arg mpg123_copy_string(mpg123_string* from, mpg123_string* to)
Packit c32a2d
{
Packit c32a2d
	size_t fill;
Packit c32a2d
	char  *text;
Packit c32a2d
Packit c32a2d
	debug2("called copy_string with %p -> %p", (void*)from, (void*)to);
Packit c32a2d
	if(to == NULL)
Packit c32a2d
		return 0;
Packit c32a2d
	if(from == NULL)
Packit c32a2d
	{
Packit c32a2d
		fill = 0;
Packit c32a2d
		text = NULL;
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
		fill = from->fill;
Packit c32a2d
		text = from->p;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	if(mpg123_resize_string(to, fill))
Packit c32a2d
	{
Packit c32a2d
		if(fill) /* Avoid memcpy(NULL, NULL, 0) */
Packit c32a2d
			memcpy(to->p, text, fill);
Packit c32a2d
		to->fill = fill;
Packit c32a2d
		return 1;
Packit c32a2d
	}
Packit c32a2d
	else return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int attribute_align_arg mpg123_add_string(mpg123_string* sb, const char* stuff)
Packit c32a2d
{
Packit c32a2d
	debug1("adding %s", stuff);
Packit c32a2d
	return mpg123_add_substring(sb, stuff, 0, stuff ? strlen(stuff) : 0);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int attribute_align_arg mpg123_add_substring(mpg123_string *sb, const char *stuff, size_t from, size_t count)
Packit c32a2d
{
Packit c32a2d
	debug("adding a substring");
Packit c32a2d
	if(!sb || !stuff)
Packit c32a2d
		return 0;
Packit c32a2d
	if(sb->fill) /* includes zero byte... */
Packit c32a2d
	{
Packit c32a2d
		if( (SIZE_MAX - sb->fill >= count) /* Avoid overflow. */
Packit c32a2d
		    && (sb->size >= sb->fill+count || mpg123_grow_string(sb, sb->fill+count)) )
Packit c32a2d
		{
Packit c32a2d
			memcpy(sb->p+sb->fill-1, stuff+from, count);
Packit c32a2d
			sb->fill += count;
Packit c32a2d
			sb->p[sb->fill-1] = 0; /* Terminate! */
Packit c32a2d
		}
Packit c32a2d
		else return 0;
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
		if( count < SIZE_MAX && mpg123_grow_string(sb, count+1) )
Packit c32a2d
		{
Packit c32a2d
			memcpy(sb->p, stuff+from, count);
Packit c32a2d
			sb->fill = count+1;
Packit c32a2d
			sb->p[sb->fill-1] = 0; /* Terminate! */
Packit c32a2d
		}
Packit c32a2d
		else return 0;
Packit c32a2d
	}
Packit c32a2d
	return 1;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int attribute_align_arg mpg123_set_substring(mpg123_string* sb, const char* stuff, size_t from, size_t count)
Packit c32a2d
{
Packit c32a2d
	if(!sb)
Packit c32a2d
		return 0;
Packit c32a2d
	sb->fill = 0;
Packit c32a2d
	return mpg123_add_substring(sb, stuff, from, count);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int attribute_align_arg mpg123_set_string(mpg123_string* sb, const char* stuff)
Packit c32a2d
{
Packit c32a2d
	if(!sb)
Packit c32a2d
		return 0;
Packit c32a2d
	sb->fill = 0;
Packit c32a2d
	return mpg123_add_string(sb, stuff);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
size_t attribute_align_arg mpg123_strlen(mpg123_string *sb, int utf8)
Packit c32a2d
{
Packit c32a2d
	size_t i;
Packit c32a2d
	size_t bytelen;
Packit c32a2d
Packit c32a2d
	/* 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. */
Packit c32a2d
	if(!sb || sb->fill < 2 || sb->p[0] == 0) return 0;
Packit c32a2d
Packit c32a2d
	/* Find the first non-null character from the back.
Packit c32a2d
	   We already established that the first character is non-null
Packit c32a2d
	   That at fill-2 has to be null, though. */
Packit c32a2d
	for(i=sb->fill-2; i>0; --i)
Packit c32a2d
	if(sb->p[i] != 0) break;
Packit c32a2d
Packit c32a2d
	/* For simple byte strings, we are done now. */
Packit c32a2d
	bytelen = i+1;
Packit c32a2d
Packit c32a2d
	if(!utf8) return bytelen;
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
		/* Work out the actual count of UTF8 bytes.
Packit c32a2d
		   This employs no particular encoding error checking. */
Packit c32a2d
		size_t len = 0;
Packit c32a2d
		for(i=0; i
Packit c32a2d
		{
Packit c32a2d
			/* Every byte that is not a continuation byte ( 0xc0 == 10xx xxxx ) stands for a character. */
Packit c32a2d
			if((sb->p[i] & 0xc0) != 0x80) len++;
Packit c32a2d
		}
Packit c32a2d
		return len;
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int attribute_align_arg mpg123_chomp_string(mpg123_string *sb)
Packit c32a2d
{
Packit c32a2d
	ssize_t i;
Packit c32a2d
	if(!sb || !sb->fill) return 0;
Packit c32a2d
Packit c32a2d
	/* Ensure that it is zero-terminated. */
Packit c32a2d
	sb->p[sb->fill-1] = 0;
Packit c32a2d
	for(i=sb->fill-2; i>=0; --i)
Packit c32a2d
	{
Packit c32a2d
		char *c = sb->p+i;
Packit c32a2d
		/* Stop at the first proper character. */
Packit c32a2d
		if(*c && *c != '\r' && *c != '\n') break;
Packit c32a2d
		else *c = 0;
Packit c32a2d
	}
Packit c32a2d
	/* initial fill at least 1, so i at least -1,
Packit c32a2d
	   +2 means nothing happened for fill=1 .
Packit c32a2d
	   With i=0, we got one non-null character, fill shall be 2
Packit c32a2d
	   to accomodate the trailing zero. */
Packit c32a2d
	sb->fill = (size_t)i+2;
Packit c32a2d
Packit c32a2d
	return 1;
Packit c32a2d
}