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