Working Wavpack filter for compressing WAV filies.
Improved error handling of filter routines. Improved verbose logging.
This commit is contained in:
parent
fd087a8949
commit
af39994a59
9 changed files with 382 additions and 57 deletions
|
@ -64,15 +64,17 @@ ssize_t packpnm_filter(struct filter_info *fi, void *filter_private);
|
|||
|
||||
#ifdef _ENABLE_WAVPACK_
|
||||
extern size_t wavpack_filter_encode(uchar_t *in_buf, size_t len, uchar_t **out_buf);
|
||||
extern size_t wavpack_filter_decode(uchar_t *in_buf, size_t len, uchar_t **out_buf,
|
||||
ssize_t out_len);
|
||||
ssize_t wavpack_filter(struct filter_info *fi, void *filter_private);
|
||||
#endif
|
||||
|
||||
void
|
||||
add_filters_by_type(struct type_data *typetab, struct filter_flags *ff)
|
||||
{
|
||||
#ifndef _MPLV2_LICENSE_
|
||||
struct scratch_buffer *sdat;
|
||||
struct scratch_buffer *sdat = NULL;
|
||||
int slot;
|
||||
#ifndef _MPLV2_LICENSE_
|
||||
|
||||
if (ff->enable_packjpg) {
|
||||
sdat = (struct scratch_buffer *)malloc(sizeof (struct scratch_buffer));
|
||||
|
@ -95,6 +97,21 @@ add_filters_by_type(struct type_data *typetab, struct filter_flags *ff)
|
|||
typetab[slot].filter_name = "packPNM";
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _ENABLE_WAVPACK_
|
||||
if (ff->enable_wavpack) {
|
||||
if (!sdat) {
|
||||
sdat = (struct scratch_buffer *)malloc(sizeof (struct scratch_buffer));
|
||||
sdat->in_buff = NULL;
|
||||
sdat->in_bufflen = 0;
|
||||
}
|
||||
|
||||
slot = TYPE_WAV >> 3;
|
||||
typetab[slot].filter_private = sdat;
|
||||
typetab[slot].filter_func = wavpack_filter;
|
||||
typetab[slot].filter_name = "WavPack";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -279,13 +296,13 @@ packjpg_filter(struct filter_info *fi, void *filter_private)
|
|||
out = NULL;
|
||||
if ((len = packjpg_filter_process(mapbuf, in_size, &out)) == 0) {
|
||||
/*
|
||||
* If filter failed we write out the original data and indicate skip
|
||||
* to continue the archive extraction.
|
||||
* If filter failed we write out the original data and indicate a
|
||||
* soft error to continue the archive extraction.
|
||||
*/
|
||||
free(out);
|
||||
if (write_archive_data(fi->target_arc, mapbuf, len1, fi->block_size) < len1)
|
||||
return (FILTER_RETURN_ERROR);
|
||||
return (FILTER_RETURN_SKIP);
|
||||
return (FILTER_RETURN_SOFT_ERROR);
|
||||
}
|
||||
rv = write_archive_data(fi->target_arc, out, len, fi->block_size);
|
||||
free(out);
|
||||
|
@ -382,13 +399,13 @@ packpnm_filter(struct filter_info *fi, void *filter_private)
|
|||
out = NULL;
|
||||
if ((len = packpnm_filter_process(mapbuf, in_size, &out)) == 0) {
|
||||
/*
|
||||
* If filter failed we write out the original data and indicate skip
|
||||
* to continue the archive extraction.
|
||||
* If filter failed we write out the original data and indicate a
|
||||
* soft error to continue the archive extraction.
|
||||
*/
|
||||
free(out);
|
||||
if (write_archive_data(fi->target_arc, mapbuf, len1, fi->block_size) < len1)
|
||||
return (FILTER_RETURN_ERROR);
|
||||
return (FILTER_RETURN_SKIP);
|
||||
return (FILTER_RETURN_SOFT_ERROR);
|
||||
}
|
||||
rv = write_archive_data(fi->target_arc, out, len, fi->block_size);
|
||||
free(out);
|
||||
|
@ -413,7 +430,7 @@ wavpack_filter(struct filter_info *fi, void *filter_private)
|
|||
if (fi->compressing) {
|
||||
mapbuf = mmap(NULL, len, PROT_READ, MAP_SHARED, fi->fd, 0);
|
||||
if (mapbuf == NULL) {
|
||||
log_msg(LOG_ERR, 1, "Mmap failed in packPNM filter.");
|
||||
log_msg(LOG_ERR, 1, "Mmap failed in WavPack filter.");
|
||||
return (FILTER_RETURN_ERROR);
|
||||
}
|
||||
|
||||
|
@ -475,7 +492,7 @@ wavpack_filter(struct filter_info *fi, void *filter_private)
|
|||
}
|
||||
munmap(mapbuf, len1);
|
||||
|
||||
in_size = LE64(len);
|
||||
in_size = LE64(len1);
|
||||
rv = archive_write_data(fi->target_arc, &in_size, 8);
|
||||
if (rv != 8)
|
||||
return (rv);
|
||||
|
@ -488,15 +505,15 @@ wavpack_filter(struct filter_info *fi, void *filter_private)
|
|||
* Decompression case.
|
||||
*/
|
||||
out = NULL;
|
||||
if ((len = wavpack_filter_encode(mapbuf, in_size, &out)) == 0) {
|
||||
if ((len = wavpack_filter_decode(mapbuf, len, &out, in_size)) == 0) {
|
||||
/*
|
||||
* If filter failed we write out the original data and indicate skip
|
||||
* to continue the archive extraction.
|
||||
* If filter failed we write out the original data and indicate a
|
||||
* soft error to continue the archive extraction.
|
||||
*/
|
||||
free(out);
|
||||
if (write_archive_data(fi->target_arc, mapbuf, len1, fi->block_size) < len1)
|
||||
return (FILTER_RETURN_ERROR);
|
||||
return (FILTER_RETURN_SKIP);
|
||||
return (FILTER_RETURN_SOFT_ERROR);
|
||||
}
|
||||
rv = write_archive_data(fi->target_arc, out, len, fi->block_size);
|
||||
free(out);
|
||||
|
|
|
@ -39,6 +39,7 @@ extern "C" {
|
|||
|
||||
#define FILTER_RETURN_SKIP (1)
|
||||
#define FILTER_RETURN_ERROR (-1)
|
||||
#define FILTER_RETURN_SOFT_ERROR (-2)
|
||||
#define FILTER_XATTR_ENTRY "_._pc_filter_xattr"
|
||||
|
||||
struct filter_info {
|
||||
|
@ -52,6 +53,7 @@ struct filter_info {
|
|||
|
||||
struct filter_flags {
|
||||
int enable_packjpg;
|
||||
int enable_wavpack;
|
||||
};
|
||||
|
||||
typedef ssize_t (*filter_func_ptr)(struct filter_info *fi, void *filter_private);
|
||||
|
|
|
@ -1156,8 +1156,7 @@ archiver_thread_func(void *dat) {
|
|||
} else {
|
||||
archive_entry_set_size(entry, archive_entry_size(entry));
|
||||
}
|
||||
if (pctx->verbose)
|
||||
log_msg(LOG_INFO, 0, "%5d/%5d %8" PRIu64 " %s", ctr, pctx->archive_members_count,
|
||||
log_msg(LOG_VERBOSE, 0, "%5d/%5d %8" PRIu64 " %s", ctr, pctx->archive_members_count,
|
||||
archive_entry_size(entry), name);
|
||||
|
||||
archive_entry_linkify(resolver, &entry, &spare_entry);
|
||||
|
@ -1201,7 +1200,7 @@ start_archiver(pc_ctx_t *pctx) {
|
|||
*/
|
||||
static int
|
||||
copy_data_out(struct archive *ar, struct archive *aw, struct archive_entry *entry,
|
||||
int typ)
|
||||
int typ, pc_ctx_t *pctx)
|
||||
{
|
||||
int64_t offset;
|
||||
const void *buff;
|
||||
|
@ -1219,7 +1218,18 @@ copy_data_out(struct archive *ar, struct archive *aw, struct archive_entry *entr
|
|||
return (ARCHIVE_FATAL);
|
||||
|
||||
} else if (rv == FILTER_RETURN_SKIP) {
|
||||
log_msg(LOG_WARN, 0, "Filter function failed for entry.");
|
||||
log_msg(LOG_WARN, 0, "Filter function skipped.");
|
||||
return (ARCHIVE_WARN);
|
||||
|
||||
} else if (rv == FILTER_RETURN_SOFT_ERROR) {
|
||||
log_msg(LOG_WARN, 0, "Filter function failed for entry: %s.",
|
||||
archive_entry_pathname(entry));
|
||||
pctx->errored_count++;
|
||||
if (pctx->err_paths_fd) {
|
||||
fprintf(pctx->err_paths_fd, "%s,%s",
|
||||
archive_entry_pathname(entry),
|
||||
typetab[(typ >> 3)].filter_name);
|
||||
}
|
||||
return (ARCHIVE_WARN);
|
||||
} else {
|
||||
return (ARCHIVE_OK);
|
||||
|
@ -1247,7 +1257,7 @@ copy_data_out(struct archive *ar, struct archive *aw, struct archive_entry *entr
|
|||
|
||||
static int
|
||||
archive_extract_entry(struct archive *a, struct archive_entry *entry,
|
||||
struct archive *ad, int typ)
|
||||
struct archive *ad, int typ, pc_ctx_t *pctx)
|
||||
{
|
||||
int r, r2;
|
||||
char *filter_name;
|
||||
|
@ -1271,7 +1281,7 @@ archive_extract_entry(struct archive *a, struct archive_entry *entry,
|
|||
archive_copy_error(a, ad);
|
||||
} else if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) > 0) {
|
||||
/* Otherwise, pour data into the entry. */
|
||||
r = copy_data_out(a, ad, entry, typ);
|
||||
r = copy_data_out(a, ad, entry, typ, pctx);
|
||||
}
|
||||
r2 = archive_write_finish_entry(ad);
|
||||
if (r2 < ARCHIVE_WARN)
|
||||
|
@ -1375,6 +1385,11 @@ extractor_thread_func(void *dat) {
|
|||
log_msg(LOG_ERR, 1, "Cannot change to dir: %s", pctx->to_filename);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open list file for pathnames that had filter errors (if any).
|
||||
*/
|
||||
pctx->err_paths_fd = fopen("filter_failures.txt", "w");
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1431,7 +1446,7 @@ extractor_thread_func(void *dat) {
|
|||
#endif
|
||||
|
||||
if (!pctx->list_mode) {
|
||||
rv = archive_extract_entry(arc, entry, awd, typ);
|
||||
rv = archive_extract_entry(arc, entry, awd, typ, pctx);
|
||||
} else {
|
||||
rv = archive_list_entry(arc, entry, typ);
|
||||
}
|
||||
|
@ -1439,8 +1454,8 @@ extractor_thread_func(void *dat) {
|
|||
log_msg(LOG_WARN, 0, "%s: %s", archive_entry_pathname(entry),
|
||||
archive_error_string(arc));
|
||||
|
||||
} else if (pctx->verbose) {
|
||||
log_msg(LOG_INFO, 0, "%5d %8" PRIu64 " %s", ctr, archive_entry_size(entry),
|
||||
} else {
|
||||
log_msg(LOG_VERBOSE, 0, "%5d %8" PRIu64 " %s", ctr, archive_entry_size(entry),
|
||||
archive_entry_pathname(entry));
|
||||
}
|
||||
|
||||
|
@ -1452,12 +1467,26 @@ extractor_thread_func(void *dat) {
|
|||
}
|
||||
|
||||
if (!pctx->list_mode) {
|
||||
if (pctx->errored_count > 0) {
|
||||
log_msg(LOG_WARN, 0, "WARN: %d pathnames failed filter decoding.");
|
||||
if (pctx->err_paths_fd) {
|
||||
fclose(pctx->err_paths_fd);
|
||||
log_msg(LOG_WARN, 0, "Please see file filter_failures.txt.");
|
||||
}
|
||||
} else {
|
||||
if (pctx->err_paths_fd) {
|
||||
fclose(pctx->err_paths_fd);
|
||||
(void) unlink("filter_failures.txt");
|
||||
}
|
||||
}
|
||||
|
||||
if (got_cwd) {
|
||||
rv = chdir(cwd);
|
||||
}
|
||||
}
|
||||
archive_read_free(arc);
|
||||
archive_write_free(awd);
|
||||
|
||||
done:
|
||||
return (NULL);
|
||||
}
|
||||
|
|
|
@ -93,11 +93,11 @@ read_block(read_data *rdat, uchar_t *tgt, uint32_t len, uint32_t *numread)
|
|||
numcopy = rdat->bufsize - rdat->bytes_read;
|
||||
|
||||
if (numcopy == 0)
|
||||
return (1);
|
||||
return (FALSE);
|
||||
memcpy(tgt, rdat->buf + rdat->bytes_read, numcopy);
|
||||
rdat->bytes_read += numcopy;
|
||||
*numread = numcopy;
|
||||
return (0);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -116,13 +116,106 @@ read_block_ref(read_data *rdat, uchar_t **ref, uint32_t len, uint32_t *numread)
|
|||
numcopy = rdat->bufsize - rdat->bytes_read;
|
||||
|
||||
if (numcopy == 0)
|
||||
return (1);
|
||||
return (FALSE);
|
||||
*ref = rdat->buf + rdat->bytes_read;
|
||||
rdat->bytes_read += numcopy;
|
||||
*numread = numcopy;
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Memory buffer I/O functions mirroring semantics of stdio, for Wavpack
|
||||
* I/O ops structure.
|
||||
*/
|
||||
static int32_t
|
||||
read_bytes(void *id, void *data, int32_t bcount)
|
||||
{
|
||||
read_data *rdat = (read_data *)id;
|
||||
uint32_t numread;
|
||||
|
||||
if (!read_block(rdat, (uchar_t *)data, bcount, &numread)) {
|
||||
return (0);
|
||||
}
|
||||
return (numread);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
get_pos(void *id)
|
||||
{
|
||||
read_data *rdat = (read_data *)id;
|
||||
return (rdat->bytes_read);
|
||||
}
|
||||
|
||||
static int
|
||||
set_pos_abs(void *id, uint32_t pos)
|
||||
{
|
||||
read_data *rdat = (read_data *)id;
|
||||
|
||||
if (pos > rdat->bufsize)
|
||||
pos = rdat->bufsize;
|
||||
rdat->bytes_read = pos;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
set_pos_rel(void *id, int32_t delta, int mode)
|
||||
{
|
||||
read_data *rdat = (read_data *)id;
|
||||
int64_t br;
|
||||
|
||||
br = rdat->bytes_read;
|
||||
if (mode == SEEK_SET) {
|
||||
br = delta;
|
||||
} else if (mode == SEEK_CUR) {
|
||||
br += delta;
|
||||
} else if (mode == SEEK_END) {
|
||||
br = rdat->bufsize - delta;
|
||||
} else {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
if (br < 0) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
if (br > rdat->bufsize)
|
||||
br = rdat->bufsize;
|
||||
rdat->bytes_read = br;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
push_back_byte(void *id, int c)
|
||||
{
|
||||
read_data *rdat = (read_data *)id;
|
||||
|
||||
if (rdat->bytes_read > 0) {
|
||||
rdat->bytes_read--;
|
||||
rdat->buf[rdat->bytes_read] = c;
|
||||
return (c);
|
||||
} else {
|
||||
return (EOF);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
get_length(void *id)
|
||||
{
|
||||
read_data *rdat = (read_data *)id;
|
||||
return (rdat->bufsize);
|
||||
}
|
||||
|
||||
static int
|
||||
can_seek(void *id)
|
||||
{
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
static WavpackStreamReader memreader = {
|
||||
read_bytes, get_pos, set_pos_abs, set_pos_rel, push_back_byte,
|
||||
get_length, can_seek, write_block
|
||||
};
|
||||
|
||||
#define INPUT_SAMPLES 65536
|
||||
|
||||
static int
|
||||
|
@ -140,7 +233,6 @@ pack_audio(WavpackContext *wpc, read_data *rdat)
|
|||
|
||||
WavpackPackInit(wpc);
|
||||
bytes_per_sample = WavpackGetBytesPerSample (wpc) * WavpackGetNumChannels (wpc);
|
||||
//input_buffer = malloc(input_samples * bytes_per_sample);
|
||||
sample_buffer = malloc(input_samples * sizeof (int32_t) * WavpackGetNumChannels (wpc));
|
||||
samples_remaining = WavpackGetNumSamples (wpc);
|
||||
|
||||
|
@ -212,7 +304,7 @@ pack_audio(WavpackContext *wpc, read_data *rdat)
|
|||
|
||||
/*
|
||||
* Helper routine for wavpack. Higher level encoding interface adapted from
|
||||
* pack_file() in cli/wavpack.c
|
||||
* pack_file() in cli/wavpack.c and unpack_file() in cli/wvunpack.c
|
||||
*/
|
||||
size_t
|
||||
wavpack_filter_encode(uchar_t *in_buf, size_t len, uchar_t **out_buf)
|
||||
|
@ -233,27 +325,29 @@ wavpack_filter_encode(uchar_t *in_buf, size_t len, uchar_t **out_buf)
|
|||
memset(&loc_config, 0, sizeof (loc_config));
|
||||
adobe_mode = 0;
|
||||
|
||||
/*
|
||||
* Default WavPack config.
|
||||
*/
|
||||
loc_config.flags |= CONFIG_FAST_FLAG;
|
||||
|
||||
*out_buf = (uchar_t *)malloc(len);
|
||||
if (*out_buf == NULL)
|
||||
if (*out_buf == NULL) {
|
||||
log_msg(LOG_ERR, 1, "malloc failed.");
|
||||
return (0);
|
||||
}
|
||||
|
||||
wv_dat.buf = *out_buf;
|
||||
wv_dat.bufsize = len;
|
||||
wpc = WavpackOpenFileOutput (write_block, &wv_dat, NULL);
|
||||
wpc = WavpackOpenFileOutput(write_block, &wv_dat, NULL);
|
||||
|
||||
rd_dat.buf = in_buf;
|
||||
rd_dat.bufsize = len;
|
||||
|
||||
// read (and copy to output) initial RIFF form header
|
||||
if (read_block(&rd_dat, (uchar_t *)&riff_chunk_header, sizeof (RiffChunkHeader), &bcount) ||
|
||||
bcount != sizeof (RiffChunkHeader) || strncmp (riff_chunk_header.ckID, "RIFF", 4) ||
|
||||
strncmp (riff_chunk_header.formType, "WAVE", 4)) {
|
||||
WavpackCloseFile (wpc);
|
||||
// Read (and copy to output) initial RIFF form header
|
||||
if (!read_block(&rd_dat, (uchar_t *)&riff_chunk_header, sizeof (RiffChunkHeader), &bcount) ||
|
||||
bcount != sizeof (RiffChunkHeader) || strncmp(riff_chunk_header.ckID, "RIFF", 4) ||
|
||||
strncmp(riff_chunk_header.formType, "WAVE", 4)) {
|
||||
WavpackCloseFile(wpc);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (!WavpackAddWrapper(wpc, &riff_chunk_header, sizeof (RiffChunkHeader))) {
|
||||
WavpackCloseFile(wpc);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -261,9 +355,14 @@ wavpack_filter_encode(uchar_t *in_buf, size_t len, uchar_t **out_buf)
|
|||
// (until the data chunk) and copy them to the output
|
||||
//
|
||||
while (1) {
|
||||
if (read_block(&rd_dat, (uchar_t *)&chunk_header, sizeof (ChunkHeader), &bcount) ||
|
||||
if (!read_block(&rd_dat, (uchar_t *)&chunk_header, sizeof (ChunkHeader), &bcount) ||
|
||||
bcount != sizeof (ChunkHeader)) {
|
||||
WavpackCloseFile (wpc);
|
||||
WavpackCloseFile(wpc);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (!WavpackAddWrapper(wpc, &chunk_header, sizeof (ChunkHeader))) {
|
||||
WavpackCloseFile(wpc);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -278,9 +377,14 @@ wavpack_filter_encode(uchar_t *in_buf, size_t len, uchar_t **out_buf)
|
|||
if (chunk_header.ckSize < 16 || chunk_header.ckSize > sizeof (WaveHeader) ||
|
||||
!read_block(&rd_dat, (uchar_t *)&WaveHeader, chunk_header.ckSize, &bcount) ||
|
||||
bcount != chunk_header.ckSize) {
|
||||
WavpackCloseFile (wpc);
|
||||
WavpackCloseFile(wpc);
|
||||
return (0);
|
||||
}
|
||||
if (!WavpackAddWrapper(wpc, &WaveHeader, chunk_header.ckSize)) {
|
||||
WavpackCloseFile(wpc);
|
||||
return (0);
|
||||
}
|
||||
|
||||
WavpackLittleEndianToNative (&WaveHeader, WaveHeaderFormat);
|
||||
|
||||
if (chunk_header.ckSize > 16 && WaveHeader.cbSize == 2)
|
||||
|
@ -306,7 +410,7 @@ wavpack_filter_encode(uchar_t *in_buf, size_t len, uchar_t **out_buf)
|
|||
supported = FALSE;
|
||||
|
||||
if (!supported) {
|
||||
WavpackCloseFile (wpc);
|
||||
WavpackCloseFile(wpc);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -367,7 +471,7 @@ wavpack_filter_encode(uchar_t *in_buf, size_t len, uchar_t **out_buf)
|
|||
}
|
||||
|
||||
if (!WavpackSetConfiguration(wpc, &loc_config, total_samples)) {
|
||||
WavpackCloseFile (wpc);
|
||||
WavpackCloseFile(wpc);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -401,6 +505,167 @@ wavpack_filter_encode(uchar_t *in_buf, size_t len, uchar_t **out_buf)
|
|||
return (wv_dat.bytes_written);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reformat samples from longs in processor's native endian mode to
|
||||
* little-endian data with (possibly) less than 4 bytes / sample.
|
||||
*/
|
||||
static unsigned char *
|
||||
format_samples(int bps, unsigned char *dst, int32_t *src, uint32_t samcnt)
|
||||
{
|
||||
int32_t temp;
|
||||
|
||||
switch (bps) {
|
||||
|
||||
case 1:
|
||||
while (samcnt--)
|
||||
*dst++ = *src++ + 128;
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
while (samcnt--) {
|
||||
*dst++ = (unsigned char) (temp = *src++);
|
||||
*dst++ = (unsigned char) (temp >> 8);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 3:
|
||||
while (samcnt--) {
|
||||
*dst++ = (unsigned char) (temp = *src++);
|
||||
*dst++ = (unsigned char) (temp >> 8);
|
||||
*dst++ = (unsigned char) (temp >> 16);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 4:
|
||||
while (samcnt--) {
|
||||
*dst++ = (unsigned char) (temp = *src++);
|
||||
*dst++ = (unsigned char) (temp >> 8);
|
||||
*dst++ = (unsigned char) (temp >> 16);
|
||||
*dst++ = (unsigned char) (temp >> 24);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
size_t
|
||||
wavpack_filter_decode(uchar_t *in_buf, size_t len, uchar_t **out_buf, ssize_t out_len)
|
||||
{
|
||||
write_data wr_dat;
|
||||
read_data rd_dat;
|
||||
WavpackContext *wpc;
|
||||
int bytes_per_sample, num_channels, bps, result;
|
||||
int32_t *temp_buffer;
|
||||
uchar_t *output_ptr = NULL, *output_buffer = NULL;
|
||||
uint32_t total_unpacked_samples = 0, output_buffer_size = 0;
|
||||
char error[80];
|
||||
|
||||
rd_dat.buf = in_buf;
|
||||
rd_dat.bufsize = len;
|
||||
rd_dat.bytes_read = 0;
|
||||
wpc = WavpackOpenFileInputEx(&memreader, &rd_dat, NULL, error, OPEN_WRAPPER, 0);
|
||||
if (!wpc) {
|
||||
log_msg(LOG_ERR, 0, error);
|
||||
return (0);
|
||||
}
|
||||
|
||||
num_channels = WavpackGetNumChannels(wpc);
|
||||
bps = WavpackGetBytesPerSample(wpc);
|
||||
bytes_per_sample = num_channels * bps;
|
||||
|
||||
*out_buf = (uchar_t *)malloc(out_len);
|
||||
if (*out_buf == NULL) {
|
||||
log_msg(LOG_ERR, 1, "malloc failed.");
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Must start with a wrapper.
|
||||
*/
|
||||
wr_dat.buf = *out_buf;
|
||||
wr_dat.bufsize = len;
|
||||
wr_dat.bytes_written = 0;
|
||||
wr_dat.first_block_size = 0;
|
||||
wr_dat.error = 0;
|
||||
if (WavpackGetWrapperBytes(wpc)) {
|
||||
if (!write_block(&wr_dat, WavpackGetWrapperData(wpc),
|
||||
WavpackGetWrapperBytes(wpc))) {
|
||||
WavpackFreeWrapper(wpc);
|
||||
WavpackCloseFile(wpc);
|
||||
log_msg(LOG_ERR, 0, "Wavpack: Header write failed.");
|
||||
return (0);
|
||||
}
|
||||
WavpackFreeWrapper(wpc);
|
||||
} else {
|
||||
log_msg(LOG_ERR, 0, "Wavpack: RIFF wrapper size if zero. File corrupt?");
|
||||
WavpackCloseFile(wpc);
|
||||
return (0);
|
||||
}
|
||||
|
||||
result = TRUE;
|
||||
temp_buffer = malloc (4096L * num_channels * 4);
|
||||
output_buffer_size = 1024 * 256;
|
||||
output_buffer = malloc(output_buffer_size);
|
||||
output_ptr = output_buffer;
|
||||
|
||||
while (result) {
|
||||
uint32_t samples_to_unpack, samples_unpacked;
|
||||
|
||||
samples_to_unpack = (output_buffer_size -
|
||||
(uint32_t)(output_ptr - output_buffer)) / bytes_per_sample;
|
||||
if (samples_to_unpack > 4096)
|
||||
samples_to_unpack = 4096;
|
||||
|
||||
samples_unpacked = WavpackUnpackSamples(wpc, temp_buffer, samples_to_unpack);
|
||||
total_unpacked_samples += samples_unpacked;
|
||||
|
||||
if (samples_unpacked) {
|
||||
output_ptr = format_samples(bps, output_ptr, temp_buffer,
|
||||
samples_unpacked * num_channels);
|
||||
}
|
||||
if (!samples_unpacked || (output_buffer_size -
|
||||
(output_ptr - output_buffer)) < (uint32_t)bytes_per_sample) {
|
||||
if (!write_block(&wr_dat, output_buffer,
|
||||
(uint32_t)(output_ptr - output_buffer))) {
|
||||
if (temp_buffer)
|
||||
free(temp_buffer);
|
||||
WavpackCloseFile(wpc);
|
||||
log_msg(LOG_ERR, 0, "Wavpack: Writing samples failed.");
|
||||
return (0);
|
||||
}
|
||||
output_ptr = output_buffer;
|
||||
}
|
||||
|
||||
if (!samples_unpacked)
|
||||
break;
|
||||
}
|
||||
|
||||
if (output_buffer)
|
||||
free(output_buffer);
|
||||
|
||||
while (WavpackGetWrapperBytes(wpc)) {
|
||||
if (!write_block(&wr_dat, WavpackGetWrapperData(wpc),
|
||||
WavpackGetWrapperBytes(wpc))) {
|
||||
if (temp_buffer)
|
||||
free(temp_buffer);
|
||||
WavpackCloseFile(wpc);
|
||||
log_msg(LOG_ERR, 0, "Wavpack: Writing trailing data failed.");
|
||||
return (0);
|
||||
}
|
||||
WavpackFreeWrapper(wpc);
|
||||
WavpackUnpackSamples(wpc, temp_buffer, 1); // perhaps there's more RIFF info...
|
||||
}
|
||||
|
||||
free(temp_buffer);
|
||||
WavpackCloseFile(wpc);
|
||||
|
||||
return (wr_dat.bytes_written);
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
17
pcompress.c
17
pcompress.c
|
@ -2854,6 +2854,7 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[])
|
|||
strcpy(pctx->exec_name, pos);
|
||||
pctx->advanced_opts = 0;
|
||||
ff.enable_packjpg = 0;
|
||||
ff.enable_wavpack = 0;
|
||||
|
||||
pthread_mutex_lock(&opt_parse);
|
||||
while ((opt = getopt(argc, argv, "dc:s:l:pt:MCDGEe:w:LPS:B:Fk:avmKjxi")) != -1) {
|
||||
|
@ -3010,7 +3011,7 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[])
|
|||
break;
|
||||
|
||||
case 'v':
|
||||
pctx->verbose = 1;
|
||||
set_log_level(LOG_VERBOSE);
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
|
@ -3024,6 +3025,7 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[])
|
|||
case 'j':
|
||||
pctx->advanced_opts = 1;
|
||||
ff.enable_packjpg = 1;
|
||||
ff.enable_wavpack = 1;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
|
@ -3142,9 +3144,10 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[])
|
|||
}
|
||||
|
||||
/*
|
||||
* Dispack and PackJPG are only valid when archiving files.
|
||||
* Dispack, PackJPG and WavPack are only valid when archiving files.
|
||||
*/
|
||||
if ((pctx->dispack_preprocess || ff.enable_packjpg) && !pctx->archive_mode) {
|
||||
if ((pctx->dispack_preprocess || ff.enable_packjpg || ff.enable_wavpack)
|
||||
&& !pctx->archive_mode) {
|
||||
log_msg(LOG_ERR, 0, "Dispack Executable Preprocessor and PackJPG are only valid when archiving.");
|
||||
return (1);
|
||||
}
|
||||
|
@ -3305,9 +3308,13 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[])
|
|||
* Selectively enable filters while archiving, depending on compression level.
|
||||
*/
|
||||
if (pctx->archive_mode) {
|
||||
if (pctx->level > 10) ff.enable_packjpg = 1;
|
||||
if (pctx->level > 10) {
|
||||
ff.enable_packjpg = 1;
|
||||
ff.enable_wavpack = 1;
|
||||
}
|
||||
init_filters(&ff);
|
||||
pctx->enable_packjpg = ff.enable_packjpg;
|
||||
pctx->enable_wavpack = ff.enable_wavpack;
|
||||
if (pctx->level > 8) pctx->dispack_preprocess = 1;
|
||||
}
|
||||
|
||||
|
@ -3345,7 +3352,9 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[])
|
|||
* Enable all filters while decompressing. Obviously!
|
||||
*/
|
||||
ff.enable_packjpg = 1;
|
||||
ff.enable_wavpack = 1;
|
||||
pctx->enable_packjpg = 1;
|
||||
pctx->enable_wavpack = 1;
|
||||
init_filters(&ff);
|
||||
}
|
||||
pctx->inited = 1;
|
||||
|
|
|
@ -217,7 +217,6 @@ typedef struct pc_ctx {
|
|||
int dispack_preprocess;
|
||||
int encrypt_type;
|
||||
int archive_mode;
|
||||
int verbose;
|
||||
int enable_archive_sort;
|
||||
int pagesize;
|
||||
int force_archive_perms;
|
||||
|
@ -246,7 +245,10 @@ typedef struct pc_ctx {
|
|||
int btype, ctype;
|
||||
int min_chunk;
|
||||
int enable_packjpg;
|
||||
int enable_wavpack;
|
||||
int list_mode;
|
||||
FILE *err_paths_fd;
|
||||
uint32_t errored_count;
|
||||
|
||||
unsigned int chunk_num;
|
||||
uint64_t largest_chunk, smallest_chunk, avg_chunk;
|
||||
|
|
|
@ -61,7 +61,7 @@ static mach_timebase_info_data_t sTimebaseInfo;
|
|||
|
||||
processor_cap_t proc_info;
|
||||
pthread_mutex_t f_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int cur_log_level = 2;
|
||||
static int cur_log_level = LOG_INFO;
|
||||
static log_dest_t ldest = {LOG_OUTPUT, LOG_INFO, NULL};
|
||||
static char *f_name_list[512];
|
||||
static int f_count = 512, f_inited = 0;
|
||||
|
|
|
@ -277,7 +277,7 @@ typedef enum {
|
|||
/*
|
||||
* Sub-types.
|
||||
*/
|
||||
#define NUM_SUB_TYPES 32
|
||||
#define NUM_SUB_TYPES 33
|
||||
TYPE_EXE32 = 8,
|
||||
TYPE_JPEG = 16,
|
||||
TYPE_MARKUP = 24,
|
||||
|
@ -386,7 +386,8 @@ typedef enum {
|
|||
typedef enum {
|
||||
LOG_ERR,
|
||||
LOG_WARN,
|
||||
LOG_INFO
|
||||
LOG_INFO,
|
||||
LOG_VERBOSE
|
||||
} log_level_t;
|
||||
|
||||
typedef void (*log_callback_ptr)(char *msg);
|
||||
|
|
Loading…
Reference in a new issue