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