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