From af39994a59005224c949f255ef654a81d1ec2ed2 Mon Sep 17 00:00:00 2001 From: Moinak Ghosh Date: Wed, 17 Sep 2014 20:34:38 +0530 Subject: [PATCH] Working Wavpack filter for compressing WAV filies. Improved error handling of filter routines. Improved verbose logging. --- archive/pc_arc_filter.c | 45 ++++-- archive/pc_arc_filter.h | 2 + archive/pc_archive.c | 51 +++++-- archive/pc_archive.h | 4 +- archive/wavpack_helper.c | 309 ++++++++++++++++++++++++++++++++++++--- pcompress.c | 17 ++- pcompress.h | 4 +- utils/utils.c | 2 +- utils/utils.h | 5 +- 9 files changed, 382 insertions(+), 57 deletions(-) diff --git a/archive/pc_arc_filter.c b/archive/pc_arc_filter.c index d36df14..390cbdd 100644 --- a/archive/pc_arc_filter.c +++ b/archive/pc_arc_filter.c @@ -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); diff --git a/archive/pc_arc_filter.h b/archive/pc_arc_filter.h index b69326b..5cf89cd 100644 --- a/archive/pc_arc_filter.h +++ b/archive/pc_arc_filter.h @@ -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); diff --git a/archive/pc_archive.c b/archive/pc_archive.c index 7f74196..a2442cc 100644 --- a/archive/pc_archive.c +++ b/archive/pc_archive.c @@ -1156,9 +1156,8 @@ 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, - archive_entry_size(entry), name); + 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); ent = entry; @@ -1194,14 +1193,14 @@ start_archiver(pc_ctx_t *pctx) { /* * The next two functions are from libArchive source/example: * https://github.com/libarchive/libarchive/wiki/Examples#wiki-A_Complete_Extractor - * + * * We have to use low-level APIs to extract entries to disk. Normally one would use * archive_read_extract2() but LibArchive has no option to set user-defined filter * routines, so we have to handle here. */ 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); } diff --git a/archive/pc_archive.h b/archive/pc_archive.h index fb2fbdc..d79224a 100644 --- a/archive/pc_archive.h +++ b/archive/pc_archive.h @@ -20,7 +20,7 @@ * If not, see . * * moinakg@belenix.org, http://moinakg.wordpress.com/ - * + * */ #ifndef _PC_ARCHIVE_H @@ -60,4 +60,4 @@ void init_filters(struct filter_flags *ff); } #endif -#endif +#endif diff --git a/archive/wavpack_helper.c b/archive/wavpack_helper.c index a271e0f..3fb4a11 100644 --- a/archive/wavpack_helper.c +++ b/archive/wavpack_helper.c @@ -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 diff --git a/pcompress.c b/pcompress.c index 73aac7d..7d44fd7 100644 --- a/pcompress.c +++ b/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; diff --git a/pcompress.h b/pcompress.h index 601f5b3..c383c70 100644 --- a/pcompress.h +++ b/pcompress.h @@ -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; diff --git a/utils/utils.c b/utils/utils.c index 72115de..41669d2 100644 --- a/utils/utils.c +++ b/utils/utils.c @@ -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; diff --git a/utils/utils.h b/utils/utils.h index 30612e2..e61855f 100644 --- a/utils/utils.h +++ b/utils/utils.h @@ -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);