xref: /third_party/libsnd/src/sd2.c (revision b815c7f3)
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
53enum
54{	RSRC_STR = 111,
55	RSRC_BIN
56} ;
57
58typedef 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
77typedef 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
89static int sd2_close	(SF_PRIVATE *psf) ;
90
91static int sd2_parse_rsrc_fork (SF_PRIVATE *psf) ;
92static int parse_str_rsrc (SF_PRIVATE *psf, SD2_RSRC * rsrc) ;
93
94static int sd2_write_rsrc_fork (SF_PRIVATE *psf, int calc_length) ;
95
96/*------------------------------------------------------------------------------
97** Public functions.
98*/
99
100int
101sd2_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
163error_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
174static int
175sd2_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
190static int
191sd2_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)) ;
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
312static inline int
313read_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
320static inline int
321read_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
328static inline int
329read_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
336static inline int
337read_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
351static void
352read_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
369static int
370sd2_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
499parse_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
509static int
510parse_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