xref: /third_party/libsnd/src/strings.c (revision b815c7f3)
1/*
2** Copyright (C) 2001-2016 Erik de Castro Lopo <erikd@mega-nerd.com>
3**
4** This program is free software; you can redistribute it and/or modify
5** it under the terms of the GNU Lesser General Public License as published by
6** the Free Software Foundation; either version 2.1 of the License, or
7** (at your option) any later version.
8**
9** This program is distributed in the hope that it will be useful,
10** but WITHOUT ANY WARRANTY; without even the implied warranty of
11** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12** GNU Lesser General Public License for more details.
13**
14** You should have received a copy of the GNU Lesser General Public License
15** along with this program; if not, write to the Free Software
16** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17*/
18
19#include	"sfconfig.h"
20
21#include	<stdio.h>
22#include	<string.h>
23#include	<math.h>
24
25#include	"sndfile.h"
26#include	"common.h"
27
28#define STRINGS_DEBUG 0
29
30int
31psf_store_string (SF_PRIVATE *psf, int str_type, const char *str)
32{	char	new_str [128] ;
33	size_t	str_len ;
34	int		k, str_flags ;
35
36	if (str == NULL)
37		return SFE_STR_BAD_STRING ;
38
39	str_len = strlen (str) ;
40
41	/* A few extra checks for write mode. */
42	if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
43	{	if ((psf->strings.flags & SF_STR_ALLOW_START) == 0)
44			return SFE_STR_NO_SUPPORT ;
45		if (psf->have_written && (psf->strings.flags & SF_STR_ALLOW_END) == 0)
46			return SFE_STR_NO_SUPPORT ;
47		/* Only allow zero length strings for software. */
48		if (str_type != SF_STR_SOFTWARE && str_len == 0)
49			return SFE_STR_BAD_STRING ;
50		} ;
51
52	/* Find the next free slot in table. */
53	for (k = 0 ; k < SF_MAX_STRINGS ; k++)
54	{	/* If we find a matching entry clear it. */
55		if (psf->strings.data [k].type == str_type)
56			psf->strings.data [k].type = -1 ;
57
58		if (psf->strings.data [k].type == 0)
59			break ;
60		} ;
61
62	/* Determine flags */
63	str_flags = SF_STR_LOCATE_START ;
64	if (psf->file.mode == SFM_RDWR || psf->have_written)
65	{	if ((psf->strings.flags & SF_STR_ALLOW_END) == 0)
66			return SFE_STR_NO_ADD_END ;
67		str_flags = SF_STR_LOCATE_END ;
68		} ;
69
70	/* More sanity checking. */
71	if (k >= SF_MAX_STRINGS)
72		return SFE_STR_MAX_COUNT ;
73
74	if (k == 0 && psf->strings.storage_used != 0)
75	{	psf_log_printf (psf, "SFE_STR_WEIRD : k == 0 && psf->strings.storage_used != 0\n") ;
76		return SFE_STR_WEIRD ;
77		} ;
78
79	if (k != 0 && psf->strings.storage_used == 0)
80	{	psf_log_printf (psf, "SFE_STR_WEIRD : k != 0 && psf->strings.storage_used == 0\n") ;
81		return SFE_STR_WEIRD ;
82		} ;
83
84	/* Special case for the first string. */
85	if (k == 0)
86		psf->strings.storage_used = 0 ;
87
88	switch (str_type)
89	{	case SF_STR_SOFTWARE :
90				/* In write mode, want to append libsndfile-version to string. */
91				if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
92				{	if (strstr (str, PACKAGE_NAME) == NULL)
93					{	/*
94						** If the supplied string does not already contain a
95						** libsndfile-X.Y.Z component, then add it.
96						*/
97						if (strlen (str) == 0)
98							snprintf (new_str, sizeof (new_str), "%s-%s", PACKAGE_NAME, PACKAGE_VERSION) ;
99						else
100							snprintf (new_str, sizeof (new_str), "%s (%s-%s)", str, PACKAGE_NAME, PACKAGE_VERSION) ;
101						}
102					else
103						snprintf (new_str, sizeof (new_str), "%s", str) ;
104
105					str = new_str ;
106					} ;
107				break ;
108
109		case SF_STR_TITLE :
110		case SF_STR_COPYRIGHT :
111		case SF_STR_ARTIST :
112		case SF_STR_COMMENT :
113		case SF_STR_DATE :
114		case SF_STR_ALBUM :
115		case SF_STR_LICENSE :
116		case SF_STR_TRACKNUMBER :
117		case SF_STR_GENRE :
118				break ;
119
120		default :
121			psf_log_printf (psf, "%s : SFE_STR_BAD_TYPE\n", __func__) ;
122			return SFE_STR_BAD_TYPE ;
123		} ;
124
125	/* Plus one to catch string terminator. */
126	str_len = strlen (str) + 1 ;
127
128	if (psf->strings.storage_used + str_len + 1 > psf->strings.storage_len)
129	{	char * temp = psf->strings.storage ;
130		size_t newlen = 2 * psf->strings.storage_len + str_len + 1 ;
131
132		newlen = newlen < 256 ? 256 : newlen ;
133
134		if ((psf->strings.storage = realloc (temp, newlen)) == NULL)
135		{	psf->strings.storage = temp ;
136			return SFE_MALLOC_FAILED ;
137			} ;
138
139		psf->strings.storage_len = newlen ;
140		} ;
141
142	psf->strings.data [k].type = str_type ;
143	psf->strings.data [k].offset = psf->strings.storage_used ;
144	psf->strings.data [k].flags = str_flags ;
145
146	memcpy (psf->strings.storage + psf->strings.storage_used, str, str_len) ;
147	psf->strings.storage_used += str_len ;
148
149	psf->strings.flags |= str_flags ;
150
151#if STRINGS_DEBUG
152	printf ("storage_used         : %zd / %zd\n", psf->strings.storage_used, psf->strings.storage_len) ;
153	psf_hexdump (psf->strings.storage, psf->strings.storage_used) ;
154#endif
155
156	return 0 ;
157} /* psf_store_string */
158
159int
160psf_set_string (SF_PRIVATE *psf, int str_type, const char *str)
161{	if (psf->file.mode == SFM_READ)
162		return SFE_STR_NOT_WRITE ;
163
164	return psf_store_string (psf, str_type, str) ;
165} /* psf_set_string */
166
167const char*
168psf_get_string (SF_PRIVATE *psf, int str_type)
169{	int k ;
170
171	for (k = 0 ; k < SF_MAX_STRINGS ; k++)
172		if (str_type == psf->strings.data [k].type)
173			return psf->strings.storage + psf->strings.data [k].offset ;
174
175	return NULL ;
176} /* psf_get_string */
177
178int
179psf_location_string_count (const SF_PRIVATE * psf, int location)
180{	int k, count = 0 ;
181
182	for (k = 0 ; k < SF_MAX_STRINGS ; k++)
183		if (psf->strings.data [k].type > 0 && psf->strings.data [k].flags & location)
184			count ++ ;
185
186	return count ;
187} /* psf_location_string_count */
188