diff options
| author | Mathieu Malaterre <mathieu.malaterre@gmail.com> | 2012-09-28 08:11:41 +0000 |
|---|---|---|
| committer | Mathieu Malaterre <mathieu.malaterre@gmail.com> | 2012-09-28 08:11:41 +0000 |
| commit | d518970039a19a2a9b6d2bdd592cc88a43897bbb (patch) | |
| tree | 57bac2cf7e63e9352228231062763baac627563c /src/lib/openjpip/jpip_parser.c | |
| parent | 8363a6ab1e031bb4b2e40a92e56efd40fdab1aa1 (diff) | |
[trunk] Start FolderReorgProposal task
Update issue 177
Diffstat (limited to 'src/lib/openjpip/jpip_parser.c')
| -rw-r--r-- | src/lib/openjpip/jpip_parser.c | 460 |
1 files changed, 460 insertions, 0 deletions
diff --git a/src/lib/openjpip/jpip_parser.c b/src/lib/openjpip/jpip_parser.c new file mode 100644 index 00000000..663214e4 --- /dev/null +++ b/src/lib/openjpip/jpip_parser.c @@ -0,0 +1,460 @@ +/* + * $Id$ + * + * Copyright (c) 2002-2011, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2011, Professor Benoit Macq + * Copyright (c) 2010-2011, Kaori Hagihara + * Copyright (c) 2011, Lucian Corlaciu, GSoC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <math.h> +#include "jpip_parser.h" +#include "channel_manager.h" +#include "imgreg_manager.h" + +#ifdef SERVER +#include "fcgi_stdio.h" +#define logstream FCGI_stdout +#else +#define FCGI_stdout stdout +#define FCGI_stderr stderr +#define logstream stderr +#endif /*SERVER*/ + + +bool identify_target( query_param_t query_param, targetlist_param_t *targetlist, target_param_t **target) +{ + if( query_param.tid){ + if( strcmp( query_param.tid, "0") != 0 ){ + if( query_param.cid[0] != '\0'){ + fprintf( FCGI_stdout, "Reason: Target can not be specified both through tid and cid\r\n"); + fprintf( FCGI_stdout, "Status: 400\r\n"); + return false; + } + if( ( *target = search_targetBytid( query_param.tid, targetlist))) + return true; + } + } + + if( query_param.target) + if( !( *target = search_target( query_param.target, targetlist))) + if(!( *target = gene_target( targetlist, query_param.target))) + return false; + + if( *target){ + fprintf( FCGI_stdout, "JPIP-tid: %s\r\n", (*target)->tid); + return true; + } + else{ + fprintf( FCGI_stdout, "Reason: target not found\r\n"); + fprintf( FCGI_stdout, "Status: 400\r\n"); + return false; + } +} + +bool associate_channel( query_param_t query_param, + sessionlist_param_t *sessionlist, + session_param_t **cursession, + channel_param_t **curchannel) +{ + if( search_session_and_channel( query_param.cid, sessionlist, cursession, curchannel)){ + + if( !query_param.cnew) + set_channel_variable_param( query_param, *curchannel); + } + else{ + fprintf( FCGI_stderr, "Error: process canceled\n"); + return false; + } + return true; +} + +bool open_channel( query_param_t query_param, + sessionlist_param_t *sessionlist, + auxtrans_param_t auxtrans, + target_param_t *target, + session_param_t **cursession, + channel_param_t **curchannel) +{ + cachemodel_param_t *cachemodel = NULL; + + if( target){ + if( !(*cursession)) + *cursession = gene_session( sessionlist); + if( !( cachemodel = search_cachemodel( target, (*cursession)->cachemodellist))) + if( !(cachemodel = gene_cachemodel( (*cursession)->cachemodellist, target, query_param.return_type==JPPstream))) + return false; + } + else + if( *curchannel) + cachemodel = (*curchannel)->cachemodel; + + *curchannel = gene_channel( query_param, auxtrans, cachemodel, (*cursession)->channellist); + if( *curchannel == NULL) + return false; + + return true; +} + +bool close_channel( query_param_t query_param, + sessionlist_param_t *sessionlist, + session_param_t **cursession, + channel_param_t **curchannel) +{ + char *cclose; + int i; + + if( query_param.cclose[0] =='*'){ +#ifndef SERVER + fprintf( logstream, "local log: close all\n"); +#endif + /* all channels associatd with the session will be closed */ + if( !delete_session( cursession, sessionlist)) + return false; + } + else{ + /* check if all entry belonging to the same session */ + + for( i=0, cclose=query_param.cclose; i<query_param.numOfcclose; i++, cclose += (strlen(cclose)+1)){ + + /* In case of the first entry of close cid */ + if( *cursession == NULL){ + if( !search_session_and_channel( cclose, sessionlist, cursession, curchannel)) + return false; + } + else /* second or more entry of close cid */ + if( !(*curchannel=search_channel( cclose, (*cursession)->channellist))){ + fprintf( FCGI_stdout, "Reason: Cclose id %s is from another session\r\n", cclose); + return false; + } + } + + /* delete channels */ + for( i=0, cclose=query_param.cclose; i<query_param.numOfcclose; i++, cclose += (strlen(cclose)+1)){ + *curchannel = search_channel( cclose, (*cursession)->channellist); + delete_channel( curchannel, (*cursession)->channellist); + } + + if( (*cursession)->channellist->first == NULL || (*cursession)->channellist->last == NULL) + /* In case of empty session */ + delete_session( cursession, sessionlist); + } + return true; +} + + +/** + * enqueue tiles or precincts into the message queue + * + * @param[in] query_param structured query + * @param[in] msgqueue message queue pointer + */ +void enqueue_imagedata( query_param_t query_param, msgqueue_param_t *msgqueue); + +/** + * enqueue metadata bins into the message queue + * + * @param[in] query_param structured query + * @param[in] metadatalist pointer to metadata bin list + * @param[in,out] msgqueue message queue pointer + * @return if succeeded (true) or failed (false) + */ +bool enqueue_metabins( query_param_t query_param, metadatalist_param_t *metadatalist, msgqueue_param_t *msgqueue); + + +bool gene_JPIPstream( query_param_t query_param, + target_param_t *target, + session_param_t *cursession, + channel_param_t *curchannel, + msgqueue_param_t **msgqueue) +{ + index_param_t *codeidx; + cachemodel_param_t *cachemodel; + + if( !cursession || !curchannel){ /* stateless */ + if( !target) + return false; + if( !(cachemodel = gene_cachemodel( NULL, target, query_param.return_type==JPPstream))) + return false; + *msgqueue = gene_msgqueue( true, cachemodel); + } + else{ /* session */ + cachemodel = curchannel->cachemodel; + target = cachemodel->target; + *msgqueue = gene_msgqueue( false, cachemodel); + } + + codeidx = target->codeidx; + + if( cachemodel->jppstream) + fprintf( FCGI_stdout, "Content-type: image/jpp-stream\r\n"); + else + fprintf( FCGI_stdout, "Content-type: image/jpt-stream\r\n"); + + if( query_param.layers != -1){ + if( query_param.layers > codeidx->COD.numOflayers){ + fprintf( FCGI_stdout, "JPIP-layers: %d\r\n", codeidx->COD.numOflayers); + query_param.layers = codeidx->COD.numOflayers; + } + } + + /*meta*/ + if( query_param.box_type[0][0] != 0 && query_param.len != 0) + if( !enqueue_metabins( query_param, codeidx->metadatalist, *msgqueue)) + return false; + + if( query_param.metadata_only) + return true; + + /* main header */ + if( !cachemodel->mhead_model && query_param.len != 0) + enqueue_mainheader( *msgqueue); + + /* image codestream */ + if( (query_param.fx > 0 && query_param.fy > 0)) + enqueue_imagedata( query_param, *msgqueue); + + return true; +} + + +/** + * enqueue precinct data-bins into the queue + * + * @param[in] xmin min x coordinate in the tile at the decomposition level + * @param[in] xmax max x coordinate in the tile at the decomposition level + * @param[in] ymin min y coordinate in the tile at the decomposition level + * @param[in] ymax max y coordinate in the tile at the decomposition level + * @param[in] tile_id tile index + * @param[in] level decomposition level + * @param[in] lastcomp last component number + * @param[in] comps pointer to the array that stores the requested components + * @param[in] layers number of quality layers + * @param[in] msgqueue message queue + * @return + */ +void enqueue_precincts( int xmin, int xmax, int ymin, int ymax, int tile_id, int level, int lastcomp, bool *comps, int layers, msgqueue_param_t *msgqueue); + +/** + * enqueue all precincts inside a tile into the queue + * + * @param[in] tile_id tile index + * @param[in] level decomposition level + * @param[in] lastcomp last component number + * @param[in] comps pointer to the array that stores the requested components + * @param[in] layers number of quality layers + * @param[in] msgqueue message queue + * @return + */ +void enqueue_allprecincts( int tile_id, int level, int lastcomp, bool *comps, int layers, msgqueue_param_t *msgqueue); + +void enqueue_imagedata( query_param_t query_param, msgqueue_param_t *msgqueue) +{ + index_param_t *codeidx; + imgreg_param_t imgreg; + range_param_t tile_Xrange, tile_Yrange; + Byte4_t u, v, tile_id; + int xmin, xmax, ymin, ymax; + int numOfreslev; + + codeidx = msgqueue->cachemodel->target->codeidx; + + if( !(msgqueue->cachemodel->jppstream) && get_nmax( codeidx->tilepart) == 1) /* normally not the case */ + numOfreslev = 1; + else + numOfreslev = codeidx->COD.numOfdecomp+1; + + imgreg = map_viewin2imgreg( query_param.fx, query_param.fy, + query_param.rx, query_param.ry, query_param.rw, query_param.rh, + (int)codeidx->SIZ.XOsiz, (int)codeidx->SIZ.YOsiz, (int)codeidx->SIZ.Xsiz, (int)codeidx->SIZ.Ysiz, + numOfreslev ); + + if( query_param.len == 0) + return; + + for( u=0, tile_id=0; u<codeidx->SIZ.YTnum; u++){ + tile_Yrange = get_tile_Yrange( codeidx->SIZ, tile_id, imgreg.level); + + for( v=0; v<codeidx->SIZ.XTnum; v++, tile_id++){ + tile_Xrange = get_tile_Xrange( codeidx->SIZ, tile_id, imgreg.level); + + if( tile_Xrange.minvalue < tile_Xrange.maxvalue && tile_Yrange.minvalue < tile_Yrange.maxvalue){ + if( tile_Xrange.maxvalue <= (Byte4_t)(imgreg.xosiz + imgreg.ox) || + tile_Xrange.minvalue >= (Byte4_t)(imgreg.xosiz + imgreg.ox + imgreg.sx) || + tile_Yrange.maxvalue <= (Byte4_t)(imgreg.yosiz + imgreg.oy) || + tile_Yrange.minvalue >= (Byte4_t)(imgreg.yosiz + imgreg.oy + imgreg.sy)) { + /*printf("Tile completely excluded from view-window %d\n", tile_id);*/ + /* Tile completely excluded from view-window */ + } + else if( tile_Xrange.minvalue >= (Byte4_t)(imgreg.xosiz + imgreg.ox) && + tile_Xrange.maxvalue <= (Byte4_t)(imgreg.xosiz + imgreg.ox + imgreg.sx) && + tile_Yrange.minvalue >= (Byte4_t)(imgreg.yosiz + imgreg.oy) && + tile_Yrange.maxvalue <= (Byte4_t)(imgreg.yosiz + imgreg.oy + imgreg.sy)) { + /* Tile completely contained within view-window */ + /* high priority */ + /*printf("Tile completely contained within view-window %d\n", tile_id);*/ + if( msgqueue->cachemodel->jppstream){ + enqueue_tileheader( (int)tile_id, msgqueue); + enqueue_allprecincts( (int)tile_id, imgreg.level, query_param.lastcomp, query_param.comps, query_param.layers, msgqueue); + } + else + enqueue_tile( tile_id, imgreg.level, msgqueue); + } + else{ + /* Tile partially overlaps view-window */ + /* low priority */ + /*printf("Tile partially overlaps view-window %d\n", tile_id);*/ + if( msgqueue->cachemodel->jppstream){ + enqueue_tileheader( (int)tile_id, msgqueue); + + /* FIXME: The following code is suspicious it implicitely cast an unsigned int to int, which truncates values */ + xmin = tile_Xrange.minvalue >= (Byte4_t)(imgreg.xosiz + imgreg.ox) ? 0 : imgreg.xosiz + imgreg.ox - (int)tile_Xrange.minvalue; + xmax = tile_Xrange.maxvalue <= (Byte4_t)(imgreg.xosiz + imgreg.ox + imgreg.sx) ? (int)(tile_Xrange.maxvalue - tile_Xrange.minvalue -1) : (int)(imgreg.xosiz + imgreg.ox + imgreg.sx - (int)tile_Xrange.minvalue - 1); + ymin = tile_Yrange.minvalue >= (Byte4_t)(imgreg.yosiz + imgreg.oy) ? 0 : imgreg.yosiz + imgreg.oy - (int)tile_Yrange.minvalue; + ymax = tile_Yrange.maxvalue <= (Byte4_t)(imgreg.yosiz + imgreg.oy + imgreg.sy) ? (int)(tile_Yrange.maxvalue - tile_Yrange.minvalue - 1) : (int)(imgreg.yosiz + imgreg.oy + imgreg.sy - (int)tile_Yrange.minvalue - 1); + enqueue_precincts( xmin, xmax, ymin, ymax, (int)tile_id, imgreg.level, query_param.lastcomp, query_param.comps, query_param.layers, msgqueue); + } + else + enqueue_tile( tile_id, imgreg.level, msgqueue); + } + } + } + } +} + + +void enqueue_precincts( int xmin, int xmax, int ymin, int ymax, int tile_id, int level, int lastcomp, bool *comps, int layers, msgqueue_param_t *msgqueue) +{ + index_param_t *codeidx; + int c, u, v, res_lev, dec_lev; + int seq_id; + Byte4_t XTsiz, YTsiz; + Byte4_t XPsiz, YPsiz; + Byte4_t xminP, xmaxP, yminP, ymaxP; + + codeidx = msgqueue->cachemodel->target->codeidx; + /* MM: shouldnt xmin/xmax be Byte4_t instead ? */ + if( xmin < 0 || xmax < 0 || ymin < 0 || ymax < 0) + return; + /* MM: I think the API should not really be int should it ? */ + if( tile_id < 0 ) + return; + + for( c=0; c<codeidx->SIZ.Csiz; c++) + if( lastcomp == -1 /*all*/ || ( c<=lastcomp && comps[c])){ + seq_id = 0; + for( res_lev=0, dec_lev=codeidx->COD.numOfdecomp; dec_lev>=level; res_lev++, dec_lev--){ + + XTsiz = get_tile_XSiz( codeidx->SIZ, (Byte4_t)tile_id, dec_lev); + YTsiz = get_tile_YSiz( codeidx->SIZ, (Byte4_t)tile_id, dec_lev); + + XPsiz = ( codeidx->COD.Scod & 0x01) ? codeidx->COD.XPsiz[ res_lev] : XTsiz; + YPsiz = ( codeidx->COD.Scod & 0x01) ? codeidx->COD.YPsiz[ res_lev] : YTsiz; + + for( u=0; u<ceil((double)YTsiz/(double)YPsiz); u++){ + yminP = (Byte4_t)u*YPsiz; + ymaxP = (Byte4_t)(u+1)*YPsiz-1; + if( YTsiz <= ymaxP) + ymaxP = YTsiz-1; + + for( v=0; v<ceil((double)XTsiz/(double)XPsiz); v++, seq_id++){ + xminP = (Byte4_t)v*XPsiz; + xmaxP = (Byte4_t)(v+1)*XPsiz-1; + if( XTsiz <= xmaxP) + xmaxP = XTsiz-1; + + if( xmaxP < (Byte4_t)xmin || xminP > (Byte4_t)xmax || ymaxP < (Byte4_t)ymin || yminP > (Byte4_t)ymax){ + /* Precinct completely excluded from view-window */ + } + else if( xminP >= (Byte4_t)xmin && xmaxP <= (Byte4_t)xmax && yminP >= (Byte4_t)ymin && ymaxP <= (Byte4_t)ymax){ + /* Precinct completely contained within view-window + high priority */ + enqueue_precinct( seq_id, tile_id, c, (dec_lev>level)?-1:layers, msgqueue); + } + else{ + /* Precinct partially overlaps view-window + low priority */ + enqueue_precinct( seq_id, tile_id, c, (dec_lev>level)?-1:layers, msgqueue); + } + } + } + } + } +} + +void enqueue_allprecincts( int tile_id, int level, int lastcomp, bool *comps, int layers, msgqueue_param_t *msgqueue) +{ + index_param_t *codeidx; + int c, i, res_lev, dec_lev; + int seq_id; + Byte4_t XTsiz, YTsiz; + Byte4_t XPsiz, YPsiz; + + codeidx = msgqueue->cachemodel->target->codeidx; + if( tile_id < 0 ) + return; + + for( c=0; c<codeidx->SIZ.Csiz; c++) + if( lastcomp == -1 /*all*/ || ( c<=lastcomp && comps[c])){ + seq_id = 0; + for( res_lev=0, dec_lev=codeidx->COD.numOfdecomp; dec_lev>=level; res_lev++, dec_lev--){ + + XTsiz = get_tile_XSiz( codeidx->SIZ, (Byte4_t)tile_id, dec_lev); + YTsiz = get_tile_YSiz( codeidx->SIZ, (Byte4_t)tile_id, dec_lev); + + XPsiz = ( codeidx->COD.Scod & 0x01) ? codeidx->COD.XPsiz[ res_lev] : XTsiz; + YPsiz = ( codeidx->COD.Scod & 0x01) ? codeidx->COD.YPsiz[ res_lev] : YTsiz; + + for( i=0; i<ceil((double)YTsiz/(double)YPsiz)*ceil((double)XTsiz/(double)XPsiz); i++, seq_id++) + enqueue_precinct( seq_id, tile_id, c, (dec_lev>level)?-1:layers, msgqueue); + } + } +} + +bool enqueue_metabins( query_param_t query_param, metadatalist_param_t *metadatalist, msgqueue_param_t *msgqueue) +{ + int i; + for( i=0; query_param.box_type[i][0]!=0 && i<MAX_NUMOFBOX; i++){ + if( query_param.box_type[i][0] == '*'){ + fprintf( FCGI_stdout, "Status: 501\r\n"); + fprintf( FCGI_stdout, "Reason: metareq with all box-property * not implemented\r\n"); + return false; + } + else{ + Byte8_t idx = search_metadataidx( query_param.box_type[i], metadatalist); + + if( idx != (Byte8_t)-1) + enqueue_metadata( idx, msgqueue); + else{ + fprintf( FCGI_stdout, "Status: 400\r\n"); + fprintf( FCGI_stdout, "Reason: box-type %.4s not found\r\n", query_param.box_type[i]); + return false; + } + } + } + return true; +} |
