int psf_get_format_info (SF_FORMAT_INFO *data) { int k, format ; if (SF_CONTAINER (data->format)) { format = SF_CONTAINER (data->format) ; for (k = 0 ; k < (SIGNED_SIZEOF (major_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO)) ; k++) { if (format == major_formats [k].format) { memcpy (data, &(major_formats [k]), sizeof (SF_FORMAT_INFO)) ; return 0 ; } ; } ; } else if (SF_CODEC (data->format)) { format = SF_CODEC (data->format) ; for (k = 0 ; k < (SIGNED_SIZEOF (subtype_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO)) ; k++) { if (format == subtype_formats [k].format) { memcpy (data, &(subtype_formats [k]), sizeof (SF_FORMAT_INFO)) ; return 0 ; } ; } ; } ; memset (data, 0, sizeof (SF_FORMAT_INFO)) ; return SFE_BAD_COMMAND_PARAM ; } /* psf_get_format_info */
int psf_get_format_simple (SF_FORMAT_INFO *data) { int indx ; if (data->format < 0 || data->format >= (SIGNED_SIZEOF (simple_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO))) return SFE_BAD_COMMAND_PARAM ; indx = data->format ; memcpy (data, &(simple_formats [indx]), SIGNED_SIZEOF (SF_FORMAT_INFO)) ; return 0 ; } /* psf_get_format_simple */
void hexdump_file (const char * filename, sf_count_t offset, sf_count_t length) { FILE * file ; char buffer [16] ; int k, m, ch, readcount ; if (length > 1000000) { printf ("\n\nError : length (%ld) too long.\n\n", SF_COUNT_TO_LONG (offset)) ; exit (1) ; } ; if ((file = fopen (filename, "r")) == NULL) { printf ("\n\nError : hexdump_file (%s) could not open file for read.\n\n", filename) ; exit (1) ; } ; if (fseek (file, offset, SEEK_SET) != 0) { printf ("\n\nError : fseek(file, %ld, SEEK_SET) failed : %s\n\n", SF_COUNT_TO_LONG (offset), strerror (errno)) ; exit (1) ; } ; puts ("\n\n") ; for (k = 0 ; k < length ; k+= sizeof (buffer)) { readcount = fread (buffer, 1, sizeof (buffer), file) ; printf ("%08lx : ", SF_COUNT_TO_LONG (offset + k)) ; for (m = 0 ; m < readcount ; m++) printf ("%02x ", buffer [m] & 0xFF) ; for (m = readcount ; m < SIGNED_SIZEOF (buffer) ; m++) printf (" ") ; printf (" ") ; for (m = 0 ; m < readcount ; m++) { ch = isprint (buffer [m]) ? buffer [m] : '.' ; putchar (ch) ; } ; if (readcount < SIGNED_SIZEOF (buffer)) break ; putchar ('\n') ; } ; puts ("\n") ; fclose (file) ; } /* hexdump_file */
int broadcast_add_coding_history (SF_BROADCAST_INFO* bext, unsigned int channels, unsigned int samplerate) { char chnstr [16] ; int count ; switch (channels) { case 0 : return SF_FALSE ; case 1 : strncpy (chnstr, "mono", sizeof (chnstr)) ; break ; case 2 : strncpy (chnstr, "stereo", sizeof (chnstr)) ; break ; default : LSF_SNPRINTF (chnstr, sizeof (chnstr), "%uchn", channels) ; break ; } count = LSF_SNPRINTF (bext->coding_history, sizeof (bext->coding_history), "F=%u,A=PCM,M=%s,W=24,T=%s-%s", samplerate, chnstr, PACKAGE, VERSION) ; if (count >= SIGNED_SIZEOF (bext->coding_history)) bext->coding_history_size = sizeof (bext->coding_history) ; else { count += count & 1 ; bext->coding_history_size = count ; } ; return SF_TRUE ; } /* broadcast_add_coding_history */
static void show_lseek_error (void) { static const char *filename = "fstat.dat" ; static char data [256] ; INT64 retval ; int fd, mode, flags ; puts ("\n64 bit lseek() test.\n--------------------") ; printf ("0) Create a file, write %d bytes and close it.\n", SIGNED_SIZEOF (data)) ; mode = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ; flags = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ; if ((fd = open (filename, mode, flags)) < 0) { printf ("\n\nLine %d: open() failed : %s\n\n", __LINE__, strerror (errno)) ; return ; } ; assert (write (fd, data, sizeof (data)) > 0) ; close (fd) ; printf ("1) Re-open file in read/write mode and write another %d bytes at the end.\n", SIGNED_SIZEOF (data)) ; mode = O_RDWR | O_BINARY ; flags = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ; if ((fd = open (filename, mode, flags)) < 0) { printf ("\n\nLine %d: open() failed : %s\n\n", __LINE__, strerror (errno)) ; return ; } ; LSEEK (fd, 0, SEEK_END) ; assert (write (fd, data, sizeof (data)) > 0) ; printf ("2) Now use system (\"%s %s\") to show the file length.\n\n", dir_cmd, filename) ; /* Would use snprintf, but thats not really available on windows. */ memset (data, 0, sizeof (data)) ; strncpy (data, dir_cmd, sizeof (data) - 1) ; strncat (data, " ", sizeof (data) - 1 - strlen (data)) ; strncat (data, filename, sizeof (data) - 1 - strlen (data)) ; assert (system (data) >= 0) ; puts ("") ; printf ("3) Now use lseek() to go to the end of the file.\n") ; retval = LSEEK (fd, 0, SEEK_END) ; printf ("4) We are now at position %ld, ", (long) retval) ; close (fd) ; if (retval != 2 * sizeof (data)) printf ("but thats just plain ***WRONG***.\n\n") ; else { printf ("which is correct.\n\n") ; unlink (filename) ; } ; } /* show_lseek_error */
static void show_stat_fstat_error (void) { static const char *filename = "stat_fstat.dat" ; static char data [256] ; int fd, mode, flags ; int stat_size, fstat_size ; struct stat buf ; /* Known to fail on WinXP. */ puts ("\nstat/fstat test.\n----------------") ; printf ("0) Create a file and write %d bytes.\n", SIGNED_SIZEOF (data)) ; mode = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ; flags = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ; if ((fd = open (filename, mode, flags)) < 0) { printf ("\n\nLine %d: open() failed : %s\n\n", __LINE__, strerror (errno)) ; return ; } ; assert (write (fd, data, sizeof (data)) > 0) ; printf ("1) Now call stat and fstat on the file and retreive the file lengths.\n") ; if (stat (filename, &buf) != 0) { printf ("\n\nLine %d: stat() failed : %s\n\n", __LINE__, strerror (errno)) ; goto error_exit ; } ; stat_size = buf.st_size ; if (fstat (fd, &buf) != 0) { printf ("\n\nLine %d: fstat() failed : %s\n\n", __LINE__, strerror (errno)) ; goto error_exit ; } ; fstat_size = buf.st_size ; printf ("2) Size returned by stat and fstat is %d and %d, ", stat_size, fstat_size) ; if (stat_size == 0 || stat_size != fstat_size) printf ("but thats just plain ***WRONG***.\n\n") ; else printf ("which is correct.\n\n") ; error_exit : close (fd) ; unlink (filename) ; return ; } /* show_stat_fstat_error */
static sf_count_t vfwrite (const void *ptr, sf_count_t count, void *user_data) { VIO_DATA *vf = (VIO_DATA *) user_data ; /* ** This will break badly for files over 2Gig in length, but ** is sufficient for testing. */ if (vf->offset >= SIGNED_SIZEOF (vf->data)) return 0 ; if (vf->offset + count > SIGNED_SIZEOF (vf->data)) count = sizeof (vf->data) - vf->offset ; memcpy (vf->data + vf->offset, ptr, (size_t) count) ; vf->offset += count ; if (vf->offset > vf->length) vf->length = vf->offset ; return count ; } /* vfwrite */
static int w64_read_header (SF_PRIVATE *psf, int *blockalign, int *framesperblock) { WAV_PRIVATE *wpriv ; WAV_FMT *wav_fmt ; int dword = 0, marker, format = 0 ; sf_count_t chunk_size, bytesread = 0 ; int parsestage = 0, error, done = 0 ; if ((wpriv = psf->container_data) == NULL) return SFE_INTERNAL ; wav_fmt = &wpriv->wav_fmt ; /* Set position to start of file to begin reading header. */ psf_binheader_readf (psf, "p", 0) ; while (! done) { /* Each new chunk must start on an 8 byte boundary, so jump if needed. */ if (psf->headindex & 0x7) psf_binheader_readf (psf, "j", 8 - (psf->headindex & 0x7)) ; /* Generate hash of 16 byte marker. */ marker = chunk_size = 0 ; bytesread = psf_binheader_readf (psf, "eh8", &marker, &chunk_size) ; if (bytesread == 0) break ; switch (marker) { case riff_HASH16 : if (parsestage) return SFE_W64_NO_RIFF ; if (psf->filelength != chunk_size) psf_log_printf (psf, "riff : %D (should be %D)\n", chunk_size, psf->filelength) ; else psf_log_printf (psf, "riff : %D\n", chunk_size) ; parsestage |= HAVE_riff ; bytesread += psf_binheader_readf (psf, "h", &marker) ; if (marker == wave_HASH16) { if ((parsestage & HAVE_riff) != HAVE_riff) return SFE_W64_NO_WAVE ; psf_log_printf (psf, "wave\n") ; parsestage |= HAVE_wave ; } ; chunk_size = 0 ; break ; case ACID_HASH16: psf_log_printf (psf, "Looks like an ACID file. Exiting.\n") ; return SFE_UNIMPLEMENTED ; case fmt_HASH16 : if ((parsestage & (HAVE_riff | HAVE_wave)) != (HAVE_riff | HAVE_wave)) return SFE_WAV_NO_FMT ; psf_log_printf (psf, " fmt : %D\n", chunk_size) ; /* size of 16 byte marker and 8 byte chunk_size value. */ chunk_size -= 24 ; if ((error = wav_w64_read_fmt_chunk (psf, (int) chunk_size))) return error ; if (chunk_size % 8) psf_binheader_readf (psf, "j", 8 - (chunk_size % 8)) ; format = wav_fmt->format ; parsestage |= HAVE_fmt ; chunk_size = 0 ; break ; case fact_HASH16: { sf_count_t frames ; psf_binheader_readf (psf, "e8", &frames) ; psf_log_printf (psf, " fact : %D\n frames : %D\n", chunk_size, frames) ; } ; chunk_size = 0 ; break ; case data_HASH16 : if ((parsestage & (HAVE_riff | HAVE_wave | HAVE_fmt)) != (HAVE_riff | HAVE_wave | HAVE_fmt)) return SFE_W64_NO_DATA ; psf->dataoffset = psf_ftell (psf) ; psf->datalength = SF_MIN (chunk_size - 24, psf->filelength - psf->dataoffset) ; if (chunk_size % 8) chunk_size += 8 - (chunk_size % 8) ; psf_log_printf (psf, "data : %D\n", chunk_size) ; parsestage |= HAVE_data ; if (! psf->sf.seekable) break ; /* Seek past data and continue reading header. */ psf_fseek (psf, chunk_size, SEEK_CUR) ; chunk_size = 0 ; break ; case levl_HASH16 : psf_log_printf (psf, "levl : %D\n", chunk_size) ; chunk_size -= 24 ; break ; case list_HASH16 : psf_log_printf (psf, "list : %D\n", chunk_size) ; chunk_size -= 24 ; break ; case junk_HASH16 : psf_log_printf (psf, "junk : %D\n", chunk_size) ; chunk_size -= 24 ; break ; case bext_MARKER : psf_log_printf (psf, "bext : %D\n", chunk_size) ; chunk_size -= 24 ; break ; case MARKER_HASH16 : psf_log_printf (psf, "marker : %D\n", chunk_size) ; chunk_size -= 24 ; break ; case SUMLIST_HASH16 : psf_log_printf (psf, "summary list : %D\n", chunk_size) ; chunk_size -= 24 ; break ; default : psf_log_printf (psf, "*** Unknown chunk marker (%X) at position %D with length %D. Exiting parser.\n", marker, psf_ftell (psf) - 8, chunk_size) ; done = SF_TRUE ; break ; } ; /* switch (dword) */ if (chunk_size >= psf->filelength) { psf_log_printf (psf, "*** Chunk size %u > file length %D. Exiting parser.\n", chunk_size, psf->filelength) ; break ; } ; if (psf->sf.seekable == 0 && (parsestage & HAVE_data)) break ; if (psf_ftell (psf) >= (psf->filelength - (2 * SIGNED_SIZEOF (dword)))) break ; if (chunk_size > 0 && chunk_size < 0xffff0000) { dword = chunk_size ; psf_binheader_readf (psf, "j", dword - 24) ; } ; } ; /* while (1) */ if (psf->dataoffset <= 0) return SFE_W64_NO_DATA ; if (psf->sf.channels < 1) return SFE_CHANNEL_COUNT_ZERO ; if (psf->sf.channels >= SF_MAX_CHANNELS) return SFE_CHANNEL_COUNT ; psf->endian = SF_ENDIAN_LITTLE ; /* All W64 files are little endian. */ if (psf_ftell (psf) != psf->dataoffset) psf_fseek (psf, psf->dataoffset, SEEK_SET) ; if (psf->blockwidth) { if (psf->filelength - psf->dataoffset < psf->datalength) psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ; else psf->sf.frames = psf->datalength / psf->blockwidth ; } ; switch (format) { case WAVE_FORMAT_PCM : case WAVE_FORMAT_EXTENSIBLE : /* extensible might be FLOAT, MULAW, etc as well! */ psf->sf.format = SF_FORMAT_W64 | u_bitwidth_to_subformat (psf->bytewidth * 8) ; break ; case WAVE_FORMAT_MULAW : psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_ULAW) ; break ; case WAVE_FORMAT_ALAW : psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_ALAW) ; break ; case WAVE_FORMAT_MS_ADPCM : psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_MS_ADPCM) ; *blockalign = wav_fmt->msadpcm.blockalign ; *framesperblock = wav_fmt->msadpcm.samplesperblock ; break ; case WAVE_FORMAT_IMA_ADPCM : psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_IMA_ADPCM) ; *blockalign = wav_fmt->ima.blockalign ; *framesperblock = wav_fmt->ima.samplesperblock ; break ; case WAVE_FORMAT_GSM610 : psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_GSM610) ; break ; case WAVE_FORMAT_IEEE_FLOAT : psf->sf.format = SF_FORMAT_W64 ; psf->sf.format |= (psf->bytewidth == 8) ? SF_FORMAT_DOUBLE : SF_FORMAT_FLOAT ; break ; default : return SFE_UNIMPLEMENTED ; } ; return 0 ; } /* w64_read_header */
static void file_truncate_test (const char *filename) { SF_PRIVATE sf_data, *psf ; unsigned char buffer [256] ; int k ; /* ** Open a new file and write two blocks of data to the file. After each ** write, test that psf_get_filelen() returns the new length. */ printf (" %-24s : ", "file_truncate_test") ; fflush (stdout) ; memset (&sf_data, 0, sizeof (sf_data)) ; memset (buffer, 0xEE, sizeof (buffer)) ; psf = &sf_data ; strncpy (psf->filename, filename, sizeof (psf->filename)) ; /* ** Open the file write mode, write 0xEE data and then extend the file ** using truncate (the extended data should be 0x00). */ psf->mode = SFM_WRITE ; test_open_or_die (psf, __LINE__) ; test_write_or_die (psf, buffer, sizeof (buffer) / 2, 1, sizeof (buffer) / 2, __LINE__) ; psf_ftruncate (psf, sizeof (buffer)) ; test_close_or_die (psf, __LINE__) ; /* Open the file in read mode and check the data. */ psf->mode = SFM_READ ; test_open_or_die (psf, __LINE__) ; test_read_or_die (psf, buffer, sizeof (buffer), 1, sizeof (buffer), __LINE__) ; test_close_or_die (psf, __LINE__) ; for (k = 0 ; k < SIGNED_SIZEOF (buffer) / 2 ; k++) if (buffer [k] != 0xEE) { printf ("\n\nLine %d : buffer [%d] = %d (should be 0xEE)\n\n", __LINE__, k, buffer [k]) ; exit (1) ; } ; for (k = SIGNED_SIZEOF (buffer) / 2 ; k < SIGNED_SIZEOF (buffer) ; k++) if (buffer [k] != 0) { printf ("\n\nLine %d : buffer [%d] = %d (should be 0)\n\n", __LINE__, k, buffer [k]) ; exit (1) ; } ; /* Open the file in read/write and shorten the file using truncate. */ psf->mode = SFM_RDWR ; test_open_or_die (psf, __LINE__) ; psf_ftruncate (psf, sizeof (buffer) / 4) ; test_close_or_die (psf, __LINE__) ; /* Check the file length. */ psf->mode = SFM_READ ; test_open_or_die (psf, __LINE__) ; test_seek_or_die (psf, 0, SEEK_END, SIGNED_SIZEOF (buffer) / 4, __LINE__) ; test_close_or_die (psf, __LINE__) ; puts ("ok") ; } /* file_truncate_test */
static void file_read_write_test (const char *filename) { static int data_out [512] ; static int data_in [512] ; SF_PRIVATE sf_data, *psf ; sf_count_t retval ; /* ** Open a new file and write two blocks of data to the file. After each ** write, test that psf_get_filelen() returns the new length. */ printf (" %-24s : ", "file_write_test") ; fflush (stdout) ; memset (&sf_data, 0, sizeof (sf_data)) ; psf = &sf_data ; strncpy (psf->filename, filename, sizeof (psf->filename)) ; /* Test file open in write mode. */ psf->mode = SFM_WRITE ; test_open_or_die (psf, __LINE__) ; make_data (data_out, ARRAY_LEN (data_out), 1) ; test_write_or_die (psf, data_out, sizeof (data_out [0]), ARRAY_LEN (data_out), sizeof (data_out), __LINE__) ; if ((retval = psf_get_filelen (psf)) != sizeof (data_out)) { printf ("\n\nLine %d: file length after write is not correct (%ld should be %d).\n\n", __LINE__, (long) retval, (int) sizeof (data_out)) ; if (retval == 0) printf ("An fsync() may be necessary before fstat() in psf_get_filelen().\n\n") ; exit (1) ; } ; make_data (data_out, ARRAY_LEN (data_out), 2) ; test_write_or_die (psf, data_out, ARRAY_LEN (data_out), sizeof (data_out [0]), 2 * sizeof (data_out), __LINE__) ; if ((retval = psf_get_filelen (psf)) != 2 * sizeof (data_out)) { printf ("\n\nLine %d: file length after write is not correct. (%ld should be %d)\n\n", __LINE__, (long) retval, 2 * ((int) sizeof (data_out))) ; exit (1) ; } ; test_close_or_die (psf, __LINE__) ; puts ("ok") ; /* ** Now open the file in read mode, check the file length and check ** that the data is correct. */ printf (" %-24s : ", "file_read_test") ; fflush (stdout) ; /* Test file open in write mode. */ psf->mode = SFM_READ ; test_open_or_die (psf, __LINE__) ; make_data (data_out, ARRAY_LEN (data_out), 1) ; test_read_or_die (psf, data_in, 1, sizeof (data_in), sizeof (data_in), __LINE__) ; test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; make_data (data_out, ARRAY_LEN (data_out), 2) ; test_read_or_die (psf, data_in, sizeof (data_in [0]), ARRAY_LEN (data_in), 2 * sizeof (data_in), __LINE__) ; test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; test_close_or_die (psf, __LINE__) ; puts ("ok") ; /* ** Open the file in read/write mode, seek around a bit and then seek to ** the end of the file and write another block of data (3rd block). Then ** go back and check that all three blocks are correct. */ printf (" %-24s : ", "file_seek_test") ; fflush (stdout) ; /* Test file open in read/write mode. */ psf->mode = SFM_RDWR ; test_open_or_die (psf, __LINE__) ; test_seek_or_die (psf, 0, SEEK_SET, 0, __LINE__) ; test_seek_or_die (psf, 0, SEEK_END, 2 * SIGNED_SIZEOF (data_out), __LINE__) ; test_seek_or_die (psf, -1 * SIGNED_SIZEOF (data_out), SEEK_CUR, (sf_count_t) sizeof (data_out), __LINE__) ; test_seek_or_die (psf, SIGNED_SIZEOF (data_out), SEEK_CUR, 2 * SIGNED_SIZEOF (data_out), __LINE__) ; make_data (data_out, ARRAY_LEN (data_out), 3) ; test_write_or_die (psf, data_out, sizeof (data_out [0]), ARRAY_LEN (data_out), 3 * sizeof (data_out), __LINE__) ; test_seek_or_die (psf, 0, SEEK_SET, 0, __LINE__) ; make_data (data_out, ARRAY_LEN (data_out), 1) ; test_read_or_die (psf, data_in, 1, sizeof (data_in), sizeof (data_in), __LINE__) ; test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; test_seek_or_die (psf, 2 * SIGNED_SIZEOF (data_out), SEEK_SET, 2 * SIGNED_SIZEOF (data_out), __LINE__) ; make_data (data_out, ARRAY_LEN (data_out), 3) ; test_read_or_die (psf, data_in, 1, sizeof (data_in), 3 * sizeof (data_in), __LINE__) ; test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; test_seek_or_die (psf, SIGNED_SIZEOF (data_out), SEEK_SET, SIGNED_SIZEOF (data_out), __LINE__) ; make_data (data_out, ARRAY_LEN (data_out), 2) ; test_read_or_die (psf, data_in, 1, sizeof (data_in), 2 * sizeof (data_in), __LINE__) ; test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; test_close_or_die (psf, __LINE__) ; puts ("ok") ; /* ** Now test operations with a non-zero psf->fileoffset field. This field ** sets an artificial file start positions so that a seek to the start of ** the file will actually be a seek to the value given by psf->fileoffset. */ printf (" %-24s : ", "file_offset_test") ; fflush (stdout) ; /* Test file open in read/write mode. */ psf->mode = SFM_RDWR ; psf->fileoffset = sizeof (data_out [0]) * ARRAY_LEN (data_out) ; test_open_or_die (psf, __LINE__) ; if ((retval = psf_get_filelen (psf)) != 3 * sizeof (data_out)) { printf ("\n\nLine %d: file length after write is not correct. (%ld should be %d)\n\n", __LINE__, (long) retval, 3 * ((int) sizeof (data_out))) ; exit (1) ; } ; test_seek_or_die (psf, SIGNED_SIZEOF (data_out), SEEK_SET, SIGNED_SIZEOF (data_out), __LINE__) ; make_data (data_out, ARRAY_LEN (data_out), 5) ; test_write_or_die (psf, data_out, sizeof (data_out [0]), ARRAY_LEN (data_out), 2 * sizeof (data_out), __LINE__) ; test_close_or_die (psf, __LINE__) ; /* final test with psf->fileoffset == 0. */ psf->mode = SFM_RDWR ; psf->fileoffset = 0 ; test_open_or_die (psf, __LINE__) ; if ((retval = psf_get_filelen (psf)) != 3 * sizeof (data_out)) { printf ("\n\nLine %d: file length after write is not correct. (%ld should be %d)\n\n", __LINE__, (long) retval, 3 * ((int) sizeof (data_out))) ; exit (1) ; } ; make_data (data_out, ARRAY_LEN (data_out), 1) ; test_read_or_die (psf, data_in, 1, sizeof (data_in), sizeof (data_in), __LINE__) ; test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; make_data (data_out, ARRAY_LEN (data_out), 2) ; test_read_or_die (psf, data_in, 1, sizeof (data_in), 2 * sizeof (data_in), __LINE__) ; test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; make_data (data_out, ARRAY_LEN (data_out), 5) ; test_read_or_die (psf, data_in, 1, sizeof (data_in), 3 * sizeof (data_in), __LINE__) ; test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; test_close_or_die (psf, __LINE__) ; puts ("ok") ; } /* file_read_write_test */
static int mat4_read_header (SF_PRIVATE *psf) { int marker, rows, cols, imag ; unsigned namesize ; double value ; const char *marker_str ; char name [64] ; psf_binheader_readf (psf, "pm", 0, &marker) ; /* MAT4 file must start with a double for the samplerate. */ if (marker == MAT4_BE_DOUBLE) { psf->endian = psf->rwf_endian = SF_ENDIAN_BIG ; marker_str = "big endian double" ; } else if (marker == MAT4_LE_DOUBLE) { psf->endian = psf->rwf_endian = SF_ENDIAN_LITTLE ; marker_str = "little endian double" ; } else return SFE_UNIMPLEMENTED ; psf_log_printf (psf, "GNU Octave 2.0 / MATLAB v4.2 format\nMarker : %s\n", marker_str) ; psf_binheader_readf (psf, "444", &rows, &cols, &imag) ; psf_log_printf (psf, " Rows : %d\n Cols : %d\n Imag : %s\n", rows, cols, imag ? "True" : "False") ; psf_binheader_readf (psf, "4", &namesize) ; if (namesize >= SIGNED_SIZEOF (name)) return SFE_MAT4_BAD_NAME ; psf_binheader_readf (psf, "b", name, namesize) ; name [namesize] = 0 ; psf_log_printf (psf, " Name : %s\n", name) ; psf_binheader_readf (psf, "d", &value) ; snprintf (psf->u.cbuf, sizeof (psf->u.cbuf), " Value : %f\n", value) ; psf_log_printf (psf, psf->u.cbuf) ; if ((rows != 1) || (cols != 1)) return SFE_MAT4_NO_SAMPLERATE ; psf->sf.samplerate = (int)lrint(value); // kengo: /* Now write out the audio data. */ psf_binheader_readf (psf, "m", &marker) ; psf_log_printf (psf, "Marker : %s\n", mat4_marker_to_str (marker)) ; psf_binheader_readf (psf, "444", &rows, &cols, &imag) ; psf_log_printf (psf, " Rows : %d\n Cols : %d\n Imag : %s\n", rows, cols, imag ? "True" : "False") ; psf_binheader_readf (psf, "4", &namesize) ; if (namesize >= SIGNED_SIZEOF (name)) return SFE_MAT4_BAD_NAME ; psf_binheader_readf (psf, "b", name, namesize) ; name [namesize] = 0 ; psf_log_printf (psf, " Name : %s\n", name) ; psf->dataoffset = psf_ftell (psf) ; if (rows == 0 && cols == 0) { psf_log_printf (psf, "*** Error : zero channel count.\n") ; return SFE_CHANNEL_COUNT_ZERO ; } ; psf->sf.channels = rows ; psf->sf.frames = cols ; psf->sf.format = psf->endian | SF_FORMAT_MAT4 ; switch (marker) { case MAT4_BE_DOUBLE : case MAT4_LE_DOUBLE : psf->sf.format |= SF_FORMAT_DOUBLE ; psf->bytewidth = 8 ; break ; case MAT4_BE_FLOAT : case MAT4_LE_FLOAT : psf->sf.format |= SF_FORMAT_FLOAT ; psf->bytewidth = 4 ; break ; case MAT4_BE_PCM_32 : case MAT4_LE_PCM_32 : psf->sf.format |= SF_FORMAT_PCM_32 ; psf->bytewidth = 4 ; break ; case MAT4_BE_PCM_16 : case MAT4_LE_PCM_16 : psf->sf.format |= SF_FORMAT_PCM_16 ; psf->bytewidth = 2 ; break ; default : psf_log_printf (psf, "*** Error : Bad marker %08X\n", marker) ; return SFE_UNIMPLEMENTED ; } ; if ((psf->filelength - psf->dataoffset) < psf->sf.channels * psf->sf.frames * psf->bytewidth) { psf_log_printf (psf, "*** File seems to be truncated. %D <--> %D\n", psf->filelength - psf->dataoffset, psf->sf.channels * psf->sf.frames * psf->bytewidth) ; } else if ((psf->filelength - psf->dataoffset) > psf->sf.channels * psf->sf.frames * psf->bytewidth) psf->dataend = psf->dataoffset + rows * cols * psf->bytewidth ; psf->datalength = psf->filelength - psf->dataoffset - psf->dataend ; psf->sf.sections = 1 ; return 0 ; } /* mat4_read_header */
static int caf_read_header (SF_PRIVATE *psf) { CAF_PRIVATE *pcaf ; BUF_UNION ubuf ; DESC_CHUNK desc ; sf_count_t chunk_size ; double srate ; short version, flags ; int marker, k, have_data = 0, error ; if ((pcaf = psf->container_data) == NULL) return SFE_INTERNAL ; memset (&desc, 0, sizeof (desc)) ; /* Set position to start of file to begin reading header. */ psf_binheader_readf (psf, "pmE2E2", 0, &marker, &version, &flags) ; psf_log_printf (psf, "%M\n Version : %d\n Flags : %x\n", marker, version, flags) ; if (marker != caff_MARKER) return SFE_CAF_NOT_CAF ; psf_binheader_readf (psf, "mE8b", &marker, &chunk_size, ubuf.ucbuf, 8) ; srate = double64_be_read (ubuf.ucbuf) ; snprintf (ubuf.cbuf, sizeof (ubuf.cbuf), "%5.3f", srate) ; psf_log_printf (psf, "%M : %D\n Sample rate : %s\n", marker, chunk_size, ubuf.cbuf) ; if (marker != desc_MARKER) return SFE_CAF_NO_DESC ; if (chunk_size < SIGNED_SIZEOF (DESC_CHUNK)) { psf_log_printf (psf, "**** Chunk size too small. Should be > 32 bytes.\n") ; return SFE_MALFORMED_FILE ; } ; psf->sf.samplerate = lrint (srate) ; psf_binheader_readf (psf, "mE44444", &desc.fmt_id, &desc.fmt_flags, &desc.pkt_bytes, &desc.frames_per_packet, &desc.channels_per_frame, &desc.bits_per_chan) ; psf_log_printf (psf, " Format id : %M\n Format flags : %x\n Bytes / packet : %u\n" " Frames / packet : %u\n Channels / frame : %u\n Bits / channel : %u\n", desc.fmt_id, desc.fmt_flags, desc.pkt_bytes, desc.frames_per_packet, desc.channels_per_frame, desc.bits_per_chan) ; if (desc.channels_per_frame > SF_MAX_CHANNELS) { psf_log_printf (psf, "**** Bad channels per frame value %u.\n", desc.channels_per_frame) ; return SFE_MALFORMED_FILE ; } ; if (chunk_size > SIGNED_SIZEOF (DESC_CHUNK)) psf_binheader_readf (psf, "j", (int) (chunk_size - sizeof (DESC_CHUNK))) ; psf->sf.channels = desc.channels_per_frame ; while (1) { marker = 0 ; chunk_size = 0 ; psf_binheader_readf (psf, "mE8", &marker, &chunk_size) ; if (marker == 0) { sf_count_t pos = psf_ftell (psf) ; psf_log_printf (psf, "Have 0 marker at position %D (0x%x).\n", pos, pos) ; break ; } ; if (chunk_size < 0) { psf_log_printf (psf, "%M : %D *** Should be >= 0 ***\n", marker, chunk_size) ; break ; } ; psf_store_read_chunk_u32 (&psf->rchunks, marker, psf_ftell (psf), chunk_size) ; switch (marker) { case peak_MARKER : psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ; if (chunk_size != CAF_PEAK_CHUNK_SIZE (psf->sf.channels)) { psf_binheader_readf (psf, "j", make_size_t (chunk_size)) ; psf_log_printf (psf, "*** File PEAK chunk %D should be %d.\n", chunk_size, CAF_PEAK_CHUNK_SIZE (psf->sf.channels)) ; return SFE_CAF_BAD_PEAK ; } ; if ((psf->peak_info = peak_info_calloc (psf->sf.channels)) == NULL) return SFE_MALLOC_FAILED ; /* read in rest of PEAK chunk. */ psf_binheader_readf (psf, "E4", & (psf->peak_info->edit_number)) ; psf_log_printf (psf, " edit count : %d\n", psf->peak_info->edit_number) ; psf_log_printf (psf, " Ch Position Value\n") ; for (k = 0 ; k < psf->sf.channels ; k++) { sf_count_t position ; float value ; psf_binheader_readf (psf, "Ef8", &value, &position) ; psf->peak_info->peaks [k].value = value ; psf->peak_info->peaks [k].position = position ; snprintf (ubuf.cbuf, sizeof (ubuf.cbuf), " %2d %-12" PRId64 " %g\n", k, position, value) ; psf_log_printf (psf, ubuf.cbuf) ; } ; psf->peak_info->peak_loc = SF_PEAK_START ; break ; case chan_MARKER : if (chunk_size < 12) { psf_log_printf (psf, "%M : %D (should be >= 12)\n", marker, chunk_size) ; psf_binheader_readf (psf, "j", make_size_t (chunk_size)) ; break ; } psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ; if ((error = caf_read_chanmap (psf, chunk_size))) return error ; break ; case free_MARKER : psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ; psf_binheader_readf (psf, "j", make_size_t (chunk_size)) ; break ; case data_MARKER : psf_binheader_readf (psf, "E4", &k) ; if (chunk_size == -1) { psf_log_printf (psf, "%M : -1\n") ; chunk_size = psf->filelength - psf->headindex ; } else if (psf->filelength > 0 && chunk_size > psf->filelength - psf->headindex + 10) { psf_log_printf (psf, "%M : %D (should be %D)\n", marker, chunk_size, psf->filelength - psf->headindex - 8) ; psf->datalength = psf->filelength - psf->headindex - 8 ; } else { psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ; /* Subtract the 4 bytes of the 'edit' field above. */ psf->datalength = chunk_size - 4 ; } ; psf_log_printf (psf, " edit : %u\n", k) ; psf->dataoffset = psf->headindex ; if (psf->datalength + psf->dataoffset < psf->filelength) psf->dataend = psf->datalength + psf->dataoffset ; psf_binheader_readf (psf, "j", make_size_t (psf->datalength)) ; have_data = 1 ; break ; case kuki_MARKER : psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ; pcaf->alac.kuki_offset = psf_ftell (psf) - 12 ; psf_binheader_readf (psf, "j", make_size_t (chunk_size)) ; break ; case pakt_MARKER : if (chunk_size < 24) { psf_log_printf (psf, "%M : %D (should be > 24)\n", marker, chunk_size) ; return SFE_MALFORMED_FILE ; } else if (chunk_size > psf->filelength - psf->headindex) { psf_log_printf (psf, "%M : %D (should be < %D)\n", marker, chunk_size, psf->filelength - psf->headindex) ; return SFE_MALFORMED_FILE ; } else psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ; psf_binheader_readf (psf, "E8844", &pcaf->alac.packets, &pcaf->alac.valid_frames, &pcaf->alac.priming_frames, &pcaf->alac.remainder_frames) ; psf_log_printf (psf, " Packets : %D\n" " Valid frames : %D\n" " Priming frames : %d\n" " Remainder frames : %d\n", pcaf->alac.packets, pcaf->alac.valid_frames, pcaf->alac.priming_frames, pcaf->alac.remainder_frames ) ; if (pcaf->alac.packets == 0 && pcaf->alac.valid_frames == 0 && pcaf->alac.priming_frames == 0 && pcaf->alac.remainder_frames == 0) psf_log_printf (psf, "*** 'pakt' chunk header is all zero.\n") ; pcaf->alac.pakt_offset = psf_ftell (psf) - 12 ; psf_binheader_readf (psf, "j", make_size_t (chunk_size) - 24) ; break ; case info_MARKER : if (chunk_size < 4) { psf_log_printf (psf, "%M : %D (should be > 4)\n", marker, chunk_size) ; return SFE_MALFORMED_FILE ; } else if (chunk_size > psf->filelength - psf->headindex) { psf_log_printf (psf, "%M : %D (should be < %D)\n", marker, chunk_size, psf->filelength - psf->headindex) ; return SFE_MALFORMED_FILE ; } ; psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ; caf_read_strings (psf, chunk_size) ; break ; default : psf_log_printf (psf, "%M : %D (skipped)\n", marker, chunk_size) ; psf_binheader_readf (psf, "j", make_size_t (chunk_size)) ; break ; } ; if (marker != data_MARKER && chunk_size >= 0xffffff00) break ; if (! psf->sf.seekable && have_data) break ; if (psf_ftell (psf) >= psf->filelength - SIGNED_SIZEOF (chunk_size)) { psf_log_printf (psf, "End\n") ; break ; } ; } ; if (have_data == 0) { psf_log_printf (psf, "**** Error, could not find 'data' chunk.\n") ; return SFE_MALFORMED_FILE ; } ; psf->endian = (desc.fmt_flags & 2) ? SF_ENDIAN_LITTLE : SF_ENDIAN_BIG ; psf_fseek (psf, psf->dataoffset, SEEK_SET) ; if ((psf->sf.format = decode_desc_chunk (psf, &desc)) == 0) return SFE_UNSUPPORTED_ENCODING ; if (psf->bytewidth > 0) psf->sf.frames = psf->datalength / psf->bytewidth ; return 0 ; } /* caf_read_header */
static int mat5_read_header (SF_PRIVATE *psf) { char name [32] ; short version, endian ; int type, size, flags1, flags2, rows, cols ; psf_binheader_readf (psf, "pb", 0, psf->u.scbuf, 124) ; psf->u.scbuf [125] = 0 ; if (strlen (psf->u.scbuf) >= 124) return SFE_UNIMPLEMENTED ; if (strstr (psf->u.cbuf, "MATLAB 5.0 MAT-file") == psf->u.cbuf) psf_log_printf (psf, "%s\n", psf->u.scbuf) ; psf_binheader_readf (psf, "E22", &version, &endian) ; if (endian == MI_MARKER) { psf->endian = psf->rwf_endian = SF_ENDIAN_BIG ; if (CPU_IS_LITTLE_ENDIAN) version = ENDSWAP_SHORT (version) ; } else if (endian == IM_MARKER) { psf->endian = psf->rwf_endian = SF_ENDIAN_LITTLE ; if (CPU_IS_BIG_ENDIAN) version = ENDSWAP_SHORT (version) ; } else return SFE_MAT5_BAD_ENDIAN ; if ((CPU_IS_LITTLE_ENDIAN && endian == IM_MARKER) || (CPU_IS_BIG_ENDIAN && endian == MI_MARKER)) version = ENDSWAP_SHORT (version) ; psf_log_printf (psf, "Version : 0x%04X\n", version) ; psf_log_printf (psf, "Endian : 0x%04X => %s\n", endian, (psf->endian == SF_ENDIAN_LITTLE) ? "Little" : "Big") ; /*========================================================*/ psf_binheader_readf (psf, "44", &type, &size) ; psf_log_printf (psf, "Block\n Type : %X Size : %d\n", type, size) ; if (type != MAT5_TYPE_ARRAY) return SFE_MAT5_NO_BLOCK ; psf_binheader_readf (psf, "44", &type, &size) ; psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ; if (type != MAT5_TYPE_UINT32) return SFE_MAT5_NO_BLOCK ; psf_binheader_readf (psf, "44", &flags1, &flags2) ; psf_log_printf (psf, " Flg1 : %X Flg2 : %d\n", flags1, flags2) ; psf_binheader_readf (psf, "44", &type, &size) ; psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ; if (type != MAT5_TYPE_INT32) return SFE_MAT5_NO_BLOCK ; psf_binheader_readf (psf, "44", &rows, &cols) ; psf_log_printf (psf, " Rows : %X Cols : %d\n", rows, cols) ; if (rows != 1 || cols != 1) return SFE_MAT5_SAMPLE_RATE ; psf_binheader_readf (psf, "4", &type) ; if (type == MAT5_TYPE_SCHAR) { psf_binheader_readf (psf, "4", &size) ; psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ; if (size > SIGNED_SIZEOF (name) - 1) { psf_log_printf (psf, "Error : Bad name length.\n") ; return SFE_MAT5_NO_BLOCK ; } ; psf_binheader_readf (psf, "bj", name, size, (8 - (size % 8)) % 8) ; name [size] = 0 ; } else if ((type & 0xFFFF) == MAT5_TYPE_SCHAR) { size = type >> 16 ; if (size > 4) { psf_log_printf (psf, "Error : Bad name length.\n") ; return SFE_MAT5_NO_BLOCK ; } ; psf_log_printf (psf, " Type : %X\n", type) ; psf_binheader_readf (psf, "4", &name) ; name [size] = 0 ; }
static int voc_read_header (SF_PRIVATE *psf) { VOC_DATA *pvoc ; char creative [20] ; unsigned char block_type, rate_byte ; short version, checksum, encoding, dataoffset ; int offset ; /* Set position to start of file to begin reading header. */ offset = psf_binheader_readf (psf, "pb", 0, creative, SIGNED_SIZEOF (creative)) ; if (creative [sizeof (creative) - 1] != 0x1A) return SFE_VOC_NO_CREATIVE ; /* Terminate the string. */ creative [sizeof (creative) - 1] = 0 ; if (strcmp ("Creative Voice File", creative)) return SFE_VOC_NO_CREATIVE ; psf_log_printf (psf, "%s\n", creative) ; offset += psf_binheader_readf (psf, "e222", &dataoffset, &version, &checksum) ; psf->dataoffset = dataoffset ; psf_log_printf (psf, "dataoffset : %d\n" "version : 0x%X\n" "checksum : 0x%X\n", psf->dataoffset, version, checksum) ; if (version != 0x010A && version != 0x0114) return SFE_VOC_BAD_VERSION ; if (! (psf->codec_data = malloc (sizeof (VOC_DATA)))) return SFE_MALLOC_FAILED ; pvoc = (VOC_DATA*) psf->codec_data ; memset (pvoc, 0, sizeof (VOC_DATA)) ; /* Set the default encoding now. */ psf->sf.format = SF_FORMAT_VOC ; /* Major format */ encoding = SF_FORMAT_PCM_U8 ; /* Minor format */ psf->endian = SF_ENDIAN_LITTLE ; while (1) { char header [256] ; unsigned size ; short count ; block_type = 0 ; offset += psf_binheader_readf (psf, "1", &block_type) ; switch (block_type) { case VOC_ASCII : offset += psf_binheader_readf (psf, "e3", &size) ; psf_log_printf (psf, " ASCII : %d\n", size) ; if (size < sizeof (header) - 1) { offset += psf_binheader_readf (psf, "b", header, size) ; header [size] = 0 ; psf_log_printf (psf, " text : %s\n", header) ; continue ; } offset += psf_binheader_readf (psf, "j", size) ; continue ; case VOC_REPEAT : offset += psf_binheader_readf (psf, "e32", &size, &count) ; psf_log_printf (psf, " Repeat : %d\n", count) ; continue ; case VOC_SOUND_DATA : case VOC_EXTENDED : case VOC_EXTENDED_II : break ; default : psf_log_printf (psf, "*** Weird block marker (%d)\n", block_type) ; } ; break ; } ; if (block_type == VOC_SOUND_DATA) { unsigned char compression ; int size ; offset += psf_binheader_readf (psf, "e311", &size, &rate_byte, &compression) ; psf->sf.samplerate = 1000000 / (256 - (rate_byte & 0xFF)) ; psf_log_printf (psf, " Sound Data : %d\n sr : %d => %dHz\n comp : %d\n", size, rate_byte, psf->sf.samplerate, compression) ; if (offset + size - 1 > psf->filelength) { psf_log_printf (psf, "Seems to be a truncated file.\n") ; psf_log_printf (psf, "offset: %d size: %d sum: %d filelength: %D\n", offset, size, offset + size, psf->filelength) ; return SFE_VOC_BAD_SECTIONS ; } else if (psf->filelength - offset - size > 4) { psf_log_printf (psf, "Seems to be a multi-segment file (#1).\n") ; psf_log_printf (psf, "offset: %d size: %d sum: %d filelength: %D\n", offset, size, offset + size, psf->filelength) ; return SFE_VOC_BAD_SECTIONS ; } ; psf->dataoffset = offset ; psf->dataend = psf->filelength - 1 ; psf->sf.channels = 1 ; psf->bytewidth = 1 ; psf->sf.format = SF_FORMAT_VOC | SF_FORMAT_PCM_U8 ; return 0 ; } ; if (block_type == VOC_EXTENDED) { unsigned char pack, stereo, compression ; unsigned short rate_short ; int size ; offset += psf_binheader_readf (psf, "e3211", &size, &rate_short, &pack, &stereo) ; psf_log_printf (psf, " Extended : %d\n", size) ; if (size == 4) psf_log_printf (psf, " size : 4\n") ; else psf_log_printf (psf, " size : %d (should be 4)\n", size) ; psf_log_printf (psf, " pack : %d\n" " stereo : %s\n", pack, (stereo ? "yes" : "no")) ; if (stereo) { psf->sf.channels = 2 ; psf->sf.samplerate = 128000000 / (65536 - rate_short) ; } else { psf->sf.channels = 1 ; psf->sf.samplerate = 256000000 / (65536 - rate_short) ; } ; psf_log_printf (psf, " sr : %d => %dHz\n", (rate_short & 0xFFFF), psf->sf.samplerate) ; offset += psf_binheader_readf (psf, "1", &block_type) ; if (block_type != VOC_SOUND_DATA) { psf_log_printf (psf, "*** Expecting VOC_SOUND_DATA section.\n") ; return SFE_VOC_BAD_FORMAT ; } ; offset += psf_binheader_readf (psf, "e311", &size, &rate_byte, &compression) ; psf_log_printf (psf, " Sound Data : %d\n" " sr : %d\n" " comp : %d\n", size, rate_byte, compression) ; if (offset + size - 1 > psf->filelength) { psf_log_printf (psf, "Seems to be a truncated file.\n") ; psf_log_printf (psf, "offset: %d size: %d sum: %d filelength: %D\n", offset, size, offset + size, psf->filelength) ; return SFE_VOC_BAD_SECTIONS ; } else if (offset + size - 1 < psf->filelength) { psf_log_printf (psf, "Seems to be a multi-segment file (#2).\n") ; psf_log_printf (psf, "offset: %d size: %d sum: %d filelength: %D\n", offset, size, offset + size, psf->filelength) ; return SFE_VOC_BAD_SECTIONS ; } ; psf->dataoffset = offset ; psf->dataend = psf->filelength - 1 ; psf->bytewidth = 1 ; psf->sf.format = SF_FORMAT_VOC | SF_FORMAT_PCM_U8 ; return 0 ; } if (block_type == VOC_EXTENDED_II) { unsigned char bitwidth, channels ; int size, fourbytes ; offset += psf_binheader_readf (psf, "e341124", &size, &psf->sf.samplerate, &bitwidth, &channels, &encoding, &fourbytes) ; if (size * 2 == psf->filelength - 39) { int temp_size = psf->filelength - 31 ; psf_log_printf (psf, " Extended II : %d (SoX bug: should be %d)\n", size, temp_size) ; size = temp_size ; } else psf_log_printf (psf, " Extended II : %d\n", size) ; psf_log_printf (psf, " sample rate : %d\n" " bit width : %d\n" " channels : %d\n", psf->sf.samplerate, bitwidth, channels) ; if (bitwidth == 16 && encoding == 0) { encoding = 4 ; psf_log_printf (psf, " encoding : 0 (SoX bug: should be 4 for 16 bit signed PCM)\n") ; } else psf_log_printf (psf, " encoding : %d => %s\n", encoding, voc_encoding2str (encoding)) ; psf_log_printf (psf, " fourbytes : %X\n", fourbytes) ; psf->sf.channels = channels ; psf->dataoffset = offset ; psf->dataend = psf->filelength - 1 ; if (size + 31 == psf->filelength + 1) { /* Hack for reading files produced using ** sf_command (SFC_UPDATE_HEADER_NOW). */ psf_log_printf (psf, "Missing zero byte at end of file.\n") ; size = psf->filelength - 30 ; psf->dataend = 0 ; } else if (size + 31 > psf->filelength) { psf_log_printf (psf, "Seems to be a truncated file.\n") ; size = psf->filelength - 31 ; } else if (size + 31 < psf->filelength) psf_log_printf (psf, "Seems to be a multi-segment file (#3).\n") ; switch (encoding) { case 0 : psf->sf.format = SF_FORMAT_VOC | SF_FORMAT_PCM_U8 ; psf->bytewidth = 1 ; break ; case 4 : psf->sf.format = SF_FORMAT_VOC | SF_FORMAT_PCM_16 ; psf->bytewidth = 2 ; break ; case 6 : psf->sf.format = SF_FORMAT_VOC | SF_FORMAT_ALAW ; psf->bytewidth = 1 ; break ; case 7 : psf->sf.format = SF_FORMAT_VOC | SF_FORMAT_ULAW ; psf->bytewidth = 1 ; break ; default : /* Unknown */ return SFE_UNKNOWN_FORMAT ; break ; } ; } ; return 0 ; } /* voc_read_header */
int rx2_open (SF_PRIVATE *psf) { int error, marker, length, glob_offset, slce_count ; int sdat_length = 0, slce_total = 0 ; /* So far only doing read. */ psf_binheader_readf (psf, "Epm4", 0, &marker, &length) ; if (marker != CAT_MARKER) { psf_log_printf (psf, "length : %d\n", length) ; return -1000 ; } ; if (length != psf->filelength - 8) psf_log_printf (psf, "%M : %d (should be %d)\n", marker, length, psf->filelength - 8) ; else psf_log_printf (psf, "%M : %d\n", marker, length) ; /* 'REX2' marker */ psf_binheader_readf (psf, "m", &marker) ; psf_log_printf (psf, "%M", marker) ; /* 'HEAD' marker */ psf_binheader_readf (psf, "m", &marker) ; psf_log_printf (psf, "%M\n", marker) ; /* Grab 'GLOB' offset. */ psf_binheader_readf (psf, "E4", &glob_offset) ; glob_offset += 0x14 ; /* Add the current file offset. */ /* Jump to offset 0x30 */ psf_binheader_readf (psf, "p", 0x30) ; /* Get name length */ length = 0 ; psf_binheader_readf (psf, "1", &length) ; if (length >= SIGNED_SIZEOF (psf->buffer)) { psf_log_printf (psf, " Text : %d *** Error : Too sf_count_t!\n") ; return -1001 ; } memset (psf->buffer, 0, SIGNED_SIZEOF (psf->buffer)) ; psf_binheader_readf (psf, "b", psf->buffer, length) ; psf_log_printf (psf, " Text : \"%s\"\n", psf->buffer) ; /* Jump to GLOB offset position. */ if (glob_offset & 1) glob_offset ++ ; psf_binheader_readf (psf, "p", glob_offset) ; slce_count = 0 ; /* GLOB */ while (1) { psf_binheader_readf (psf, "m", &marker) ; if (marker != SLCE_MARKER && slce_count > 0) { psf_log_printf (psf, " SLCE count : %d\n", slce_count) ; slce_count = 0 ; } switch (marker) { case GLOB_MARKER: psf_binheader_readf (psf, "E4", &length) ; psf_log_printf (psf, " %M : %d\n", marker, length) ; psf_binheader_readf (psf, "j", length) ; break ; case RECY_MARKER: psf_binheader_readf (psf, "E4", &length) ; psf_log_printf (psf, " %M : %d\n", marker, length) ; psf_binheader_readf (psf, "j", (length+1) & 0xFFFFFFFE) ; /* ?????? */ break ; case CAT_MARKER: psf_binheader_readf (psf, "E4", &length) ; psf_log_printf (psf, " %M : %d\n", marker, length) ; /*-psf_binheader_readf (psf, "j", length) ;-*/ break ; case DEVL_MARKER: psf_binheader_readf (psf, "mE4", &marker, &length) ; psf_log_printf (psf, " DEVL%M : %d\n", marker, length) ; if (length & 1) length ++ ; psf_binheader_readf (psf, "j", length) ; break ; case EQ_MARKER: case COMP_MARKER: psf_binheader_readf (psf, "E4", &length) ; psf_log_printf (psf, " %M : %d\n", marker, length) ; /* This is weird!!!! why make this (length - 1) */ if (length & 1) length ++ ; psf_binheader_readf (psf, "j", length) ; break ; case SLCL_MARKER: psf_log_printf (psf, " %M\n", marker) ; slce_count = 0 ; break ; case SLCE_MARKER: /*-psf_log_printf (psf, " %M\n", marker) ;-*/ psf_binheader_readf (psf, "E4", &length) ; /*-psf_log_printf (psf, " ???????? : 0x%X\n", length) ;-*/ psf_binheader_readf (psf, "E4", &length) ; /*-psf_log_printf (psf, " Start ? : %d\n", length) ;-*/ psf_binheader_readf (psf, "E4", &length) ; /*-psf_log_printf (psf, " Length ? : %d\n", length) ;-*/ slce_total += length ; psf_binheader_readf (psf, "E4", &length) ; /*-psf_log_printf (psf, " ???????? : 0x%X\n", length) ;-*/ slce_count ++ ; break ; case SINF_MARKER: psf_binheader_readf (psf, "E4", &length) ; psf_log_printf (psf, " %M : %d\n", marker, length) ; psf_binheader_readf (psf, "E2", &length) ; psf_log_printf (psf, " REX Version : %X ?\n", length) ; psf_binheader_readf (psf, "E44", &psf->sf.samplerate, &psf->sf.frames) ; psf_log_printf (psf, " Sample Rate : %d\n", psf->sf.samplerate) ; psf_log_printf (psf, " Frames : %d\n", psf->sf.frames) ; psf_binheader_readf (psf, "E4", &length) ; psf_log_printf (psf, " ??????????? : %d\n", length) ; psf_binheader_readf (psf, "E4", &length) ; psf_log_printf (psf, " ??????????? : %d\n", length) ; break ; case SDAT_MARKER: psf_binheader_readf (psf, "E4", &length) ; sdat_length = length ; /* Get the current offset. */ psf->dataoffset = psf_binheader_readf (psf, NULL) ; if (psf->dataoffset + length != psf->filelength) psf_log_printf (psf, " %M : %d (should be %d)\n", marker, length, psf->dataoffset + psf->filelength) ; else psf_log_printf (psf, " %M : %d\n", marker, length) ; break ; default : psf_log_printf (psf, "Unknown marker : 0x%X %M", marker, marker) ; return -1003 ; break ; } ; /* SDAT always last marker in file. */ if (marker == SDAT_MARKER) break ; } ; puts (psf->logbuffer) ; puts ("-----------------------------------") ; printf ("SDAT length : %d\n", sdat_length) ; printf ("SLCE samples : %d\n", slce_total) ; /* Two bytes per sample. */ printf ("Comp Ratio : %f:1\n", (2.0 * slce_total) / sdat_length) ; puts (" ") ; psf->logbuffer [0] = 0 ; /* OK, have the header althought not too sure what it all means. */ psf->endian = SF_ENDIAN_BIG ; psf->datalength = psf->filelength - psf->dataoffset ; if (psf_fseek (psf->filedes, psf->dataoffset, SEEK_SET)) return SFE_BAD_SEEK ; psf->sf.format = (SF_FORMAT_REX2 | SF_FORMAT_DWVW_12) ; psf->sf.channels = 1 ; psf->bytewidth = 2 ; psf->blockwidth = psf->sf.channels * psf->bytewidth ; if ((error = dwvw_init (psf, 16))) return error ; psf->close = rx2_close ; if (! psf->sf.frames && psf->blockwidth) psf->sf.frames = psf->datalength / psf->blockwidth ; /* All done. */ return 0 ; } /* rx2_open */
int psf_store_string (SF_PRIVATE *psf, int str_type, const char *str) { char new_str [128] ; size_t len_remaining, str_len ; int k, str_flags ; if (str == NULL) return SFE_STR_BAD_STRING ; str_len = strlen (str) ; /* A few extra checks for write mode. */ if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) { if ((psf->str_flags & SF_STR_ALLOW_START) == 0) return SFE_STR_NO_SUPPORT ; if (psf->have_written && (psf->str_flags & SF_STR_ALLOW_END) == 0) return SFE_STR_NO_SUPPORT ; /* Only allow zero length strings for software. */ if (str_type != SF_STR_SOFTWARE && str_len == 0) return SFE_STR_BAD_STRING ; } ; /* Find the next free slot in table. */ for (k = 0 ; k < SF_MAX_STRINGS ; k++) { /* If we find a matching entry clear it. */ if (psf->strings [k].type == str_type) psf->strings [k].type = -1 ; if (psf->strings [k].type == 0) break ; } ; /* Determine flags */ str_flags = SF_STR_LOCATE_START ; if (psf->file.mode == SFM_RDWR || psf->have_written) { if ((psf->str_flags & SF_STR_ALLOW_END) == 0) return SFE_STR_NO_ADD_END ; str_flags = SF_STR_LOCATE_END ; } ; /* More sanity checking. */ if (k >= SF_MAX_STRINGS) return SFE_STR_MAX_COUNT ; if (k == 0 && psf->str_end != NULL) { psf_log_printf (psf, "SFE_STR_WEIRD : k == 0 && psf->str_end != NULL\n") ; return SFE_STR_WEIRD ; } ; if (k != 0 && psf->str_end == NULL) { psf_log_printf (psf, "SFE_STR_WEIRD : k != 0 && psf->str_end == NULL\n") ; return SFE_STR_WEIRD ; } ; /* Special case for the first string. */ if (k == 0) psf->str_end = psf->str_storage ; switch (str_type) { case SF_STR_SOFTWARE : /* In write mode, want to append libsndfile-version to string. */ if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) { if (strstr (str, PACKAGE) == NULL) { /* ** If the supplied string does not already contain a ** libsndfile-X.Y.Z component, then add it. */ if (strlen (str) == 0) snprintf (new_str, sizeof (new_str), "%s-%s", PACKAGE, VERSION) ; else snprintf (new_str, sizeof (new_str), "%s (%s-%s)", str, PACKAGE, VERSION) ; } else snprintf (new_str, sizeof (new_str), "%s", str) ; str = new_str ; } ; break ; case SF_STR_TITLE : case SF_STR_COPYRIGHT : case SF_STR_ARTIST : case SF_STR_COMMENT : case SF_STR_DATE : case SF_STR_ALBUM : case SF_STR_LICENSE : case SF_STR_TRACKNUMBER : case SF_STR_GENRE : break ; default : psf_log_printf (psf, "%s : SFE_STR_BAD_TYPE\n", __func__) ; return SFE_STR_BAD_TYPE ; } ; str_len = strlen (str) ; len_remaining = SIGNED_SIZEOF (psf->str_storage) - (psf->str_end - psf->str_storage) ; if (len_remaining < str_len + 2) return SFE_STR_MAX_DATA ; psf->strings [k].type = str_type ; psf->strings [k].str = psf->str_end ; psf->strings [k].flags = str_flags ; memcpy (psf->str_end, str, str_len + 1) ; /* Plus one to catch string terminator. */ psf->str_end += str_len + 1 ; psf->str_flags |= str_flags ; #if STRINGS_DEBUG psf_log_printf (psf, "str_storage : %X\n", (int) psf->str_storage) ; psf_log_printf (psf, "str_end : %X\n", (int) psf->str_end) ; psf_log_printf (psf, "sizeof (str_storage) : %d\n", SIGNED_SIZEOF (psf->str_storage)) ; psf_log_printf (psf, "used : %d\n", (int ) (psf->str_end - psf->str_storage)) ; psf_log_printf (psf, "remaining : %d\n", SIGNED_SIZEOF (psf->str_storage) - (psf->str_end - psf->str_storage)) ; hexdump (psf->str_storage, 300) ; #endif return 0 ; } /* psf_store_string */
static int caf_read_header (SF_PRIVATE *psf) { DESC_CHUNK desc ; sf_count_t chunk_size ; double srate ; short version, flags ; int marker, k, have_data = 0, error ; memset (&desc, 0, sizeof (desc)) ; /* Set position to start of file to begin reading header. */ psf_binheader_readf (psf, "pmE2E2", 0, &marker, &version, &flags) ; psf_log_printf (psf, "%M\n Version : %d\n Flags : %x\n", marker, version, flags) ; if (marker != caff_MARKER) return SFE_CAF_NOT_CAF ; psf_binheader_readf (psf, "mE8b", &marker, &chunk_size, psf->u.ucbuf, 8) ; srate = double64_be_read (psf->u.ucbuf) ; snprintf (psf->u.cbuf, sizeof (psf->u.cbuf), "%5.3f", srate) ; psf_log_printf (psf, "%M : %D\n Sample rate : %s\n", marker, chunk_size, psf->u.cbuf) ; if (marker != desc_MARKER) return SFE_CAF_NO_DESC ; if (chunk_size < SIGNED_SIZEOF (DESC_CHUNK)) { psf_log_printf (psf, "**** Chunk size too small. Should be > 32 bytes.\n") ; return SFE_MALFORMED_FILE ; } ; psf->sf.samplerate = lrint (srate) ; psf_binheader_readf (psf, "mE44444", &desc.fmt_id, &desc.fmt_flags, &desc.pkt_bytes, &desc.pkt_frames, &desc.channels_per_frame, &desc.bits_per_chan) ; psf_log_printf (psf, " Format id : %M\n Format flags : %x\n Bytes / packet : %u\n" " Frames / packet : %u\n Channels / frame : %u\n Bits / channel : %u\n", desc.fmt_id, desc.fmt_flags, desc.pkt_bytes, desc.pkt_frames, desc.channels_per_frame, desc.bits_per_chan) ; if (desc.channels_per_frame > SF_MAX_CHANNELS) { psf_log_printf (psf, "**** Bad channels per frame value %u.\n", desc.channels_per_frame) ; return SFE_MALFORMED_FILE ; } ; if (chunk_size > SIGNED_SIZEOF (DESC_CHUNK)) psf_binheader_readf (psf, "j", (int) (chunk_size - sizeof (DESC_CHUNK))) ; psf->sf.channels = desc.channels_per_frame ; while (have_data == 0 && psf_ftell (psf) < psf->filelength - SIGNED_SIZEOF (marker)) { psf_binheader_readf (psf, "mE8", &marker, &chunk_size) ; switch (marker) { case peak_MARKER : psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ; if (chunk_size != CAF_PEAK_CHUNK_SIZE (psf->sf.channels)) { psf_binheader_readf (psf, "j", (int) chunk_size) ; psf_log_printf (psf, "*** File PEAK chunk %D should be %d.\n", chunk_size, CAF_PEAK_CHUNK_SIZE (psf->sf.channels)) ; return SFE_CAF_BAD_PEAK ; } ; if ((psf->peak_info = peak_info_calloc (psf->sf.channels)) == NULL) return SFE_MALLOC_FAILED ; /* read in rest of PEAK chunk. */ psf_binheader_readf (psf, "E4", & (psf->peak_info->edit_number)) ; psf_log_printf (psf, " edit count : %d\n", psf->peak_info->edit_number) ; psf_log_printf (psf, " Ch Position Value\n") ; for (k = 0 ; k < psf->sf.channels ; k++) { sf_count_t position ; float value ; psf_binheader_readf (psf, "Ef8", &value, &position) ; psf->peak_info->peaks [k].value = value ; psf->peak_info->peaks [k].position = position ; snprintf (psf->u.cbuf, sizeof (psf->u.cbuf), " %2d %-12" PRId64 " %g\n", k, position, value) ; psf_log_printf (psf, psf->u.cbuf) ; } ; psf->peak_info->peak_loc = SF_PEAK_START ; break ; case chan_MARKER : if (chunk_size < 12) { psf_log_printf (psf, "%M : %D (should be >= 12)\n", marker, chunk_size) ; psf_binheader_readf (psf, "j", (int) chunk_size) ; break ; } psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ; if ((error = caf_read_chanmap (psf, chunk_size))) return error ; break ; case free_MARKER : psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ; psf_binheader_readf (psf, "j", (int) chunk_size) ; break ; case data_MARKER : psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ; psf_binheader_readf (psf, "E4", &k) ; psf_log_printf (psf, " edit : %u\n", k) ; have_data = 1 ; break ; default : psf_log_printf (psf, " %M : %D (skipped)\n", marker, chunk_size) ; psf_binheader_readf (psf, "j", (int) chunk_size) ; break ; } ; } ; if (have_data == 0) { psf_log_printf (psf, "**** Error, could not find 'data' chunk.\n") ; return SFE_MALFORMED_FILE ; } ; psf_log_printf (psf, "End\n") ; psf->dataoffset = psf_ftell (psf) ; psf->datalength = psf->filelength - psf->dataoffset ; psf->endian = (desc.fmt_flags & 2) ? SF_ENDIAN_LITTLE : SF_ENDIAN_BIG ; if ((psf->sf.format = decode_desc_chunk (psf, &desc)) == 0) return SFE_UNSUPPORTED_ENCODING ; if (psf->bytewidth > 0) psf->sf.frames = psf->datalength / psf->bytewidth ; return 0 ; } /* caf_read_header */
int psf_store_string (SF_PRIVATE *psf, int str_type, const char *str) { static char lsf_name [] = PACKAGE "-" VERSION ; static char bracket_name [] = " (" PACKAGE "-" VERSION ")" ; int k, str_len, len_remaining, str_flags ; if (str == NULL) return SFE_STR_BAD_STRING ; str_len = strlen (str) ; /* A few extra checks for write mode. */ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { if ((psf->str_flags & SF_STR_ALLOW_START) == 0) return SFE_STR_NO_SUPPORT ; if ((psf->str_flags & SF_STR_ALLOW_END) == 0) return SFE_STR_NO_SUPPORT ; /* Only allow zero length strings for software. */ if (str_type != SF_STR_SOFTWARE && str_len == 0) return SFE_STR_BAD_STRING ; } ; /* Determine flags */ str_flags = SF_STR_LOCATE_START ; if (psf->have_written) { if ((psf->str_flags & SF_STR_ALLOW_END) == 0) return SFE_STR_NO_ADD_END ; str_flags = SF_STR_LOCATE_END ; } ; /* Find next free slot in table. */ for (k = 0 ; k < SF_MAX_STRINGS ; k++) if (psf->strings [k].type == 0) break ; /* More sanity checking. */ if (k >= SF_MAX_STRINGS) return SFE_STR_MAX_COUNT ; if (k == 0 && psf->str_end != NULL) { psf_log_printf (psf, "SFE_STR_WEIRD : k == 0 && psf->str_end != NULL\n") ; return SFE_STR_WEIRD ; } ; if (k != 0 && psf->str_end == NULL) { psf_log_printf (psf, "SFE_STR_WEIRD : k != 0 && psf->str_end == NULL\n") ; return SFE_STR_WEIRD ; } ; /* Special case for the first string. */ if (k == 0) psf->str_end = psf->str_storage ; #if STRINGS_DEBUG psf_log_printf (psf, "str_storage : %X\n", (int) psf->str_storage) ; psf_log_printf (psf, "str_end : %X\n", (int) psf->str_end) ; psf_log_printf (psf, "sizeof (str_storage) : %d\n", SIGNED_SIZEOF (psf->str_storage)) ; #endif len_remaining = SIGNED_SIZEOF (psf->str_storage) - (psf->str_end - psf->str_storage) ; if (len_remaining < str_len + 2) return SFE_STR_MAX_DATA ; switch (str_type) { case SF_STR_SOFTWARE : /* In write mode, want to append libsndfile-version to string. */ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { psf->strings [k].type = str_type ; psf->strings [k].str = psf->str_end ; psf->strings [k].flags = str_flags ; memcpy (psf->str_end, str, str_len + 1) ; psf->str_end += str_len ; /* ** If the supplied string does not already contain a ** libsndfile-X.Y.Z component, then add it. */ if (strstr (str, PACKAGE) == NULL && len_remaining > (int) (strlen (bracket_name) + str_len + 2)) { if (strlen (str) == 0) strncat (psf->str_end, lsf_name, len_remaining) ; else strncat (psf->str_end, bracket_name, len_remaining) ; psf->str_end += strlen (psf->str_end) ; } ; /* Plus one to catch string terminator. */ psf->str_end += 1 ; break ; } ; /* Fall though if not write mode. */ case SF_STR_TITLE : case SF_STR_COPYRIGHT : case SF_STR_ARTIST : case SF_STR_COMMENT : case SF_STR_DATE : psf->strings [k].type = str_type ; psf->strings [k].str = psf->str_end ; psf->strings [k].flags = str_flags ; /* Plus one to catch string terminator. */ memcpy (psf->str_end, str, str_len + 1) ; psf->str_end += str_len + 1 ; break ; default : return SFE_STR_BAD_TYPE ; } ; psf->str_flags |= (psf->have_written) ? SF_STR_LOCATE_END : SF_STR_LOCATE_START ; #if STRINGS_DEBUG hexdump (psf->str_storage, 300) ; #endif return 0 ; } /* psf_store_string */
static void show_fstat_error (void) { static const char *filename = "fstat.dat" ; static char data [256] ; STATBUF statbuf ; int fd, mode, flags ; if (sizeof (statbuf.st_size) != sizeof (INT64)) { printf ("\n\nLine %d: Error, sizeof (statbuf.st_size) != 8.\n\n", __LINE__) ; return ; } ; puts ("\n64 bit fstat() test.\n--------------------") ; printf ("0) Create a file, write %d bytes and close it.\n", SIGNED_SIZEOF (data)) ; mode = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ; flags = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ; if ((fd = open (filename, mode, flags)) < 0) { printf ("\n\nLine %d: open() failed : %s\n\n", __LINE__, strerror (errno)) ; return ; } ; assert (write (fd, data, sizeof (data)) > 0) ; close (fd) ; printf ("1) Re-open file in read/write mode and write another %d bytes at the end.\n", SIGNED_SIZEOF (data)) ; mode = O_RDWR | O_BINARY ; flags = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ; if ((fd = open (filename, mode, flags)) < 0) { printf ("\n\nLine %d: open() failed : %s\n\n", __LINE__, strerror (errno)) ; return ; } ; LSEEK (fd, 0, SEEK_END) ; assert (write (fd, data, sizeof (data)) > 0) ; printf ("2) Now use system (\"%s %s\") to show the file length.\n\n", dir_cmd, filename) ; /* Would use snprintf, but thats not really available on windows. */ memset (data, 0, sizeof (data)) ; strncpy (data, dir_cmd, sizeof (data) - 1) ; strncat (data, " ", sizeof (data) - 1 - strlen (data)) ; strncat (data, filename, sizeof (data) - 1 - strlen (data)) ; assert (system (data) >= 0) ; puts ("") ; printf ("3) Now use fstat() to get the file length.\n") ; if (FSTAT (fd, &statbuf) != 0) { printf ("\n\nLine %d: fstat() returned error : %s\n", __LINE__, strerror (errno)) ; return ; } ; printf ("4) According to fstat(), the file length is %ld, ", (long) statbuf.st_size) ; close (fd) ; if (statbuf.st_size != 2 * sizeof (data)) printf ("but thats just plain ***WRONG***.\n\n") ; else { printf ("which is correct.\n\n") ; unlink (filename) ; } ; } /* show_fstat_error */