Commit message: Double-check that the input image's density is valid

Fixes a bug that could result in division by zero, at least for a JPEG
source image.
Fixes issues #19, #20
CVE: CVE-2017-9201
CWE: CWE-369
Vulnerability description: imagew-cmd.c:850:46 in libimageworsener.a in ImageWorsener 1.3.1 allows remote attackers to cause a denial of service (divide-by-zero error) via a crafted image, related to imagew-api.c.

Project: imageworsener

IW_IMPL(size_t) iw_calc_bytesperrow(int num_pixels, int bits_per_pixel)
{
	return (size_t)(((num_pixels*bits_per_pixel)+7)/8);
}

Project: imageworsener

IW_IMPL(struct iw_context*) iw_create_context(struct iw_init_params *params)
{
	struct iw_context *ctx;

	if(params && params->mallocfn) {
		ctx = (*params->mallocfn)(params->userdata,IW_MALLOCFLAG_ZEROMEM,sizeof(struct iw_context));
	}
	else {
		ctx = iwpvt_default_malloc(NULL,IW_MALLOCFLAG_ZEROMEM,sizeof(struct iw_context));
	}

	if(!ctx) return NULL;

	if(params) {
		ctx->userdata = params->userdata;
		ctx->caller_api_version = params->api_version;
	}

	if(params && params->mallocfn) {
		ctx->mallocfn = params->mallocfn;
		ctx->freefn = params->freefn;
	}
	else {
		ctx->mallocfn = iwpvt_default_malloc;
		ctx->freefn = iwpvt_default_free;
	}

	ctx->max_malloc = IW_DEFAULT_MAX_MALLOC;
	ctx->max_width = ctx->max_height = IW_DEFAULT_MAX_DIMENSION;
	default_resize_settings(&ctx->resize_settings[IW_DIMENSION_H]);
	default_resize_settings(&ctx->resize_settings[IW_DIMENSION_V]);
	ctx->input_w = -1;
	ctx->input_h = -1;
	iw_make_srgb_csdescr_2(&ctx->img1cs);
	iw_make_srgb_csdescr_2(&ctx->img2cs);
	ctx->to_grayscale=0;
	ctx->grayscale_formula = IW_GSF_STANDARD;
	ctx->req.include_screen = 1;
	ctx->opt_grayscale = 1;
	ctx->opt_palette = 1;
	ctx->opt_16_to_8 = 1;
	ctx->opt_strip_alpha = 1;
	ctx->opt_binary_trns = 1;

	return ctx;
}

Project: imageworsener

IW_IMPL(const struct iw_palette*) iw_get_output_palette(struct iw_context *ctx)
{
	return ctx->optctx.palette;
}

Project: imageworsener

IW_IMPL(void) iw_make_srgb_csdescr(struct iw_csdescr *cs, int srgb_intent)
{
	cs->cstype = IW_CSTYPE_SRGB;
	cs->gamma = 0.0;
	cs->srgb_intent = srgb_intent;
}

Project: imageworsener

IW_IMPL(void) iw_set_apply_bkgd_2(struct iw_context *ctx, const struct iw_color *clr)
{
	ctx->req.bkgd_valid=1;
	ctx->req.bkgd = *clr;
}

Project: imageworsener

IW_IMPL(void) iw_set_bkgd_checkerboard(struct iw_context *ctx, int checkersize,
    double r2, double g2, double b2)
{
	struct iw_color clr;
	clr.c[IW_CHANNELTYPE_RED]=r2;
	clr.c[IW_CHANNELTYPE_GREEN]=g2;
	clr.c[IW_CHANNELTYPE_BLUE]=b2;
	clr.c[IW_CHANNELTYPE_ALPHA]=1.0;
	iw_set_bkgd_checkerboard_2(ctx, checkersize, &clr);
}

Project: imageworsener

IW_IMPL(void) iw_set_dither_type(struct iw_context *ctx, int channeltype, int f, int s)
{
	if(channeltype>=0 && channeltype<IW_NUM_CHANNELTYPES) {
		ctx->ditherfamily_by_channeltype[channeltype] = f;
		ctx->dithersubtype_by_channeltype[channeltype] = s;
	}

	switch(channeltype) {
	case IW_CHANNELTYPE_ALL:
		ctx->ditherfamily_by_channeltype[IW_CHANNELTYPE_ALPHA] = f;
		ctx->dithersubtype_by_channeltype[IW_CHANNELTYPE_ALPHA] = s;
	case IW_CHANNELTYPE_NONALPHA:
		ctx->ditherfamily_by_channeltype[IW_CHANNELTYPE_RED] = f;
		ctx->dithersubtype_by_channeltype[IW_CHANNELTYPE_RED] = s;
		ctx->ditherfamily_by_channeltype[IW_CHANNELTYPE_GREEN] = f;
		ctx->dithersubtype_by_channeltype[IW_CHANNELTYPE_GREEN] = s;
		ctx->ditherfamily_by_channeltype[IW_CHANNELTYPE_BLUE] = f;
		ctx->dithersubtype_by_channeltype[IW_CHANNELTYPE_BLUE] = s;
		ctx->ditherfamily_by_channeltype[IW_CHANNELTYPE_GRAY] = f;
		ctx->dithersubtype_by_channeltype[IW_CHANNELTYPE_GRAY] = s;
		break;
	}
}

Project: imageworsener

IW_IMPL(void) iw_set_output_bkgd_label_2(struct iw_context *ctx, const struct iw_color *clr)
{
	ctx->req.output_bkgd_label_valid = 1;
	ctx->req.output_bkgd_label = *clr;
}

Project: imageworsener

IW_IMPL(void) iw_set_resize_alg(struct iw_context *ctx, int dimension, int family,
    double blur, double param1, double param2)
{
	struct iw_resize_settings *rs;

	if(dimension<0 || dimension>1) dimension=0;
	rs=&ctx->resize_settings[dimension];

	rs->family = family;
	rs->blur_factor = blur;
	rs->param1 = param1;
	rs->param2 = param2;
}

Project: imageworsener

IW_IMPL(void) iw_set_value(struct iw_context *ctx, int code, int n)
{
	switch(code) {
	case IW_VAL_API_VERSION:
		ctx->caller_api_version = n;
		break;
	case IW_VAL_CVT_TO_GRAYSCALE:
		ctx->to_grayscale = n;
		break;
	case IW_VAL_DISABLE_GAMMA:
		ctx->no_gamma = n;
		break;
	case IW_VAL_NO_CSLABEL:
		ctx->req.suppress_output_cslabel = n;
		break;
	case IW_VAL_INT_CLAMP:
		ctx->intclamp = n;
		break;
	case IW_VAL_EDGE_POLICY_X:
		ctx->resize_settings[IW_DIMENSION_H].edge_policy = n;
		break;
	case IW_VAL_EDGE_POLICY_Y:
		ctx->resize_settings[IW_DIMENSION_V].edge_policy = n;
		break;
	case IW_VAL_PREF_UNITS:
		ctx->pref_units = n;
		break;
	case IW_VAL_GRAYSCALE_FORMULA:
		ctx->grayscale_formula = n;
		break;
	case IW_VAL_INPUT_NATIVE_GRAYSCALE:
		ctx->img1.native_grayscale = n;
		break;
	case IW_VAL_COMPRESSION:
		ctx->req.compression = n;
		break;
	case IW_VAL_PAGE_TO_READ:
		ctx->req.page_to_read = n;
		break;
	case IW_VAL_INCLUDE_SCREEN:
		ctx->req.include_screen = n;
		break;
	case IW_VAL_JPEG_QUALITY:
		iw_set_option(ctx, "jpeg:quality", iwpvt_strdup_dbl(ctx, (double)n));
		break;
	case IW_VAL_JPEG_SAMP_FACTOR_H:
		iw_set_option(ctx, "jpeg:sampling-x", iwpvt_strdup_dbl(ctx, (double)n));
		break;
	case IW_VAL_JPEG_SAMP_FACTOR_V:
		iw_set_option(ctx, "jpeg:sampling-y", iwpvt_strdup_dbl(ctx, (double)n));
		break;
	case IW_VAL_JPEG_ARITH_CODING:
		iw_set_option(ctx, "jpeg:arith", iwpvt_strdup_dbl(ctx, (double)n));
		break;
	case IW_VAL_DEFLATE_CMPR_LEVEL:
		iw_set_option(ctx, "deflate:cmprlevel", iwpvt_strdup_dbl(ctx, (double)n)); 
		break;
	case IW_VAL_OUTPUT_INTERLACED:
		ctx->req.interlaced = n;
		break;
	case IW_VAL_USE_BKGD_LABEL:
		ctx->req.use_bkgd_label_from_file = n;
		break;
	case IW_VAL_BMP_NO_FILEHEADER:
		ctx->req.bmp_no_fileheader = n;
		break;
	case IW_VAL_BMP_VERSION:
		iw_set_option(ctx, "bmp:version", iwpvt_strdup_dbl(ctx, (double)n));
		break;
	case IW_VAL_MAX_WIDTH:
		ctx->max_width = n;
		break;
	case IW_VAL_MAX_HEIGHT:
		ctx->max_height = n;
		break;
	case IW_VAL_NO_BKGD_LABEL:
		ctx->req.suppress_output_bkgd_label = n;
		break;
	case IW_VAL_INTENT:
		ctx->req.output_rendering_intent = n;
		break;
	case IW_VAL_OUTPUT_SAMPLE_TYPE:
		ctx->req.output_sample_type = n;
		break;
	case IW_VAL_OUTPUT_COLOR_TYPE:
		if(n==IW_COLORTYPE_RGB) {
			iw_set_option(ctx, "deflate:colortype", "rgb"); 
		}
		break;
	case IW_VAL_OUTPUT_FORMAT:
		ctx->req.output_format = n;
		break;
	case IW_VAL_NEGATE_TARGET:
		ctx->req.negate_target = n;
		break;
	}
}

Project: imageworsener

IW_IMPL(void) iw_set_value_dbl(struct iw_context *ctx, int code, double n)
{
	switch(code) {
	case IW_VAL_WEBP_QUALITY:
		iw_set_option(ctx, "webp:quality", iwpvt_strdup_dbl(ctx, n)); 
		break;
	case IW_VAL_TRANSLATE_X:
		ctx->resize_settings[IW_DIMENSION_H].translate = n;
		break;
	case IW_VAL_TRANSLATE_Y:
		ctx->resize_settings[IW_DIMENSION_V].translate = n;
		break;
	}
}

Project: imageworsener

IW_IMPL(void) iw_set_zlib_module(struct iw_context *ctx, struct iw_zlib_module *z)
{
	ctx->zlib_module = z;
}

Project: imageworsener

IW_IMPL(void) iw_translate(struct iw_context *ctx, unsigned int flags,
	char *dst, size_t dstlen, const char *src)
{
	int ret;

	dst[0]='\0';

	if(ctx && ctx->translate_fn) {
		ret = (*ctx->translate_fn)(ctx,flags,dst,dstlen,src);
	}
	else {
		ret = 0;
	}

	if(!ret) {
		iw_strlcpy(dst,src,dstlen);
	}
}