webpmux: allow reading argument from a file
if a single text file name is supplied as argument (e.g.: 'webpmux my_long_list_of_frames.txt'), the command line arguments are actually parsed from this file. Tokenizer will remove space, tabs, LF, CR, returns, etc. + changed ImgIoUtilReadFile() to return a null-terminated data, for convenience. + misc clean-up in the code BUG=webp:355 Change-Id: I76796305641d660933de5881763d723006712fa9 ---
This commit is contained in:
parent
b69f18a73a
commit
a7f93fe32d
@ -33,6 +33,7 @@ Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT
|
||||
webpmux -info INPUT
|
||||
webpmux [-h|-help]
|
||||
webpmux -version
|
||||
webpmux argument_file_name
|
||||
|
||||
GET_OPTIONS:
|
||||
Extract relevant data:
|
||||
@ -92,6 +93,9 @@ INPUT & OUTPUT are in WebP format.
|
||||
Note: The nature of EXIF, XMP and ICC data is not checked and is assumed to be
|
||||
valid.
|
||||
|
||||
Note: if a single file name is passed as the argument, the arguments will be
|
||||
tokenized from this file. The file name must not start with the character '-'.
|
||||
|
||||
Visualization tool:
|
||||
===================
|
||||
|
||||
|
@ -47,6 +47,7 @@
|
||||
webpmux -info in.webp
|
||||
webpmux [ -h | -help ]
|
||||
webpmux -version
|
||||
webpmux argument_file_name
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
@ -108,28 +109,29 @@ static const char* const kDescriptions[LAST_FEATURE] = {
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
FeatureType type_;
|
||||
FeatureArg* args_;
|
||||
int arg_count_;
|
||||
} Feature;
|
||||
// command line arguments
|
||||
int argc_;
|
||||
const char** argv_;
|
||||
WebPData argv_data_;
|
||||
int own_argv_;
|
||||
|
||||
typedef struct {
|
||||
ActionType action_type_;
|
||||
const char* input_;
|
||||
const char* output_;
|
||||
Feature feature_;
|
||||
} WebPMuxConfig;
|
||||
FeatureType type_;
|
||||
FeatureArg* args_;
|
||||
int arg_count_;
|
||||
} Config;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helper functions.
|
||||
|
||||
static int CountOccurrences(const char* arglist[], int list_length,
|
||||
const char* arg) {
|
||||
static int CountOccurrences(const Config* const config, const char* arg) {
|
||||
int i;
|
||||
int num_occurences = 0;
|
||||
|
||||
for (i = 0; i < list_length; ++i) {
|
||||
if (!strcmp(arglist[i], arg)) {
|
||||
for (i = 0; i < config->argc_; ++i) {
|
||||
if (!strcmp(config->argv_[i], arg)) {
|
||||
++num_occurences;
|
||||
}
|
||||
}
|
||||
@ -301,6 +303,7 @@ static void PrintHelp(void) {
|
||||
printf(" webpmux -info INPUT\n");
|
||||
printf(" webpmux [-h|-help]\n");
|
||||
printf(" webpmux -version\n");
|
||||
printf(" webpmux argument_file_name\n");
|
||||
|
||||
printf("\n");
|
||||
printf("GET_OPTIONS:\n");
|
||||
@ -369,6 +372,10 @@ static void PrintHelp(void) {
|
||||
|
||||
printf("\nNote: The nature of EXIF, XMP and ICC data is not checked");
|
||||
printf(" and is assumed to be\nvalid.\n");
|
||||
printf("\nNote: if a single file name is passed as the argument, the "
|
||||
"arguments will be\n");
|
||||
printf("tokenized from this file. The file name must not start with "
|
||||
"the character '-'.\n");
|
||||
}
|
||||
|
||||
static void WarnAboutOddOffset(const WebPMuxFrameInfo* const info) {
|
||||
@ -394,7 +401,7 @@ static int CreateMux(const char* const filename, WebPMux** mux) {
|
||||
assert(mux != NULL);
|
||||
if (!ReadFileToWebPData(filename, &bitstream)) return 0;
|
||||
*mux = WebPMuxCreate(&bitstream, 1);
|
||||
free((void*)bitstream.bytes);
|
||||
WebPDataClear(&bitstream);
|
||||
if (*mux != NULL) return 1;
|
||||
fprintf(stderr, "Failed to create mux object from file %s.\n", filename);
|
||||
return 0;
|
||||
@ -517,10 +524,15 @@ static int ParseBgcolorArgs(const char* args, uint32_t* const bgcolor) {
|
||||
//------------------------------------------------------------------------------
|
||||
// Clean-up.
|
||||
|
||||
static void DeleteConfig(WebPMuxConfig* config) {
|
||||
static void DeleteConfig(Config* const config) {
|
||||
if (config != NULL) {
|
||||
free(config->feature_.args_);
|
||||
free(config->args_);
|
||||
if (config->own_argv_) {
|
||||
free(config->argv_);
|
||||
WebPDataClear(&config->argv_data_);
|
||||
}
|
||||
memset(config, 0, sizeof(*config));
|
||||
WebPDataInit(&config->argv_data_);
|
||||
}
|
||||
}
|
||||
|
||||
@ -531,7 +543,7 @@ static void DeleteConfig(WebPMuxConfig* config) {
|
||||
// Returns 1 on valid, 0 otherwise.
|
||||
// Also fills up num_feature_args to be number of feature arguments given.
|
||||
// (e.g. if there are 4 '-frame's and 1 '-loop', then num_feature_args = 5).
|
||||
static int ValidateCommandLine(int argc, const char* argv[],
|
||||
static int ValidateCommandLine(const Config* const config,
|
||||
int* num_feature_args) {
|
||||
int num_frame_args;
|
||||
int num_loop_args;
|
||||
@ -543,27 +555,27 @@ static int ValidateCommandLine(int argc, const char* argv[],
|
||||
*num_feature_args = 0;
|
||||
|
||||
// Simple checks.
|
||||
if (CountOccurrences(argv, argc, "-get") > 1) {
|
||||
if (CountOccurrences(config, "-get") > 1) {
|
||||
ERROR_GOTO1("ERROR: Multiple '-get' arguments specified.\n", ErrValidate);
|
||||
}
|
||||
if (CountOccurrences(argv, argc, "-set") > 1) {
|
||||
if (CountOccurrences(config, "-set") > 1) {
|
||||
ERROR_GOTO1("ERROR: Multiple '-set' arguments specified.\n", ErrValidate);
|
||||
}
|
||||
if (CountOccurrences(argv, argc, "-strip") > 1) {
|
||||
if (CountOccurrences(config, "-strip") > 1) {
|
||||
ERROR_GOTO1("ERROR: Multiple '-strip' arguments specified.\n", ErrValidate);
|
||||
}
|
||||
if (CountOccurrences(argv, argc, "-info") > 1) {
|
||||
if (CountOccurrences(config, "-info") > 1) {
|
||||
ERROR_GOTO1("ERROR: Multiple '-info' arguments specified.\n", ErrValidate);
|
||||
}
|
||||
if (CountOccurrences(argv, argc, "-o") > 1) {
|
||||
if (CountOccurrences(config, "-o") > 1) {
|
||||
ERROR_GOTO1("ERROR: Multiple output files specified.\n", ErrValidate);
|
||||
}
|
||||
|
||||
// Compound checks.
|
||||
num_frame_args = CountOccurrences(argv, argc, "-frame");
|
||||
num_loop_args = CountOccurrences(argv, argc, "-loop");
|
||||
num_bgcolor_args = CountOccurrences(argv, argc, "-bgcolor");
|
||||
num_durations_args = CountOccurrences(argv, argc, "-duration");
|
||||
num_frame_args = CountOccurrences(config, "-frame");
|
||||
num_loop_args = CountOccurrences(config, "-loop");
|
||||
num_bgcolor_args = CountOccurrences(config, "-bgcolor");
|
||||
num_durations_args = CountOccurrences(config, "-duration");
|
||||
|
||||
if (num_loop_args > 1) {
|
||||
ERROR_GOTO1("ERROR: Multiple loop counts specified.\n", ErrValidate);
|
||||
@ -598,7 +610,7 @@ static int ValidateCommandLine(int argc, const char* argv[],
|
||||
|
||||
#define ACTION_IS_NIL (config->action_type_ == NIL_ACTION)
|
||||
|
||||
#define FEATURETYPE_IS_NIL (feature->type_ == NIL_FEATURE)
|
||||
#define FEATURETYPE_IS_NIL (config->type_ == NIL_FEATURE)
|
||||
|
||||
#define CHECK_NUM_ARGS_LESS(NUM, LABEL) \
|
||||
if (argc < i + (NUM)) { \
|
||||
@ -614,15 +626,15 @@ static int ValidateCommandLine(int argc, const char* argv[],
|
||||
|
||||
// Parses command-line arguments to fill up config object. Also performs some
|
||||
// semantic checks.
|
||||
static int ParseCommandLine(int argc, const char* argv[],
|
||||
WebPMuxConfig* config) {
|
||||
static int ParseCommandLine(Config* config) {
|
||||
int i = 0;
|
||||
int feature_arg_index = 0;
|
||||
int ok = 1;
|
||||
int argc = config->argc_;
|
||||
const char* const* argv = config->argv_;
|
||||
|
||||
while (i < argc) {
|
||||
Feature* const feature = &config->feature_;
|
||||
FeatureArg* const arg = &feature->args_[feature_arg_index];
|
||||
FeatureArg* const arg = &config->args_[feature_arg_index];
|
||||
if (argv[i][0] == '-') { // One of the action types or output.
|
||||
if (!strcmp(argv[i], "-set")) {
|
||||
if (ACTION_IS_NIL) {
|
||||
@ -638,8 +650,8 @@ static int ParseCommandLine(int argc, const char* argv[],
|
||||
} else {
|
||||
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
|
||||
}
|
||||
if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_DURATION) {
|
||||
feature->type_ = FEATURE_DURATION;
|
||||
if (FEATURETYPE_IS_NIL || config->type_ == FEATURE_DURATION) {
|
||||
config->type_ = FEATURE_DURATION;
|
||||
} else {
|
||||
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
|
||||
}
|
||||
@ -656,7 +668,7 @@ static int ParseCommandLine(int argc, const char* argv[],
|
||||
} else if (!strcmp(argv[i], "-strip")) {
|
||||
if (ACTION_IS_NIL) {
|
||||
config->action_type_ = ACTION_STRIP;
|
||||
feature->arg_count_ = 0;
|
||||
config->arg_count_ = 0;
|
||||
} else {
|
||||
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
|
||||
}
|
||||
@ -668,8 +680,8 @@ static int ParseCommandLine(int argc, const char* argv[],
|
||||
} else {
|
||||
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
|
||||
}
|
||||
if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_ANMF) {
|
||||
feature->type_ = FEATURE_ANMF;
|
||||
if (FEATURETYPE_IS_NIL || config->type_ == FEATURE_ANMF) {
|
||||
config->type_ = FEATURE_ANMF;
|
||||
} else {
|
||||
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
|
||||
}
|
||||
@ -685,8 +697,8 @@ static int ParseCommandLine(int argc, const char* argv[],
|
||||
} else {
|
||||
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
|
||||
}
|
||||
if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_ANMF) {
|
||||
feature->type_ = FEATURE_ANMF;
|
||||
if (FEATURETYPE_IS_NIL || config->type_ == FEATURE_ANMF) {
|
||||
config->type_ = FEATURE_ANMF;
|
||||
} else {
|
||||
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
|
||||
}
|
||||
@ -705,7 +717,7 @@ static int ParseCommandLine(int argc, const char* argv[],
|
||||
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
|
||||
} else {
|
||||
config->action_type_ = ACTION_INFO;
|
||||
feature->arg_count_ = 0;
|
||||
config->arg_count_ = 0;
|
||||
config->input_ = argv[i + 1];
|
||||
}
|
||||
i += 2;
|
||||
@ -741,7 +753,7 @@ static int ParseCommandLine(int argc, const char* argv[],
|
||||
if (!strcmp(argv[i], "icc") || !strcmp(argv[i], "exif") ||
|
||||
!strcmp(argv[i], "xmp")) {
|
||||
if (FEATURETYPE_IS_NIL) {
|
||||
feature->type_ = (!strcmp(argv[i], "icc")) ? FEATURE_ICCP :
|
||||
config->type_ = (!strcmp(argv[i], "icc")) ? FEATURE_ICCP :
|
||||
(!strcmp(argv[i], "exif")) ? FEATURE_EXIF : FEATURE_XMP;
|
||||
} else {
|
||||
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
|
||||
@ -757,7 +769,7 @@ static int ParseCommandLine(int argc, const char* argv[],
|
||||
} else if (!strcmp(argv[i], "frame") &&
|
||||
(config->action_type_ == ACTION_GET)) {
|
||||
CHECK_NUM_ARGS_LESS(2, ErrParse);
|
||||
feature->type_ = FEATURE_ANMF;
|
||||
config->type_ = FEATURE_ANMF;
|
||||
arg->params_ = argv[i + 1];
|
||||
++feature_arg_index;
|
||||
i += 2;
|
||||
@ -777,9 +789,8 @@ static int ParseCommandLine(int argc, const char* argv[],
|
||||
}
|
||||
|
||||
// Additional checks after config is filled.
|
||||
static int ValidateConfig(WebPMuxConfig* config) {
|
||||
static int ValidateConfig(Config* const config) {
|
||||
int ok = 1;
|
||||
Feature* const feature = &config->feature_;
|
||||
|
||||
// Action.
|
||||
if (ACTION_IS_NIL) {
|
||||
@ -795,7 +806,7 @@ static int ValidateConfig(WebPMuxConfig* config) {
|
||||
if (config->input_ == NULL) {
|
||||
if (config->action_type_ != ACTION_SET) {
|
||||
ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
|
||||
} else if (feature->type_ != FEATURE_ANMF) {
|
||||
} else if (config->type_ != FEATURE_ANMF) {
|
||||
ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
|
||||
}
|
||||
}
|
||||
@ -809,29 +820,63 @@ static int ValidateConfig(WebPMuxConfig* config) {
|
||||
return ok;
|
||||
}
|
||||
|
||||
// Create config object from command-line arguments.
|
||||
static int InitializeConfig(int argc, const char* argv[],
|
||||
WebPMuxConfig* config) {
|
||||
int num_feature_args = 0;
|
||||
int ok = 1;
|
||||
|
||||
#define MAX_ARGC 16384
|
||||
static int SetArguments(int argc, const char* argv[],
|
||||
Config* const config) {
|
||||
assert(config != NULL);
|
||||
memset(config, 0, sizeof(*config));
|
||||
WebPDataInit(&config->argv_data_);
|
||||
if (argc == 1 && argv[0][0] != '-') {
|
||||
char* cur;
|
||||
const char sep[] = " \t\r\n\f\v";
|
||||
if (!ReadFileToWebPData(argv[0], &config->argv_data_)) {
|
||||
return 0;
|
||||
}
|
||||
config->own_argv_ = 1;
|
||||
config->argv_ = (const char**)malloc(MAX_ARGC * sizeof(*config->argv_));
|
||||
if (config->argv_ == NULL) return 0;
|
||||
|
||||
argc = 0;
|
||||
for (cur = strtok((char*)config->argv_data_.bytes, sep);
|
||||
cur != NULL;
|
||||
cur = strtok(NULL, sep)) {
|
||||
if (argc == MAX_ARGC) {
|
||||
fprintf(stderr, "ERROR: Arguments limit %d reached\n", MAX_ARGC);
|
||||
return 0;
|
||||
}
|
||||
assert(strlen(cur) != 0);
|
||||
config->argv_[argc++] = cur;
|
||||
}
|
||||
config->argc_ = argc;
|
||||
} else {
|
||||
config->argc_ = argc;
|
||||
config->argv_ = argv;
|
||||
config->own_argv_ = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create config object from command-line arguments.
|
||||
static int InitializeConfig(int argc, const char* argv[],
|
||||
Config* const config) {
|
||||
int num_feature_args = 0;
|
||||
int ok = SetArguments(argc, argv, config);
|
||||
|
||||
if (!ok) return 0;
|
||||
|
||||
// Validate command-line arguments.
|
||||
if (!ValidateCommandLine(argc, argv, &num_feature_args)) {
|
||||
if (!ValidateCommandLine(config, &num_feature_args)) {
|
||||
ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1);
|
||||
}
|
||||
|
||||
config->feature_.arg_count_ = num_feature_args;
|
||||
config->feature_.args_ =
|
||||
(FeatureArg*)calloc(num_feature_args, sizeof(*config->feature_.args_));
|
||||
if (config->feature_.args_ == NULL) {
|
||||
config->arg_count_ = num_feature_args;
|
||||
config->args_ = (FeatureArg*)calloc(num_feature_args, sizeof(*config->args_));
|
||||
if (config->args_ == NULL) {
|
||||
ERROR_GOTO1("ERROR: Memory allocation error.\n", Err1);
|
||||
}
|
||||
|
||||
// Parse command-line.
|
||||
if (!ParseCommandLine(argc, argv, config) || !ValidateConfig(config)) {
|
||||
if (!ParseCommandLine(config) || !ValidateConfig(config)) {
|
||||
ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1);
|
||||
}
|
||||
|
||||
@ -847,7 +892,7 @@ static int InitializeConfig(int argc, const char* argv[],
|
||||
//------------------------------------------------------------------------------
|
||||
// Processing.
|
||||
|
||||
static int GetFrame(const WebPMux* mux, const WebPMuxConfig* config) {
|
||||
static int GetFrame(const WebPMux* mux, const Config* config) {
|
||||
WebPMuxError err = WEBP_MUX_OK;
|
||||
WebPMux* mux_single = NULL;
|
||||
int num = 0;
|
||||
@ -857,7 +902,7 @@ static int GetFrame(const WebPMux* mux, const WebPMuxConfig* config) {
|
||||
WebPMuxFrameInfo info;
|
||||
WebPDataInit(&info.bitstream);
|
||||
|
||||
num = ExUtilGetInt(config->feature_.args_[0].params_, 10, &parse_error);
|
||||
num = ExUtilGetInt(config->args_[0].params_, 10, &parse_error);
|
||||
if (num < 0) {
|
||||
ERROR_GOTO1("ERROR: Frame/Fragment index must be non-negative.\n", ErrGet);
|
||||
}
|
||||
@ -891,18 +936,17 @@ static int GetFrame(const WebPMux* mux, const WebPMuxConfig* config) {
|
||||
}
|
||||
|
||||
// Read and process config.
|
||||
static int Process(const WebPMuxConfig* config) {
|
||||
static int Process(const Config* config) {
|
||||
WebPMux* mux = NULL;
|
||||
WebPData chunk;
|
||||
WebPMuxError err = WEBP_MUX_OK;
|
||||
int ok = 1;
|
||||
const Feature* const feature = &config->feature_;
|
||||
|
||||
switch (config->action_type_) {
|
||||
case ACTION_GET: {
|
||||
ok = CreateMux(config->input_, &mux);
|
||||
if (!ok) goto Err2;
|
||||
switch (feature->type_) {
|
||||
switch (config->type_) {
|
||||
case FEATURE_ANMF:
|
||||
ok = GetFrame(mux, config);
|
||||
break;
|
||||
@ -910,10 +954,10 @@ static int Process(const WebPMuxConfig* config) {
|
||||
case FEATURE_ICCP:
|
||||
case FEATURE_EXIF:
|
||||
case FEATURE_XMP:
|
||||
err = WebPMuxGetChunk(mux, kFourccList[feature->type_], &chunk);
|
||||
err = WebPMuxGetChunk(mux, kFourccList[config->type_], &chunk);
|
||||
if (err != WEBP_MUX_OK) {
|
||||
ERROR_GOTO3("ERROR (%s): Could not get the %s.\n",
|
||||
ErrorString(err), kDescriptions[feature->type_], Err2);
|
||||
ErrorString(err), kDescriptions[config->type_], Err2);
|
||||
}
|
||||
ok = WriteData(config->output_, &chunk);
|
||||
break;
|
||||
@ -925,7 +969,7 @@ static int Process(const WebPMuxConfig* config) {
|
||||
break;
|
||||
}
|
||||
case ACTION_SET: {
|
||||
switch (feature->type_) {
|
||||
switch (config->type_) {
|
||||
case FEATURE_ANMF: {
|
||||
int i;
|
||||
WebPMuxAnimParams params = { 0xFFFFFFFF, 0 };
|
||||
@ -934,11 +978,11 @@ static int Process(const WebPMuxConfig* config) {
|
||||
ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n",
|
||||
ErrorString(WEBP_MUX_MEMORY_ERROR), Err2);
|
||||
}
|
||||
for (i = 0; i < feature->arg_count_; ++i) {
|
||||
switch (feature->args_[i].subtype_) {
|
||||
for (i = 0; i < config->arg_count_; ++i) {
|
||||
switch (config->args_[i].subtype_) {
|
||||
case SUBTYPE_BGCOLOR: {
|
||||
uint32_t bgcolor;
|
||||
ok = ParseBgcolorArgs(feature->args_[i].params_, &bgcolor);
|
||||
ok = ParseBgcolorArgs(config->args_[i].params_, &bgcolor);
|
||||
if (!ok) {
|
||||
ERROR_GOTO1("ERROR: Could not parse the background color \n",
|
||||
Err2);
|
||||
@ -949,7 +993,7 @@ static int Process(const WebPMuxConfig* config) {
|
||||
case SUBTYPE_LOOP: {
|
||||
int parse_error = 0;
|
||||
const int loop_count =
|
||||
ExUtilGetInt(feature->args_[i].params_, 10, &parse_error);
|
||||
ExUtilGetInt(config->args_[i].params_, 10, &parse_error);
|
||||
if (loop_count < 0 || loop_count > 65535) {
|
||||
// Note: This is only a 'necessary' condition for loop_count
|
||||
// to be valid. The 'sufficient' conditioned in checked in
|
||||
@ -965,10 +1009,10 @@ static int Process(const WebPMuxConfig* config) {
|
||||
case SUBTYPE_ANMF: {
|
||||
WebPMuxFrameInfo frame;
|
||||
frame.id = WEBP_CHUNK_ANMF;
|
||||
ok = ReadFileToWebPData(feature->args_[i].filename_,
|
||||
ok = ReadFileToWebPData(config->args_[i].filename_,
|
||||
&frame.bitstream);
|
||||
if (!ok) goto Err2;
|
||||
ok = ParseFrameArgs(feature->args_[i].params_, &frame);
|
||||
ok = ParseFrameArgs(config->args_[i].params_, &frame);
|
||||
if (!ok) {
|
||||
WebPDataClear(&frame.bitstream);
|
||||
ERROR_GOTO1("ERROR: Could not parse frame properties.\n",
|
||||
@ -1001,13 +1045,13 @@ static int Process(const WebPMuxConfig* config) {
|
||||
case FEATURE_XMP: {
|
||||
ok = CreateMux(config->input_, &mux);
|
||||
if (!ok) goto Err2;
|
||||
ok = ReadFileToWebPData(feature->args_[0].filename_, &chunk);
|
||||
ok = ReadFileToWebPData(config->args_[0].filename_, &chunk);
|
||||
if (!ok) goto Err2;
|
||||
err = WebPMuxSetChunk(mux, kFourccList[feature->type_], &chunk, 1);
|
||||
err = WebPMuxSetChunk(mux, kFourccList[config->type_], &chunk, 1);
|
||||
free((void*)chunk.bytes);
|
||||
if (err != WEBP_MUX_OK) {
|
||||
ERROR_GOTO3("ERROR (%s): Could not set the %s.\n",
|
||||
ErrorString(err), kDescriptions[feature->type_], Err2);
|
||||
ErrorString(err), kDescriptions[config->type_], Err2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1043,11 +1087,11 @@ static int Process(const WebPMuxConfig* config) {
|
||||
for (i = 0; i < num_frames; ++i) durations[i] = -1;
|
||||
|
||||
// Parse intervals to process.
|
||||
for (i = 0; i < feature->arg_count_; ++i) {
|
||||
for (i = 0; i < config->arg_count_; ++i) {
|
||||
int k;
|
||||
int args[3];
|
||||
int duration, start, end;
|
||||
const int nb_args = ExUtilGetInts(feature->args_[i].params_,
|
||||
const int nb_args = ExUtilGetInts(config->args_[i].params_,
|
||||
10, 3, args);
|
||||
ok = (nb_args >= 1);
|
||||
if (!ok) goto Err3;
|
||||
@ -1105,12 +1149,12 @@ static int Process(const WebPMuxConfig* config) {
|
||||
case ACTION_STRIP: {
|
||||
ok = CreateMux(config->input_, &mux);
|
||||
if (!ok) goto Err2;
|
||||
if (feature->type_ == FEATURE_ICCP || feature->type_ == FEATURE_EXIF ||
|
||||
feature->type_ == FEATURE_XMP) {
|
||||
err = WebPMuxDeleteChunk(mux, kFourccList[feature->type_]);
|
||||
if (config->type_ == FEATURE_ICCP || config->type_ == FEATURE_EXIF ||
|
||||
config->type_ == FEATURE_XMP) {
|
||||
err = WebPMuxDeleteChunk(mux, kFourccList[config->type_]);
|
||||
if (err != WEBP_MUX_OK) {
|
||||
ERROR_GOTO3("ERROR (%s): Could not strip the %s.\n",
|
||||
ErrorString(err), kDescriptions[feature->type_], Err2);
|
||||
ErrorString(err), kDescriptions[config->type_], Err2);
|
||||
}
|
||||
} else {
|
||||
ERROR_GOTO1("ERROR: Invalid feature for action 'strip'.\n", Err2);
|
||||
@ -1140,7 +1184,7 @@ static int Process(const WebPMuxConfig* config) {
|
||||
// Main.
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
WebPMuxConfig config;
|
||||
Config config;
|
||||
int ok = InitializeConfig(argc - 1, argv + 1, &config);
|
||||
if (ok) {
|
||||
ok = Process(&config);
|
||||
|
@ -47,7 +47,8 @@ int ImgIoUtilReadFromStdin(const uint8_t** data, size_t* data_size) {
|
||||
while (!feof(stdin)) {
|
||||
// We double the buffer size each time and read as much as possible.
|
||||
const size_t extra_size = (max_size == 0) ? kBlockSize : max_size;
|
||||
void* const new_data = realloc(input, max_size + extra_size);
|
||||
// we allocate one extra byte for the \0 terminator
|
||||
void* const new_data = realloc(input, max_size + extra_size + 1);
|
||||
if (new_data == NULL) goto Error;
|
||||
input = (uint8_t*)new_data;
|
||||
max_size += extra_size;
|
||||
@ -55,6 +56,7 @@ int ImgIoUtilReadFromStdin(const uint8_t** data, size_t* data_size) {
|
||||
if (size < max_size) break;
|
||||
}
|
||||
if (ferror(stdin)) goto Error;
|
||||
if (input != NULL) input[size] = '\0'; // convenient 0-terminator
|
||||
*data = input;
|
||||
*data_size = size;
|
||||
return 1;
|
||||
@ -68,7 +70,7 @@ int ImgIoUtilReadFromStdin(const uint8_t** data, size_t* data_size) {
|
||||
int ImgIoUtilReadFile(const char* const file_name,
|
||||
const uint8_t** data, size_t* data_size) {
|
||||
int ok;
|
||||
void* file_data;
|
||||
uint8_t* file_data;
|
||||
size_t file_size;
|
||||
FILE* in;
|
||||
const int from_stdin = (file_name == NULL) || !strcmp(file_name, "-");
|
||||
@ -87,7 +89,8 @@ int ImgIoUtilReadFile(const char* const file_name,
|
||||
fseek(in, 0, SEEK_END);
|
||||
file_size = ftell(in);
|
||||
fseek(in, 0, SEEK_SET);
|
||||
file_data = malloc(file_size);
|
||||
// we allocate one extra byte for the \0 terminator
|
||||
file_data = (uint8_t*)malloc(file_size + 1);
|
||||
if (file_data == NULL) {
|
||||
fclose(in);
|
||||
fprintf(stderr, "memory allocation failure when reading file %s\n",
|
||||
@ -103,11 +106,14 @@ int ImgIoUtilReadFile(const char* const file_name,
|
||||
free(file_data);
|
||||
return 0;
|
||||
}
|
||||
*data = (uint8_t*)file_data;
|
||||
file_data[file_size] = '\0'; // convenient 0-terminator
|
||||
*data = file_data;
|
||||
*data_size = file_size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
int ImgIoUtilWriteFile(const char* const file_name,
|
||||
const uint8_t* data, size_t data_size) {
|
||||
int ok;
|
||||
|
@ -30,6 +30,9 @@ FILE* ImgIoUtilSetBinaryMode(FILE* file);
|
||||
// Allocates storage for entire file 'file_name' and returns contents and size
|
||||
// in 'data' and 'data_size'. Returns 1 on success, 0 otherwise. '*data' should
|
||||
// be deleted using free().
|
||||
// Note: for convenience, the data will be null-terminated with an extra byte
|
||||
// (not accounted for in *data_size), in case the file is text and intended
|
||||
// to be used as a C-string.
|
||||
// If 'file_name' is NULL or equal to "-", input is read from stdin by calling
|
||||
// the function ImgIoUtilReadFromStdin().
|
||||
int ImgIoUtilReadFile(const char* const file_name,
|
||||
|
@ -1,5 +1,5 @@
|
||||
.\" Hey, EMACS: -*- nroff -*-
|
||||
.TH WEBPMUX 1 "November 10, 2016"
|
||||
.TH WEBPMUX 1 "December 1, 2017"
|
||||
.SH NAME
|
||||
webpmux \- create animated WebP files from non\-animated WebP images, extract
|
||||
frames from animated WebP images, and manage XMP/EXIF metadata and ICC profile.
|
||||
@ -48,6 +48,8 @@ frames from animated WebP images, and manage XMP/EXIF metadata and ICC profile.
|
||||
.B webpmux [\-h|\-help]
|
||||
.br
|
||||
.B webpmux \-version
|
||||
.br
|
||||
.B webpmux argument_file_name
|
||||
.SH DESCRIPTION
|
||||
This manual page documents the
|
||||
.B webpmux
|
||||
@ -55,6 +57,9 @@ command.
|
||||
.PP
|
||||
\fBwebpmux\fP can be used to create/extract from animated WebP files, as well as
|
||||
to add/extract/strip XMP/EXIF metadata and ICC profile.
|
||||
If a single file name (not starting with the character '\-') is supplied as
|
||||
the argument, the command line argument are actually tokenized from this file.
|
||||
This allows for easy scripting or using large number of arguments.
|
||||
.SH OPTIONS
|
||||
.SS GET_OPTIONS (\-get):
|
||||
.TP
|
||||
|
Loading…
Reference in New Issue
Block a user