root/mod_small_light.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. create_small_light_server_conf
  2. small_light_define_pattern
  3. small_light_find_pattern
  4. small_light_post_config
  5. small_light_filter
  6. small_light_register_hooks
  7. small_light_init_param
  8. small_light_parse_uri_param
  9. small_light_parse_param
  10. small_light_parse_flag
  11. small_light_parse_int
  12. small_light_parse_double
  13. small_light_parse_coord
  14. small_light_calc_coord
  15. small_light_parse_color
  16. small_light_alloc
  17. small_light_realloc
  18. small_light_free
  19. small_light_timeval_diff
  20. small_light_receive_data
  21. small_light_calc_image_size

/* 
**  mod_small_light.c -- Apache sample small_light module
**  [Autogenerated via ``apxs -n small_light -g'']
**
**  To play with this sample module first compile it into a
**  DSO file and install it into Apache's modules directory 
**  by running:
**
**    $ apxs -c -i mod_small_light.c
**
**  Then activate it in Apache's httpd.conf file for instance
**  for the URL /small_light in as follows:
**
**    #   httpd.conf
**    LoadModule small_light_module modules/mod_small_light.so
**    <Location /small_light>
**        SetHandler small_light
**    </Location>
**
**  Then after restarting Apache via
**
**    $ apachectl restart
**
**  you immediately can request the URL /small_light and watch for the
**  output of this module. This can be achieved for instance via:
**
**    $ lynx -mime_header http://localhost/small_light 
**
**  The output should be similar to the following one:
**
**    HTTP/1.1 200 OK
**    Date: Tue, 31 Mar 1998 14:42:22 GMT
**    Server: Apache/1.3.4 (Unix)
**    Connection: close
**    Content-Type: text/html
**  
**    The sample page from mod_small_light.c
*/ 

#include "mod_small_light.h"

small_light_filter_prototype(dummy);
small_light_filter_prototype(imlib2);
small_light_filter_prototype(imagemagick);

static const char small_light_filter_name[] = "SMALL_LIGHT";
module AP_MODULE_DECLARE_DATA small_light_module;

static void *create_small_light_server_conf(apr_pool_t *p, server_rec *s)
{
    small_light_server_conf_t *conf;
    conf = (small_light_server_conf_t *)apr_pcalloc(p, sizeof(small_light_server_conf_t));
    conf->p = p;
    conf->h = apr_hash_make(conf->p);
    return conf;
}

static const char *small_light_define_pattern(cmd_parms *cmd, void *ctx, const char *arg1, const char *arg2)
{
    small_light_server_conf_t *sc = ap_get_module_config(
        cmd->server->module_config, &small_light_module);

    const char *key = arg1;
    const char *value = arg2;
    
    if (apr_hash_get(sc->h, key, APR_HASH_KEY_STRING)) {
        return (char *)(size_t)apr_psprintf(cmd->pool, "SmallLightPatternDefine %s is already defined", key);
    }

    small_light_pattern_t *ptn;
    ptn = (small_light_pattern_t *)apr_pcalloc(sc->p, sizeof(small_light_pattern_t));
    ptn->name = key;
    ptn->param_str = (char *)apr_pstrdup(cmd->pool, value);
    apr_hash_set(sc->h, key, APR_HASH_KEY_STRING, ptn);

    return NULL;
}

static small_light_pattern_t *small_light_find_pattern(request_rec *r, char *name)
{
    small_light_server_conf_t *sc = ap_get_module_config(
        r->server->module_config, &small_light_module);
    small_light_pattern_t *ptn = apr_hash_get(sc->h, name, APR_HASH_KEY_STRING);
    return ptn;
}

static int small_light_post_config(
    apr_pool_t *pconf,
    apr_pool_t *plog,
    apr_pool_t *ptemp,
    server_rec *s
)
{
#if APR_HAS_THREADS
    int mpm_threads;
    ap_mpm_query(AP_MPMQ_MAX_THREADS, &mpm_threads);
    if (mpm_threads >= 1) {
        ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
            "small_light module only works with mpm prefork mode"
        );
        return HTTP_INTERNAL_SERVER_ERROR;
    }
#endif
    return APR_SUCCESS;
}

static apr_status_t small_light_filter(ap_filter_t *f, apr_bucket_brigade *bb)
{
    request_rec *r = f->r;
    small_light_module_ctx_t *ctx = f->ctx;

    // do nothing if bucket brigade is empty.
    if (APR_BRIGADE_EMPTY(bb))
        return APR_SUCCESS;

    // initialize context at first time.
    if (!ctx) {
        // main request only.
        if (r->main) {
            ap_remove_output_filter(f);
            return ap_pass_brigade(f->next, bb);
        }

        // modify redirect location if HTTP_MOVED_PERMANENTLY
        // or HTTP_MOVED_TEMPORARILY or HTTP_SEE_OTHER.
        if (r->status == HTTP_MOVED_PERMANENTLY ||
            r->status == HTTP_MOVED_TEMPORARILY ||
            r->status == HTTP_SEE_OTHER) {
            char *base_uri = (char *)apr_table_get(r->headers_in, "X-SmallLight-Base-URI");
            if (base_uri) {
                char *loc = (char *)apr_table_get(r->headers_out, "Location");
                char *sl_loc = (char *)(size_t)apr_psprintf(r->pool, "%s%s", base_uri, loc);
                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Location: %s -> %s", loc, sl_loc);
                apr_table_set(r->headers_out, "Location", sl_loc);
            }
            ap_remove_output_filter(f);
            return ap_pass_brigade(f->next, bb);
        }

        // do nothing if not HTTP_OK.
        if (r->status != HTTP_OK) {
            ap_remove_output_filter(f);
            return ap_pass_brigade(f->next, bb);
        }

        // No need to process HEAD or 204/304, by mod_deflate.
        if (APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(bb))) {
            ap_remove_output_filter(f);
            return ap_pass_brigade(f->next, bb);
        }

        // initialize context.
        f->ctx = ctx = (small_light_module_ctx_t *)apr_pcalloc(r->pool, sizeof(small_light_module_ctx_t));

        // parse pattern or engine in uri.
        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "uri=%s", r->uri);
        int res;
        char param_str[SMALL_LIGHT_PARAM_STR_MAX];
        res = small_light_parse_uri_param(r, param_str, r->unparsed_uri);
        if (res != OK) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "parse_uri_param failed: %s", r->unparsed_uri);
            r->status = HTTP_BAD_REQUEST;
            ap_remove_output_filter(f);
            return ap_pass_brigade(f->next, bb);
        }
        ctx->prm = apr_table_make(r->pool, 10);
        small_light_init_param(ctx->prm);
        res = small_light_parse_param(r, ctx->prm, param_str);
        if (res != OK) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "parse_param failed: %s", r->unparsed_uri);
            r->status = HTTP_BAD_REQUEST;
            ap_remove_output_filter(f);
            return ap_pass_brigade(f->next, bb);
        }
        char *pattern = (char *)apr_table_get(ctx->prm, "p");
        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "pattern=%s", pattern);
        small_light_pattern_t *ptn = NULL;
        if (pattern && pattern[0] != '\0') {
            ptn = small_light_find_pattern(r, pattern);
            if (!ptn) {
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "pattern not found: %s", param_str);
                r->status = HTTP_BAD_REQUEST;
                ap_remove_output_filter(f);
                return ap_pass_brigade(f->next, bb);
            }
            apr_table_clear(ctx->prm);
            small_light_init_param(ctx->prm);
            small_light_parse_param(r, ctx->prm, ptn->param_str);
            res = small_light_parse_param(r, ctx->prm, param_str);
            if (res != OK) {
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "parse_param failed: %s", param_str);
                r->status = HTTP_BAD_REQUEST;
                ap_remove_output_filter(f);
                return ap_pass_brigade(f->next, bb);
            }
        }
        char *engine = (char *)apr_table_get(ctx->prm, "e");
        if (!engine || engine[0] == '\0') {
            apr_table_set(ctx->prm, "e", SMALL_LIGHT_DEFAULT_ENGINE);
        }
        engine = (char *)apr_table_get(ctx->prm, "e");
        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "engine=%s", engine);

        // set function.
        if (strcmp(engine, SMALL_LIGHT_ENGINE_IMLIB2) == 0) {
            ctx->init_func = (SMALL_LIGHT_FILTER_INIT)small_light_filter_imlib2_init;
            ctx->receive_data_func = (SMALL_LIGHT_FILTER_RECEIVE_DATA)small_light_filter_imlib2_receive_data;
            ctx->output_data_func = (SMALL_LIGHT_FILTER_OUTPUT_DATA)small_light_filter_imlib2_output_data;
        } else if (strcmp(engine, SMALL_LIGHT_ENGINE_IMAGEMAGICK) == 0) {
            ctx->init_func = (SMALL_LIGHT_FILTER_INIT)small_light_filter_imagemagick_init;
            ctx->receive_data_func = (SMALL_LIGHT_FILTER_RECEIVE_DATA)small_light_filter_imagemagick_receive_data;
            ctx->output_data_func = (SMALL_LIGHT_FILTER_OUTPUT_DATA)small_light_filter_imagemagick_output_data;
        }
        if (ctx->init_func == NULL) {
            ctx->init_func = (SMALL_LIGHT_FILTER_INIT)small_light_filter_dummy_init;
            ctx->receive_data_func = (SMALL_LIGHT_FILTER_RECEIVE_DATA)small_light_filter_dummy_receive_data;
            ctx->output_data_func = (SMALL_LIGHT_FILTER_OUTPUT_DATA)small_light_filter_dummy_output_data;
        }

        // init filter engine.
        ctx->init_func(f, bb, ctx);

        // create bucket brigade.
        ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc);

        gettimeofday(&ctx->t, NULL);
    }

    // bucket brigade loop.
    while (!APR_BRIGADE_EMPTY(bb))
    {
        apr_bucket *e;
        const char *data;
        apr_size_t len;
        apr_status_t rv;

        e = APR_BRIGADE_FIRST(bb);

        if (APR_BUCKET_IS_EOS(e)) {
            // finally, output data process
            rv = ctx->output_data_func(f, bb, ctx, e);
            if ( rv != APR_SUCCESS ) {
                 apr_brigade_cleanup(bb);
                 f->r->status_line = "500 Internal Server Error";
                 e = ap_bucket_error_create(HTTP_INTERNAL_SERVER_ERROR,
                                            NULL, r->pool,
                                            f->c->bucket_alloc);
                 APR_BRIGADE_INSERT_TAIL(bb, e);
                 e = apr_bucket_eos_create(f->c->bucket_alloc);
                 APR_BRIGADE_INSERT_TAIL(bb, e);
                 ap_pass_brigade(f->next, bb);
                 return AP_FILTER_ERROR;
            }
            return rv;
        }

        if (APR_BUCKET_IS_FLUSH(e)) {
            // need to flush
            APR_BUCKET_REMOVE(e);
            APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
            continue;
        }
        if (APR_BUCKET_IS_METADATA(e)) {
            // remove meta data bucket
            APR_BUCKET_REMOVE(e);
            APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
            continue;
        }

        // read
        apr_bucket_read(e, &data, &len, APR_BLOCK_READ);

        // receive data process
        ctx->receive_data_func(f, bb, ctx, e, data, len);

        apr_bucket_delete(e);
    }

    apr_brigade_cleanup(bb);
    return APR_SUCCESS;
}

static void small_light_register_hooks(apr_pool_t *p)
{
    ap_hook_post_config(
        small_light_post_config,
        NULL,
        NULL,
        APR_HOOK_MIDDLE
    );
    ap_register_output_filter(
        small_light_filter_name,
        small_light_filter,
        NULL,
        AP_FTYPE_RESOURCE
    );
}

static const command_rec small_light_cmds[] =
{
    AP_INIT_TAKE2(
        "SmallLightPatternDefine",
        small_light_define_pattern,
        NULL,
        RSRC_CONF,
        "define pattern"),
    {NULL}
};

/* Dispatch list for API hooks */
module AP_MODULE_DECLARE_DATA small_light_module =
{
    STANDARD20_MODULE_STUFF, 
    NULL,                           /* create per-dir    config structures */
    NULL,                           /* merge  per-dir    config structures */
    create_small_light_server_conf, /* create per-server config structures */
    NULL,                           /* merge  per-server config structures */
    small_light_cmds,               /* table of config file commands       */
    small_light_register_hooks      /* register hooks                      */
};

void small_light_init_param(apr_table_t *prm)
{
    apr_table_set(prm, "sx", "");
    apr_table_set(prm, "sy", "");
    apr_table_set(prm, "sw", "");
    apr_table_set(prm, "sh", "");
    apr_table_set(prm, "dx", "");
    apr_table_set(prm, "dy", "");
    apr_table_set(prm, "dw", "");
    apr_table_set(prm, "dh", "");
    apr_table_set(prm, "da", "l");
    apr_table_set(prm, "ds", "n");
    apr_table_set(prm, "cw", "");
    apr_table_set(prm, "ch", "");
    apr_table_set(prm, "cc", "000000");
    apr_table_set(prm, "bw", "");
    apr_table_set(prm, "bh", "");
    apr_table_set(prm, "bc", "000000");
    apr_table_set(prm, "pt", "n");
    apr_table_set(prm, "q", "0");
    apr_table_set(prm, "of", "jpeg");
    apr_table_set(prm, "info", "0");
    apr_table_set(prm, "inhexif", "n");
    apr_table_set(prm, "jpeghint", "n");
}

int small_light_parse_uri_param(request_rec *r, char *param_str, const char *uri_str)
{
    // parse param string.
    // if ($str =~ m#/small_light\(([^\)]*)\)#i) { my $buf = $1; }
    int regsuccess;
    ap_regmatch_t regmatch[2];
    ap_regex_t *regex = ap_pregcomp(r->pool, "small_light\\(([^\\)]*)\\)", REG_EXTENDED | REG_ICASE | REG_NOSUB);
    regsuccess = ap_regexec(regex, uri_str, 2, regmatch, 0);
    ap_pregfree(r->pool, regex);
    if (regsuccess != 0) {
        return DECLINED;
    }
    if (regmatch[1].rm_so < 0) {
        return DECLINED;
    }
    int start = regmatch[1].rm_so;
    int len = regmatch[1].rm_eo - regmatch[1].rm_so;
    if (len >= SMALL_LIGHT_PARAM_STR_MAX) {
        return DECLINED;
    }
    memcpy(param_str, uri_str + start, len);
    param_str[len] = '\0';
    return OK;
}

int small_light_parse_param(
    request_rec *r,
    apr_table_t *prm,
    const char *param_str)
{
    // tokenize.
    const char *ptr1 = param_str;
    char *token;
    for (;;) {
        token = ap_get_token(r->pool, &ptr1, 0);
        if (!(token && *token)) {
            break;
        }
        const char *ptr2 = token, *key;
        key = ap_getword(r->pool, &ptr2, '=');
        apr_table_set(prm, key, ptr2);
        if (!*ptr1) {
            break;
        }
        ptr1++;
    }
    return OK;
}

int small_light_parse_flag(request_rec *r, const char *str)
{
    if (str != NULL && str[0] == 'y') {
        return 1;
    }
    return 0;
}

int small_light_parse_int(request_rec *r, const char *str)
{
    return atoi(str);
}

double small_light_parse_double(request_rec *r, const char *str)
{
    return atof(str);
}

int small_light_parse_coord(request_rec *r, small_light_coord_t *crd, const char *str)
{
    if (str[0] == '\0') {
        crd->v = 0;
        crd->u = SMALL_LIGHT_COORD_UNIT_NONE;
        return OK;
    }
    crd->v = atof(str);
    while (((*str >= '0' && *str <= '9') || *str == '.') && *str != '\0') str++;
    if (*str == 'p') {
        crd->u = SMALL_LIGHT_COORD_UNIT_PERCENT;
        return OK;
    } else if (*str == '\0') {
        crd->u = SMALL_LIGHT_COORD_UNIT_PIXEL;
        return OK;
    }
    return DECLINED;
}

double small_light_calc_coord(small_light_coord_t *crd, double v)
{
    if (crd->u == SMALL_LIGHT_COORD_UNIT_PIXEL) {
        return crd->v;
    } else if (crd->u == SMALL_LIGHT_COORD_UNIT_PERCENT) {
        return (v * crd->v * 0.01);
    }
    return SMALL_LIGHT_COORD_INVALID_VALUE;
}

int small_light_parse_color(request_rec *r, small_light_color_t *color, const char *str)
{
    int res;
    int len = strlen(str);
    if (len == 3) {
        res = sscanf(str, "%1hx%1hx%1hx", &color->r, &color->g, &color->b);
        if (res != EOF) {
            color->a = 255;
            return OK;
        }
    } else if (len == 4) {
        res = sscanf(str, "%1hx%1hx%1hx%1hx", &color->r, &color->g, &color->b, &color->a);
        if (res != EOF) {
            return OK;
        }
    } else if (len == 6) {
        res = sscanf(str, "%02hx%02hx%02hx", &color->r, &color->g, &color->b);
        if (res != EOF) {
            color->a = 255;
            return OK;
        }
    } else if (len == 8) {
        res = sscanf(str, "%02hx%02hx%02hx%02hx", &color->r, &color->g, &color->b, &color->a);
        if (res != EOF) {
            return OK;
        }
    }
    return DECLINED;
}

void *small_light_alloc(apr_pool_t *pool, apr_size_t size)
{
    void *new_ptr = malloc(size);
    return new_ptr;
}

void *small_light_realloc(apr_pool_t *pool, void *ptr, apr_size_t size, apr_size_t old_size)
{
    void *new_ptr = realloc(ptr, size);
    return new_ptr;
}

void small_light_free(apr_pool_t *pool, void *ptr)
{
    free(ptr);
}

long small_light_timeval_diff(struct timeval *st, struct timeval *et)
{
    return (long)(et->tv_sec - st->tv_sec) * 1000000 + (et->tv_usec - st->tv_usec);
}

apr_status_t small_light_receive_data(
    unsigned char **image,
    size_t *image_len,
    const ap_filter_t *f,
    const apr_bucket_brigade *bb,
    const char *data,
    const apr_size_t data_len)
{
    request_rec *r = f->r;

    const char *next_buff;
    next_buff = (const char *)small_light_realloc(r->pool, *image, *image_len + data_len, *image_len);
    if (next_buff == NULL) {
        if (*image) {
            small_light_free(r->pool, *image);
            *image = NULL;
        }
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "memory allocation failed");
        ap_pass_brigade(f->next, (apr_bucket_brigade *)bb);
        return DECLINED;
    }
    *image = (unsigned char *)next_buff;
    memcpy(*image + *image_len, data, data_len);
    *image_len += data_len;

    return APR_SUCCESS;
}

void small_light_calc_image_size(
    small_light_image_size_t *sz,
    request_rec *r,
    small_light_module_ctx_t *ctx,
    double iw, double ih)
{
    // calc image size.
    small_light_coord_t sx_coord, sy_coord, sw_coord, sh_coord;
    small_light_coord_t dx_coord, dy_coord, dw_coord, dh_coord;
    small_light_parse_coord(r, &sx_coord, (char *)apr_table_get(ctx->prm, "sx"));
    small_light_parse_coord(r, &sy_coord, (char *)apr_table_get(ctx->prm, "sy"));
    small_light_parse_coord(r, &sw_coord, (char *)apr_table_get(ctx->prm, "sw"));
    small_light_parse_coord(r, &sh_coord, (char *)apr_table_get(ctx->prm, "sh"));
    small_light_parse_coord(r, &dx_coord, (char *)apr_table_get(ctx->prm, "dx"));
    small_light_parse_coord(r, &dy_coord, (char *)apr_table_get(ctx->prm, "dy"));
    small_light_parse_coord(r, &dw_coord, (char *)apr_table_get(ctx->prm, "dw"));
    small_light_parse_coord(r, &dh_coord, (char *)apr_table_get(ctx->prm, "dh"));
    sz->sx = small_light_calc_coord(&sx_coord, iw);
    if (sz->sx == SMALL_LIGHT_COORD_INVALID_VALUE) {
        sz->sx = 0;
    }
    sz->sy = small_light_calc_coord(&sy_coord, ih);
    if (sz->sy == SMALL_LIGHT_COORD_INVALID_VALUE) {
        sz->sy = 0;
    }
    sz->sw = small_light_calc_coord(&sw_coord, iw);
    if (sz->sw == SMALL_LIGHT_COORD_INVALID_VALUE) {
        sz->sw = iw;
    }
    sz->sh = small_light_calc_coord(&sh_coord, ih);
    if (sz->sh == SMALL_LIGHT_COORD_INVALID_VALUE) {
        sz->sh = ih;
    }
    sz->dx = small_light_calc_coord(&dx_coord, iw);
    sz->dy = small_light_calc_coord(&dy_coord, ih);
    sz->dw = small_light_calc_coord(&dw_coord, iw);
    sz->dh = small_light_calc_coord(&dh_coord, ih);
    sz->aspect = sz->sw / sz->sh;
    char *da_str = (char *)apr_table_get(ctx->prm, "da");
    char da = da_str[0] ? da_str[0] : 'l';
    if (sz->dw != SMALL_LIGHT_COORD_INVALID_VALUE && sz->dh != SMALL_LIGHT_COORD_INVALID_VALUE) {
        if (da == 'l') {
            if (sz->sw / sz->dw < sz->sh / sz->dh) {
                sz->dw = sz->dh * sz->aspect;
            } else {
                sz->dh = sz->dw / sz->aspect;
            }
        } else if (da == 's') {
            if (sz->sw / sz->dw < sz->sh / sz->dh) {
                sz->dh = sz->dw / sz->aspect;
            } else {
                sz->dw = sz->dh * sz->aspect;
            }
        }
    } else {
        if (sz->dw == SMALL_LIGHT_COORD_INVALID_VALUE && sz->dh == sz->dw) {
            double dwo = sz->dw;
            sz->dw = sz->dh / sz->aspect;
            sz->dh = dwo / sz->aspect;
        } else if (sz->dw == SMALL_LIGHT_COORD_INVALID_VALUE) {
            sz->dw = sz->dh * sz->aspect;
        } else if (sz->dh == SMALL_LIGHT_COORD_INVALID_VALUE) {
            sz->dh = sz->dw / sz->aspect;
        }
    }
    sz->cw = small_light_parse_double(r, (char *)apr_table_get(ctx->prm, "cw"));
    sz->ch = small_light_parse_double(r, (char *)apr_table_get(ctx->prm, "ch"));
    small_light_parse_color(r, &sz->cc, (char *)apr_table_get(ctx->prm, "cc"));
    sz->bw = small_light_parse_double(r, (char *)apr_table_get(ctx->prm, "bw"));
    sz->bh = small_light_parse_double(r, (char *)apr_table_get(ctx->prm, "bh"));
    small_light_parse_color(r, &sz->bc, (char *)apr_table_get(ctx->prm, "bc"));
    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
        "size info:sx=%f,sy=%f,sw=%f,sh=%f,dw=%f,dh=%f,cw=%f,ch=%f,bw=%f,bh=%f",
        sz->sx, sz->sy, sz->sw, sz->sh,
        sz->dw, sz->dh, sz->cw, sz->ch, sz->bw, sz->bh);

    // get pass through option.
    int pt_flg = 0;
    char *pt = (char *)apr_table_get(ctx->prm, "pt");
    if (pt[0] == '\0' || strcmp(pt, "ptss") == 0) {
        if (sz->sw < sz->cw && sz->sh < sz->ch) {
            pt_flg = 1;
        }
    } else if (strcmp(pt, "ptls") == 0) {
        if (sz->sw > sz->cw || sz->sh > sz->ch) {
            pt_flg = 1;
        }
    }
    sz->pt_flg = pt_flg;

    // get scaling option.
    char *prm_ds_str = (char *)apr_table_get(ctx->prm, "ds");
    char prm_ds = prm_ds_str[0] ? prm_ds_str[0] : 'l';
    if (prm_ds == 's' || (sz->dw < sz->sw - sz->sx) || (sz->dh < sz->sh - sz->sy)) {
        sz->scale_flg = 1;
    } else {
        sz->scale_flg = 0;
        sz->dw = iw;
        sz->dh = ih;
    }
    if (sz->dx == SMALL_LIGHT_COORD_INVALID_VALUE) {
        sz->dx = (sz->cw - sz->dw) * 0.5;
    }
    if (sz->dy == SMALL_LIGHT_COORD_INVALID_VALUE) {
        sz->dy = (sz->ch - sz->dh) * 0.5;
    }

    // get exif option.
    int inhexif_flg = 0;
    char *inhexif = (char *)apr_table_get(ctx->prm, "inhexif");
    if (inhexif[0] == 'y') {
        inhexif_flg = 1;
    } else {
        inhexif_flg = 0;
    }
    sz->inhexif_flg = inhexif_flg;

    // get jpeghint option.
    sz->jpeghint_flg = small_light_parse_flag(r, (char *)apr_table_get(ctx->prm, "jpeghint"));
}


/* [<][>][^][v][top][bottom][index][help] */