From 101af138e47b95320b6d179b2bf7018d0f938034 Mon Sep 17 00:00:00 2001 From: giraffedata Date: Sun, 29 Jul 2007 02:10:42 +0000 Subject: Add bitwise functions to Pamfunc git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@365 9d0c8265-081b-0410-96cb-a4ca84ce46f8 --- doc/HISTORY | 3 + editor/pamfunc.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 175 insertions(+), 18 deletions(-) diff --git a/doc/HISTORY b/doc/HISTORY index 83553c28..5720d444 100644 --- a/doc/HISTORY +++ b/doc/HISTORY @@ -6,6 +6,9 @@ CHANGE HISTORY not yet BJH Release 10.40.00 + pamfunc: Add -andmask, -ormask, -xormask, -not, + -shiftleft, -shiftright. + anytopnm, pnmmargin, pamstretch-gen, ppmquantall: fix small temporary file security exposure. diff --git a/editor/pamfunc.c b/editor/pamfunc.c index dbb1ca70..d380303a 100644 --- a/editor/pamfunc.c +++ b/editor/pamfunc.c @@ -18,10 +18,24 @@ ******************************************************************************/ -#include "pam.h" +#include "mallocvar.h" #include "shhopt.h" +#include "pam.h" -enum function {FN_MULTIPLY, FN_DIVIDE, FN_ADD, FN_SUBTRACT, FN_MIN, FN_MAX}; +enum function { + FN_MULTIPLY, + FN_DIVIDE, + FN_ADD, + FN_SUBTRACT, + FN_MIN, + FN_MAX, + FN_AND, + FN_OR, + FN_XOR, + FN_NOT, + FN_SHIFTLEFT, + FN_SHIFTRIGHT +}; /* Note that when the user specifies a minimum, that means he's requesting a "max" function. @@ -40,11 +54,30 @@ struct cmdlineInfo { int subtractor; unsigned int max; unsigned int min; + unsigned int mask; + unsigned int shiftCount; } u; unsigned int verbose; }; + +static unsigned int +parseHex(const char * const hexString) { + + unsigned int retval; + char * tail; + + retval = strtol(hexString, &tail, 16); + + if (*tail != '\0') + pm_error("Invalid hex string '%s'. Junk: '%s'", hexString, tail); + + return retval; +} + + + static void parseCommandLine(int argc, char ** const argv, struct cmdlineInfo * const cmdlineP) { @@ -52,29 +85,46 @@ parseCommandLine(int argc, char ** const argv, Note that the file spec array we return is stored in the storage that was passed to us as the argv array. -----------------------------------------------------------------------------*/ - optEntry *option_def = malloc(100*sizeof(optEntry)); - /* Instructions to OptParseOptions2 on how to parse our options. - */ + optEntry * option_def; + /* Instructions to OptParseOptions3 on how to parse our options. */ optStruct3 opt; unsigned int option_def_index; unsigned int multiplierSpec, divisorSpec, adderSpec, subtractorSpec; unsigned int maxSpec, minSpec; + unsigned int andmaskSpec, ormaskSpec, xormaskSpec, notSpec; + unsigned int shiftleftSpec, shiftrightSpec; + + const char * mask; + + MALLOCARRAY(option_def, 100); - option_def_index = 0; /* incremented by OPTENTRY */ + option_def_index = 0; /* incremented by OPTENT3 */ OPTENT3(0, "multiplier", OPT_FLOAT, &cmdlineP->u.multiplier, &multiplierSpec, 0); OPTENT3(0, "divisor", OPT_FLOAT, &cmdlineP->u.divisor, - &divisorSpec, 0); + &divisorSpec, 0); OPTENT3(0, "adder", OPT_INT, &cmdlineP->u.adder, - &adderSpec, 0); + &adderSpec, 0); OPTENT3(0, "subtractor", OPT_INT, &cmdlineP->u.subtractor, &subtractorSpec, 0); OPTENT3(0, "min", OPT_UINT, &cmdlineP->u.min, - &minSpec, 0); + &minSpec, 0); OPTENT3(0, "max", OPT_UINT, &cmdlineP->u.max, - &maxSpec, 0); + &maxSpec, 0); + OPTENT3(0, "andmask", OPT_STRING, &mask, + &andmaskSpec, 0); + OPTENT3(0, "ormask", OPT_STRING, &mask, + &ormaskSpec, 0); + OPTENT3(0, "xormask", OPT_STRING, &mask, + &xormaskSpec, 0); + OPTENT3(0, "not", OPT_FLAG, NULL, + ¬Spec, 0); + OPTENT3(0, "shiftleft", OPT_UINT, &cmdlineP->u.shiftCount, + &shiftleftSpec, 0); + OPTENT3(0, "shiftright", OPT_UINT, &cmdlineP->u.shiftCount, + &shiftrightSpec, 0); OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); opt.opt_table = option_def; @@ -85,9 +135,12 @@ parseCommandLine(int argc, char ** const argv, /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (multiplierSpec + divisorSpec + adderSpec + subtractorSpec + - minSpec + maxSpec > 1) + minSpec + maxSpec + andmaskSpec + ormaskSpec + xormaskSpec + notSpec + + shiftleftSpec + shiftrightSpec > 1) pm_error("You may specify at most one of -multiplier, -divisor," - "-adder, -subtractor, -min, and -max"); + "-adder, -subtractor, -min, -max, " + "-andmask, -ormask, -xormask, -not, " + "-shiftleft, and -shiftright"); if (multiplierSpec) { cmdlineP->function = FN_MULTIPLY; @@ -107,9 +160,25 @@ parseCommandLine(int argc, char ** const argv, cmdlineP->function = FN_MAX; } else if (maxSpec) { cmdlineP->function = FN_MIN; + } else if (andmaskSpec) { + cmdlineP->function = FN_AND; + cmdlineP->u.mask = parseHex(mask); + } else if (ormaskSpec) { + cmdlineP->function = FN_OR; + cmdlineP->u.mask = parseHex(mask); + } else if (xormaskSpec) { + cmdlineP->function = FN_XOR; + cmdlineP->u.mask = parseHex(mask); + } else if (notSpec) { + cmdlineP->function = FN_NOT; + } else if (shiftleftSpec) { + cmdlineP->function = FN_SHIFTLEFT; + } else if (shiftrightSpec) { + cmdlineP->function = FN_SHIFTRIGHT; } else pm_error("You must specify one of -multiplier, -divisor, " - "-adder, -subtractor, -min, or -max"); + "-adder, -subtractor, -min, -max, " + "-and, -or, -xor, -not, -shiftleft, or -shiftright"); if (argc-1 > 1) pm_error("Too many arguments (%d). File spec is the only argument.", @@ -124,6 +193,70 @@ parseCommandLine(int argc, char ** const argv, +static bool +isDyadicMaskFunction(enum function const fn) { + + return (fn == FN_AND || fn == FN_OR || fn == FN_XOR); +} + + + +static bool +isMaskFunction(enum function const fn) { + + return (isDyadicMaskFunction(fn) || fn == FN_NOT); +} + + + +static bool +isShiftFunction(enum function const fn) { + + return (fn == FN_SHIFTLEFT || fn == FN_SHIFTRIGHT); +} + + + +static bool +isBitstringFunction(enum function const fn) { + + return isMaskFunction(fn) || isShiftFunction(fn); +} + + + +static void +validateFunction(struct cmdlineInfo const cmdline, + const struct pam * const pamP) { + + if (isBitstringFunction(cmdline.function)) { + if (pm_bitstomaxval(pm_maxvaltobits(pamP->maxval)) != pamP->maxval) + pm_error("For a bit string function, the maxval must be a full " + "binary count, i.e. a power of two minus one such as " + "0xff or 0x1. You have 0x%x", + (unsigned)pamP->maxval); + + if (isDyadicMaskFunction(cmdline.function)) { + if ((cmdline.u.mask & pamP->maxval) != cmdline.u.mask) + pm_error("Your bit string mask 0x%x is wider than the samples " + "of the image (%u bits, according to the maxval %lu", + cmdline.u.mask, pm_maxvaltobits(pamP->maxval), + pamP->maxval); + } + + if (isShiftFunction(cmdline.function)) { + if (cmdline.u.shiftCount > pm_maxvaltobits(pamP->maxval)) + pm_error("Your shift count (%u) is greater than the width " + "of the samples of the image (%u bits, according " + "to the maxval %lu)", + cmdline.u.shiftCount, pm_maxvaltobits(pamP->maxval), + pamP->maxval); + } + } +} + + + static void applyFunction(struct cmdlineInfo const cmdline, struct pam const inpam, @@ -168,6 +301,25 @@ applyFunction(struct cmdlineInfo const cmdline, case FN_MIN: outSample = MIN(inSample, cmdline.u.max); break; + case FN_AND: + outSample = inSample & cmdline.u.mask; + break; + case FN_OR: + outSample = inSample | cmdline.u.mask; + break; + case FN_XOR: + outSample = inSample ^ cmdline.u.mask; + break; + case FN_NOT: + outSample = ~inSample; + break; + case FN_SHIFTLEFT: + outSample = + (inSample << cmdline.u.shiftCount) & outpam.maxval; + break; + case FN_SHIFTRIGHT: + outSample = inSample >> cmdline.u.shiftCount; + break; } outputRow[col][plane] = MIN(outpam.maxval, outSample); } @@ -179,15 +331,15 @@ applyFunction(struct cmdlineInfo const cmdline, int main(int argc, char *argv[]) { - FILE* ifP; - tuple* inputRow; /* Row from input image */ - tuple* outputRow; /* Row of output image */ + FILE * ifP; + tuple * inputRow; /* Row from input image */ + tuple * outputRow; /* Row of output image */ int row; struct cmdlineInfo cmdline; struct pam inpam; /* Input PAM image */ struct pam outpam; /* Output PAM image */ - pnm_init( &argc, argv ); + pnm_init(&argc, argv); parseCommandLine(argc, argv, &cmdline); @@ -195,6 +347,8 @@ main(int argc, char *argv[]) { pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); + validateFunction(cmdline, &inpam); + inputRow = pnm_allocpamrow(&inpam); outpam = inpam; /* Initial value -- most fields should be same */ @@ -216,6 +370,6 @@ main(int argc, char *argv[]) { pm_close(inpam.file); pm_close(outpam.file); - exit(0); + return 0; } -- cgit 1.4.1