a39a57a56e1692689d02b049da97f5fef375374c
2 ** Copyright (C) 2010-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
4 ** All rights reserved.
6 ** Redistribution and use in source and binary forms, with or without
7 ** modification, are permitted provided that the following conditions are
10 ** * Redistributions of source code must retain the above copyright
11 ** notice, this list of conditions and the following disclaimer.
12 ** * Redistributions in binary form must reproduce the above copyright
13 ** notice, this list of conditions and the following disclaimer in
14 ** the documentation and/or other materials provided with the
16 ** * Neither the author nor the names of any contributors may be used
17 ** to endorse or promote products derived from this software without
18 ** specific prior written permission.
20 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 ** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 ** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 ** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 ** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 ** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 ** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
30 ** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 #include <sys/types.h>
49 #define BUFFER_LEN (1 << 16)
51 #define NOT(x) (! (x))
54 static void usage_exit (const char *progname
) ;
55 static void salvage_file (const char * broken_wav
, const char * fixed_w64
) ;
58 main (int argc
, char *argv
[])
61 usage_exit (program_name (argv
[0])) ;
63 salvage_file (argv
[1], argv
[2]) ;
68 /*==============================================================================
71 static void lseek_or_die (int fd
, off_t offset
, int whence
) ;
72 static sf_count_t
get_file_length (int fd
, const char * name
) ;
73 static sf_count_t
find_data_offset (int fd
, int format
) ;
74 static void copy_data (int fd
, SNDFILE
* sndfile
, int readsize
) ;
78 usage_exit (const char *progname
)
79 { printf ("Usage :\n\n %s <broken wav file> <fixed w64 file>\n\n", progname
) ;
80 puts ("Salvages the audio data from WAV files which are more than 4G in length.\n") ;
81 printf ("Using %s.\n\n", sf_version_string ()) ;
86 salvage_file (const char * broken_wav
, const char * fixed_w64
)
89 sf_count_t broken_len
, data_offset
;
92 if (strcmp (broken_wav
, fixed_w64
) == 0)
93 { printf ("Error : Input and output files must be different.\n\n") ;
97 if ((fd
= open (broken_wav
, O_RDONLY
)) < 0)
98 { printf ("Error : Not able to open file '%s' : %s\n", broken_wav
, strerror (errno
)) ;
102 broken_len
= get_file_length (fd
, broken_wav
) ;
103 if (broken_len
<= 0xffffffff)
104 printf ("File is not greater than 4Gig but salvaging anyway.\n") ;
106 /* Grab the format info from the broken file. */
107 memset (&sfinfo
, 0, sizeof (sfinfo
)) ;
108 if ((sndfile
= sf_open (broken_wav
, SFM_READ
, &sfinfo
)) == NULL
)
109 { printf ("sf_open ('%s') failed : %s\n", broken_wav
, sf_strerror (NULL
)) ;
114 data_offset
= find_data_offset (fd
, sfinfo
.format
& SF_FORMAT_TYPEMASK
) ;
116 printf ("Offset to audio data : %" PRId64
"\n", data_offset
) ;
118 switch (sfinfo
.format
& SF_FORMAT_TYPEMASK
)
119 { case SF_FORMAT_WAV
:
120 case SF_FORMAT_WAVEX
:
121 sfinfo
.format
= SF_FORMAT_W64
| (sfinfo
.format
& SF_FORMAT_SUBMASK
) ;
125 printf ("Don't currently support this file type.\n") ;
129 switch (sfinfo
.format
& SF_FORMAT_SUBMASK
)
130 { case SF_FORMAT_PCM_U8
:
131 case SF_FORMAT_PCM_S8
:
135 case SF_FORMAT_PCM_16
:
139 case SF_FORMAT_PCM_24
:
143 case SF_FORMAT_PCM_32
:
144 case SF_FORMAT_FLOAT
:
148 case SF_FORMAT_DOUBLE
:
153 printf ("Sorry, don't currently support this file encoding type.\n") ;
157 read_size
*= sfinfo
.channels
;
159 if ((sndfile
= sf_open (fixed_w64
, SFM_WRITE
, &sfinfo
)) == NULL
)
160 { printf ("sf_open ('%s') failed : %s\n", broken_wav
, sf_strerror (NULL
)) ;
164 lseek_or_die (fd
, data_offset
, SEEK_SET
) ;
166 copy_data (fd
, sndfile
, read_size
) ;
173 /*------------------------------------------------------------------------------
177 lseek_or_die (int fd
, off_t offset
, int whence
)
179 if (lseek (fd
, offset
, whence
) < 0)
180 { printf ("lseek failed : %s\n", strerror (errno
)) ;
189 get_file_length (int fd
, const char * name
)
192 if (sizeof (sbuf
.st_size
) != 8)
193 { puts ("Error : sizeof (sbuf.st_size) != 8. Was program compiled with\n"
194 " 64 bit file offsets?\n") ;
198 if (fstat (fd
, &sbuf
) != 0)
199 { printf ("Error : fstat ('%s') failed : %s\n", name
, strerror (errno
)) ;
203 return sbuf
.st_size
;
204 } /* get_file_length */
207 find_data_offset (int fd
, int format
)
208 { char buffer
[8192], *cptr
;
209 const char * target
= "XXXX" ;
210 sf_count_t offset
= -1, extra
;
214 { case SF_FORMAT_WAV
:
215 case SF_FORMAT_WAVEX
:
220 case SF_FORMAT_AIFF
:
226 puts ("Error : Sorry, don't handle this input file format.\n") ;
230 slen
= strlen (target
) ;
232 lseek_or_die (fd
, 0, SEEK_SET
) ;
234 printf ("Searching for '%s' maker.\n", target
) ;
236 if ((rlen
= read (fd
, buffer
, sizeof (buffer
))) < 0)
237 { printf ("Error : failed read : %s\n", strerror (errno
)) ;
241 cptr
= memchr (buffer
, target
[0], rlen
- slen
) ;
242 if (cptr
&& memcmp (cptr
, target
, slen
) == 0)
243 offset
= cptr
- buffer
;
245 { printf ("Error : Could not find data offset.\n") ;
249 return offset
+ extra
;
250 } /* find_data_offset */
253 copy_data (int fd
, SNDFILE
* sndfile
, int readsize
)
254 { static char * buffer
;
255 sf_count_t readlen
, count
;
256 int bufferlen
, done
= 0 ;
258 bufferlen
= readsize
* 1024 ;
259 buffer
= malloc (bufferlen
) ;
261 while (NOT (done
) && (readlen
= read (fd
, buffer
, bufferlen
)) >= 0)
262 { if (readlen
< bufferlen
)
263 { readlen
-= readlen
% readsize
;
267 if ((count
= sf_write_raw (sndfile
, buffer
, readlen
)) != readlen
)
268 { printf ("Error : sf_write_raw returned %" PRId64
" : %s\n", count
, sf_strerror (sndfile
)) ;