• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 ** Copyright (C) 2001-2020 Erik de Castro Lopo <erikd@mega-nerd.com>
3 ** Copyright (C) 2004 Paavo Jumppanen
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU Lesser General Public License as published by
7 ** the Free Software Foundation; either version 2.1 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 ** GNU Lesser General Public License for more details.
14 **
15 ** You should have received a copy of the GNU Lesser General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19 
20 /*
21 ** The sd2 support implemented in this file was partially sponsored
22 ** (financially) by Paavo Jumppanen.
23 */
24 
25 /*
26 ** Documentation on the Mac resource fork was obtained here :
27 ** http://developer.apple.com/documentation/mac/MoreToolbox/MoreToolbox-99.html
28 */
29 
30 #include	"sfconfig.h"
31 
32 #include	<stdio.h>
33 #include	<stdlib.h>
34 #include	<string.h>
35 #include	<ctype.h>
36 
37 #include	"sndfile.h"
38 #include	"sfendian.h"
39 #include	"common.h"
40 
41 /*------------------------------------------------------------------------------
42  * Markers.
43 */
44 
45 #define	Sd2f_MARKER			MAKE_MARKER ('S', 'd', '2', 'f')
46 #define	Sd2a_MARKER			MAKE_MARKER ('S', 'd', '2', 'a')
47 #define	ALCH_MARKER			MAKE_MARKER ('A', 'L', 'C', 'H')
48 #define lsf1_MARKER			MAKE_MARKER ('l', 's', 'f', '1')
49 
50 #define STR_MARKER			MAKE_MARKER ('S', 'T', 'R', ' ')
51 #define sdML_MARKER			MAKE_MARKER ('s', 'd', 'M', 'L')
52 
53 enum
54 {	RSRC_STR = 111,
55 	RSRC_BIN
56 } ;
57 
58 typedef struct
59 {	unsigned char * rsrc_data ;
60 	int rsrc_len ;
61 	int need_to_free_rsrc_data ;
62 
63 	int data_offset, data_length ;
64 	int map_offset, map_length ;
65 
66 	int type_count, type_offset ;
67 	int item_offset ;
68 
69 	int str_index, str_count ;
70 
71 	int string_offset ;
72 
73 	/* All the above just to get these three. */
74 	int sample_size, sample_rate, channels ;
75 } SD2_RSRC ;
76 
77 typedef struct
78 {	int type ;
79 	int id ;
80 	char name [32] ;
81 	char value [32] ;
82 	int value_len ;
83 } STR_RSRC ;
84 
85 /*------------------------------------------------------------------------------
86  * Private static functions.
87 */
88 
89 static int sd2_close	(SF_PRIVATE *psf) ;
90 
91 static int sd2_parse_rsrc_fork (SF_PRIVATE *psf) ;
92 static int parse_str_rsrc (SF_PRIVATE *psf, SD2_RSRC * rsrc) ;
93 
94 static int sd2_write_rsrc_fork (SF_PRIVATE *psf, int calc_length) ;
95 
96 /*------------------------------------------------------------------------------
97 ** Public functions.
98 */
99 
100 int
sd2_open(SF_PRIVATE * psf)101 sd2_open (SF_PRIVATE *psf)
102 {	int subformat, error = 0, valid ;
103 
104 	/* SD2 is always big endian. */
105 	psf->endian = SF_ENDIAN_BIG ;
106 
107 	if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->rsrclength > 0))
108 	{	psf_use_rsrc (psf, SF_TRUE) ;
109 		valid = psf_file_valid (psf) ;
110 		psf_use_rsrc (psf, SF_FALSE) ;
111 		if (! valid)
112 		{	psf_log_printf (psf, "sd2_open : psf->rsrc.filedes < 0\n") ;
113 			return SFE_SD2_BAD_RSRC ;
114 			} ;
115 
116 		error = sd2_parse_rsrc_fork (psf) ;
117 
118 		if (error)
119 			goto error_cleanup ;
120 		} ;
121 
122 	if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_SD2)
123 	{	error = SFE_BAD_OPEN_FORMAT ;
124 		goto error_cleanup ;
125 		} ;
126 
127 	subformat = SF_CODEC (psf->sf.format) ;
128 	psf->dataoffset = 0 ;
129 
130 	/* Only open and write the resource in RDWR mode is its current length is zero. */
131 	if (psf->file.mode == SFM_WRITE || (psf->file.mode == SFM_RDWR && psf->rsrclength == 0))
132 	{	psf->rsrc.mode = psf->file.mode ;
133 		psf_open_rsrc (psf) ;
134 
135 		error = sd2_write_rsrc_fork (psf, SF_FALSE) ;
136 
137 		if (error)
138 			goto error_cleanup ;
139 
140 		/* Not needed. */
141 		psf->write_header = NULL ;
142 		} ;
143 
144 	psf->container_close = sd2_close ;
145 
146 	psf->blockwidth = psf->bytewidth * psf->sf.channels ;
147 
148 	switch (subformat)
149 	{	case SF_FORMAT_PCM_S8 :	/* 8-bit linear PCM. */
150 		case SF_FORMAT_PCM_16 :	/* 16-bit linear PCM. */
151 		case SF_FORMAT_PCM_24 :	/* 24-bit linear PCM */
152 		case SF_FORMAT_PCM_32 :	/* 32-bit linear PCM */
153 				error = pcm_init (psf) ;
154 				break ;
155 
156 		default :
157 				error = SFE_UNIMPLEMENTED ;
158 				break ;
159 		} ;
160 
161 	psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
162 
163 error_cleanup:
164 
165 	/* Close the resource fork regardless. We won't need it again. */
166 	psf_close_rsrc (psf) ;
167 
168 	return error ;
169 } /* sd2_open */
170 
171 /*------------------------------------------------------------------------------
172 */
173 
174 static int
sd2_close(SF_PRIVATE * psf)175 sd2_close	(SF_PRIVATE *psf)
176 {
177 	if (psf->file.mode == SFM_WRITE)
178 	{	/*  Now we know for certain the audio_length of the file we can re-write
179 		**	correct values for the FORM, 8SVX and BODY chunks.
180 		*/
181 
182 		} ;
183 
184 	return 0 ;
185 } /* sd2_close */
186 
187 /*------------------------------------------------------------------------------
188 */
189 
190 static int
sd2_write_rsrc_fork(SF_PRIVATE * psf,int UNUSED (calc_length))191 sd2_write_rsrc_fork (SF_PRIVATE *psf, int UNUSED (calc_length))
192 {	SD2_RSRC rsrc ;
193 	STR_RSRC str_rsrc [] =
194 	{	{ RSRC_STR, 1000, "_sample-size", "", 0 },
195 		{ RSRC_STR, 1001, "_sample-rate", "", 0 },
196 		{ RSRC_STR, 1002, "_channels", "", 0 },
197 		{ RSRC_BIN, 1000, "_Markers", "", 8 }
198 		} ;
199 
200 	int k, str_offset, data_offset, next_str ;
201 
202 	psf_use_rsrc (psf, SF_TRUE) ;
203 
204 	memset (&rsrc, 0, sizeof (rsrc)) ;
205 
206 	rsrc.sample_rate = psf->sf.samplerate ;
207 	rsrc.sample_size = psf->bytewidth ;
208 	rsrc.channels = psf->sf.channels ;
209 
210 	rsrc.rsrc_data = psf->header.ptr ;
211 	rsrc.rsrc_len = psf->header.len ;
212 	memset (rsrc.rsrc_data, 0xea, rsrc.rsrc_len) ;
213 
214 	snprintf (str_rsrc [0].value, sizeof (str_rsrc [0].value), "_%d", rsrc.sample_size) ;
215 	snprintf (str_rsrc [1].value, sizeof (str_rsrc [1].value), "_%d.000000", rsrc.sample_rate) ;
216 	snprintf (str_rsrc [2].value, sizeof (str_rsrc [2].value), "_%d", rsrc.channels) ;
217 
218 	for (k = 0 ; k < ARRAY_LEN (str_rsrc) ; k++)
219 	{	if (str_rsrc [k].value_len == 0)
220 		{	str_rsrc [k].value_len = strlen (str_rsrc [k].value) ;
221 			str_rsrc [k].value [0] = str_rsrc [k].value_len - 1 ;
222 			} ;
223 
224 		/* Turn name string into a pascal string. */
225 		str_rsrc [k].name [0] = strlen (str_rsrc [k].name) - 1 ;
226 		} ;
227 
228 	rsrc.data_offset = 0x100 ;
229 
230 	/*
231 	** Calculate data length :
232 	**		length of strings, plus the length of the sdML chunk.
233 	*/
234 	rsrc.data_length = 0 ;
235 	for (k = 0 ; k < ARRAY_LEN (str_rsrc) ; k++)
236 		rsrc.data_length += str_rsrc [k].value_len + 4 ;
237 
238 	rsrc.map_offset = rsrc.data_offset + rsrc.data_length ;
239 
240 	/* Very start of resource fork. */
241 	psf_binheader_writef (psf, "E444", BHW4 (rsrc.data_offset), BHW4 (rsrc.map_offset), BHW4 (rsrc.data_length)) ;
242 
243 	psf_binheader_writef (psf, "Eop", BHWo (0x30), BHWp (psf->file.name.c)) ;
244 	psf_binheader_writef (psf, "Eo2mm", BHWo (0x50), BHW2 (0), BHWm (Sd2f_MARKER), BHWm (lsf1_MARKER)) ;
245 
246 	/* Very start of resource map. */
247 	psf_binheader_writef (psf, "E4444", BHW4 (rsrc.map_offset), BHW4 (rsrc.data_offset), BHW4 (rsrc.map_offset), BHW4 (rsrc.data_length)) ;
248 
249 	/* These I don't currently understand. */
250 	if (1)
251 	{	psf_binheader_writef (psf, "Eo1422", BHWo (rsrc.map_offset + 16), BHW1 (1), BHW4 (0x12345678), BHW2 (0xabcd), BHW2 (0)) ;
252 		} ;
253 
254 	/* Resource type offset. */
255 	rsrc.type_offset = rsrc.map_offset + 30 ;
256 	psf_binheader_writef (psf, "Eo2", BHWo (rsrc.map_offset + 24), BHW2 (rsrc.type_offset - rsrc.map_offset - 2)) ;
257 
258 	/* Type index max. */
259 	rsrc.type_count = 2 ;
260 	psf_binheader_writef (psf, "Eo2", BHWo (rsrc.map_offset + 28), BHW2 (rsrc.type_count - 1)) ;
261 
262 	rsrc.item_offset = rsrc.type_offset + rsrc.type_count * 8 ;
263 
264 	rsrc.str_count = ARRAY_LEN (str_rsrc) ;
265 	rsrc.string_offset = rsrc.item_offset + (rsrc.str_count + 1) * 12 - rsrc.map_offset ;
266 	psf_binheader_writef (psf, "Eo2", BHWo (rsrc.map_offset + 26), BHW2 (rsrc.string_offset)) ;
267 
268 	/* Write 'STR ' resource type. */
269 	rsrc.str_count = 3 ;
270 	psf_binheader_writef (psf, "Eom22", BHWo (rsrc.type_offset), BHWm (STR_MARKER), BHW2 (rsrc.str_count - 1), BHW2 (0x12)) ;
271 
272 	/* Write 'sdML' resource type. */
273 	psf_binheader_writef (psf, "Em22", BHWm (sdML_MARKER), BHW2 (0), BHW2 (0x36)) ;
274 
275 	str_offset = rsrc.map_offset + rsrc.string_offset ;
276 	next_str = 0 ;
277 	data_offset = rsrc.data_offset ;
278 	for (k = 0 ; k < ARRAY_LEN (str_rsrc) ; k++)
279 	{	psf_binheader_writef (psf, "Eop", BHWo (str_offset), BHWp (str_rsrc [k].name)) ;
280 		psf_binheader_writef (psf, "Eo22", BHWo (rsrc.item_offset + k * 12), BHW2 (str_rsrc [k].id), BHW2 (next_str)) ;
281 
282 		str_offset += strlen (str_rsrc [k].name) ;
283 		next_str += strlen (str_rsrc [k].name) ;
284 
285 		psf_binheader_writef (psf, "Eo4", BHWo (rsrc.item_offset + k * 12 + 4), BHW4 (data_offset - rsrc.data_offset)) ;
286 		psf_binheader_writef (psf, "Eo4", BHWo (data_offset), BHW4 (str_rsrc [k].value_len)) ;
287 
288 		psf_binheader_writef (psf, "Eob", BHWo (data_offset + 4), BHWv (str_rsrc [k].value), BHWz (str_rsrc [k].value_len)) ;
289 		data_offset += 4 + str_rsrc [k].value_len ;
290 		} ;
291 
292 	/* Finally, calculate and set map length. */
293 	rsrc.map_length = str_offset - rsrc.map_offset ;
294 	psf_binheader_writef (psf, "Eo4o4", BHWo (12), BHW4 (rsrc.map_length),
295 							BHWo (rsrc.map_offset + 12), BHW4 (rsrc.map_length)) ;
296 
297 	psf->header.indx = rsrc.map_offset + rsrc.map_length ;
298 
299 	psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ;
300 
301 	psf_use_rsrc (psf, SF_FALSE) ;
302 
303 	if (psf->error)
304 		return psf->error ;
305 
306 	return 0 ;
307 } /* sd2_write_rsrc_fork */
308 
309 /*------------------------------------------------------------------------------
310 */
311 
312 static inline int
read_rsrc_char(const SD2_RSRC * prsrc,int offset)313 read_rsrc_char (const SD2_RSRC *prsrc, int offset)
314 {	const unsigned char * data = prsrc->rsrc_data ;
315 	if (offset < 0 || offset >= prsrc->rsrc_len)
316 		return 0 ;
317 	return data [offset] ;
318 } /* read_rsrc_char */
319 
320 static inline int
read_rsrc_short(const SD2_RSRC * prsrc,int offset)321 read_rsrc_short (const SD2_RSRC *prsrc, int offset)
322 {	const unsigned char * data = prsrc->rsrc_data ;
323 	if (offset < 0 || offset + 1 >= prsrc->rsrc_len)
324 		return 0 ;
325 	return (data [offset] << 8) + data [offset + 1] ;
326 } /* read_rsrc_short */
327 
328 static inline int
read_rsrc_int(const SD2_RSRC * prsrc,int offset)329 read_rsrc_int (const SD2_RSRC *prsrc, int offset)
330 {	const unsigned char * data = prsrc->rsrc_data ;
331 	if (offset < 0 || offset + 3 >= prsrc->rsrc_len)
332 		return 0 ;
333 	return (((uint32_t) data [offset]) << 24) + (data [offset + 1] << 16) + (data [offset + 2] << 8) + data [offset + 3] ;
334 } /* read_rsrc_int */
335 
336 static inline int
read_rsrc_marker(const SD2_RSRC * prsrc,int offset)337 read_rsrc_marker (const SD2_RSRC *prsrc, int offset)
338 {	const unsigned char * data = prsrc->rsrc_data ;
339 
340 	if (offset < 0 || offset + 3 >= prsrc->rsrc_len)
341 		return 0 ;
342 
343 	if (CPU_IS_BIG_ENDIAN)
344 		return (((uint32_t) data [offset]) << 24) + (data [offset + 1] << 16) + (data [offset + 2] << 8) + data [offset + 3] ;
345 	if (CPU_IS_LITTLE_ENDIAN)
346 		return data [offset] + (data [offset + 1] << 8) + (data [offset + 2] << 16) + (((uint32_t) data [offset + 3]) << 24) ;
347 
348 	return 0 ;
349 } /* read_rsrc_marker */
350 
351 static void
read_rsrc_str(const SD2_RSRC * prsrc,int offset,char * buffer,int buffer_len)352 read_rsrc_str (const SD2_RSRC *prsrc, int offset, char * buffer, int buffer_len)
353 {	const unsigned char * data = prsrc->rsrc_data ;
354 	int k ;
355 
356 	memset (buffer, 0, buffer_len) ;
357 
358 	if (offset < 0 || offset + buffer_len >= prsrc->rsrc_len)
359 		return ;
360 
361 	for (k = 0 ; k < buffer_len - 1 ; k++)
362 	{	if (psf_isprint (data [offset + k]) == 0)
363 			return ;
364 		buffer [k] = data [offset + k] ;
365 		} ;
366 	return ;
367 } /* read_rsrc_str */
368 
369 static int
sd2_parse_rsrc_fork(SF_PRIVATE * psf)370 sd2_parse_rsrc_fork (SF_PRIVATE *psf)
371 {	SD2_RSRC rsrc ;
372 	int k, marker, error = 0 ;
373 
374 	psf_use_rsrc (psf, SF_TRUE) ;
375 
376 	memset (&rsrc, 0, sizeof (rsrc)) ;
377 
378 	rsrc.rsrc_len = psf_get_filelen (psf) ;
379 	psf_log_printf (psf, "Resource length : %d (0x%04X)\n", rsrc.rsrc_len, rsrc.rsrc_len) ;
380 
381 	if (rsrc.rsrc_len > psf->header.len)
382 	{	rsrc.rsrc_data = calloc (1, rsrc.rsrc_len) ;
383 		rsrc.need_to_free_rsrc_data = SF_TRUE ;
384 		}
385 	else
386 	{
387 		rsrc.rsrc_data = psf->header.ptr ;
388 		// rsrc.rsrc_len > psf->header.len ;
389 		rsrc.need_to_free_rsrc_data = SF_FALSE ;
390 		} ;
391 
392 	/* Read in the whole lot. */
393 	psf_fread (rsrc.rsrc_data, rsrc.rsrc_len, 1, psf) ;
394 
395 	/* Reset the header storage because we have changed to the rsrcdes. */
396 	psf->header.indx = psf->header.end = rsrc.rsrc_len ;
397 
398 	rsrc.data_offset = read_rsrc_int (&rsrc, 0) ;
399 	rsrc.map_offset = read_rsrc_int (&rsrc, 4) ;
400 	rsrc.data_length = read_rsrc_int (&rsrc, 8) ;
401 	rsrc.map_length = read_rsrc_int (&rsrc, 12) ;
402 
403 	if (rsrc.data_offset == 0x51607 && rsrc.map_offset == 0x20000)
404 	{	psf_log_printf (psf, "Trying offset of 0x52 bytes.\n") ;
405 		rsrc.data_offset = read_rsrc_int (&rsrc, 0x52 + 0) + 0x52 ;
406 		rsrc.map_offset = read_rsrc_int (&rsrc, 0x52 + 4) + 0x52 ;
407 		rsrc.data_length = read_rsrc_int (&rsrc, 0x52 + 8) ;
408 		rsrc.map_length = read_rsrc_int (&rsrc, 0x52 + 12) ;
409 		} ;
410 
411 	psf_log_printf (psf, "  data offset : 0x%04X\n  map  offset : 0x%04X\n"
412 				"  data length : 0x%04X\n  map  length : 0x%04X\n",
413 				rsrc.data_offset, rsrc.map_offset, rsrc.data_length, rsrc.map_length) ;
414 
415 	if (rsrc.data_offset > rsrc.rsrc_len)
416 	{	psf_log_printf (psf, "Error : rsrc.data_offset (%d, 0x%x) > len\n", rsrc.data_offset, rsrc.data_offset) ;
417 		error = SFE_SD2_BAD_DATA_OFFSET ;
418 		goto parse_rsrc_fork_cleanup ;
419 		} ;
420 
421 	if (rsrc.map_offset > rsrc.rsrc_len)
422 	{	psf_log_printf (psf, "Error : rsrc.map_offset > len\n") ;
423 		error = SFE_SD2_BAD_MAP_OFFSET ;
424 		goto parse_rsrc_fork_cleanup ;
425 		} ;
426 
427 	if (rsrc.data_length > rsrc.rsrc_len)
428 	{	psf_log_printf (psf, "Error : rsrc.data_length > len\n") ;
429 		error = SFE_SD2_BAD_DATA_LENGTH ;
430 		goto parse_rsrc_fork_cleanup ;
431 		} ;
432 
433 	if (rsrc.map_length > rsrc.rsrc_len)
434 	{	psf_log_printf (psf, "Error : rsrc.map_length > len\n") ;
435 		error = SFE_SD2_BAD_MAP_LENGTH ;
436 		goto parse_rsrc_fork_cleanup ;
437 		} ;
438 
439 	if (rsrc.data_offset + rsrc.data_length != rsrc.map_offset || rsrc.map_offset + rsrc.map_length != rsrc.rsrc_len)
440 	{	psf_log_printf (psf, "Error : This does not look like a MacOSX resource fork.\n") ;
441 		error = SFE_SD2_BAD_RSRC ;
442 		goto parse_rsrc_fork_cleanup ;
443 		} ;
444 
445 	if (rsrc.map_offset + 28 >= rsrc.rsrc_len)
446 	{	psf_log_printf (psf, "Bad map offset (%d + 28 > %d).\n", rsrc.map_offset, rsrc.rsrc_len) ;
447 		error = SFE_SD2_BAD_RSRC ;
448 		goto parse_rsrc_fork_cleanup ;
449 		} ;
450 
451 	rsrc.string_offset = rsrc.map_offset + read_rsrc_short (&rsrc, rsrc.map_offset + 26) ;
452 	if (rsrc.string_offset > rsrc.rsrc_len)
453 	{	psf_log_printf (psf, "Bad string offset (%d).\n", rsrc.string_offset) ;
454 		error = SFE_SD2_BAD_RSRC ;
455 		goto parse_rsrc_fork_cleanup ;
456 		} ;
457 
458 	rsrc.type_offset = rsrc.map_offset + 30 ;
459 
460 	if (rsrc.map_offset + 28 > rsrc.rsrc_len)
461 	{	psf_log_printf (psf, "Bad map offset.\n") ;
462 		goto parse_rsrc_fork_cleanup ;
463 		} ;
464 
465 	rsrc.type_count = read_rsrc_short (&rsrc, rsrc.map_offset + 28) + 1 ;
466 	if (rsrc.type_count < 1)
467 	{	psf_log_printf (psf, "Bad type count.\n") ;
468 		error = SFE_SD2_BAD_RSRC ;
469 		goto parse_rsrc_fork_cleanup ;
470 		} ;
471 
472 	rsrc.item_offset = rsrc.type_offset + rsrc.type_count * 8 ;
473 	if (rsrc.item_offset < 0 || rsrc.item_offset > rsrc.rsrc_len)
474 	{	psf_log_printf (psf, "Bad item offset (%d).\n", rsrc.item_offset) ;
475 		error = SFE_SD2_BAD_RSRC ;
476 		goto parse_rsrc_fork_cleanup ;
477 		} ;
478 
479 	rsrc.str_index = -1 ;
480 	for (k = 0 ; k < rsrc.type_count ; k ++)
481 	{	if (rsrc.type_offset + k * 8 > rsrc.rsrc_len)
482 		{	psf_log_printf (psf, "Bad rsrc marker.\n") ;
483 			goto parse_rsrc_fork_cleanup ;
484 			} ;
485 
486 		marker = read_rsrc_marker (&rsrc, rsrc.type_offset + k * 8) ;
487 
488 		if (marker == STR_MARKER)
489 		{	rsrc.str_index = k ;
490 			rsrc.str_count = read_rsrc_short (&rsrc, rsrc.type_offset + k * 8 + 4) + 1 ;
491 			error = parse_str_rsrc (psf, &rsrc) ;
492 			goto parse_rsrc_fork_cleanup ;
493 			} ;
494 		} ;
495 
496 	psf_log_printf (psf, "No 'STR ' resource.\n") ;
497 	error = SFE_SD2_BAD_RSRC ;
498 
499 parse_rsrc_fork_cleanup :
500 
501 	psf_use_rsrc (psf, SF_FALSE) ;
502 
503 	if (rsrc.need_to_free_rsrc_data)
504 		free (rsrc.rsrc_data) ;
505 
506 	return error ;
507 } /* sd2_parse_rsrc_fork */
508 
509 static int
parse_str_rsrc(SF_PRIVATE * psf,SD2_RSRC * rsrc)510 parse_str_rsrc (SF_PRIVATE *psf, SD2_RSRC * rsrc)
511 {	char name [32], value [32] ;
512 	int k, str_offset, rsrc_id, data_offset = 0, data_len = 0 ;
513 
514 	psf_log_printf (psf, "Finding parameters :\n") ;
515 
516 	str_offset = rsrc->string_offset ;
517 	psf_log_printf (psf, "  Offset    RsrcId    dlen    slen    Value\n") ;
518 
519 
520 	for (k = 0 ; data_offset + data_len < rsrc->rsrc_len ; k++)
521 	{	int slen ;
522 
523 		slen = read_rsrc_char (rsrc, str_offset) ;
524 		read_rsrc_str (rsrc, str_offset + 1, name, SF_MIN (SIGNED_SIZEOF (name), slen + 1)) ;
525 		str_offset += slen + 1 ;
526 
527 		// work-around for GitHub issue #340
528 		int id_offset = rsrc->item_offset + k * 12 ;
529 		if (id_offset < 0 || id_offset + 1 >= rsrc->rsrc_len)
530 		{	psf_log_printf (psf, "Exiting parser on id_offset of %d.\n", id_offset) ;
531 			break ;
532 			}
533 		rsrc_id = read_rsrc_short (rsrc, id_offset) ;
534 
535 		data_offset = rsrc->data_offset + read_rsrc_int (rsrc, rsrc->item_offset + k * 12 + 4) ;
536 		if (data_offset < 0 || data_offset > rsrc->rsrc_len)
537 		{	psf_log_printf (psf, "Exiting parser on data offset of %d.\n", data_offset) ;
538 			break ;
539 			} ;
540 
541 		data_len = read_rsrc_int (rsrc, data_offset) ;
542 		if (data_len < 0 || data_len > rsrc->rsrc_len)
543 		{	psf_log_printf (psf, "Exiting parser on data length of %d.\n", data_len) ;
544 			break ;
545 			} ;
546 
547 		slen = read_rsrc_char (rsrc, data_offset + 4) ;
548 		read_rsrc_str (rsrc, data_offset + 5, value, SF_MIN (SIGNED_SIZEOF (value), slen + 1)) ;
549 
550 		psf_log_printf (psf, "  0x%04x     %4d     %4d     %3d    '%s'\n", data_offset, rsrc_id, data_len, slen, value) ;
551 
552 		if (strstr (value, "Photoshop"))
553 		{	psf_log_printf (psf, "Exiting parser on Photoshop data.\n", data_offset) ;
554 			break ;
555 			} ;
556 
557 		if (rsrc_id == 1000 && rsrc->sample_size == 0)
558 			rsrc->sample_size = strtol (value, NULL, 10) ;
559 		else if (rsrc_id == 1001 && rsrc->sample_rate == 0)
560 			rsrc->sample_rate = strtol (value, NULL, 10) ;
561 		else if (rsrc_id == 1002 && rsrc->channels == 0)
562 			rsrc->channels = strtol (value, NULL, 10) ;
563 		} ;
564 
565 	psf_log_printf (psf, "Found Parameters :\n") ;
566 	psf_log_printf (psf, "  sample-size : %d\n", rsrc->sample_size) ;
567 	psf_log_printf (psf, "  sample-rate : %d\n", rsrc->sample_rate) ;
568 	psf_log_printf (psf, "  channels    : %d\n", rsrc->channels) ;
569 
570 	if (rsrc->sample_rate <= 4 && rsrc->sample_size > 4)
571 	{	int temp ;
572 
573 		psf_log_printf (psf, "Geez!! Looks like sample rate and sample size got switched.\nCorrecting this screw up.\n") ;
574 		temp = rsrc->sample_rate ;
575 		rsrc->sample_rate = rsrc->sample_size ;
576 		rsrc->sample_size = temp ;
577 		} ;
578 
579 	if (rsrc->sample_rate < 0)
580 	{	psf_log_printf (psf, "Bad sample rate (%d)\n", rsrc->sample_rate) ;
581 		return SFE_SD2_BAD_RSRC ;
582 		} ;
583 
584 	if (rsrc->channels < 0)
585 	{	psf_log_printf (psf, "Bad channel count (%d)\n", rsrc->channels) ;
586 		return SFE_SD2_BAD_RSRC ;
587 		} ;
588 
589 	psf->sf.samplerate = rsrc->sample_rate ;
590 	psf->sf.channels = rsrc->channels ;
591 	psf->bytewidth = rsrc->sample_size ;
592 
593 	switch (rsrc->sample_size)
594 	{	case 1 :
595 			psf->sf.format = SF_FORMAT_SD2 | SF_FORMAT_PCM_S8 ;
596 			break ;
597 
598 		case 2 :
599 			psf->sf.format = SF_FORMAT_SD2 | SF_FORMAT_PCM_16 ;
600 			break ;
601 
602 		case 3 :
603 			psf->sf.format = SF_FORMAT_SD2 | SF_FORMAT_PCM_24 ;
604 			break ;
605 
606 		case 4 :
607 			psf->sf.format = SF_FORMAT_SD2 | SF_FORMAT_PCM_32 ;
608 			break ;
609 
610 		default :
611 			psf_log_printf (psf, "Bad sample size (%d)\n", rsrc->sample_size) ;
612 			return SFE_SD2_BAD_SAMPLE_SIZE ;
613 		} ;
614 
615 	psf_log_printf (psf, "ok\n") ;
616 
617 	return 0 ;
618 } /* parse_str_rsrc */
619 
620