Reformat whole codebase with astyle.options (#128)
[openjpeg.git] / src / lib / openjpip / msgqueue_manager.c
1 /*
2  * $Id$
3  *
4  * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium
5  * Copyright (c) 2002-2014, 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 #include <stdio.h>
33 #include <stdlib.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include <assert.h>
39 #include <limits.h>
40 #ifdef _WIN32
41 #include <io.h>
42 #else
43 #include <unistd.h>
44 #endif
45 #include "msgqueue_manager.h"
46 #include "metadata_manager.h"
47 #include "index_manager.h"
48 #include "opj_inttypes.h"
49
50 #ifdef SERVER
51 #include "fcgi_stdio.h"
52 #define logstream FCGI_stdout
53 #else
54 #define FCGI_stdout stdout
55 #define FCGI_stderr stderr
56 #define logstream stderr
57 #endif /*SERVER*/
58
59 msgqueue_param_t * gene_msgqueue(OPJ_BOOL stateless,
60                                  cachemodel_param_t *cachemodel)
61 {
62     msgqueue_param_t *msgqueue;
63
64     msgqueue = (msgqueue_param_t *)opj_malloc(sizeof(msgqueue_param_t));
65
66     msgqueue->first = NULL;
67     msgqueue->last  = NULL;
68
69     msgqueue->stateless = stateless;
70     msgqueue->cachemodel = cachemodel;
71
72     return msgqueue;
73 }
74
75 void delete_msgqueue(msgqueue_param_t **msgqueue)
76 {
77     message_param_t *ptr, *next;
78
79     if (!(*msgqueue)) {
80         return;
81     }
82
83     ptr = (*msgqueue)->first;
84
85     while (ptr) {
86         next = ptr->next;
87         opj_free(ptr);
88         ptr = next;
89     }
90     if ((*msgqueue)->stateless && (*msgqueue)->cachemodel) {
91         delete_cachemodel(&((*msgqueue)->cachemodel));
92     }
93
94     opj_free(*msgqueue);
95 }
96
97 void print_msgqueue(msgqueue_param_t *msgqueue)
98 {
99     message_param_t *ptr;
100     static const char *message_class[] = { "Precinct", "Ext-Prec", "TileHead", "non",
101                                            "Tile", "Ext-Tile", "Main", "non", "Meta"
102                                          };
103
104     if (!msgqueue) {
105         return;
106     }
107
108     fprintf(logstream, "message queue:\n");
109     ptr = msgqueue->first;
110
111     while (ptr) {
112         fprintf(logstream, "\t class_id: %" PRId64 " %s\n", ptr->class_id,
113                 message_class[ptr->class_id]);
114         fprintf(logstream, "\t in_class_id: %" PRId64 "\n", ptr->in_class_id);
115         fprintf(logstream, "\t csn: %" PRId64 "\n", ptr->csn);
116         fprintf(logstream, "\t bin_offset: %#" PRIx64 "\n", ptr->bin_offset);
117         fprintf(logstream, "\t length: %#" PRIx64 "\n", ptr->length);
118         if (ptr->class_id % 2) {
119             fprintf(logstream, "\t aux: %" PRId64 "\n", ptr->aux);
120         }
121         fprintf(logstream, "\t last_byte: %d\n", ptr->last_byte);
122         if (ptr->phld) {
123             print_placeholder(ptr->phld);
124         } else {
125             fprintf(logstream, "\t res_offset: %#" PRIx64 "\n", ptr->res_offset);
126         }
127         fprintf(logstream, "\n");
128
129         ptr = ptr->next;
130     }
131 }
132
133 void enqueue_message(message_param_t *msg, msgqueue_param_t *msgqueue);
134
135 void enqueue_mainheader(msgqueue_param_t *msgqueue)
136 {
137     cachemodel_param_t *cachemodel;
138     target_param_t *target;
139     index_param_t *codeidx;
140     message_param_t *msg;
141
142     cachemodel = msgqueue->cachemodel;
143     target = cachemodel->target;
144     codeidx = target->codeidx;
145
146     msg = (message_param_t *)opj_malloc(sizeof(message_param_t));
147
148     msg->last_byte = OPJ_TRUE;
149     msg->in_class_id = 0;
150     msg->class_id = MAINHEADER_MSG;
151     assert(target->csn >= 0);
152     msg->csn = (Byte8_t)target->csn;
153     msg->bin_offset = 0;
154     msg->length = codeidx->mhead_length;
155     msg->aux = 0; /* non exist*/
156     msg->res_offset = codeidx->offset;
157     msg->phld = NULL;
158     msg->next = NULL;
159
160     enqueue_message(msg, msgqueue);
161
162     cachemodel->mhead_model = OPJ_TRUE;
163 }
164
165 void enqueue_tileheader(int tile_id, msgqueue_param_t *msgqueue)
166 {
167     cachemodel_param_t *cachemodel;
168     target_param_t *target;
169     index_param_t *codeidx;
170     message_param_t *msg;
171
172     cachemodel = msgqueue->cachemodel;
173     target = cachemodel->target;
174     codeidx = target->codeidx;
175
176     if (!cachemodel->th_model[ tile_id]) {
177         msg = (message_param_t *)opj_malloc(sizeof(message_param_t));
178         msg->last_byte = OPJ_TRUE;
179         assert(tile_id >= 0);
180         msg->in_class_id = (Byte8_t)tile_id;
181         msg->class_id = TILE_HEADER_MSG;
182         assert(target->csn >= 0);
183         msg->csn = (Byte8_t)target->csn;
184         msg->bin_offset = 0;
185         msg->length = codeidx->tileheader[tile_id]->tlen -
186                       2; /* SOT marker segment is removed*/
187         msg->aux = 0; /* non exist*/
188         msg->res_offset = codeidx->offset + (OPJ_OFF_T)get_elemOff(codeidx->tilepart, 0,
189                           (Byte8_t)tile_id) + 2; /* skip SOT marker seg*/
190         msg->phld = NULL;
191         msg->next = NULL;
192
193         enqueue_message(msg, msgqueue);
194         cachemodel->th_model[ tile_id] = OPJ_TRUE;
195     }
196 }
197
198 void enqueue_tile(Byte4_t tile_id, int level, msgqueue_param_t *msgqueue)
199 {
200     cachemodel_param_t *cachemodel;
201     target_param_t *target;
202     OPJ_BOOL *tp_model;
203     Byte8_t numOftparts; /* num of tile parts par tile*/
204     Byte8_t numOftiles;
205     index_param_t *codeidx;
206     faixbox_param_t *tilepart;
207     message_param_t *msg;
208     Byte8_t binOffset, binLength, class_id;
209     Byte8_t i;
210
211     cachemodel = msgqueue->cachemodel;
212     target = cachemodel->target;
213     codeidx  = target->codeidx;
214     tilepart = codeidx->tilepart;
215
216     numOftparts = get_nmax(tilepart);
217     numOftiles  = get_m(tilepart);
218
219     class_id = (numOftparts == 1) ? TILE_MSG : EXT_TILE_MSG;
220
221     if (/*tile_id < 0 ||*/ numOftiles <= (Byte8_t)tile_id) {
222         fprintf(FCGI_stderr, "Error, Invalid tile-id %d\n", tile_id);
223         return;
224     }
225
226     tp_model = &cachemodel->tp_model[ tile_id * numOftparts];
227
228     binOffset = 0;
229     for (i = 0; i < numOftparts - (Byte8_t)level; i++) {
230         binLength = get_elemLen(tilepart, i, tile_id);
231
232         if (!tp_model[i]) {
233             msg = (message_param_t *)opj_malloc(sizeof(message_param_t));
234
235             msg->last_byte = (i == numOftparts - 1);
236             msg->in_class_id = tile_id;
237             msg->class_id = class_id;
238             assert(target->csn >= 0);
239             msg->csn = (Byte8_t)target->csn;
240             msg->bin_offset = binOffset;
241             msg->length = binLength;
242             msg->aux = numOftparts - i;
243             msg->res_offset = codeidx->offset + (OPJ_OFF_T)get_elemOff(tilepart, i,
244                               tile_id)/*-1*/;
245             msg->phld = NULL;
246             msg->next = NULL;
247
248             enqueue_message(msg, msgqueue);
249
250             tp_model[i] = OPJ_TRUE;
251         }
252         binOffset += binLength;
253     }
254 }
255
256 void enqueue_precinct(int seq_id, int tile_id, int comp_id, int layers,
257                       msgqueue_param_t *msgqueue)
258 {
259     cachemodel_param_t *cachemodel;
260     index_param_t *codeidx;
261     faixbox_param_t *precpacket;
262     message_param_t *msg;
263     Byte8_t nmax, binOffset, binLength;
264     int layer_id, numOflayers;
265
266     cachemodel = msgqueue->cachemodel;
267     codeidx = cachemodel->target->codeidx;
268     precpacket = codeidx->precpacket[ comp_id];
269     numOflayers = codeidx->COD.numOflayers;
270
271     nmax = get_nmax(precpacket);
272     assert(nmax < INT_MAX);
273     if (layers < 0) {
274         layers = numOflayers;
275     }
276     assert(tile_id >= 0);
277
278     binOffset = 0;
279     for (layer_id = 0; layer_id < layers; layer_id++) {
280
281         binLength = get_elemLen(precpacket, (Byte8_t)(seq_id * numOflayers + layer_id),
282                                 (Byte8_t)tile_id);
283
284         if (!cachemodel->pp_model[comp_id][tile_id * (int)nmax + seq_id * numOflayers +
285                                            layer_id]) {
286
287             msg = (message_param_t *)opj_malloc(sizeof(message_param_t));
288             msg->last_byte = (layer_id == (numOflayers - 1));
289             msg->in_class_id = comp_precinct_id(tile_id, comp_id, seq_id, codeidx->SIZ.Csiz,
290                                                 (int)codeidx->SIZ.XTnum * (int) codeidx->SIZ.YTnum);
291             msg->class_id = PRECINCT_MSG;
292             msg->csn = (Byte8_t)cachemodel->target->csn;
293             msg->bin_offset = binOffset;
294             msg->length = binLength;
295             msg->aux = 0;
296             msg->res_offset = codeidx->offset + (OPJ_OFF_T)get_elemOff(precpacket,
297                               (Byte8_t)(seq_id * numOflayers + layer_id), (Byte8_t)tile_id);
298             msg->phld = NULL;
299             msg->next = NULL;
300
301             enqueue_message(msg, msgqueue);
302
303             cachemodel->pp_model[comp_id][tile_id * (int)nmax + seq_id * numOflayers +
304                                           layer_id] = OPJ_TRUE;
305         }
306         binOffset += binLength;
307     }
308 }
309
310 /* MM FIXME: each params is coded on int, this is really not clear from the specs what it should be */
311 Byte8_t comp_precinct_id(int t, int c, int s, int num_components, int num_tiles)
312 {
313     return (Byte8_t)(t + (c + s * num_components) * num_tiles);
314 }
315
316 void enqueue_box(Byte8_t meta_id, boxlist_param_t *boxlist,
317                  msgqueue_param_t *msgqueue, Byte8_t *binOffset);
318 void enqueue_phld(Byte8_t meta_id, placeholderlist_param_t *phldlist,
319                   msgqueue_param_t *msgqueue, Byte8_t *binOffset);
320 void enqueue_boxcontents(Byte8_t meta_id, boxcontents_param_t *boxcontents,
321                          msgqueue_param_t *msgqueue, Byte8_t *binOffset);
322
323 void enqueue_metadata(Byte8_t meta_id, msgqueue_param_t *msgqueue)
324 {
325     metadatalist_param_t *metadatalist;
326     metadata_param_t *metadata;
327     Byte8_t binOffset;
328
329     metadatalist = msgqueue->cachemodel->target->codeidx->metadatalist;
330     metadata = search_metadata(meta_id, metadatalist);
331
332     if (!metadata) {
333         fprintf(FCGI_stderr, "Error: metadata-bin %" PRIu64 " not found\n", meta_id);
334         return;
335     }
336     binOffset = 0;
337
338     if (metadata->boxlist) {
339         enqueue_box(meta_id, metadata->boxlist, msgqueue, &binOffset);
340     }
341
342     if (metadata->placeholderlist) {
343         enqueue_phld(meta_id, metadata->placeholderlist, msgqueue, &binOffset);
344     }
345
346     if (metadata->boxcontents) {
347         enqueue_boxcontents(meta_id, metadata->boxcontents, msgqueue, &binOffset);
348     }
349
350     msgqueue->last->last_byte = OPJ_TRUE;
351 }
352
353 message_param_t * gene_metamsg(Byte8_t meta_id, Byte8_t binoffset,
354                                Byte8_t length, OPJ_OFF_T res_offset, placeholder_param_t *phld, Byte8_t csn);
355
356 void enqueue_box(Byte8_t meta_id, boxlist_param_t *boxlist,
357                  msgqueue_param_t *msgqueue, Byte8_t *binOffset)
358 {
359     box_param_t *box;
360     message_param_t *msg;
361
362     box = boxlist->first;
363     assert(msgqueue->cachemodel->target->csn >= 0);
364     while (box) {
365         msg = gene_metamsg(meta_id, *binOffset, box->length, box->offset, NULL,
366                            (Byte8_t)msgqueue->cachemodel->target->csn);
367         enqueue_message(msg, msgqueue);
368
369         *binOffset += box->length;
370         box = box->next;
371     }
372 }
373
374 void enqueue_phld(Byte8_t meta_id, placeholderlist_param_t *phldlist,
375                   msgqueue_param_t *msgqueue, Byte8_t *binOffset)
376 {
377     placeholder_param_t *phld;
378     message_param_t *msg;
379
380     phld = phldlist->first;
381     assert(msgqueue->cachemodel->target->csn >= 0);
382     while (phld) {
383         msg = gene_metamsg(meta_id, *binOffset, phld->LBox, 0, phld,
384                            (Byte8_t)msgqueue->cachemodel->target->csn);
385         enqueue_message(msg, msgqueue);
386
387         *binOffset += phld->LBox;
388         phld = phld->next;
389     }
390 }
391
392 void enqueue_boxcontents(Byte8_t meta_id, boxcontents_param_t *boxcontents,
393                          msgqueue_param_t *msgqueue, Byte8_t *binOffset)
394 {
395     message_param_t *msg;
396
397     assert(msgqueue->cachemodel->target->csn >= 0);
398     msg = gene_metamsg(meta_id, *binOffset, boxcontents->length,
399                        boxcontents->offset, NULL, (Byte8_t)msgqueue->cachemodel->target->csn);
400     enqueue_message(msg, msgqueue);
401
402     *binOffset += boxcontents->length;
403 }
404
405 message_param_t * gene_metamsg(Byte8_t meta_id, Byte8_t binOffset,
406                                Byte8_t length, OPJ_OFF_T res_offset, placeholder_param_t *phld, Byte8_t csn)
407 {
408     message_param_t *msg;
409
410     msg = (message_param_t *)opj_malloc(sizeof(message_param_t));
411
412     msg->last_byte = OPJ_FALSE;
413     msg->in_class_id = meta_id;
414     msg->class_id = METADATA_MSG;
415     msg->csn = csn;
416     msg->bin_offset = binOffset;
417     msg->length = length;
418     msg->aux = 0; /* non exist*/
419     msg->res_offset = res_offset;
420     msg->phld = phld;
421     msg->next = NULL;
422
423     return msg;
424 }
425
426 void enqueue_message(message_param_t *msg, msgqueue_param_t *msgqueue)
427 {
428     if (msgqueue->first) {
429         msgqueue->last->next = msg;
430     } else {
431         msgqueue->first = msg;
432     }
433
434     msgqueue->last = msg;
435 }
436
437 void add_bin_id_vbas_stream(Byte_t bb, Byte_t c, Byte8_t in_class_id,
438                             int tmpfd);
439 void add_vbas_stream(Byte8_t code, int tmpfd);
440 void add_body_stream(message_param_t *msg, int fd, int tmpfd);
441 void add_placeholder_stream(placeholder_param_t *phld, int tmpfd);
442
443 void recons_stream_from_msgqueue(msgqueue_param_t *msgqueue, int tmpfd)
444 {
445     message_param_t *msg;
446     Byte8_t class_id, csn;
447     Byte_t bb, c;
448
449     if (!(msgqueue)) {
450         return;
451     }
452
453     msg = msgqueue->first;
454     class_id = (Byte8_t) - 1;
455     csn = (Byte8_t) - 1;
456     while (msg) {
457         if (msg->csn == csn) {
458             if (msg->class_id == class_id) {
459                 bb = 1;
460             } else {
461                 bb = 2;
462                 class_id = msg->class_id;
463             }
464         } else {
465             bb = 3;
466             class_id = msg->class_id;
467             csn = msg->csn;
468         }
469
470         c = msg->last_byte ? 1 : 0;
471
472         add_bin_id_vbas_stream(bb, c, msg->in_class_id, tmpfd);
473
474         if (bb >= 2) {
475             add_vbas_stream(class_id, tmpfd);
476         }
477         if (bb == 3) {
478             add_vbas_stream(csn, tmpfd);
479         }
480
481         add_vbas_stream(msg->bin_offset, tmpfd);
482         add_vbas_stream(msg->length, tmpfd);
483
484         if (msg->class_id % 2) { /* Aux is present only if the id is odd*/
485             add_vbas_stream(msg->aux, tmpfd);
486         }
487
488         if (msg->phld) {
489             add_placeholder_stream(msg->phld, tmpfd);
490         } else {
491             add_body_stream(msg, msgqueue->cachemodel->target->fd, tmpfd);
492         }
493
494         msg = msg->next;
495     }
496 }
497
498 void add_vbas_with_bytelen_stream(Byte8_t code, int bytelength, int tmpfd);
499 void print_binarycode(Byte8_t n, int segmentlen);
500
501 void add_bin_id_vbas_stream(Byte_t bb, Byte_t c, Byte8_t in_class_id, int tmpfd)
502 {
503     int bytelength;
504     Byte8_t tmp;
505
506     /* A.2.3 In-class identifiers */
507     /* 7k-3bits, where k is the number of bytes in the VBAS*/
508     bytelength = 1;
509     tmp = in_class_id >> 4;
510     while (tmp) {
511         bytelength ++;
512         tmp >>= 7;
513     }
514
515     in_class_id |= (Byte8_t)((((bb & 3) << 5) | (c & 1) << 4) << ((
516                                  bytelength - 1) * 7));
517
518     add_vbas_with_bytelen_stream(in_class_id, bytelength, tmpfd);
519 }
520
521 void add_vbas_stream(Byte8_t code, int tmpfd)
522 {
523     int bytelength;
524     Byte8_t tmp;
525
526     bytelength = 1;
527     tmp = code;
528     while (tmp >>= 7) {
529         bytelength ++;
530     }
531
532     add_vbas_with_bytelen_stream(code, bytelength, tmpfd);
533 }
534
535 void add_vbas_with_bytelen_stream(Byte8_t code, int bytelength, int tmpfd)
536 {
537     int n;
538     Byte8_t seg;
539
540     n = bytelength - 1;
541     while (n >= 0) {
542         seg = (code >> (n * 7)) & 0x7f;
543         if (n) {
544             seg |= 0x80;
545         }
546         if (write(tmpfd, (Byte4_t *)&seg, 1) != 1) {
547             fprintf(FCGI_stderr, "Error: failed to write vbas\n");
548             return;
549         }
550         n--;
551     }
552 }
553
554 void add_body_stream(message_param_t *msg, int fd, int tmpfd)
555 {
556     Byte_t *data;
557
558     if (!(data = fetch_bytes(fd, msg->res_offset, msg->length))) {
559         fprintf(FCGI_stderr, "Error: fetch_bytes in add_body_stream()\n");
560         return;
561     }
562
563     if (write(tmpfd, data, msg->length) < 1) {
564         opj_free(data);
565         fprintf(FCGI_stderr, "Error: fwrite in add_body_stream()\n");
566         return;
567     }
568     opj_free(data);
569 }
570
571 void add_bigendian_bytestream(Byte8_t code, int bytelength, int tmpfd);
572
573 void add_placeholder_stream(placeholder_param_t *phld, int tmpfd)
574 {
575     add_bigendian_bytestream(phld->LBox, 4, tmpfd);
576     if (write(tmpfd, phld->TBox, 4) < 1) {
577         fprintf(FCGI_stderr, "Error: fwrite in add_placeholder_stream()\n");
578         return;
579     }
580     add_bigendian_bytestream(phld->Flags, 4, tmpfd);
581     add_bigendian_bytestream(phld->OrigID, 8, tmpfd);
582
583     if (write(tmpfd, phld->OrigBH, phld->OrigBHlen) < 1) {
584         fprintf(FCGI_stderr, "Error: fwrite in add_placeholder_stream()\n");
585         return;
586     }
587 }
588
589 void add_bigendian_bytestream(Byte8_t code, int bytelength, int tmpfd)
590 {
591     int n;
592     Byte8_t seg;
593
594     n = bytelength - 1;
595     while (n >= 0) {
596         seg = (code >> (n * 8)) & 0xff;
597         if (write(tmpfd, (Byte4_t *)&seg, 1) != 1) {
598             fprintf(FCGI_stderr, "ERROR: failed to write bigendian_bytestream\n");
599             return;
600         }
601         n--;
602     }
603 }
604
605 void print_binarycode(Byte8_t n, int segmentlen)
606 {
607     char buf[256];
608     int i = 0, j, k;
609
610     do {
611         buf[i++] = n % 2 ? '1' : '0';
612     } while ((n = n / 2));
613
614     for (j = segmentlen - 1; j >= i; j--) {
615         putchar('0');
616     }
617
618     for (j = i - 1, k = 0; j >= 0; j--, k++) {
619         putchar(buf[j]);
620         if (!((k + 1) % segmentlen)) {
621             printf(" ");
622         }
623     }
624     printf("\n");
625 }
626
627 Byte_t * parse_bin_id_vbas(Byte_t *streamptr, Byte_t *bb, Byte_t *c,
628                            Byte8_t *in_class_id);
629 Byte_t * parse_vbas(Byte_t *streamptr, Byte8_t *elem);
630
631 void parse_JPIPstream(Byte_t *JPIPstream, Byte8_t streamlen, OPJ_OFF_T offset,
632                       msgqueue_param_t *msgqueue)
633 {
634     Byte_t *ptr;  /* stream pointer*/
635     message_param_t *msg;
636     Byte_t bb, c;
637     Byte8_t class_id, csn;
638
639     class_id = (Byte8_t) - 1; /* dummy*/
640     csn = (Byte8_t) - 1;
641     ptr = JPIPstream;
642     while ((Byte8_t)(ptr - JPIPstream) < streamlen) {
643         msg = (message_param_t *)opj_malloc(sizeof(message_param_t));
644
645         ptr = parse_bin_id_vbas(ptr, &bb, &c, &msg->in_class_id);
646
647         msg->last_byte   = c == 1 ? OPJ_TRUE : OPJ_FALSE;
648
649         if (bb >= 2) {
650             ptr = parse_vbas(ptr, &class_id);
651         }
652
653         msg->class_id = class_id;
654
655         if (bb == 3) {
656             ptr = parse_vbas(ptr, &csn);
657         }
658         msg->csn = csn;
659
660         ptr = parse_vbas(ptr, &msg->bin_offset);
661         ptr = parse_vbas(ptr, &msg->length);
662
663         if (msg->class_id % 2) { /* Aux is present only if the id is odd*/
664             ptr = parse_vbas(ptr, &msg->aux);
665         } else {
666             msg->aux = 0;
667         }
668
669         msg->res_offset = ptr - JPIPstream + offset;
670         msg->phld = NULL;
671         msg->next = NULL;
672
673         if (msgqueue->first) {
674             msgqueue->last->next = msg;
675         } else {
676             msgqueue->first = msg;
677         }
678         msgqueue->last = msg;
679
680         ptr += msg->length;
681     }
682 }
683
684 void parse_metadata(metadata_param_t *metadata, message_param_t *msg,
685                     Byte_t *stream);
686
687 void parse_metamsg(msgqueue_param_t *msgqueue, Byte_t *stream,
688                    Byte8_t streamlen, metadatalist_param_t *metadatalist)
689 {
690     message_param_t *msg;
691     (void)streamlen;
692
693     if (metadatalist == NULL) {
694         return;
695     }
696
697     msg = msgqueue->first;
698     while (msg) {
699         if (msg->class_id == METADATA_MSG) {
700             metadata_param_t *metadata = gene_metadata(msg->in_class_id, NULL, NULL, NULL);
701             insert_metadata_into_list(metadata, metadatalist);
702             parse_metadata(metadata, msg, stream + msg->res_offset);
703         }
704         msg = msg->next;
705     }
706 }
707
708 placeholder_param_t * parse_phld(Byte_t *datastream, Byte8_t metalength);
709
710 void parse_metadata(metadata_param_t *metadata, message_param_t *msg,
711                     Byte_t *datastream)
712 {
713     box_param_t *box;
714     placeholder_param_t *phld;
715     char *boxtype = (char *)(datastream + 4);
716
717     msg->phld = NULL;
718
719     if (strncmp(boxtype, "phld", 4) == 0) {
720         if (!metadata->placeholderlist) {
721             metadata->placeholderlist = gene_placeholderlist();
722         }
723
724         phld = parse_phld(datastream, msg->length);
725         msg->phld = phld;
726         insert_placeholder_into_list(phld, metadata->placeholderlist);
727     } else if (isalpha(boxtype[0]) && isalpha(boxtype[1]) &&
728                (isalnum(boxtype[2]) || isspace(boxtype[2])) &&
729                (isalpha(boxtype[3]) || isspace(boxtype[3]))) {
730         if (!metadata->boxlist) {
731             metadata->boxlist = gene_boxlist();
732         }
733
734         box = gene_boxbyOffinStream(datastream, msg->res_offset);
735         insert_box_into_list(box, metadata->boxlist);
736     } else {
737         metadata->boxcontents = gene_boxcontents(msg->res_offset, msg->length);
738     }
739 }
740
741 placeholder_param_t * parse_phld(Byte_t *datastream, Byte8_t metalength)
742 {
743     placeholder_param_t *phld;
744
745     phld = (placeholder_param_t *)opj_malloc(sizeof(placeholder_param_t));
746
747     phld->LBox = big4(datastream);
748     strncpy(phld->TBox, "phld", 4);
749     phld->Flags = big4(datastream + 8);
750     phld->OrigID = big8(datastream + 12);
751     phld->OrigBHlen = (Byte_t)(metalength - 20);
752     phld->OrigBH = (Byte_t *)opj_malloc(phld->OrigBHlen);
753     memcpy(phld->OrigBH, datastream + 20, phld->OrigBHlen);
754     phld->next = NULL;
755
756     return phld;
757 }
758
759 Byte_t * parse_bin_id_vbas(Byte_t *streamptr, Byte_t *bb, Byte_t *c,
760                            Byte8_t *in_class_id)
761 {
762     Byte_t code;
763     Byte_t *ptr;
764
765     ptr = streamptr;
766     code = *(ptr++);
767
768     *bb = (code >> 5) & 3;
769     *c  = (code >> 4) & 1;
770
771     *in_class_id = code & 15;
772
773     while (code >> 7) {
774         code = *(ptr++);
775         *in_class_id = (*in_class_id << 7) | (code & 0x7f);
776     }
777     return ptr;
778 }
779
780 Byte_t * parse_vbas(Byte_t *streamptr, Byte8_t *elem)
781 {
782     Byte_t code;
783     Byte_t *ptr;
784
785     *elem = 0;
786     ptr = streamptr;
787     do {
788         code = *(ptr++);
789         *elem = (*elem << 7) | (code & 0x7f);
790     } while (code >> 7);
791
792     return ptr;
793 }
794
795 void delete_message_in_msgqueue(message_param_t **msg,
796                                 msgqueue_param_t *msgqueue)
797 {
798     message_param_t *ptr;
799
800     if (!(*msg)) {
801         return;
802     }
803
804     if (*msg == msgqueue->first) {
805         msgqueue->first = (*msg)->next;
806     } else {
807         ptr = msgqueue->first;
808         while (ptr->next != *msg) {
809             ptr = ptr->next;
810         }
811
812         ptr->next = (*msg)->next;
813
814         if (*msg == msgqueue->last) {
815             msgqueue->last = ptr;
816         }
817     }
818     opj_free(*msg);
819 }