1 /*
2  * $Id: query_parser.c 53 2011-05-09 16:55:39Z kaori $
3  *
4  * Copyright (c) 2002-2011, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium
5  * Copyright (c) 2002-2011, Professor Benoit Macq
6  * Copyright (c) 2010-2011, Kaori Hagihara
7  * Copyright (c) 2011,      Lucian Corlaciu, GSoC
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 
33 #ifdef _WIN32
34 #include <windows.h>
35 #define strcasecmp  _stricmp
36 #define strncasecmp _strnicmp
37 #else
38 #include <strings.h>
39 #endif
40 
41 #include <stdio.h>
42 #include <string.h>
43 #include <stdlib.h>
44 #include "query_parser.h"
45 
46 #ifdef SERVER
47 #include "fcgi_stdio.h"
48 #define logstream FCGI_stdout
49 #else
50 #define FCGI_stdout stdout
51 #define FCGI_stderr stderr
52 #define logstream stderr
53 #endif /*SERVER*/
54 
55 
56 /**
57  * Get initialized query parameters
58  *
59  * @return initial query parameters
60  */
61 query_param_t * get_initquery(void);
62 
63 /*
64  * get a pair of field name and value from the string starting fieldname=fieldval&... format
65  *
66  * @param[in] stringptr pointer to the beginning of the parsing string
67  * @param[out] fieldname string to copy the field name, if not found, NULL
68  * @param[out] fieldval string to copy the field value, if not found, NULL
69  * @return pointer to the next field string, if there is none, NULL
70  */
71 char * get_fieldparam( char *stringptr, char *fieldname, char *fieldval);
72 
73 void parse_cclose( char *src, query_param_t *query_param);
74 void parse_metareq( char *field, query_param_t *query_param);
75 
76 /* parse the requested components (parses forms like:a; a,b; a-b; a-b,c;  a,b-c)*/
77 void parse_comps( char *field, query_param_t *query_param);
78 
79 
80 /** maximum length of field name*/
81 #define MAX_LENOFFIELDNAME 10
82 
83 /** maximum length of field value*/
84 #define MAX_LENOFFIELDVAL 128
85 
parse_query(char * query_string)86 query_param_t * parse_query( char *query_string)
87 {
88   query_param_t *query_param;
89   char *pquery, fieldname[MAX_LENOFFIELDNAME], fieldval[MAX_LENOFFIELDVAL];
90 
91   query_param = get_initquery();
92 
93   pquery = query_string;
94 
95   while( pquery!=NULL) {
96 
97     pquery = get_fieldparam( pquery, fieldname, fieldval);
98 
99     if( fieldname[0] != '\0'){
100       if( strcasecmp( fieldname, "target") == 0)
101 	query_param->target = strdup( fieldval);
102 
103       else if( strcasecmp( fieldname, "tid") == 0)
104 	query_param->tid = strdup( fieldval);
105 
106       else if( strcasecmp( fieldname, "fsiz") == 0)
107 	sscanf( fieldval, "%d,%d", &query_param->fx, &query_param->fy);
108 
109       else if( strcasecmp( fieldname, "roff") == 0)
110 	sscanf( fieldval, "%d,%d", &query_param->rx, &query_param->ry);
111 
112       else if( strcasecmp( fieldname, "rsiz") == 0)
113 	sscanf( fieldval, "%d,%d", &query_param->rw, &query_param->rh);
114 
115       else if( strcasecmp( fieldname, "layers") == 0)
116 	sscanf( fieldval, "%d", &query_param->layers);
117 
118       else if( strcasecmp( fieldname, "cid") == 0)
119 	query_param->cid = strdup( fieldval);
120 
121       else if( strcasecmp( fieldname, "cnew") == 0){
122 	if( strncasecmp( fieldval, "http-tcp", 8) == 0)
123 	  query_param->cnew = tcp;
124 	else if( strncasecmp( fieldval, "http", 4) == 0)
125 	  query_param->cnew = http;
126       }
127 
128       else if( strcasecmp( fieldname, "cclose") == 0)
129 	parse_cclose( fieldval, query_param);
130 
131       else if( strcasecmp( fieldname, "metareq") == 0)
132 	parse_metareq( fieldval, query_param);
133 
134       else if( strcasecmp( fieldname, "comps") == 0)
135 	parse_comps( fieldval, query_param);
136 
137       else if( strcasecmp( fieldname, "type") == 0){
138 	if( strncasecmp( fieldval, "jpp-stream", 10) == 0)
139 	  query_param->return_type = JPPstream;
140 	else if( strncasecmp( fieldval, "jpt-stream", 10) == 0)
141 	  query_param->return_type = JPTstream;
142       }
143 
144       else if( strcasecmp( fieldname, "len") == 0){
145 	sscanf( fieldval, "%d", &query_param->len);
146 	if( query_param->len == 2000) /* for kakadu client*/
147 	  strncpy( query_param->box_type[0], "ftyp", 4);
148       }
149     }
150   }
151   return query_param;
152 }
153 
get_initquery(void)154 query_param_t * get_initquery(void)
155 {
156   query_param_t *query;
157   int i;
158 
159   query = (query_param_t *)malloc( sizeof(query_param_t));
160 
161   query->target = NULL;
162   query->tid = NULL;
163   query->fx = -1;
164   query->fy = -1;
165   query->rx = -1;
166   query->ry = -1;
167   query->rw = -1;
168   query->rh = -1;
169   query->layers = -1;
170   query->lastcomp = -1;
171   query->comps = NULL;
172   query->cid = NULL;
173   query->cnew = non;
174   query->cclose = NULL;
175   query->numOfcclose = 0;
176   memset( query->box_type, 0, MAX_NUMOFBOX*4);
177   memset( query->limit, 0, MAX_NUMOFBOX*sizeof(int));
178   for( i=0; i<MAX_NUMOFBOX; i++){
179     query->w[i] = false;
180     query->s[i] = false;
181     query->g[i] = false;
182     query->a[i] = false;
183     query->priority[i] = false;
184   }
185   query->root_bin = 0;
186   query->max_depth = -1;
187   query->metadata_only = false;
188   query->return_type = UNKNOWN;
189   query->len = -1;
190 
191   return query;
192 }
193 
194 
get_fieldparam(char * stringptr,char * fieldname,char * fieldval)195 char * get_fieldparam( char *stringptr, char *fieldname, char *fieldval)
196 {
197   char *eqp, *andp, *nexfieldptr;
198 
199   if((eqp = strchr( stringptr, '='))==NULL){
200     fprintf( stderr, "= not found\n");
201     strcpy( fieldname, "");
202     strcpy( fieldval, "");
203     return NULL;
204   }
205   if((andp = strchr( stringptr, '&'))==NULL){
206     andp = strchr( stringptr, '\0');
207     nexfieldptr = NULL;
208   }
209   else
210     nexfieldptr = andp+1;
211 
212   strncpy( fieldname, stringptr, eqp-stringptr);
213   fieldname[eqp-stringptr]='\0';
214   strncpy( fieldval, eqp+1, andp-eqp-1);
215   fieldval[andp-eqp-1]='\0';
216 
217   return nexfieldptr;
218 }
219 
print_queryparam(query_param_t query_param)220 void print_queryparam( query_param_t query_param)
221 {
222   int i;
223   char *cclose;
224 
225   fprintf( logstream, "query parameters:\n");
226 
227   if( query_param.target)
228     fprintf( logstream, "\t target: %s\n", query_param.target);
229 
230   if( query_param.tid)
231     fprintf( logstream, "\t tid: %s\n", query_param.tid);
232 
233   fprintf( logstream, "\t fx,fy: %d, %d\n", query_param.fx, query_param.fy);
234   fprintf( logstream, "\t rx,ry: %d, %d \t rw,rh: %d, %d\n", query_param.rx, query_param.ry, query_param.rw, query_param.rh);
235   fprintf( logstream, "\t layers: %d\n", query_param.layers);
236   fprintf( logstream, "\t components: ");
237 
238   if( query_param.lastcomp == -1)
239     fprintf( logstream, "ALL\n");
240   else{
241     for( i=0; i<=query_param.lastcomp; i++)
242       if( query_param.comps[i])
243 	fprintf( logstream, "%d ", i);
244     fprintf( logstream, "\n");
245   }
246   fprintf( logstream, "\t cnew: %d\n", query_param.cnew);
247 
248   if( query_param.cid)
249     fprintf( logstream, "\t cid: %s\n", query_param.cid);
250 
251   if( query_param.cclose){
252     fprintf( logstream, "\t cclose: ");
253 
254     for( i=0, cclose=query_param.cclose; i<query_param.numOfcclose; i++){
255       fprintf( logstream, "%s ", cclose);
256       cclose += (strlen(cclose)+1);
257     }
258     fprintf(logstream, "\n");
259   }
260 
261   fprintf( logstream, "\t req-box-prop\n");
262   for( i=0; query_param.box_type[i][0]!=0 && i<MAX_NUMOFBOX; i++){
263     fprintf( logstream, "\t\t box_type: %.4s limit: %d w:%d s:%d g:%d a:%d priority:%d\n", query_param.box_type[i], query_param.limit[i], query_param.w[i], query_param.s[i], query_param.g[i], query_param.a[i], query_param.priority[i]);
264   }
265 
266   fprintf( logstream, "\t root-bin:  %d\n", query_param.root_bin);
267   fprintf( logstream, "\t max-depth: %d\n", query_param.max_depth);
268   fprintf( logstream, "\t metadata-only: %d\n", query_param.metadata_only);
269   fprintf( logstream, "\t image return type: %d, [JPP-stream=0, JPT-stream=1, UNKNOWN=-1]\n", query_param.return_type);
270   fprintf( logstream, "\t len:  %d\n", query_param.len);
271 }
272 
parse_cclose(char * src,query_param_t * query_param)273 void parse_cclose( char *src, query_param_t *query_param)
274 {
275   size_t i;
276   size_t len;
277 
278   len = strlen( src);
279   query_param->cclose = strdup( src);
280 
281   for( i=0; i<len; i++)
282     if( query_param->cclose[i] == ','){
283       query_param->cclose[i] = '\0';
284       query_param->numOfcclose ++;
285     }
286 
287   query_param->numOfcclose ++;
288 }
289 
290 void parse_req_box_prop( char *req_box_prop, int idx, query_param_t *query_param);
291 
parse_metareq(char * field,query_param_t * query_param)292 void parse_metareq( char *field, query_param_t *query_param)
293 {
294   char req_box_prop[20];
295   char *ptr, *src;
296   int numofboxreq = 0;
297 
298   memset( req_box_prop, 0, 20);
299 
300   /* req-box-prop*/
301   ptr = strchr( field, '[');
302   ptr++;
303   src = ptr;
304   while( *ptr != ']'){
305     if( *ptr == ';'){
306       strncpy( req_box_prop, src, ptr-src);
307       parse_req_box_prop( req_box_prop, numofboxreq++, query_param);
308       ptr++;
309       src = ptr;
310       memset( req_box_prop, 0, 20);
311     }
312     ptr++;
313   }
314   strncpy( req_box_prop, src, ptr-src);
315 
316   parse_req_box_prop( req_box_prop, numofboxreq++, query_param);
317 
318   if(( ptr = strchr( field, 'R')))
319     sscanf( ptr+1, "%d", &(query_param->root_bin));
320 
321   if(( ptr = strchr( field, 'D')))
322     sscanf( ptr+1, "%d", &(query_param->max_depth));
323 
324   if(( ptr = strstr( field, "!!")))
325     query_param->metadata_only = true;
326 }
327 
parse_req_box_prop(char * req_box_prop,int idx,query_param_t * query_param)328 void parse_req_box_prop( char *req_box_prop, int idx, query_param_t *query_param)
329 {
330   char *ptr;
331 
332   if( *req_box_prop == '*')
333     query_param->box_type[idx][0]='*';
334   else
335     strncpy( query_param->box_type[idx], req_box_prop, 4);
336 
337   if(( ptr = strchr( req_box_prop, ':'))){
338     if( *(ptr+1)=='r')
339       query_param->limit[idx] = -1;
340     else
341       sscanf( ptr+1, "%d", &(query_param->limit[idx]));
342   }
343 
344   if(( ptr = strchr( req_box_prop, '/'))){
345     ptr++;
346     while( *ptr=='w' || *ptr=='s' || *ptr=='g' || *ptr=='a'){
347       switch( *ptr){
348       case 'w': query_param->w[idx] = true; break;
349       case 's': query_param->s[idx] = true; break;
350       case 'g': query_param->g[idx] = true; break;
351       case 'a': query_param->a[idx] = true; break;
352       }
353       ptr++;
354     }
355   }
356   else{
357     query_param->g[idx] = true;
358     query_param->s[idx] = true;
359     query_param->w[idx] = true;
360   }
361 
362   if((ptr = strchr( req_box_prop, '!')))
363     query_param->priority[idx] = true;
364 
365   idx++;
366 }
367 
parse_comps(char * field,query_param_t * query_param)368 void parse_comps( char *field, query_param_t *query_param)
369 {
370   int i,start,stop,aux = -1;
371   char *ptr1,*ptr2;
372 
373   ptr1 = strchr( field, '-');
374   ptr2 = strchr( field, ',');
375 
376   if( ptr1 && ptr2)
377     if( ptr1 > ptr2)
378       sscanf( field, "%d,%d-%d",&aux, &start, &stop);
379     else
380       sscanf( field, "%d-%d,%d", &start, &stop, &aux);
381   else
382     if(ptr1)
383       sscanf( field, "%d-%d", &start, &stop);
384     else if(ptr2){
385       sscanf( field, "%d,%d", &start, &stop);
386       aux = start;
387       start = stop;
388     }
389     else{
390       sscanf( field, "%d", &stop);
391       start = stop;
392     }
393 
394   query_param->lastcomp = stop > aux ? stop : aux;
395   query_param->comps = (bool *)calloc( 1, (query_param->lastcomp+1)*sizeof(bool));
396 
397   for( i=start; i<=stop; i++)
398     query_param->comps[i]=true;
399 
400   if(aux!=-1)
401     query_param->comps[aux] = true;
402 }
403 
delete_query(query_param_t ** query)404 void delete_query( query_param_t **query)
405 {
406   if( (*query)->target)
407     free( (*query)->target);
408 
409   if( (*query)->tid)
410     free( (*query)->tid);
411 
412   if( (*query)->comps)
413     free((*query)->comps);
414 
415   if( (*query)->cid)
416     free( (*query)->cid);
417 
418   if( (*query)->cclose)
419     free( (*query)->cclose);
420 
421   free( *query);
422 }
423