annotate src/libsndfile-1.0.25/programs/sndfile-salvage.c @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +0000
parents c7265573341e
children
rev   line source
Chris@0 1 /*
Chris@0 2 ** Copyright (C) 2010-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
Chris@0 3 **
Chris@0 4 ** All rights reserved.
Chris@0 5 **
Chris@0 6 ** Redistribution and use in source and binary forms, with or without
Chris@0 7 ** modification, are permitted provided that the following conditions are
Chris@0 8 ** met:
Chris@0 9 **
Chris@0 10 ** * Redistributions of source code must retain the above copyright
Chris@0 11 ** notice, this list of conditions and the following disclaimer.
Chris@0 12 ** * Redistributions in binary form must reproduce the above copyright
Chris@0 13 ** notice, this list of conditions and the following disclaimer in
Chris@0 14 ** the documentation and/or other materials provided with the
Chris@0 15 ** distribution.
Chris@0 16 ** * Neither the author nor the names of any contributors may be used
Chris@0 17 ** to endorse or promote products derived from this software without
Chris@0 18 ** specific prior written permission.
Chris@0 19 **
Chris@0 20 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Chris@0 21 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
Chris@0 22 ** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
Chris@0 23 ** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
Chris@0 24 ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
Chris@0 25 ** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
Chris@0 26 ** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
Chris@0 27 ** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
Chris@0 28 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
Chris@0 29 ** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
Chris@0 30 ** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Chris@0 31 */
Chris@0 32
Chris@0 33 #include <stdio.h>
Chris@0 34 #include <stdlib.h>
Chris@0 35 #include <string.h>
Chris@0 36 #include <inttypes.h>
Chris@0 37 #include <ctype.h>
Chris@0 38 #include <math.h>
Chris@0 39 #include <errno.h>
Chris@0 40 #include <unistd.h>
Chris@0 41 #include <fcntl.h>
Chris@0 42 #include <sys/stat.h>
Chris@0 43 #include <sys/types.h>
Chris@0 44
Chris@0 45 #include <sndfile.h>
Chris@0 46
Chris@0 47 #include "common.h"
Chris@0 48
Chris@0 49 #define BUFFER_LEN (1 << 16)
Chris@0 50
Chris@0 51 #define NOT(x) (! (x))
Chris@0 52
Chris@0 53
Chris@0 54 static void usage_exit (const char *progname) ;
Chris@0 55 static void salvage_file (const char * broken_wav, const char * fixed_w64) ;
Chris@0 56
Chris@0 57 int
Chris@0 58 main (int argc, char *argv [])
Chris@0 59 {
Chris@0 60 if (argc != 3)
Chris@0 61 usage_exit (program_name (argv [0])) ;
Chris@0 62
Chris@0 63 salvage_file (argv [1], argv [2]) ;
Chris@0 64
Chris@0 65 return 0 ;
Chris@0 66 } /* main */
Chris@0 67
Chris@0 68 /*==============================================================================
Chris@0 69 */
Chris@0 70
Chris@0 71 static void lseek_or_die (int fd, off_t offset, int whence) ;
Chris@0 72 static sf_count_t get_file_length (int fd, const char * name) ;
Chris@0 73 static sf_count_t find_data_offset (int fd, int format) ;
Chris@0 74 static void copy_data (int fd, SNDFILE * sndfile, int readsize) ;
Chris@0 75
Chris@0 76
Chris@0 77 static void
Chris@0 78 usage_exit (const char *progname)
Chris@0 79 { printf ("Usage :\n\n %s <broken wav file> <fixed w64 file>\n\n", progname) ;
Chris@0 80 puts ("Salvages the audio data from WAV files which are more than 4G in length.\n") ;
Chris@0 81 printf ("Using %s.\n\n", sf_version_string ()) ;
Chris@0 82 exit (0) ;
Chris@0 83 } /* usage_exit */
Chris@0 84
Chris@0 85 static void
Chris@0 86 salvage_file (const char * broken_wav, const char * fixed_w64)
Chris@0 87 { SNDFILE * sndfile ;
Chris@0 88 SF_INFO sfinfo ;
Chris@0 89 sf_count_t broken_len, data_offset ;
Chris@0 90 int fd, read_size ;
Chris@0 91
Chris@0 92 if (strcmp (broken_wav, fixed_w64) == 0)
Chris@0 93 { printf ("Error : Input and output files must be different.\n\n") ;
Chris@0 94 exit (1) ;
Chris@0 95 } ;
Chris@0 96
Chris@0 97 if ((fd = open (broken_wav, O_RDONLY)) < 0)
Chris@0 98 { printf ("Error : Not able to open file '%s' : %s\n", broken_wav, strerror (errno)) ;
Chris@0 99 exit (1) ;
Chris@0 100 } ;
Chris@0 101
Chris@0 102 broken_len = get_file_length (fd, broken_wav) ;
Chris@0 103 if (broken_len <= 0xffffffff)
Chris@0 104 printf ("File is not greater than 4Gig but salvaging anyway.\n") ;
Chris@0 105
Chris@0 106 /* Grab the format info from the broken file. */
Chris@0 107 memset (&sfinfo, 0, sizeof (sfinfo)) ;
Chris@0 108 if ((sndfile = sf_open (broken_wav, SFM_READ, &sfinfo)) == NULL)
Chris@0 109 { printf ("sf_open ('%s') failed : %s\n", broken_wav, sf_strerror (NULL)) ;
Chris@0 110 exit (1) ;
Chris@0 111 } ;
Chris@0 112 sf_close (sndfile) ;
Chris@0 113
Chris@0 114 data_offset = find_data_offset (fd, sfinfo.format & SF_FORMAT_TYPEMASK) ;
Chris@0 115
Chris@0 116 printf ("Offset to audio data : %" PRId64 "\n", data_offset) ;
Chris@0 117
Chris@0 118 switch (sfinfo.format & SF_FORMAT_TYPEMASK)
Chris@0 119 { case SF_FORMAT_WAV :
Chris@0 120 case SF_FORMAT_WAVEX :
Chris@0 121 sfinfo.format = SF_FORMAT_W64 | (sfinfo.format & SF_FORMAT_SUBMASK) ;
Chris@0 122 break ;
Chris@0 123
Chris@0 124 default :
Chris@0 125 printf ("Don't currently support this file type.\n") ;
Chris@0 126 exit (1) ;
Chris@0 127 } ;
Chris@0 128
Chris@0 129 switch (sfinfo.format & SF_FORMAT_SUBMASK)
Chris@0 130 { case SF_FORMAT_PCM_U8 :
Chris@0 131 case SF_FORMAT_PCM_S8 :
Chris@0 132 read_size = 1 ;
Chris@0 133 break ;
Chris@0 134
Chris@0 135 case SF_FORMAT_PCM_16 :
Chris@0 136 read_size = 2 ;
Chris@0 137 break ;
Chris@0 138
Chris@0 139 case SF_FORMAT_PCM_24 :
Chris@0 140 read_size = 3 ;
Chris@0 141 break ;
Chris@0 142
Chris@0 143 case SF_FORMAT_PCM_32 :
Chris@0 144 case SF_FORMAT_FLOAT :
Chris@0 145 read_size = 4 ;
Chris@0 146 break ;
Chris@0 147
Chris@0 148 case SF_FORMAT_DOUBLE :
Chris@0 149 read_size = 8 ;
Chris@0 150 break ;
Chris@0 151
Chris@0 152 default :
Chris@0 153 printf ("Sorry, don't currently support this file encoding type.\n") ;
Chris@0 154 exit (1) ;
Chris@0 155 } ;
Chris@0 156
Chris@0 157 read_size *= sfinfo.channels ;
Chris@0 158
Chris@0 159 if ((sndfile = sf_open (fixed_w64, SFM_WRITE, &sfinfo)) == NULL)
Chris@0 160 { printf ("sf_open ('%s') failed : %s\n", broken_wav, sf_strerror (NULL)) ;
Chris@0 161 exit (1) ;
Chris@0 162 } ;
Chris@0 163
Chris@0 164 lseek_or_die (fd, data_offset, SEEK_SET) ;
Chris@0 165
Chris@0 166 copy_data (fd, sndfile, read_size) ;
Chris@0 167
Chris@0 168 sf_close (sndfile) ;
Chris@0 169
Chris@0 170 puts ("Done!") ;
Chris@0 171 } /* salvage_file */
Chris@0 172
Chris@0 173 /*------------------------------------------------------------------------------
Chris@0 174 */
Chris@0 175
Chris@0 176 static void
Chris@0 177 lseek_or_die (int fd, off_t offset, int whence)
Chris@0 178 {
Chris@0 179 if (lseek (fd, offset, whence) < 0)
Chris@0 180 { printf ("lseek failed : %s\n", strerror (errno)) ;
Chris@0 181 exit (1) ;
Chris@0 182 } ;
Chris@0 183
Chris@0 184 return ;
Chris@0 185 } /* lseek_or_die */
Chris@0 186
Chris@0 187
Chris@0 188 static sf_count_t
Chris@0 189 get_file_length (int fd, const char * name)
Chris@0 190 { struct stat sbuf ;
Chris@0 191
Chris@0 192 if (sizeof (sbuf.st_size) != 8)
Chris@0 193 { puts ("Error : sizeof (sbuf.st_size) != 8. Was program compiled with\n"
Chris@0 194 " 64 bit file offsets?\n") ;
Chris@0 195 exit (1) ;
Chris@0 196 } ;
Chris@0 197
Chris@0 198 if (fstat (fd, &sbuf) != 0)
Chris@0 199 { printf ("Error : fstat ('%s') failed : %s\n", name, strerror (errno)) ;
Chris@0 200 exit (1) ;
Chris@0 201 } ;
Chris@0 202
Chris@0 203 return sbuf.st_size ;
Chris@0 204 } /* get_file_length */
Chris@0 205
Chris@0 206 static sf_count_t
Chris@0 207 find_data_offset (int fd, int format)
Chris@0 208 { char buffer [8192], *cptr ;
Chris@0 209 const char * target = "XXXX" ;
Chris@0 210 sf_count_t offset = -1, extra ;
Chris@0 211 int rlen, slen ;
Chris@0 212
Chris@0 213 switch (format)
Chris@0 214 { case SF_FORMAT_WAV :
Chris@0 215 case SF_FORMAT_WAVEX :
Chris@0 216 target = "data" ;
Chris@0 217 extra = 8 ;
Chris@0 218 break ;
Chris@0 219
Chris@0 220 case SF_FORMAT_AIFF :
Chris@0 221 target = "SSND" ;
Chris@0 222 extra = 16 ;
Chris@0 223 break ;
Chris@0 224
Chris@0 225 default :
Chris@0 226 puts ("Error : Sorry, don't handle this input file format.\n") ;
Chris@0 227 exit (1) ;
Chris@0 228 } ;
Chris@0 229
Chris@0 230 slen = strlen (target) ;
Chris@0 231
Chris@0 232 lseek_or_die (fd, 0, SEEK_SET) ;
Chris@0 233
Chris@0 234 printf ("Searching for '%s' maker.\n", target) ;
Chris@0 235
Chris@0 236 if ((rlen = read (fd, buffer, sizeof (buffer))) < 0)
Chris@0 237 { printf ("Error : failed read : %s\n", strerror (errno)) ;
Chris@0 238 exit (1) ;
Chris@0 239 } ;
Chris@0 240
Chris@0 241 cptr = memchr (buffer, target [0], rlen - slen) ;
Chris@0 242 if (cptr && memcmp (cptr, target, slen) == 0)
Chris@0 243 offset = cptr - buffer ;
Chris@0 244 else
Chris@0 245 { printf ("Error : Could not find data offset.\n") ;
Chris@0 246 exit (1) ;
Chris@0 247 } ;
Chris@0 248
Chris@0 249 return offset + extra ;
Chris@0 250 } /* find_data_offset */
Chris@0 251
Chris@0 252 static void
Chris@0 253 copy_data (int fd, SNDFILE * sndfile, int readsize)
Chris@0 254 { static char * buffer ;
Chris@0 255 sf_count_t readlen, count ;
Chris@0 256 int bufferlen, done = 0 ;
Chris@0 257
Chris@0 258 bufferlen = readsize * 1024 ;
Chris@0 259 buffer = malloc (bufferlen) ;
Chris@0 260
Chris@0 261 while (NOT (done) && (readlen = read (fd, buffer, bufferlen)) >= 0)
Chris@0 262 { if (readlen < bufferlen)
Chris@0 263 { readlen -= readlen % readsize ;
Chris@0 264 done = 1 ;
Chris@0 265 } ;
Chris@0 266
Chris@0 267 if ((count = sf_write_raw (sndfile, buffer, readlen)) != readlen)
Chris@0 268 { printf ("Error : sf_write_raw returned %" PRId64 " : %s\n", count, sf_strerror (sndfile)) ;
Chris@0 269 return ;
Chris@0 270 } ;
Chris@0 271 } ;
Chris@0 272
Chris@0 273 free (buffer) ;
Chris@0 274
Chris@0 275 return ;
Chris@0 276 } /* copy_data */
Chris@0 277