Coverage Report

Created: 2025-07-12 06:10

/src/libsndfile/src/w64.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
** Copyright (C) 1999-2018 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  <ctype.h>
24
#include  <time.h>
25
26
#include  "sndfile.h"
27
#include  "sfendian.h"
28
#include  "common.h"
29
#include  "wavlike.h"
30
31
/*------------------------------------------------------------------------------
32
** W64 files use 16 byte markers as opposed to the four byte marker of
33
** WAV files.
34
** For comparison purposes, an integer is required, so make an integer
35
** hash for the 16 bytes using MAKE_HASH16 macro, but also create a 16
36
** byte array containing the complete 16 bytes required when writing the
37
** header.
38
*/
39
40
#define MAKE_HASH16(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf) \
41
51.7k
      ( (x0)      ^ ((x1) << 1) ^ ((x2) << 2) ^ ((x3) << 3) ^ \
42
51.7k
        ((x4) << 4)   ^ ((x5) << 5) ^ ((x6) << 6) ^ ((x7) << 7) ^ \
43
51.7k
        ((x8) << 8)   ^ ((x9) << 9) ^ ((xa) << 10)  ^ ((xb) << 11) ^ \
44
51.7k
        ((xc) << 12)  ^ ((xd) << 13)  ^ ((xe) << 14)  ^ ((xf) << 15)  )
45
46
#define MAKE_MARKER16(name, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf) \
47
      static unsigned char name [16] = { (x0), (x1), (x2), (x3), (x4), (x5), \
48
        (x6), (x7), (x8), (x9), (xa), (xb), (xc), (xd), (xe), (xf) }
49
50
354
#define riff_HASH16 MAKE_HASH16 ('r', 'i', 'f', 'f', 0x2E, 0x91, 0xCF, 0x11, \
51
354
                0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00)
52
53
341
#define wave_HASH16   MAKE_HASH16 ('w', 'a', 'v', 'e', 0xF3, 0xAC, 0xD3, 0x11, \
54
                0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A)
55
56
16.9k
#define fmt_HASH16    MAKE_HASH16 ('f', 'm', 't', ' ', 0xF3, 0xAC, 0xD3, 0x11, \
57
16.9k
                0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A)
58
59
1.57k
#define fact_HASH16   MAKE_HASH16 ('f', 'a', 'c', 't', 0xF3, 0xAC, 0xD3, 0x11, \
60
1.57k
                0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A)
61
62
28.0k
#define data_HASH16   MAKE_HASH16 ('d', 'a', 't', 'a', 0xF3, 0xAC, 0xD3, 0x11, \
63
28.0k
                0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A)
64
65
1
#define ACID_HASH16   MAKE_HASH16 (0x6D, 0x07, 0x1C, 0xEA, 0xA3, 0xEF, 0x78, 0x4C, \
66
1
                0x90, 0x57, 0x7F, 0x79, 0xEE, 0x25, 0x2A, 0xAE)
67
68
799
#define levl_HASH16   MAKE_HASH16 (0x6c, 0x65, 0x76, 0x6c, 0xf3, 0xac, 0xd3, 0x11, \
69
799
                0xd1, 0x8c, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A)
70
71
842
#define list_HASH16   MAKE_HASH16 (0x6C, 0x69, 0x73, 0x74, 0x2F, 0x91, 0xCF, 0x11, \
72
842
                0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00)
73
74
1.65k
#define junk_HASH16   MAKE_HASH16 (0x6A, 0x75, 0x6E, 0x6b, 0xF3, 0xAC, 0xD3, 0x11, \
75
1.65k
                0x8C, 0xD1, 0x00, 0xC0, 0x4f, 0x8E, 0xDB, 0x8A)
76
77
10
#define bext_HASH16   MAKE_HASH16 (0x62, 0x65, 0x78, 0x74, 0xf3, 0xac, 0xd3, 0xaa, \
78
10
                0xd1, 0x8c, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A)
79
80
66
#define MARKER_HASH16 MAKE_HASH16 (0x56, 0x62, 0xf7, 0xab, 0x2d, 0x39, 0xd2, 0x11, \
81
66
                0x86, 0xc7, 0x00, 0xc0, 0x4f, 0x8e, 0xdb, 0x8a)
82
83
1.06k
#define SUMLIST_HASH16  MAKE_HASH16 (0xBC, 0x94, 0x5F, 0x92, 0x5A, 0x52, 0xD2, 0x11, \
84
1.06k
                0x86, 0xDC, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A)
85
86
87
MAKE_MARKER16 (riff_MARKER16, 'r', 'i', 'f', 'f', 0x2E, 0x91, 0xCF, 0x11,
88
                0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00) ;
89
90
91
MAKE_MARKER16 (wave_MARKER16, 'w', 'a', 'v', 'e', 0xF3, 0xAC, 0xD3, 0x11,
92
                0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) ;
93
94
MAKE_MARKER16 (fmt_MARKER16, 'f', 'm', 't', ' ', 0xF3, 0xAC, 0xD3, 0x11,
95
                0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) ;
96
97
MAKE_MARKER16 (fact_MARKER16, 'f', 'a', 'c', 't', 0xF3, 0xAC, 0xD3, 0x11,
98
                0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) ;
99
100
MAKE_MARKER16 (data_MARKER16, 'd', 'a', 't', 'a', 0xF3, 0xAC, 0xD3, 0x11,
101
                0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) ;
102
103
enum
104
{ HAVE_riff = 0x01,
105
  HAVE_wave = 0x02,
106
  HAVE_fmt  = 0x04,
107
  HAVE_fact = 0x08,
108
  HAVE_data = 0x20
109
} ;
110
111
/*------------------------------------------------------------------------------
112
 * Private static functions.
113
 */
114
115
static int  w64_read_header (SF_PRIVATE *psf, int *blockalign, int *framesperblock) ;
116
static int  w64_write_header (SF_PRIVATE *psf, int calc_length) ;
117
static int  w64_close (SF_PRIVATE *psf) ;
118
119
/*------------------------------------------------------------------------------
120
** Public function.
121
*/
122
123
int
124
w64_open  (SF_PRIVATE *psf)
125
722
{ WAVLIKE_PRIVATE * wpriv ;
126
722
  int subformat, error, blockalign = 0, framesperblock = 0 ;
127
128
722
  if ((wpriv = calloc (1, sizeof (WAVLIKE_PRIVATE))) == NULL)
129
0
    return SFE_MALLOC_FAILED ;
130
722
  psf->container_data = wpriv ;
131
132
722
  if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR &&psf->filelength > 0))
133
722
  { if ((error = w64_read_header (psf, &blockalign, &framesperblock)))
134
543
      return error ;
135
722
    } ;
136
137
179
  if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_W64)
138
0
    return  SFE_BAD_OPEN_FORMAT ;
139
140
179
  subformat = SF_CODEC (psf->sf.format) ;
141
142
179
  if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
143
0
  { if (psf->is_pipe)
144
0
      return SFE_NO_PIPE_WRITE ;
145
146
0
    psf->endian = SF_ENDIAN_LITTLE ;    /* All W64 files are little endian. */
147
148
0
    psf->blockwidth = psf->bytewidth * psf->sf.channels ;
149
150
0
    if (subformat == SF_FORMAT_IMA_ADPCM || subformat == SF_FORMAT_MS_ADPCM)
151
0
    { blockalign = wavlike_srate2blocksize (psf->sf.samplerate * psf->sf.channels) ;
152
0
      framesperblock = -1 ;
153
154
      /*
155
      ** At this point we don't know the file length so set it stupidly high, but not
156
      ** so high that it triggers undefined behaviour when something is added to it.
157
      */
158
0
      psf->filelength = SF_COUNT_MAX - 10000 ;
159
0
      psf->datalength = psf->filelength ;
160
0
      if (psf->sf.frames <= 0)
161
0
        psf->sf.frames = (psf->blockwidth) ? psf->filelength / psf->blockwidth : psf->filelength ;
162
0
      } ;
163
164
0
    if ((error = w64_write_header (psf, SF_FALSE)))
165
0
      return error ;
166
167
0
    psf->write_header = w64_write_header ;
168
179
    } ;
169
170
179
  psf->container_close = w64_close ;
171
172
179
  switch (subformat)
173
179
  { case SF_FORMAT_PCM_U8 :
174
4
          error = pcm_init (psf) ;
175
4
          break ;
176
177
7
    case SF_FORMAT_PCM_16 :
178
13
    case SF_FORMAT_PCM_24 :
179
16
    case SF_FORMAT_PCM_32 :
180
16
          error = pcm_init (psf) ;
181
16
          break ;
182
183
9
    case SF_FORMAT_ULAW :
184
9
          error = ulaw_init (psf) ;
185
9
          break ;
186
187
5
    case SF_FORMAT_ALAW :
188
5
          error = alaw_init (psf) ;
189
5
          break ;
190
191
    /* Lite remove start */
192
41
    case SF_FORMAT_FLOAT :
193
41
          error = float32_init (psf) ;
194
41
          break ;
195
196
4
    case SF_FORMAT_DOUBLE :
197
4
          error = double64_init (psf) ;
198
4
          break ;
199
200
1
    case SF_FORMAT_IMA_ADPCM :
201
1
          error = wavlike_ima_init (psf, blockalign, framesperblock) ;
202
1
          break ;
203
204
16
    case SF_FORMAT_MS_ADPCM :
205
16
          error = wavlike_msadpcm_init (psf, blockalign, framesperblock) ;
206
16
          break ;
207
    /* Lite remove end */
208
209
50
    case SF_FORMAT_GSM610 :
210
50
          error = gsm610_init (psf) ;
211
50
          break ;
212
213
33
    default :   return SFE_UNIMPLEMENTED ;
214
179
    } ;
215
216
146
  return error ;
217
179
} /* w64_open */
218
219
/*=========================================================================
220
** Private functions.
221
*/
222
223
static int
224
w64_read_header (SF_PRIVATE *psf, int *blockalign, int *framesperblock)
225
722
{ WAVLIKE_PRIVATE *wpriv ;
226
722
  WAV_FMT   *wav_fmt ;
227
722
  int     dword = 0, marker, format = 0 ;
228
722
  sf_count_t  chunk_size, bytesread = 0 ;
229
722
  int     parsestage = 0, error, done = 0 ;
230
231
722
  if ((wpriv = psf->container_data) == NULL)
232
0
    return SFE_INTERNAL ;
233
722
  wav_fmt = &wpriv->wav_fmt ;
234
235
  /* Set position to start of file to begin reading header. */
236
722
  psf_binheader_readf (psf, "p", 0) ;
237
238
120k
  while (! done)
239
120k
  { /* Each new chunk must start on an 8 byte boundary, so jump if needed. */
240
120k
    if (psf->header.indx & 0x7)
241
4.74k
      psf_binheader_readf (psf, "j", 8 - (psf->header.indx & 0x7)) ;
242
243
    /* Generate hash of 16 byte marker. */
244
120k
    marker = 0 ;
245
120k
    chunk_size = 0 ;
246
247
120k
    bytesread = psf_binheader_readf (psf, "eh8", &marker, &chunk_size) ;
248
120k
    if (bytesread == 0)
249
38
      break ;
250
120k
    switch (marker)
251
120k
    { case riff_HASH16 :
252
354
          if (parsestage)
253
13
            return SFE_W64_NO_RIFF ;
254
255
341
          if (psf->filelength != chunk_size)
256
340
            psf_log_printf (psf, "riff : %D (should be %D)\n", chunk_size, psf->filelength) ;
257
1
          else
258
1
            psf_log_printf (psf, "riff : %D\n", chunk_size) ;
259
260
341
          parsestage |= HAVE_riff ;
261
262
341
          bytesread += psf_binheader_readf (psf, "h", &marker) ;
263
341
          if (marker == wave_HASH16)
264
251
          {   if ((parsestage & HAVE_riff) != HAVE_riff)
265
0
              return SFE_W64_NO_WAVE ;
266
251
            psf_log_printf (psf, "wave\n") ;
267
251
            parsestage |= HAVE_wave ;
268
341
          } ;
269
341
          chunk_size = 0 ;
270
341
          break ;
271
272
1
      case ACID_HASH16:
273
1
          psf_log_printf (psf, "Looks like an ACID file. Exiting.\n") ;
274
1
          return SFE_UNIMPLEMENTED ;
275
276
16.9k
      case fmt_HASH16 :
277
16.9k
          if ((parsestage & (HAVE_riff | HAVE_wave)) != (HAVE_riff | HAVE_wave))
278
2
            return SFE_WAV_NO_FMT ;
279
280
16.9k
          psf_log_printf (psf, " fmt : %D\n", chunk_size) ;
281
282
          /* size of 16 byte marker and 8 byte chunk_size value. */
283
16.9k
          chunk_size -= 24 ;
284
285
16.9k
          if ((error = wavlike_read_fmt_chunk (psf, (int) chunk_size)))
286
13
            return error ;
287
288
16.9k
          if (chunk_size % 8)
289
6.34k
            psf_binheader_readf (psf, "j", 8 - (chunk_size % 8)) ;
290
291
16.9k
          format    = wav_fmt->format ;
292
16.9k
          parsestage |= HAVE_fmt ;
293
16.9k
          chunk_size = 0 ;
294
16.9k
          break ;
295
296
1.57k
      case fact_HASH16:
297
1.57k
          { sf_count_t frames ;
298
299
1.57k
            psf_binheader_readf (psf, "e8", &frames) ;
300
1.57k
            psf_log_printf (psf, "fact : %D\n  frames : %D\n",
301
1.57k
                    chunk_size, frames) ;
302
1.57k
            } ;
303
1.57k
          chunk_size = 0 ;
304
1.57k
          break ;
305
306
307
28.0k
      case data_HASH16 :
308
28.0k
          if ((parsestage & (HAVE_riff | HAVE_wave | HAVE_fmt)) != (HAVE_riff | HAVE_wave | HAVE_fmt))
309
3
            return SFE_W64_NO_DATA ;
310
311
28.0k
          psf->dataoffset = psf_ftell (psf) ;
312
28.0k
          psf->datalength = SF_MIN (chunk_size - 24, psf->filelength - psf->dataoffset) ;
313
314
28.0k
          if (chunk_size % 8)
315
19.8k
            chunk_size += 8 - (chunk_size % 8) ;
316
317
28.0k
          psf_log_printf (psf, "data : %D\n", chunk_size) ;
318
319
28.0k
          parsestage |= HAVE_data ;
320
321
28.0k
          if (! psf->sf.seekable)
322
0
            break ;
323
324
          /* Seek past data and continue reading header. */
325
28.0k
          psf_fseek (psf, chunk_size, SEEK_CUR) ;
326
28.0k
          chunk_size = 0 ;
327
28.0k
          break ;
328
329
799
      case levl_HASH16 :
330
799
          psf_log_printf (psf, "levl : %D\n", chunk_size) ;
331
799
          break ;
332
333
842
      case list_HASH16 :
334
842
          psf_log_printf (psf, "list : %D\n", chunk_size) ;
335
842
          break ;
336
337
1.65k
      case junk_HASH16 :
338
1.65k
          psf_log_printf (psf, "junk : %D\n", chunk_size) ;
339
1.65k
          break ;
340
341
10
      case bext_HASH16 :
342
10
          psf_log_printf (psf, "bext : %D\n", chunk_size) ;
343
10
          break ;
344
345
66
      case MARKER_HASH16 :
346
66
          psf_log_printf (psf, "marker : %D\n", chunk_size) ;
347
66
          break ;
348
349
1.06k
      case SUMLIST_HASH16 :
350
1.06k
          psf_log_printf (psf, "summary list : %D\n", chunk_size) ;
351
1.06k
          break ;
352
353
68.6k
      default :
354
68.6k
          psf_log_printf (psf, "*** Unknown chunk marker (%X) at position %D with length %D. Skipping and continuing.\n", marker, psf_ftell (psf) - 8, chunk_size) ;
355
68.6k
          break ;
356
120k
      } ; /* switch (dword) */
357
358
120k
    if (chunk_size >= psf->filelength)
359
252
    { psf_log_printf (psf, "*** Chunk size %u > file length %D. Exiting parser.\n", chunk_size, psf->filelength) ;
360
252
      break ;
361
119k
      } ;
362
363
119k
    if (psf->sf.seekable == 0 && (parsestage & HAVE_data))
364
0
      break ;
365
366
119k
    if (psf_ftell (psf) >= (psf->filelength - (2 * SIGNED_SIZEOF (dword))))
367
400
      break ;
368
369
119k
    if (chunk_size > 0 && chunk_size < 0xffff0000)
370
4.75k
    { dword = chunk_size ;
371
4.75k
      psf_binheader_readf (psf, "j", dword - 24) ;
372
4.75k
      } ;
373
119k
    } ; /* while (1) */
374
375
690
  if (psf->dataoffset <= 0)
376
475
    return SFE_W64_NO_DATA ;
377
378
215
  if (psf->sf.channels < 1)
379
6
    return SFE_CHANNEL_COUNT_ZERO ;
380
381
209
  if (psf->sf.channels > SF_MAX_CHANNELS)
382
29
    return SFE_CHANNEL_COUNT ;
383
384
180
  psf->endian = SF_ENDIAN_LITTLE ;    /* All W64 files are little endian. */
385
386
180
  if (psf_ftell (psf) != psf->dataoffset)
387
154
    psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
388
389
180
  if (psf->blockwidth)
390
105
  { if (psf->filelength - psf->dataoffset < psf->datalength)
391
0
      psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ;
392
105
    else
393
105
      psf->sf.frames = psf->datalength / psf->blockwidth ;
394
105
    } ;
395
396
180
  switch (format)
397
180
  { case WAVE_FORMAT_PCM :
398
53
    case WAVE_FORMAT_EXTENSIBLE :
399
          /* extensible might be FLOAT, MULAW, etc as well! */
400
53
          psf->sf.format = SF_FORMAT_W64 | u_bitwidth_to_subformat (psf->bytewidth * 8) ;
401
53
          break ;
402
403
9
    case WAVE_FORMAT_MULAW :
404
9
          psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_ULAW) ;
405
9
          break ;
406
407
5
    case WAVE_FORMAT_ALAW :
408
5
          psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_ALAW) ;
409
5
          break ;
410
411
16
    case WAVE_FORMAT_MS_ADPCM :
412
16
          psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_MS_ADPCM) ;
413
16
          *blockalign = wav_fmt->msadpcm.blockalign ;
414
16
          *framesperblock = wav_fmt->msadpcm.samplesperblock ;
415
16
          break ;
416
417
1
    case WAVE_FORMAT_IMA_ADPCM :
418
1
          psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_IMA_ADPCM) ;
419
1
          *blockalign = wav_fmt->ima.blockalign ;
420
1
          *framesperblock = wav_fmt->ima.samplesperblock ;
421
1
          break ;
422
423
50
    case WAVE_FORMAT_GSM610 :
424
50
          psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_GSM610) ;
425
50
          break ;
426
427
45
    case WAVE_FORMAT_IEEE_FLOAT :
428
45
          psf->sf.format = SF_FORMAT_W64 ;
429
45
          psf->sf.format |= (psf->bytewidth == 8) ? SF_FORMAT_DOUBLE : SF_FORMAT_FLOAT ;
430
45
          break ;
431
432
1
    default : return SFE_UNIMPLEMENTED ;
433
180
    } ;
434
435
179
  return 0 ;
436
180
} /* w64_read_header */
437
438
static int
439
w64_write_header (SF_PRIVATE *psf, int calc_length)
440
0
{ sf_count_t  fmt_size, current ;
441
0
  size_t    fmt_pad = 0 ;
442
0
  int     subformat, add_fact_chunk = SF_FALSE ;
443
444
0
  current = psf_ftell (psf) ;
445
446
0
  if (calc_length)
447
0
  { psf->filelength = psf_get_filelen (psf) ;
448
449
0
    psf->datalength = psf->filelength - psf->dataoffset ;
450
0
    if (psf->dataend)
451
0
      psf->datalength -= psf->filelength - psf->dataend ;
452
453
0
    if (psf->bytewidth)
454
0
      psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ;
455
0
    } ;
456
457
  /* Reset the current header length to zero. */
458
0
  psf->header.ptr [0] = 0 ;
459
0
  psf->header.indx = 0 ;
460
0
  psf_fseek (psf, 0, SEEK_SET) ;
461
462
  /* riff marker, length, wave and 'fmt ' markers. */
463
0
  psf_binheader_writef (psf, "eh8hh", BHWh (riff_MARKER16), BHW8 (psf->filelength), BHWh (wave_MARKER16), BHWh (fmt_MARKER16)) ;
464
465
0
  subformat = SF_CODEC (psf->sf.format) ;
466
467
0
  switch (subformat)
468
0
  { case  SF_FORMAT_PCM_U8 :
469
0
    case  SF_FORMAT_PCM_16 :
470
0
    case  SF_FORMAT_PCM_24 :
471
0
    case  SF_FORMAT_PCM_32 :
472
0
          fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 ;
473
0
          fmt_pad = (size_t) ((fmt_size & 0x7) ? 8 - (fmt_size & 0x7) : 0) ;
474
0
          fmt_size += fmt_pad ;
475
476
          /* fmt : format, channels, samplerate */
477
0
          psf_binheader_writef (psf, "e8224", BHW8 (fmt_size), BHW2 (WAVE_FORMAT_PCM), BHW2 (psf->sf.channels), BHW4 (psf->sf.samplerate)) ;
478
          /*  fmt : bytespersec */
479
0
          psf_binheader_writef (psf, "e4", BHW4 (psf->sf.samplerate * psf->bytewidth * psf->sf.channels)) ;
480
          /*  fmt : blockalign, bitwidth */
481
0
          psf_binheader_writef (psf, "e22", BHW2 (psf->bytewidth * psf->sf.channels), BHW2 (psf->bytewidth * 8)) ;
482
0
          break ;
483
484
0
    case SF_FORMAT_FLOAT :
485
0
    case SF_FORMAT_DOUBLE :
486
0
          fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 ;
487
0
          fmt_pad = (size_t) ((fmt_size & 0x7) ? 8 - (fmt_size & 0x7) : 0) ;
488
0
          fmt_size += fmt_pad ;
489
490
          /* fmt : format, channels, samplerate */
491
0
          psf_binheader_writef (psf, "e8224", BHW8 (fmt_size), BHW2 (WAVE_FORMAT_IEEE_FLOAT), BHW2 (psf->sf.channels), BHW4 (psf->sf.samplerate)) ;
492
          /*  fmt : bytespersec */
493
0
          psf_binheader_writef (psf, "e4", BHW4 (psf->sf.samplerate * psf->bytewidth * psf->sf.channels)) ;
494
          /*  fmt : blockalign, bitwidth */
495
0
          psf_binheader_writef (psf, "e22", BHW2 (psf->bytewidth * psf->sf.channels), BHW2 (psf->bytewidth * 8)) ;
496
497
0
          add_fact_chunk = SF_TRUE ;
498
0
          break ;
499
500
0
    case SF_FORMAT_ULAW :
501
0
          fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 ;
502
0
          fmt_pad = (size_t) ((fmt_size & 0x7) ? 8 - (fmt_size & 0x7) : 0) ;
503
0
          fmt_size += fmt_pad ;
504
505
          /* fmt : format, channels, samplerate */
506
0
          psf_binheader_writef (psf, "e8224", BHW8 (fmt_size), BHW2 (WAVE_FORMAT_MULAW), BHW2 (psf->sf.channels), BHW4 (psf->sf.samplerate)) ;
507
          /*  fmt : bytespersec */
508
0
          psf_binheader_writef (psf, "e4", BHW4 (psf->sf.samplerate * psf->bytewidth * psf->sf.channels)) ;
509
          /*  fmt : blockalign, bitwidth */
510
0
          psf_binheader_writef (psf, "e22", BHW2 (psf->bytewidth * psf->sf.channels), BHW2 (8)) ;
511
512
0
          add_fact_chunk = SF_TRUE ;
513
0
          break ;
514
515
0
    case SF_FORMAT_ALAW :
516
0
          fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 ;
517
0
          fmt_pad = (size_t) ((fmt_size & 0x7) ? 8 - (fmt_size & 0x7) : 0) ;
518
0
          fmt_size += fmt_pad ;
519
520
          /* fmt : format, channels, samplerate */
521
0
          psf_binheader_writef (psf, "e8224", BHW8 (fmt_size), BHW2 (WAVE_FORMAT_ALAW), BHW2 (psf->sf.channels), BHW4 (psf->sf.samplerate)) ;
522
          /*  fmt : bytespersec */
523
0
          psf_binheader_writef (psf, "e4", BHW4 (psf->sf.samplerate * psf->bytewidth * psf->sf.channels)) ;
524
          /*  fmt : blockalign, bitwidth */
525
0
          psf_binheader_writef (psf, "e22", BHW2 (psf->bytewidth * psf->sf.channels), BHW2 (8)) ;
526
527
0
          add_fact_chunk = SF_TRUE ;
528
0
          break ;
529
530
    /* Lite remove start */
531
0
    case SF_FORMAT_IMA_ADPCM :
532
0
          { int   blockalign, framesperblock, bytespersec ;
533
534
0
            blockalign    = wavlike_srate2blocksize (psf->sf.samplerate * psf->sf.channels) ;
535
0
            framesperblock  = 2 * (blockalign - 4 * psf->sf.channels) / psf->sf.channels + 1 ;
536
0
            bytespersec   = (psf->sf.samplerate * blockalign) / framesperblock ;
537
538
            /* fmt chunk. */
539
0
            fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 ;
540
0
            fmt_pad = (size_t) ((fmt_size & 0x7) ? 8 - (fmt_size & 0x7) : 0) ;
541
0
            fmt_size += fmt_pad ;
542
543
            /* fmt : size, WAV format type, channels. */
544
0
            psf_binheader_writef (psf, "e822", BHW8 (fmt_size), BHW2 (WAVE_FORMAT_IMA_ADPCM), BHW2 (psf->sf.channels)) ;
545
546
            /* fmt : samplerate, bytespersec. */
547
0
            psf_binheader_writef (psf, "e44", BHW4 (psf->sf.samplerate), BHW4 (bytespersec)) ;
548
549
            /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */
550
0
            psf_binheader_writef (psf, "e2222", BHW2 (blockalign), BHW2 (4), BHW2 (2), BHW2 (framesperblock)) ;
551
0
            } ;
552
553
0
          add_fact_chunk = SF_TRUE ;
554
0
          break ;
555
556
0
    case SF_FORMAT_MS_ADPCM :
557
0
          { int blockalign, framesperblock, bytespersec, extrabytes ;
558
559
0
            blockalign    = wavlike_srate2blocksize (psf->sf.samplerate * psf->sf.channels) ;
560
0
            framesperblock  = 2 + 2 * (blockalign - 7 * psf->sf.channels) / psf->sf.channels ;
561
0
            bytespersec   = (psf->sf.samplerate * blockalign) / framesperblock ;
562
563
            /* fmt chunk. */
564
0
            extrabytes  = 2 + 2 + WAVLIKE_MSADPCM_ADAPT_COEFF_COUNT * (2 + 2) ;
565
0
            fmt_size  = 24 + 2 + 2 + 4 + 4 + 2 + 2 + 2 + extrabytes ;
566
0
            fmt_pad = (size_t) ((fmt_size & 0x7) ? 8 - (fmt_size & 0x7) : 0) ;
567
0
            fmt_size += fmt_pad ;
568
569
            /* fmt : size, W64 format type, channels. */
570
0
            psf_binheader_writef (psf, "e822", BHW8 (fmt_size), BHW2 (WAVE_FORMAT_MS_ADPCM), BHW2 (psf->sf.channels)) ;
571
572
            /* fmt : samplerate, bytespersec. */
573
0
            psf_binheader_writef (psf, "e44", BHW4 (psf->sf.samplerate), BHW4 (bytespersec)) ;
574
575
            /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */
576
0
            psf_binheader_writef (psf, "e22222", BHW2 (blockalign), BHW2 (4), BHW2 (extrabytes), BHW2 (framesperblock), BHW2 (7)) ;
577
578
0
            wavlike_msadpcm_write_adapt_coeffs (psf) ;
579
0
            } ;
580
581
0
          add_fact_chunk = SF_TRUE ;
582
0
          break ;
583
    /* Lite remove end */
584
585
0
    case SF_FORMAT_GSM610 :
586
0
          { int bytespersec ;
587
588
0
            bytespersec = (psf->sf.samplerate * WAVLIKE_GSM610_BLOCKSIZE) / WAVLIKE_GSM610_SAMPLES ;
589
590
            /* fmt chunk. */
591
0
            fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 ;
592
0
            fmt_pad = (size_t) ((fmt_size & 0x7) ? 8 - (fmt_size & 0x7) : 0) ;
593
0
            fmt_size += fmt_pad ;
594
595
            /* fmt : size, WAV format type, channels. */
596
0
            psf_binheader_writef (psf, "e822", BHW8 (fmt_size), BHW2 (WAVE_FORMAT_GSM610), BHW2 (psf->sf.channels)) ;
597
598
            /* fmt : samplerate, bytespersec. */
599
0
            psf_binheader_writef (psf, "e44", BHW4 (psf->sf.samplerate), BHW4 (bytespersec)) ;
600
601
            /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */
602
0
            psf_binheader_writef (psf, "e2222", BHW2 (WAVLIKE_GSM610_BLOCKSIZE), BHW2 (0), BHW2 (2), BHW2 (WAVLIKE_GSM610_SAMPLES)) ;
603
0
            } ;
604
605
0
          add_fact_chunk = SF_TRUE ;
606
0
          break ;
607
608
0
    default :   return SFE_UNIMPLEMENTED ;
609
0
    } ;
610
611
  /* Pad to 8 bytes with zeros. */
612
0
  if (fmt_pad > 0)
613
0
    psf_binheader_writef (psf, "z", BHWz (fmt_pad)) ;
614
615
0
  if (add_fact_chunk)
616
0
    psf_binheader_writef (psf, "eh88", BHWh (fact_MARKER16), BHW8 ((sf_count_t) (16 + 8 + 8)), BHW8 (psf->sf.frames)) ;
617
618
0
  psf_binheader_writef (psf, "eh8", BHWh (data_MARKER16), BHW8 (psf->datalength + 24)) ;
619
0
  psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ;
620
621
0
  if (psf->error)
622
0
    return psf->error ;
623
624
0
  psf->dataoffset = psf->header.indx ;
625
626
0
  if (current > 0)
627
0
    psf_fseek (psf, current, SEEK_SET) ;
628
629
0
  return psf->error ;
630
0
} /* w64_write_header */
631
632
static int
633
w64_close (SF_PRIVATE *psf)
634
179
{
635
179
  if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
636
0
    w64_write_header (psf, SF_TRUE) ;
637
638
179
  return 0 ;
639
179
} /* w64_close */
640