added tid request support to JPIP client and JPIP server quit request
[openjpeg.git] / applications / jpip / libopenjpip / msgqueue_manager.c
1 /*
2  * $Id: msgqueue_manager.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  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <math.h>
34 #include <sys/types.h>
35 #include <unistd.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include "msgqueue_manager.h"
41 #include "metadata_manager.h"
42
43
44 #ifdef SERVER
45 #include "fcgi_stdio.h"
46 #define logstream FCGI_stdout
47 #else
48 #define FCGI_stdout stdout
49 #define FCGI_stderr stderr
50 #define logstream stderr
51 #endif //SERVER
52
53 #define PRECINCT_MSG 0
54 #define EXT_PRECINCT_MSG 1
55 #define TILE_HEADER_MSG 2
56 #define TILE_MSG 4
57 #define EXT_TILE_MSG 5
58 #define MAINHEADER_MSG 6
59 #define METADATA_MSG 8
60
61 msgqueue_param_t * gene_msgqueue( bool stateless, cachemodel_param_t *cachemodel)
62 {
63   msgqueue_param_t *msgqueue;
64
65   msgqueue = (msgqueue_param_t *)malloc( sizeof(msgqueue_param_t));
66
67   msgqueue->first = NULL;
68   msgqueue->last  = NULL;
69
70   msgqueue->stateless = stateless;
71   msgqueue->cachemodel = cachemodel;
72   
73   return msgqueue;
74 }
75
76 void delete_msgqueue( msgqueue_param_t **msgqueue)
77 {
78   message_param_t *ptr, *next;
79
80   if( !(*msgqueue))
81     return;
82   
83   ptr = (*msgqueue)->first;
84
85   while( ptr){
86     next = ptr->next;
87     free( ptr);
88     ptr = next;
89   }
90   if( (*msgqueue)->stateless && (*msgqueue)->cachemodel)
91     delete_cachemodel( &((*msgqueue)->cachemodel));
92
93   free(*msgqueue); 
94 }
95
96 void print_msgqueue( msgqueue_param_t *msgqueue)
97 {
98   message_param_t *ptr;
99
100   if( !msgqueue)
101     return;
102
103   fprintf( logstream, "message queue:\n");
104   ptr = msgqueue->first;
105
106   while( ptr){
107     fprintf( logstream, "\t class_id: %lld\n", ptr->class_id );
108     fprintf( logstream, "\t in_class_id: %lld\n", ptr->in_class_id );
109     fprintf( logstream, "\t csn: %lld\n", ptr->csn );
110     fprintf( logstream, "\t bin_offset: %#llx\n", ptr->bin_offset );
111     fprintf( logstream, "\t length: %#llx\n", ptr->length );
112     fprintf( logstream, "\t aux: %lld\n", ptr->aux );
113     fprintf( logstream, "\t last_byte: %d\n", ptr->last_byte );
114     if( ptr->phld)
115       print_placeholder( ptr->phld);
116     else
117       fprintf( logstream, "\t res_offset: %#llx\n", ptr->res_offset );
118     fprintf( logstream, "\n");
119
120     ptr = ptr->next;
121   }
122 }
123
124 void enqueue_message( message_param_t *msg, msgqueue_param_t *msgqueue);
125
126 void enqueue_mainheader( msgqueue_param_t *msgqueue)
127 {
128   cachemodel_param_t *cachemodel;
129   target_param_t *target;
130   message_param_t *msg;
131
132   cachemodel = msgqueue->cachemodel;
133   target = cachemodel->target;
134
135   msg = (message_param_t *)malloc( sizeof(message_param_t));
136
137   msg->last_byte = true;
138   msg->in_class_id = 0;
139   msg->class_id = MAINHEADER_MSG;
140   msg->csn = target->csn;
141   msg->bin_offset = 0;
142   msg->length = target->codeidx->mhead_length;
143   msg->aux = 0; // non exist
144   msg->res_offset = target->codeidx->offset;
145   msg->phld = NULL;
146   msg->next = NULL;
147
148   enqueue_message( msg, msgqueue);
149
150   cachemodel->mhead_model = true;
151 }
152
153 void enqueue_tile( int tile_id, int level, msgqueue_param_t *msgqueue)
154 {
155   cachemodel_param_t *cachemodel;
156   target_param_t *target;
157   bool *tp_model;
158   Byte8_t numOftparts; // num of tile parts par tile
159   Byte8_t numOftiles;
160   index_param_t *codeidx;
161   faixbox_param_t *tilepart;
162   message_param_t *msg;
163   Byte8_t binOffset, binLength;
164   int i;
165
166   cachemodel = msgqueue->cachemodel;
167   target = cachemodel->target;
168   codeidx  = target->codeidx;
169   tilepart = codeidx->tilepart;
170   
171   numOftparts = get_nmax( tilepart);
172   numOftiles  = get_m( tilepart);
173
174   if( tile_id < 0 || numOftiles <= tile_id){
175     fprintf( FCGI_stderr, "Error, Invalid tile-id %d\n", tile_id);
176     return;
177   }
178   
179   tp_model = &cachemodel->tp_model[ tile_id*numOftparts];
180   
181   binOffset=0;
182   for( i=0; i<numOftparts-level; i++){
183     binLength = get_elemLen( tilepart, i, tile_id);
184     
185     if( !tp_model[i]){
186       msg = (message_param_t *)malloc( sizeof(message_param_t));
187       
188       msg->last_byte = i==numOftparts-1? true : false;
189       msg->in_class_id = tile_id;
190 #if 0
191       msg->class_id = TILE_MSG;
192 #else
193       msg->class_id = EXT_TILE_MSG;
194 #endif
195       msg->csn = target->csn;
196       msg->bin_offset = binOffset;
197       msg->length = binLength;
198       msg->aux = numOftparts-i;
199       msg->res_offset = codeidx->offset+get_elemOff( tilepart, i, tile_id)/*-1*/;
200       msg->phld = NULL;
201       msg->next = NULL;
202
203       enqueue_message( msg, msgqueue);
204
205       tp_model[i] = true;
206     }
207     binOffset += binLength;
208   }
209 }
210
211 void enqueue_box(  int meta_id, boxlist_param_t *boxlist, msgqueue_param_t *msgqueue, Byte8_t *binOffset);
212 void enqueue_phld( int meta_id, placeholderlist_param_t *phldlist, msgqueue_param_t *msgqueue, Byte8_t *binOffset);
213 void enqueue_boxcontents( int meta_id, boxcontents_param_t *boxcontents, msgqueue_param_t *msgqueue, Byte8_t *binOffset);
214
215 void enqueue_metadata( int meta_id, msgqueue_param_t *msgqueue)
216 {
217   metadatalist_param_t *metadatalist;
218   metadata_param_t *metadata;
219   Byte8_t binOffset;
220
221   metadatalist = msgqueue->cachemodel->target->codeidx->metadatalist;
222   metadata = search_metadata( meta_id, metadatalist);
223   
224   if( !metadata){
225     fprintf( FCGI_stderr, "Error: metadata-bin %d not found\n", meta_id);
226     return;
227   }
228   binOffset = 0;
229   
230   if( metadata->boxlist)
231     enqueue_box( meta_id, metadata->boxlist, msgqueue, &binOffset);
232
233   if( metadata->placeholderlist)
234     enqueue_phld( meta_id, metadata->placeholderlist, msgqueue, &binOffset);
235
236   if( metadata->boxcontents)
237     enqueue_boxcontents( meta_id, metadata->boxcontents, msgqueue, &binOffset);
238   
239   msgqueue->last->last_byte = true;
240 }
241
242 message_param_t * gene_metamsg( int meta_id, Byte8_t binoffset, Byte8_t length, Byte8_t res_offset, placeholder_param_t *phld, Byte8_t csn);
243
244 void enqueue_box( int meta_id, boxlist_param_t *boxlist, msgqueue_param_t *msgqueue, Byte8_t *binOffset)
245 {
246   box_param_t *box;
247   message_param_t *msg;
248   
249   box = boxlist->first;
250   while( box){
251     msg = gene_metamsg( meta_id, *binOffset, box->length, box->offset, NULL, msgqueue->cachemodel->target->csn);
252     enqueue_message( msg, msgqueue);
253
254     *binOffset += box->length;
255     box = box->next;
256   }
257 }
258
259 void enqueue_phld( int meta_id, placeholderlist_param_t *phldlist, msgqueue_param_t *msgqueue, Byte8_t *binOffset)
260 {
261   placeholder_param_t *phld;
262   message_param_t *msg;
263   
264   phld = phldlist->first;
265   while( phld){
266     msg = gene_metamsg( meta_id, *binOffset, phld->LBox, 0, phld, msgqueue->cachemodel->target->csn);
267     enqueue_message( msg, msgqueue);
268
269     *binOffset += phld->LBox;
270     phld = phld->next;
271   }
272 }
273
274 void enqueue_boxcontents( int meta_id, boxcontents_param_t *boxcontents, msgqueue_param_t *msgqueue, Byte8_t *binOffset)
275 {
276   message_param_t *msg;
277
278   msg = gene_metamsg( meta_id, *binOffset, boxcontents->length, boxcontents->offset, NULL, msgqueue->cachemodel->target->csn);
279   enqueue_message( msg, msgqueue);
280   
281   *binOffset += boxcontents->length;
282 }
283
284 message_param_t * gene_metamsg( int meta_id, Byte8_t binOffset, Byte8_t length, Byte8_t res_offset, placeholder_param_t *phld, Byte8_t csn)
285 {
286   message_param_t *msg;
287
288   msg = (message_param_t *)malloc( sizeof(message_param_t));
289     
290   msg->last_byte = false;
291   msg->in_class_id = meta_id;
292   msg->class_id = METADATA_MSG;
293   msg->csn = csn;
294   msg->bin_offset = binOffset;
295   msg->length = length;
296   msg->aux = 0; // non exist
297   msg->res_offset = res_offset;
298   msg->phld = phld;
299   msg->next = NULL;
300
301   return msg;
302 }
303
304 void enqueue_message( message_param_t *msg, msgqueue_param_t *msgqueue)
305 {
306   if( msgqueue->first)
307     msgqueue->last->next = msg;
308   else
309     msgqueue->first = msg;
310   
311   msgqueue->last = msg;
312 }
313
314
315 void emit_bin_id_vbas( Byte_t bb, Byte_t c, Byte8_t in_class_id);
316 void emit_vbas( Byte8_t code);
317 void emit_body( message_param_t *msg, int fd);
318 void emit_placeholder( placeholder_param_t *phld);
319
320 void emit_stream_from_msgqueue( msgqueue_param_t *msgqueue)
321 {
322   message_param_t *msg;
323   Byte8_t class_id, csn;
324   Byte_t bb, c;
325   
326   if( !(msgqueue))
327     return;
328
329   msg = msgqueue->first;
330   class_id = 0;
331   csn = 0;
332   while( msg){
333     if( msg->csn == csn){
334       if( msg->class_id == class_id)
335         bb = 1;
336       else{
337         bb = 2;
338         class_id = msg->class_id;
339       }
340     }
341     else{
342       bb = 3;
343       class_id = msg->class_id;
344       csn = msg->csn;
345     }
346
347     c = msg->last_byte ? 1 : 0;
348       
349     emit_bin_id_vbas( bb, c, msg->in_class_id);
350     
351     if( bb >= 2)
352       emit_vbas( class_id);
353     if (bb == 3)
354       emit_vbas( csn);
355     
356     emit_vbas( msg->bin_offset);
357     emit_vbas (msg->length);
358     
359     if( msg->class_id%2) // Aux is present only if the id is odd
360       emit_vbas( msg->aux);
361
362     if( msg->phld)
363       emit_placeholder( msg->phld);
364     else
365       emit_body( msg, msgqueue->cachemodel->target->fd);
366
367     msg = msg->next;
368   }
369 }
370
371 void emit_vbas_with_bytelen( Byte8_t code, int bytelength);
372 void print_binarycode( Byte8_t n, int segmentlen);
373
374 void emit_bin_id_vbas( Byte_t bb, Byte_t c, Byte8_t in_class_id)
375 {
376   int bytelength;
377   Byte8_t tmp;
378
379   // A.2.3 In-class identifiers 
380   // 7k-3bits, where k is the number of bytes in the VBAS
381   bytelength = 1;
382   tmp = in_class_id >> 4;
383   while( tmp){
384     bytelength ++;
385     tmp >>= 7;
386   }
387
388   in_class_id |= (((bb & 3) << 5) | (c & 1) << 4) << ((bytelength-1)*7);
389   
390   emit_vbas_with_bytelen( in_class_id, bytelength);
391 }
392
393 void emit_vbas( Byte8_t code)
394 {
395   int bytelength;
396   Byte8_t tmp;
397
398   bytelength = 1;
399   tmp = code;
400   while( tmp >>= 7)
401     bytelength ++;
402
403   emit_vbas_with_bytelen( code, bytelength);
404 }
405
406 void emit_vbas_with_bytelen( Byte8_t code, int bytelength)
407 {
408   int n;
409   Byte8_t seg;
410   
411   n = bytelength - 1;
412   while( n >= 0) {
413     seg = ( code >> (n*7)) & 0x7f;
414     if( n)
415       seg |= 0x80;
416     fputc(( Byte4_t)seg, FCGI_stdout);
417     n--;
418   }
419 }
420
421 void emit_body( message_param_t *msg, int fd)
422 {
423   Byte_t *data;
424
425   if( lseek( fd, msg->res_offset, SEEK_SET)==-1){
426     fprintf( FCGI_stderr, "Error: fseek in emit_body()\n");
427     return;
428   }
429   
430   data = (Byte_t *)malloc( msg->length);
431   if( read( fd, data, msg->length) != msg->length){
432     free( data);
433     fprintf( FCGI_stderr, "Error: fread in emit_body()\n");
434     return;
435   }
436
437   if( fwrite( data, msg->length, 1, FCGI_stdout) < 1){
438     free( data);
439     fprintf( FCGI_stderr, "Error: fwrite in emit_body()\n");
440     return;
441   }
442   free(data);
443 }
444
445 void emit_bigendian_bytes( Byte8_t code, int bytelength);
446
447 void emit_placeholder( placeholder_param_t *phld)
448 {
449   emit_bigendian_bytes( phld->LBox, 4);
450   if( fwrite( phld->TBox, 4, 1, FCGI_stdout) < 1){
451     fprintf( FCGI_stderr, "Error: fwrite in emit_placeholder()\n");
452     return;
453   }
454   emit_bigendian_bytes( phld->Flags, 4);
455   emit_bigendian_bytes( phld->OrigID, 8);
456
457   if( fwrite( phld->OrigBH, phld->OrigBHlen, 1, FCGI_stdout) < 1){
458     fprintf( FCGI_stderr, "Error: fwrite in emit_placeholder()\n");
459     return;
460   }
461 }
462
463 void emit_bigendian_bytes( Byte8_t code, int bytelength)
464 {
465   int n;
466   Byte8_t seg;
467   
468   n = bytelength - 1;
469   while( n >= 0) {
470     seg = ( code >> (n*8)) & 0xff;
471     fputc(( Byte4_t)seg, FCGI_stdout);
472     n--;
473   }
474 }
475 void print_binarycode( Byte8_t n, int segmentlen)
476 {
477   char buf[256];
478   int i=0, j, k;
479
480   do{
481     buf[i++] = n%2 ? '1' : '0';
482   }while((n=n/2));
483
484   for( j=segmentlen-1; j>=i; j--)
485     putchar('0');
486   
487   for( j=i-1, k=0; j>=0; j--, k++){
488     putchar( buf[j]);
489     if( !((k+1)%segmentlen))
490       printf(" ");
491   }
492   printf("\n");
493 }
494
495 Byte_t * parse_bin_id_vbas( Byte_t *streamptr, Byte_t *bb, Byte_t *c, Byte8_t *in_class_id);
496 Byte_t * parse_vbas( Byte_t *streamptr, Byte8_t *elem);
497
498 void parse_JPIPstream( Byte_t *JPIPstream, Byte8_t streamlen, Byte8_t offset, msgqueue_param_t *msgqueue)
499 {
500   Byte_t *ptr;  // stream pointer
501   message_param_t *msg;
502   Byte_t bb, c;
503   Byte8_t class_id, csn;
504
505   class_id = -1; // dummy
506   csn = 0;
507   ptr = JPIPstream;
508   while( ptr-JPIPstream < streamlen){
509     msg = (message_param_t *)malloc( sizeof(message_param_t));
510     
511     ptr = parse_bin_id_vbas( ptr, &bb, &c, &msg->in_class_id);
512     
513     msg->last_byte   = c == 1 ? true : false;
514     
515     if( bb >= 2){
516       ptr = parse_vbas( ptr, &class_id);
517       //      fprintf( stdout, "class_id: %lld\n", class_id);
518     }
519     msg->class_id = class_id;
520     
521     if (bb == 3)
522       ptr = parse_vbas( ptr, &csn);
523     msg->csn = csn;
524     
525     ptr = parse_vbas( ptr, &msg->bin_offset);
526     ptr = parse_vbas( ptr, &msg->length);
527     
528     if( msg->class_id%2) // Aux is present only if the id is odd
529       ptr = parse_vbas( ptr, &msg->aux);
530     else
531       msg->aux = 0;
532     
533     msg->res_offset = ptr-JPIPstream+offset;   
534     msg->phld = NULL;
535     msg->next = NULL;
536
537     if(msgqueue->first)
538       msgqueue->last->next = msg;
539     else
540       msgqueue->first = msg;
541     msgqueue->last = msg;
542     
543     ptr += msg->length;
544   }
545 }
546
547 void parse_metadata( metadata_param_t *metadata, message_param_t *msg, Byte_t *stream);
548
549 void parse_metamsg( msgqueue_param_t *msgqueue, Byte_t *stream, Byte8_t streamlen, metadatalist_param_t *metadatalist)
550 {
551   message_param_t *msg;
552
553   if( metadatalist == NULL)
554     return;
555   
556   msg = msgqueue->first;
557   while( msg){
558     if( msg->class_id == METADATA_MSG){
559       metadata_param_t *metadata = gene_metadata( msg->in_class_id, NULL, NULL, NULL);
560       insert_metadata_into_list( metadata, metadatalist);
561       parse_metadata( metadata, msg, stream+msg->res_offset);
562     }
563     msg = msg->next;
564   }
565 }
566
567 placeholder_param_t * parse_phld( Byte_t *datastream, Byte8_t metalength);
568
569 void parse_metadata( metadata_param_t *metadata, message_param_t *msg, Byte_t *datastream)
570 {
571   char *boxtype = (char *)(datastream+4);
572
573   msg->phld = NULL;
574
575   if( strncmp( boxtype, "phld", 4) == 0){
576     if( !metadata->placeholderlist)
577         metadata->placeholderlist = gene_placeholderlist();
578     
579     placeholder_param_t *phld = parse_phld( datastream, msg->length);
580     msg->phld = phld;
581     insert_placeholder_into_list( phld, metadata->placeholderlist);
582   }
583   else if( isalpha(boxtype[0]) && isalpha(boxtype[1]) &&
584            (isalnum(boxtype[2])||isblank(boxtype[2])) &&
585            (isalpha(boxtype[3])||isblank(boxtype[3]))){
586     if( !metadata->boxlist)
587       metadata->boxlist = gene_boxlist();
588     
589     box_param_t *box = gene_boxbyOffinStream( datastream, msg->res_offset);
590     insert_box_into_list( box, metadata->boxlist);
591   }
592   else
593     metadata->boxcontents = gene_boxcontents( msg->res_offset, msg->length);
594 }
595
596 placeholder_param_t * parse_phld( Byte_t *datastream, Byte8_t metalength)
597 {
598   placeholder_param_t *phld;
599
600   phld = (placeholder_param_t *)malloc( sizeof(placeholder_param_t));
601   
602   phld->LBox = big4( datastream);
603   strcpy( phld->TBox, "phld");
604   phld->Flags = big4( datastream+8);
605   phld->OrigID = big8( datastream+12);
606   phld->OrigBHlen = metalength - 20;
607   phld->OrigBH = (Byte_t *)malloc(phld->OrigBHlen);
608   memcpy( phld->OrigBH, datastream+20, phld->OrigBHlen);
609   phld->next = NULL;
610
611   return phld;
612 }
613
614 Byte_t * parse_bin_id_vbas( Byte_t *streamptr, Byte_t *bb, Byte_t *c, Byte8_t *in_class_id)
615 {
616   Byte_t code;
617   Byte_t *ptr;
618
619   ptr = streamptr;
620   code = *(ptr++);
621
622   *bb = (code >> 5) & 3;
623   *c  = (code >> 4) & 1;
624   
625   *in_class_id = code & 15;
626
627   while(code >> 7){
628     code = *(ptr++);
629     *in_class_id = (*in_class_id << 7) | (code & 0x7f);
630   }
631   return ptr;
632 }
633
634 Byte_t * parse_vbas( Byte_t *streamptr, Byte8_t *elem)
635 {
636   Byte_t code;
637   Byte_t *ptr;
638   
639   *elem = 0;
640   ptr = streamptr;
641   do{
642     code = *(ptr++);
643     *elem = (*elem << 7) | (code & 0x7f);
644   }while(code >> 7);
645   
646   return ptr;
647 }
648
649 /**
650  * search a message by class_id
651  *
652  * @param[in] class_id    class identifiers 
653  * @param[in] in_class_id in-class identifiers, -1 means any
654  * @param[in] csn         codestream number
655  * @param[in] msg         first message pointer of the searching list
656  * @return                found message pointer
657  */
658 message_param_t * search_message( Byte8_t class_id, Byte8_t in_class_id, Byte8_t csn, message_param_t *msg);
659
660
661 /**
662  * delete a message in msgqueue
663  *
664  * @param[in] message  address of the deleting message pointer
665  * @param[in] msgqueue message queue pointer
666  */
667 void delete_message_in_msgqueue( message_param_t **message, msgqueue_param_t *msgqueue);
668
669 /**
670  * reconstruct j2k codestream from JPT- (in future, JPP-) stream
671  *
672  * @param[in] msgqueue   message queue pointer
673  * @param[in] jpipstream original JPT- JPP- stream 
674  * @param[in] csn        codestream number
675  * @param[in] minlev     minimum decomposition level
676  * @param[out] codelen   codestream length
677  * @return               generated reconstructed j2k codestream
678  */
679 Byte_t * recons_codestream( msgqueue_param_t *msgqueue, Byte_t *jpipstream, Byte8_t csn, int minlev, Byte8_t *codelen);
680
681 Byte_t * recons_j2k( msgqueue_param_t *msgqueue, Byte_t *jpipstream, Byte8_t csn, int minlev, Byte8_t *j2klen)
682 {
683   Byte_t *j2kstream = NULL;
684   
685   if( !msgqueue)
686     return NULL;
687   
688   j2kstream = recons_codestream( msgqueue, jpipstream, csn, minlev, j2klen);
689
690   return j2kstream;
691 }
692
693 Byte_t * add_emptyboxstream( placeholder_param_t *phld, Byte_t *jp2stream, Byte8_t *jp2len);
694 Byte_t * add_msgstream( message_param_t *message, Byte_t *origstream, Byte_t *j2kstream, Byte8_t *j2klen);
695
696 Byte_t * recons_jp2( msgqueue_param_t *msgqueue, Byte_t *jpipstream, Byte8_t csn, Byte8_t *jp2len)
697 {
698   message_param_t *ptr;
699   Byte_t *jp2stream = NULL;
700   Byte_t *codestream = NULL;
701   Byte8_t codelen;
702   Byte8_t jp2cDBoxOffset = 0, jp2cDBoxlen = 0;
703   
704   *jp2len = 0;
705
706   if( !msgqueue)
707     return NULL;
708     
709   ptr = msgqueue->first;
710   while(( ptr = search_message( METADATA_MSG, -1, csn, ptr))!=NULL){
711     if( ptr->phld){
712       if( strncmp( (char *)ptr->phld->OrigBH+4, "jp2c", 4) == 0){
713         jp2cDBoxOffset = *jp2len + ptr->phld->OrigBHlen;
714         jp2stream = add_emptyboxstream( ptr->phld, jp2stream, jp2len); // header only
715         jp2cDBoxlen = *jp2len - jp2cDBoxOffset;
716       }
717       else
718         jp2stream = add_emptyboxstream( ptr->phld, jp2stream, jp2len); // header only
719     }
720     jp2stream = add_msgstream( ptr, jpipstream, jp2stream, jp2len);
721     ptr = ptr->next;
722   }
723   
724   codestream = recons_codestream( msgqueue, jpipstream, csn, 0, &codelen);
725   
726   if( jp2cDBoxOffset != 0 && codelen <= jp2cDBoxlen)
727     memcpy( jp2stream+jp2cDBoxOffset, codestream, codelen);
728
729   free( codestream);
730   
731   return jp2stream;
732 }
733
734 int get_last_tileID( msgqueue_param_t *msgqueue, Byte8_t csn);
735 Byte_t * add_emptytilestream( const int tileID, Byte_t *j2kstream, Byte8_t *j2klen);
736 Byte_t * add_EOC( Byte_t *j2kstream, Byte8_t *j2klen);
737
738 // usable only to JPT-stream messages
739 // PRECINCT_MSG, EXT_PRECINCT_MSG, TILE_HEADER_MSG need to be handled
740 Byte_t * recons_codestream( msgqueue_param_t *msgqueue, Byte_t *jpipstream, Byte8_t csn, int minlev, Byte8_t *codelen)
741 {
742   message_param_t *ptr;
743   Byte_t *codestream = NULL;
744   int last_tileID;
745   int tileID;
746   bool found;
747   Byte8_t binOffset;
748
749   *codelen = 0;
750
751   // main header first
752   ptr = msgqueue->first;
753   binOffset = 0;
754   while(( ptr = search_message( MAINHEADER_MSG, -1, csn, ptr))!=NULL){
755     if( ptr->bin_offset == binOffset){
756       codestream = add_msgstream( ptr, jpipstream, codestream, codelen);
757       binOffset += ptr->length;
758     }
759     ptr = ptr->next;
760   }
761
762   last_tileID = get_last_tileID( msgqueue, csn); 
763   
764   for( tileID=0; tileID <= last_tileID; tileID++){
765     found = false;
766     binOffset = 0;
767
768     ptr = msgqueue->first;
769     while(( ptr = search_message( TILE_MSG, tileID, csn, ptr))!=NULL){
770       if( ptr->bin_offset == binOffset){
771         found = true;
772         codestream = add_msgstream( ptr, jpipstream, codestream, codelen);
773         binOffset += ptr->length;
774       }
775       ptr = ptr->next;
776     }
777     ptr = msgqueue->first;
778     while(( ptr = search_message( EXT_TILE_MSG, tileID, csn, ptr))!=NULL){
779       if( ptr->aux >= minlev){
780         if( ptr->bin_offset == binOffset){
781           found = true;
782           codestream = add_msgstream( ptr, jpipstream, codestream, codelen);
783           binOffset += ptr->length;
784         }
785       }
786       ptr = ptr->next;
787     }
788     if(!found)
789       codestream = add_emptytilestream( tileID, codestream, codelen);
790   }
791   codestream = add_EOC( codestream, codelen);
792   
793   return codestream;
794 }
795
796 int get_last_tileID( msgqueue_param_t *msgqueue, Byte8_t csn)
797 {
798   int last_tileID = 0;
799   message_param_t *msg;
800   
801   msg = msgqueue->first;
802   while( msg){
803     if((msg->class_id == TILE_MSG || msg->class_id == EXT_TILE_MSG) && msg->csn == csn && last_tileID < msg->in_class_id)
804       last_tileID = msg->in_class_id;
805     msg = msg->next;
806   }
807   return last_tileID;
808 }
809
810 message_param_t * search_message( Byte8_t class_id, Byte8_t in_class_id, Byte8_t csn, message_param_t *msg)
811 {
812   while( msg != NULL){
813     if( in_class_id == -1){
814       if( msg->class_id == class_id && msg->csn == csn)
815         return msg;
816     }
817     else{
818       if( msg->class_id == class_id && msg->in_class_id == in_class_id && msg->csn == csn)
819         return msg;
820     }
821     msg = msg->next;
822   }
823   return NULL;
824 }
825
826 void delete_message_in_msgqueue( message_param_t **msg, msgqueue_param_t *msgqueue)
827 {
828   message_param_t *ptr;
829
830   if( !(*msg))
831     return;
832
833   if( *msg == msgqueue->first)
834     msgqueue->first = (*msg)->next;
835   else{
836     ptr = msgqueue->first;
837     while( ptr->next != *msg){
838       ptr=ptr->next;
839     }
840     
841     ptr->next = (*msg)->next;
842     
843     if( *msg == msgqueue->last)
844       msgqueue->last = ptr;
845   }
846   free( *msg);
847 }
848
849 Byte_t * gene_msgstream( message_param_t *message, Byte_t *stream, Byte8_t *length);
850 Byte_t * gene_emptytilestream( const int tileID, Byte8_t *length);
851
852
853 Byte_t * add_msgstream( message_param_t *message, Byte_t *origstream, Byte_t *j2kstream, Byte8_t *j2klen)
854 {
855   Byte_t *newstream;
856   Byte8_t newlen;
857   Byte_t *buf;
858
859   if( !message)
860     return NULL;
861
862   newstream = gene_msgstream( message, origstream, &newlen);
863
864   buf = (Byte_t *)malloc(( *j2klen)+newlen);
865
866   memcpy( buf, j2kstream, *j2klen);
867   memcpy( buf+(*j2klen), newstream, newlen);
868   
869   *j2klen += newlen;
870   
871   free( newstream);
872   if(j2kstream) free(j2kstream);
873
874   return buf;
875 }
876  
877
878 Byte_t * add_emptyboxstream( placeholder_param_t *phld, Byte_t *jp2stream, Byte8_t *jp2len)
879 {
880   Byte_t *newstream;
881   Byte8_t newlen;
882   Byte_t *buf;
883   
884   if( phld->OrigBHlen == 8)
885     newlen = big4(phld->OrigBH);
886   else
887     newlen = big8(phld->OrigBH+8);
888
889   newstream = (Byte_t *)malloc( newlen);
890   memset( newstream, 0, newlen);
891   memcpy( newstream, phld->OrigBH, phld->OrigBHlen);
892
893   buf = (Byte_t *)malloc(( *jp2len)+newlen);
894
895   memcpy( buf, jp2stream, *jp2len);
896   memcpy( buf+(*jp2len), newstream, newlen);
897   
898   *jp2len += newlen;
899   
900   free( newstream);
901   if(jp2stream) free(jp2stream);
902
903   return buf;
904 }
905
906 Byte_t * add_emptytilestream( const int tileID, Byte_t *j2kstream, Byte8_t *j2klen)
907 {
908   Byte_t *newstream;
909   Byte8_t newlen;
910   Byte_t *buf;
911
912   newstream = gene_emptytilestream( tileID, &newlen);
913
914   buf = (Byte_t *)malloc(( *j2klen)+newlen);
915
916   memcpy( buf, j2kstream, *j2klen);
917   memcpy( buf+(*j2klen), newstream, newlen);
918   
919   *j2klen += newlen;
920
921   free( newstream);
922   if(j2kstream) free(j2kstream);
923
924   return buf;
925 }
926
927 Byte_t * add_EOC( Byte_t *j2kstream, Byte8_t *j2klen)
928 {
929   Byte2_t EOC = 0xd9ff;
930
931   Byte_t *buf;
932
933   buf = (Byte_t *)malloc(( *j2klen)+2);
934
935   memcpy( buf, j2kstream, *j2klen);
936   memcpy( buf+(*j2klen), &EOC, 2);
937
938   *j2klen += 2;
939
940   if(j2kstream) free(j2kstream);
941
942   return buf;
943 }
944
945 Byte_t * gene_msgstream( message_param_t *message, Byte_t *stream, Byte8_t *length)
946 {
947   Byte_t *buf;
948
949   if( !message)
950     return NULL;
951
952   *length = message->length;
953   buf = (Byte_t *)malloc( *length);
954   memcpy( buf, stream+message->res_offset,  *length);
955
956   return buf;
957 }
958
959 Byte_t * gene_emptytilestream( const int tileID, Byte8_t *length)
960 {
961   Byte_t *buf;
962   const Byte2_t SOT = 0x90ff;
963   const Byte2_t Lsot = 0xa << 8;
964   Byte2_t Isot;
965   const Byte4_t Psot = 0xe << 24;
966   const Byte_t TPsot = 0, TNsot = 0;
967   const Byte2_t SOD = 0x93ff;
968
969   *length = 14;
970   buf = (Byte_t *)malloc(*length);
971
972   Isot = tileID << 8;
973   
974   memcpy( buf, &SOT, 2);
975   memcpy( buf+2, &Lsot, 2);
976   memcpy( buf+4, &Isot, 2);
977   memcpy( buf+6, &Psot, 4);
978   memcpy( buf+10, &TPsot, 1);
979   memcpy( buf+11, &TNsot, 1);
980   memcpy( buf+12, &SOD, 2);
981
982   return buf;
983 }