rollback to 3428, before the mysterious removal of libs/* at 3431/3432
[ardour.git] / libs / libsndfile / src / sd2.c
1 /*
2 ** Copyright (C) 2001-2006 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
62         int data_offset, data_length ;
63         int map_offset, map_length ;
64
65         int type_count, type_offset ;
66         int item_offset ;
67
68         int str_index, str_count ;
69
70         int string_offset ;
71
72         /* All the above just to get these three. */
73         int sample_size, sample_rate, channels ;
74 } SD2_RSRC ;
75
76 typedef struct
77 {       int type ;
78         int id ;
79         char name [32] ;
80         char value [32] ;
81         int value_len ;
82 } STR_RSRC ;
83
84 /*------------------------------------------------------------------------------
85  * Private static functions.
86 */
87
88 static int sd2_close    (SF_PRIVATE *psf) ;
89
90 static int sd2_parse_rsrc_fork (SF_PRIVATE *psf) ;
91 static int parse_str_rsrc (SF_PRIVATE *psf, SD2_RSRC * rsrc) ;
92
93 static int sd2_write_rsrc_fork (SF_PRIVATE *psf, int calc_length) ;
94
95 /*------------------------------------------------------------------------------
96 ** Public functions.
97 */
98
99 int
100 sd2_open (SF_PRIVATE *psf)
101 {       int subformat, error = 0, valid ;
102
103         /* SD2 is always big endian. */
104         psf->endian = SF_ENDIAN_BIG ;
105
106         if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->rsrclength > 0))
107         {       psf_use_rsrc (psf, SF_TRUE) ;
108                 valid = psf_file_valid (psf) ;
109                 psf_use_rsrc (psf, SF_FALSE) ;
110                 if (! valid)
111                 {       psf_log_printf (psf, "sd2_open : psf->rsrcdes < 0\n") ;
112                         return SFE_SD2_BAD_RSRC ;
113                         } ;
114
115                 error = sd2_parse_rsrc_fork (psf) ;
116
117                 if (error)
118                         goto error_cleanup ;
119                 } ;
120
121         if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_SD2)
122         {       error = SFE_BAD_OPEN_FORMAT ;
123                 goto error_cleanup ;
124                 } ;
125
126         subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
127         psf->dataoffset = 0 ;
128
129         /* Only open and write the resource in RDWR mode is its current length is zero. */
130         if (psf->mode == SFM_WRITE || (psf->mode == SFM_RDWR && psf->rsrclength == 0))
131         {       psf_open_rsrc (psf, psf->mode) ;
132
133                 error = sd2_write_rsrc_fork (psf, SF_FALSE) ;
134
135                 if (error)
136                         goto error_cleanup ;
137
138                 /* Not needed. */
139                 psf->write_header = NULL ;
140                 } ;
141
142         psf->container_close = sd2_close ;
143
144         psf->blockwidth = psf->bytewidth * psf->sf.channels ;
145
146         switch (subformat)
147         {       case SF_FORMAT_PCM_S8 : /* 8-bit linear PCM. */
148                 case SF_FORMAT_PCM_16 : /* 16-bit linear PCM. */
149                 case SF_FORMAT_PCM_24 : /* 24-bit linear PCM */
150                                 error = pcm_init (psf) ;
151                                 break ;
152
153                 default :
154                                 error = SFE_UNIMPLEMENTED ;
155                                 break ;
156                 } ;
157
158         psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
159
160 error_cleanup:
161
162         /* Close the resource fork regardless. We won't need it again. */
163         psf_close_rsrc (psf) ;
164
165         return error ;
166 } /* sd2_open */
167
168 /*------------------------------------------------------------------------------
169 */
170
171 static int
172 sd2_close       (SF_PRIVATE *psf)
173 {
174         if (psf->mode == SFM_WRITE)
175         {       /*  Now we know for certain the audio_length of the file we can re-write
176                 **      correct values for the FORM, 8SVX and BODY chunks.
177                 */
178
179                 } ;
180
181         return 0 ;
182 } /* sd2_close */
183
184 /*------------------------------------------------------------------------------
185 */
186
187 static inline void
188 write_char (unsigned char * data, int offset, char value)
189 {       data [offset] = value ;
190 } /* write_char */
191
192 static inline void
193 write_short (unsigned char * data, int offset, short value)
194 {       data [offset] = value >> 8 ;
195         data [offset + 1] = value ;
196 } /* write_char */
197
198 static inline void
199 write_int (unsigned char * data, int offset, int value)
200 {       data [offset] = value >> 24 ;
201         data [offset + 1] = value >> 16 ;
202         data [offset + 2] = value >> 8 ;
203         data [offset + 3] = value ;
204 } /* write_int */
205
206 static inline void
207 write_marker (unsigned char * data, int offset, int value)
208 {
209         if (CPU_IS_BIG_ENDIAN)
210         {       data [offset] = value >> 24 ;
211                 data [offset + 1] = value >> 16 ;
212                 data [offset + 2] = value >> 8 ;
213                 data [offset + 3] = value ;
214                 }
215         else
216         {       data [offset] = value ;
217                 data [offset + 1] = value >> 8 ;
218                 data [offset + 2] = value >> 16 ;
219                 data [offset + 3] = value >> 24 ;
220                 } ;
221 } /* write_marker */
222
223 static void
224 write_str (unsigned char * data, int offset, char * buffer, int buffer_len)
225 {       memcpy (data + offset, buffer, buffer_len) ;
226 } /* write_str */
227
228 static int
229 sd2_write_rsrc_fork (SF_PRIVATE *psf, int UNUSED (calc_length))
230 {       SD2_RSRC rsrc ;
231         STR_RSRC str_rsrc [] =
232         {       { RSRC_STR, 1000, "_sample-size", "", 0 },
233                 { RSRC_STR, 1001, "_sample-rate", "", 0 },
234                 { RSRC_STR, 1002, "_channels", "", 0 },
235                 { RSRC_BIN, 1000, "_Markers", "", 8 }
236                 } ;
237
238         int k, str_offset, data_offset, next_str ;
239
240         psf_use_rsrc (psf, SF_TRUE) ;
241
242         memset (&rsrc, 0, sizeof (rsrc)) ;
243
244         rsrc.sample_rate = psf->sf.samplerate ;
245         rsrc.sample_size = psf->bytewidth ;
246         rsrc.channels = psf->sf.channels ;
247
248         rsrc.rsrc_data = psf->header ;
249         rsrc.rsrc_len = sizeof (psf->header) ;
250         memset (rsrc.rsrc_data, 0xea, rsrc.rsrc_len) ;
251
252         LSF_SNPRINTF (str_rsrc [0].value, sizeof (str_rsrc [0].value), "_%d", rsrc.sample_size) ;
253         LSF_SNPRINTF (str_rsrc [1].value, sizeof (str_rsrc [1].value), "_%d.000000", rsrc.sample_rate) ;
254         LSF_SNPRINTF (str_rsrc [2].value, sizeof (str_rsrc [2].value), "_%d", rsrc.channels) ;
255
256         for (k = 0 ; k < ARRAY_LEN (str_rsrc) ; k++)
257         {       if (str_rsrc [k].value_len == 0)
258                 {       str_rsrc [k].value_len = strlen (str_rsrc [k].value) ;
259                         str_rsrc [k].value [0] = str_rsrc [k].value_len - 1 ;
260                         } ;
261
262                 /* Turn name string into a pascal string. */
263                 str_rsrc [k].name [0] = strlen (str_rsrc [k].name) - 1 ;
264                 } ;
265
266         rsrc.data_offset = 0x100 ;
267
268         /*
269         ** Calculate data length :
270         **              length of strings, plus the length of the sdML chunk.
271         */
272         rsrc.data_length = 0 ;
273         for (k = 0 ; k < ARRAY_LEN (str_rsrc) ; k++)
274                 rsrc.data_length += str_rsrc [k].value_len + 4 ;
275
276         rsrc.map_offset = rsrc.data_offset + rsrc.data_length ;
277
278         /* Very start of resource fork. */
279         write_int (rsrc.rsrc_data, 0, rsrc.data_offset) ;
280         write_int (rsrc.rsrc_data, 4, rsrc.map_offset) ;
281         write_int (rsrc.rsrc_data, 8, rsrc.data_length) ;
282
283         write_char (rsrc.rsrc_data, 0x30, strlen (psf->filename)) ;
284         write_str (rsrc.rsrc_data, 0x31, psf->filename, strlen (psf->filename)) ;
285
286         write_short (rsrc.rsrc_data, 0x50, 0) ;
287         write_marker (rsrc.rsrc_data, 0x52, Sd2f_MARKER) ;
288         write_marker (rsrc.rsrc_data, 0x56, lsf1_MARKER) ;
289
290         /* Very start of resource map. */
291         write_int (rsrc.rsrc_data, rsrc.map_offset + 0, rsrc.data_offset) ;
292         write_int (rsrc.rsrc_data, rsrc.map_offset + 4, rsrc.map_offset) ;
293         write_int (rsrc.rsrc_data, rsrc.map_offset + 8, rsrc.data_length) ;
294
295         /* These I don't currently understand. */
296         if (1)
297         {       write_char (rsrc.rsrc_data, rsrc.map_offset+ 16, 1) ;
298                 /* Next resource map. */
299                 write_int (rsrc.rsrc_data, rsrc.map_offset + 17, 0x12345678) ;
300                 /* File ref number. */
301                 write_short (rsrc.rsrc_data, rsrc.map_offset + 21, 0xabcd) ;
302                 /* Fork attributes. */
303                 write_short (rsrc.rsrc_data, rsrc.map_offset + 23, 0) ;
304                 } ;
305
306         /* Resource type offset. */
307         rsrc.type_offset = rsrc.map_offset + 30 ;
308         write_short (rsrc.rsrc_data, rsrc.map_offset + 24, rsrc.type_offset - rsrc.map_offset - 2) ;
309
310         /* Type index max. */
311         rsrc.type_count = 2 ;
312         write_short (rsrc.rsrc_data, rsrc.map_offset + 28, rsrc.type_count - 1) ;
313
314         rsrc.item_offset = rsrc.type_offset + rsrc.type_count * 8 ;
315
316         rsrc.str_count = ARRAY_LEN (str_rsrc) ;
317         rsrc.string_offset = rsrc.item_offset + (rsrc.str_count + 1) * 12 - rsrc.map_offset ;
318         write_short (rsrc.rsrc_data, rsrc.map_offset + 26, rsrc.string_offset) ;
319
320         /* Write 'STR ' resource type. */
321         rsrc.str_count = 3 ;
322         write_marker (rsrc.rsrc_data, rsrc.type_offset, STR_MARKER) ;
323         write_short (rsrc.rsrc_data, rsrc.type_offset + 4, rsrc.str_count - 1) ;
324         write_short (rsrc.rsrc_data, rsrc.type_offset + 6, 0x12) ;
325
326         /* Write 'sdML' resource type. */
327         write_marker (rsrc.rsrc_data, rsrc.type_offset + 8, sdML_MARKER) ;
328         write_short (rsrc.rsrc_data, rsrc.type_offset + 12, 0) ;
329         write_short (rsrc.rsrc_data, rsrc.type_offset + 14, 0x36) ;
330
331         str_offset = rsrc.map_offset + rsrc.string_offset ;
332         next_str = 0 ;
333         data_offset = rsrc.data_offset ;
334         for (k = 0 ; k < ARRAY_LEN (str_rsrc) ; k++)
335         {       write_str (rsrc.rsrc_data, str_offset, str_rsrc [k].name, strlen (str_rsrc [k].name)) ;
336
337                 write_short (rsrc.rsrc_data, rsrc.item_offset + k * 12, str_rsrc [k].id) ;
338                 write_short (rsrc.rsrc_data, rsrc.item_offset + k * 12 + 2, next_str) ;
339
340                 str_offset += strlen (str_rsrc [k].name) ;
341                 next_str += strlen (str_rsrc [k].name) ;
342
343                 write_int (rsrc.rsrc_data, rsrc.item_offset + k * 12 + 4, data_offset - rsrc.data_offset) ;
344
345                 write_int (rsrc.rsrc_data, data_offset, str_rsrc [k].value_len) ;
346                 write_str (rsrc.rsrc_data, data_offset + 4, str_rsrc [k].value, str_rsrc [k].value_len) ;
347                 data_offset += 4 + str_rsrc [k].value_len ;
348                 } ;
349
350         /* Finally, calculate and set map length. */
351         rsrc.map_length = str_offset - rsrc.map_offset ;
352         write_int (rsrc.rsrc_data, 12, rsrc.map_length) ;
353         write_int (rsrc.rsrc_data, rsrc.map_offset + 12, rsrc.map_length) ;
354
355         rsrc.rsrc_len = rsrc.map_offset + rsrc.map_length ;
356
357         psf_fwrite (rsrc.rsrc_data, rsrc.rsrc_len, 1, psf) ;
358
359         psf_use_rsrc (psf, SF_FALSE) ;
360
361         if (psf->error)
362                 return psf->error ;
363
364         return 0 ;
365 } /* sd2_write_rsrc_fork */
366
367 /*------------------------------------------------------------------------------
368 */
369
370 static inline int
371 read_char (const unsigned char * data, int offset)
372 {       return data [offset] ;
373 } /* read_char */
374
375 static inline int
376 read_short (const unsigned char * data, int offset)
377 {       return (data [offset] << 8) + data [offset + 1] ;
378 } /* read_short */
379
380 static inline int
381 read_int (const unsigned char * data, int offset)
382 {       return (data [offset] << 24) + (data [offset + 1] << 16) + (data [offset + 2] << 8) + data [offset + 3] ;
383 } /* read_int */
384
385 static inline int
386 read_marker (const unsigned char * data, int offset)
387 {
388         if (CPU_IS_BIG_ENDIAN)
389                 return (data [offset] << 24) + (data [offset + 1] << 16) + (data [offset + 2] << 8) + data [offset + 3] ;
390         else if (CPU_IS_LITTLE_ENDIAN)
391                 return data [offset] + (data [offset + 1] << 8) + (data [offset + 2] << 16) + (data [offset + 3] << 24) ;
392         else
393                 return 0x666 ;
394 } /* read_marker */
395
396 static void
397 read_str (const unsigned char * data, int offset, char * buffer, int buffer_len)
398 {       int k ;
399
400         memset (buffer, 0, buffer_len) ;
401
402         for (k = 0 ; k < buffer_len - 1 ; k++)
403         {       if (isprint (data [offset + k]) == 0)
404                         return ;
405                 buffer [k] = data [offset + k] ;
406                 } ;
407         return ;
408 } /* read_str */
409
410 static int
411 sd2_parse_rsrc_fork (SF_PRIVATE *psf)
412 {       SD2_RSRC rsrc ;
413         int k, marker, error = 0 ;
414
415         psf_use_rsrc (psf, SF_TRUE) ;
416
417         memset (&rsrc, 0, sizeof (rsrc)) ;
418
419         rsrc.rsrc_len = psf_get_filelen (psf) ;
420         psf_log_printf (psf, "Resource length : %d (0x%04X)\n", rsrc.rsrc_len, rsrc.rsrc_len) ;
421
422         if (rsrc.rsrc_len > SIGNED_SIZEOF (psf->header))
423                 rsrc.rsrc_data = calloc (1, rsrc.rsrc_len) ;
424         else
425                 rsrc.rsrc_data = psf->header ;
426
427         /* Read in the whole lot. */
428         psf_fread (rsrc.rsrc_data, rsrc.rsrc_len, 1, psf) ;
429
430         /* Reset the header storage because we have changed to the rsrcdes. */
431         psf->headindex = psf->headend = rsrc.rsrc_len ;
432
433         rsrc.data_offset = read_int (rsrc.rsrc_data, 0) ;
434         rsrc.map_offset = read_int (rsrc.rsrc_data, 4) ;
435         rsrc.data_length = read_int (rsrc.rsrc_data, 8) ;
436         rsrc.map_length = read_int (rsrc.rsrc_data, 12) ;
437
438         if (rsrc.data_offset == 0x51607 && rsrc.map_offset == 0x20000)
439         {       psf_log_printf (psf, "Trying offset of 0x52 bytes.\n") ;
440                 rsrc.data_offset = read_int (rsrc.rsrc_data, 0x52 + 0) + 0x52 ;
441                 rsrc.map_offset = read_int (rsrc.rsrc_data, 0x52 + 4) + 0x52 ;
442                 rsrc.data_length = read_int (rsrc.rsrc_data, 0x52 + 8) ;
443                 rsrc.map_length = read_int (rsrc.rsrc_data, 0x52 + 12) ;
444                 } ;
445
446         psf_log_printf (psf, "  data offset : 0x%04X\n  map  offset : 0x%04X\n"
447                                 "  data length : 0x%04X\n  map  length : 0x%04X\n",
448                                 rsrc.data_offset, rsrc.map_offset, rsrc.data_length, rsrc.map_length) ;
449
450         if (rsrc.data_offset > rsrc.rsrc_len)
451         {       psf_log_printf (psf, "Error : rsrc.data_offset (%d, 0x%x) > len\n", rsrc.data_offset, rsrc.data_offset) ;
452                 error = SFE_SD2_BAD_DATA_OFFSET ;
453                 goto parse_rsrc_fork_cleanup ;
454                 } ;
455
456         if (rsrc.map_offset > rsrc.rsrc_len)
457         {       psf_log_printf (psf, "Error : rsrc.map_offset > len\n") ;
458                 error = SFE_SD2_BAD_MAP_OFFSET ;
459                 goto parse_rsrc_fork_cleanup ;
460                 } ;
461
462         if (rsrc.data_length > rsrc.rsrc_len)
463         {       psf_log_printf (psf, "Error : rsrc.data_length > len\n") ;
464                 error = SFE_SD2_BAD_DATA_LENGTH ;
465                 goto parse_rsrc_fork_cleanup ;
466                 } ;
467
468         if (rsrc.map_length > rsrc.rsrc_len)
469         {       psf_log_printf (psf, "Error : rsrc.map_length > len\n") ;
470                 error = SFE_SD2_BAD_MAP_LENGTH ;
471                 goto parse_rsrc_fork_cleanup ;
472                 } ;
473
474         if (rsrc.data_offset + rsrc.data_length != rsrc.map_offset || rsrc.map_offset + rsrc.map_length != rsrc.rsrc_len)
475         {       psf_log_printf (psf, "Error : This does not look like a MacOSX resource fork.\n") ;
476                 error = SFE_SD2_BAD_RSRC ;
477                 goto parse_rsrc_fork_cleanup ;
478                 } ;
479
480         rsrc.string_offset = rsrc.map_offset + read_short (rsrc.rsrc_data, rsrc.map_offset + 26) ;
481         if (rsrc.string_offset > rsrc.rsrc_len)
482         {       psf_log_printf (psf, "Bad string offset (%d).\n", rsrc.string_offset) ;
483                 error = SFE_SD2_BAD_RSRC ;
484                 goto parse_rsrc_fork_cleanup ;
485                 } ;
486
487         rsrc.type_offset = rsrc.map_offset + 30 ;
488
489         rsrc.type_count = read_short (rsrc.rsrc_data, rsrc.map_offset + 28) + 1 ;
490         if (rsrc.type_count < 1)
491         {       psf_log_printf (psf, "Bad type count.\n") ;
492                 error = SFE_SD2_BAD_RSRC ;
493                 goto parse_rsrc_fork_cleanup ;
494                 } ;
495
496         rsrc.item_offset = rsrc.type_offset + rsrc.type_count * 8 ;
497         if (rsrc.item_offset < 0 || rsrc.item_offset > rsrc.rsrc_len)
498         {       psf_log_printf (psf, "Bad item offset (%d).\n", rsrc.item_offset) ;
499                 error = SFE_SD2_BAD_RSRC ;
500                 goto parse_rsrc_fork_cleanup ;
501                 } ;
502
503         rsrc.str_index = -1 ;
504         for (k = 0 ; k < rsrc.type_count ; k ++)
505         {       marker = read_marker (rsrc.rsrc_data, rsrc.type_offset + k * 8) ;
506
507                 if (marker == STR_MARKER)
508                 {       rsrc.str_index = k ;
509                         rsrc.str_count = read_short (rsrc.rsrc_data, rsrc.type_offset + k * 8 + 4) + 1 ;
510                         error = parse_str_rsrc (psf, &rsrc) ;
511                         goto parse_rsrc_fork_cleanup ;
512                         } ;
513                 } ;
514
515         psf_log_printf (psf, "No 'STR ' resource.\n") ;
516         error = SFE_SD2_BAD_RSRC ;
517
518 parse_rsrc_fork_cleanup :
519
520         psf_use_rsrc (psf, SF_FALSE) ;
521
522         if ((void *) rsrc.rsrc_data < (void *) psf || (void *) rsrc.rsrc_data > (void *) (psf + 1))
523                 free (rsrc.rsrc_data) ;
524
525         return error ;
526 } /* sd2_parse_rsrc_fork */
527
528 static int
529 parse_str_rsrc (SF_PRIVATE *psf, SD2_RSRC * rsrc)
530 {       char name [32], value [32] ;
531         int k, str_offset, data_offset, data_len, rsrc_id ;
532
533         psf_log_printf (psf, "Finding parameters :\n") ;
534
535         str_offset = rsrc->string_offset ;
536         for (k = 0 ; k < rsrc->str_count ; k++)
537         {       int slen ;
538
539                 slen = read_char (rsrc->rsrc_data, str_offset) ;
540                 read_str (rsrc->rsrc_data, str_offset + 1, name, SF_MIN (SIGNED_SIZEOF (name), slen + 1)) ;
541                 str_offset += slen + 1 ;
542
543                 rsrc_id = read_short (rsrc->rsrc_data, rsrc->item_offset + k * 12) ;
544
545                 data_offset = rsrc->data_offset + read_int (rsrc->rsrc_data, rsrc->item_offset + k * 12 + 4) ;
546                 if (data_offset < 0 || data_offset > rsrc->rsrc_len)
547                 {       psf_log_printf (psf, "Bad data offset (%d)\n", data_offset) ;
548                         return SFE_SD2_BAD_DATA_OFFSET ;
549                         } ;
550
551                 data_len = read_int (rsrc->rsrc_data, data_offset) ;
552                 if (data_len < 0 || data_len > rsrc->rsrc_len)
553                 {       psf_log_printf (psf, "Bad data length (%d).\n", data_len) ;
554                         return SFE_SD2_BAD_RSRC ;
555                         } ;
556
557                 slen = read_char (rsrc->rsrc_data, data_offset + 4) ;
558                 read_str (rsrc->rsrc_data, data_offset + 5, value, SF_MIN (SIGNED_SIZEOF (value), slen + 1)) ;
559
560                 psf_log_printf (psf, "  %-12s   0x%04x    %4d    %2d    %2d    '%s'\n", name, data_offset, rsrc_id, data_len, slen, value) ;
561
562                 if (strcmp (name, "sample-size") == 0 && rsrc->sample_size == 0)
563                         rsrc->sample_size = strtol (value, NULL, 10) ;
564                 else if (strcmp (name, "sample-rate") == 0 && rsrc->sample_rate == 0)
565                         rsrc->sample_rate = strtol (value, NULL, 10) ;
566                 else if (strcmp (name, "channels") == 0 && rsrc->channels == 0)
567                         rsrc->channels = strtol (value, NULL, 10) ;
568                 } ;
569
570         if (rsrc->sample_rate < 0)
571         {       psf_log_printf (psf, "Bad sample rate (%d)\n", rsrc->sample_rate) ;
572                 return SFE_SD2_BAD_RSRC ;
573                 } ;
574
575         if (rsrc->channels < 0)
576         {       psf_log_printf (psf, "Bad channel count (%d)\n", rsrc->channels) ;
577                 return SFE_SD2_BAD_RSRC ;
578                 } ;
579
580         psf->sf.samplerate = rsrc->sample_rate ;
581         psf->sf.channels = rsrc->channels ;
582         psf->bytewidth = rsrc->sample_size ;
583
584         switch (rsrc->sample_size)
585         {       case 1 :
586                         psf->sf.format = SF_FORMAT_SD2 | SF_FORMAT_PCM_S8 ;
587                         break ;
588
589                 case 2 :
590                         psf->sf.format = SF_FORMAT_SD2 | SF_FORMAT_PCM_16 ;
591                         break ;
592
593                 case 3 :
594                         psf->sf.format = SF_FORMAT_SD2 | SF_FORMAT_PCM_24 ;
595                         break ;
596
597                 default :
598                         psf_log_printf (psf, "Bad sample size (%d)\n", rsrc->sample_size) ;
599                         return SFE_SD2_BAD_SAMPLE_SIZE ;
600                 } ;
601
602         psf_log_printf (psf, "ok\n") ;
603
604         return 0 ;
605 } /* parse_str_rsrc */
606
607 /*
608 ** Do not edit or modify anything in this comment block.
609 ** The arch-tag line is a file identity tag for the GNU Arch
610 ** revision control system.
611 **
612 ** arch-tag: 1ee183e5-6b9f-4c2c-bd0a-24f35595cefc
613 */