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
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
34 #include <sys/types.h>
45 #include "msgqueue_manager.h"
46 #include "metadata_manager.h"
47 #include "index_manager.h"
48 #include "opj_inttypes.h"
51 #include "fcgi_stdio.h"
52 #define logstream FCGI_stdout
54 #define FCGI_stdout stdout
55 #define FCGI_stderr stderr
56 #define logstream stderr
59 msgqueue_param_t * gene_msgqueue(OPJ_BOOL stateless,
60 cachemodel_param_t *cachemodel)
62 msgqueue_param_t *msgqueue;
64 msgqueue = (msgqueue_param_t *)opj_malloc(sizeof(msgqueue_param_t));
66 msgqueue->first = NULL;
67 msgqueue->last = NULL;
69 msgqueue->stateless = stateless;
70 msgqueue->cachemodel = cachemodel;
75 void delete_msgqueue(msgqueue_param_t **msgqueue)
77 message_param_t *ptr, *next;
83 ptr = (*msgqueue)->first;
90 if ((*msgqueue)->stateless && (*msgqueue)->cachemodel) {
91 delete_cachemodel(&((*msgqueue)->cachemodel));
97 void print_msgqueue(msgqueue_param_t *msgqueue)
100 static const char *message_class[] = { "Precinct", "Ext-Prec", "TileHead", "non",
101 "Tile", "Ext-Tile", "Main", "non", "Meta"
108 fprintf(logstream, "message queue:\n");
109 ptr = msgqueue->first;
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);
121 fprintf(logstream, "\t last_byte: %d\n", ptr->last_byte);
123 print_placeholder(ptr->phld);
125 fprintf(logstream, "\t res_offset: %#" PRIx64 "\n", ptr->res_offset);
127 fprintf(logstream, "\n");
133 void enqueue_message(message_param_t *msg, msgqueue_param_t *msgqueue);
135 void enqueue_mainheader(msgqueue_param_t *msgqueue)
137 cachemodel_param_t *cachemodel;
138 target_param_t *target;
139 index_param_t *codeidx;
140 message_param_t *msg;
142 cachemodel = msgqueue->cachemodel;
143 target = cachemodel->target;
144 codeidx = target->codeidx;
146 msg = (message_param_t *)opj_malloc(sizeof(message_param_t));
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;
154 msg->length = codeidx->mhead_length;
155 msg->aux = 0; /* non exist*/
156 msg->res_offset = codeidx->offset;
160 enqueue_message(msg, msgqueue);
162 cachemodel->mhead_model = OPJ_TRUE;
165 void enqueue_tileheader(int tile_id, msgqueue_param_t *msgqueue)
167 cachemodel_param_t *cachemodel;
168 target_param_t *target;
169 index_param_t *codeidx;
170 message_param_t *msg;
172 cachemodel = msgqueue->cachemodel;
173 target = cachemodel->target;
174 codeidx = target->codeidx;
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;
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*/
193 enqueue_message(msg, msgqueue);
194 cachemodel->th_model[ tile_id] = OPJ_TRUE;
198 void enqueue_tile(Byte4_t tile_id, int level, msgqueue_param_t *msgqueue)
200 cachemodel_param_t *cachemodel;
201 target_param_t *target;
203 Byte8_t numOftparts; /* num of tile parts par tile*/
205 index_param_t *codeidx;
206 faixbox_param_t *tilepart;
207 message_param_t *msg;
208 Byte8_t binOffset, binLength, class_id;
211 cachemodel = msgqueue->cachemodel;
212 target = cachemodel->target;
213 codeidx = target->codeidx;
214 tilepart = codeidx->tilepart;
216 numOftparts = get_nmax(tilepart);
217 numOftiles = get_m(tilepart);
219 class_id = (numOftparts == 1) ? TILE_MSG : EXT_TILE_MSG;
221 if (/*tile_id < 0 ||*/ numOftiles <= (Byte8_t)tile_id) {
222 fprintf(FCGI_stderr, "Error, Invalid tile-id %d\n", tile_id);
226 tp_model = &cachemodel->tp_model[ tile_id * numOftparts];
229 for (i = 0; i < numOftparts - (Byte8_t)level; i++) {
230 binLength = get_elemLen(tilepart, i, tile_id);
233 msg = (message_param_t *)opj_malloc(sizeof(message_param_t));
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,
248 enqueue_message(msg, msgqueue);
250 tp_model[i] = OPJ_TRUE;
252 binOffset += binLength;
256 void enqueue_precinct(int seq_id, int tile_id, int comp_id, int layers,
257 msgqueue_param_t *msgqueue)
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;
266 cachemodel = msgqueue->cachemodel;
267 codeidx = cachemodel->target->codeidx;
268 precpacket = codeidx->precpacket[ comp_id];
269 numOflayers = codeidx->COD.numOflayers;
271 nmax = get_nmax(precpacket);
272 assert(nmax < INT_MAX);
274 layers = numOflayers;
276 assert(tile_id >= 0);
279 for (layer_id = 0; layer_id < layers; layer_id++) {
281 binLength = get_elemLen(precpacket, (Byte8_t)(seq_id * numOflayers + layer_id),
284 if (!cachemodel->pp_model[comp_id][tile_id * (int)nmax + seq_id * numOflayers +
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;
296 msg->res_offset = codeidx->offset + (OPJ_OFF_T)get_elemOff(precpacket,
297 (Byte8_t)(seq_id * numOflayers + layer_id), (Byte8_t)tile_id);
301 enqueue_message(msg, msgqueue);
303 cachemodel->pp_model[comp_id][tile_id * (int)nmax + seq_id * numOflayers +
304 layer_id] = OPJ_TRUE;
306 binOffset += binLength;
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)
313 return (Byte8_t)(t + (c + s * num_components) * num_tiles);
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);
323 void enqueue_metadata(Byte8_t meta_id, msgqueue_param_t *msgqueue)
325 metadatalist_param_t *metadatalist;
326 metadata_param_t *metadata;
329 metadatalist = msgqueue->cachemodel->target->codeidx->metadatalist;
330 metadata = search_metadata(meta_id, metadatalist);
333 fprintf(FCGI_stderr, "Error: metadata-bin %" PRIu64 " not found\n", meta_id);
338 if (metadata->boxlist) {
339 enqueue_box(meta_id, metadata->boxlist, msgqueue, &binOffset);
342 if (metadata->placeholderlist) {
343 enqueue_phld(meta_id, metadata->placeholderlist, msgqueue, &binOffset);
346 if (metadata->boxcontents) {
347 enqueue_boxcontents(meta_id, metadata->boxcontents, msgqueue, &binOffset);
350 msgqueue->last->last_byte = OPJ_TRUE;
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);
356 void enqueue_box(Byte8_t meta_id, boxlist_param_t *boxlist,
357 msgqueue_param_t *msgqueue, Byte8_t *binOffset)
360 message_param_t *msg;
362 box = boxlist->first;
363 assert(msgqueue->cachemodel->target->csn >= 0);
365 msg = gene_metamsg(meta_id, *binOffset, box->length, box->offset, NULL,
366 (Byte8_t)msgqueue->cachemodel->target->csn);
367 enqueue_message(msg, msgqueue);
369 *binOffset += box->length;
374 void enqueue_phld(Byte8_t meta_id, placeholderlist_param_t *phldlist,
375 msgqueue_param_t *msgqueue, Byte8_t *binOffset)
377 placeholder_param_t *phld;
378 message_param_t *msg;
380 phld = phldlist->first;
381 assert(msgqueue->cachemodel->target->csn >= 0);
383 msg = gene_metamsg(meta_id, *binOffset, phld->LBox, 0, phld,
384 (Byte8_t)msgqueue->cachemodel->target->csn);
385 enqueue_message(msg, msgqueue);
387 *binOffset += phld->LBox;
392 void enqueue_boxcontents(Byte8_t meta_id, boxcontents_param_t *boxcontents,
393 msgqueue_param_t *msgqueue, Byte8_t *binOffset)
395 message_param_t *msg;
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);
402 *binOffset += boxcontents->length;
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)
408 message_param_t *msg;
410 msg = (message_param_t *)opj_malloc(sizeof(message_param_t));
412 msg->last_byte = OPJ_FALSE;
413 msg->in_class_id = meta_id;
414 msg->class_id = METADATA_MSG;
416 msg->bin_offset = binOffset;
417 msg->length = length;
418 msg->aux = 0; /* non exist*/
419 msg->res_offset = res_offset;
426 void enqueue_message(message_param_t *msg, msgqueue_param_t *msgqueue)
428 if (msgqueue->first) {
429 msgqueue->last->next = msg;
431 msgqueue->first = msg;
434 msgqueue->last = msg;
437 void add_bin_id_vbas_stream(Byte_t bb, Byte_t c, Byte8_t in_class_id,
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);
443 void recons_stream_from_msgqueue(msgqueue_param_t *msgqueue, int tmpfd)
445 message_param_t *msg;
446 Byte8_t class_id, csn;
453 msg = msgqueue->first;
454 class_id = (Byte8_t) - 1;
457 if (msg->csn == csn) {
458 if (msg->class_id == class_id) {
462 class_id = msg->class_id;
466 class_id = msg->class_id;
470 c = msg->last_byte ? 1 : 0;
472 add_bin_id_vbas_stream(bb, c, msg->in_class_id, tmpfd);
475 add_vbas_stream(class_id, tmpfd);
478 add_vbas_stream(csn, tmpfd);
481 add_vbas_stream(msg->bin_offset, tmpfd);
482 add_vbas_stream(msg->length, tmpfd);
484 if (msg->class_id % 2) { /* Aux is present only if the id is odd*/
485 add_vbas_stream(msg->aux, tmpfd);
489 add_placeholder_stream(msg->phld, tmpfd);
491 add_body_stream(msg, msgqueue->cachemodel->target->fd, tmpfd);
498 void add_vbas_with_bytelen_stream(Byte8_t code, int bytelength, int tmpfd);
499 void print_binarycode(Byte8_t n, int segmentlen);
501 void add_bin_id_vbas_stream(Byte_t bb, Byte_t c, Byte8_t in_class_id, int tmpfd)
506 /* A.2.3 In-class identifiers */
507 /* 7k-3bits, where k is the number of bytes in the VBAS*/
509 tmp = in_class_id >> 4;
515 in_class_id |= (Byte8_t)((((bb & 3) << 5) | (c & 1) << 4) << ((
516 bytelength - 1) * 7));
518 add_vbas_with_bytelen_stream(in_class_id, bytelength, tmpfd);
521 void add_vbas_stream(Byte8_t code, int tmpfd)
532 add_vbas_with_bytelen_stream(code, bytelength, tmpfd);
535 void add_vbas_with_bytelen_stream(Byte8_t code, int bytelength, int tmpfd)
542 seg = (code >> (n * 7)) & 0x7f;
546 if (write(tmpfd, (Byte4_t *)&seg, 1) != 1) {
547 fprintf(FCGI_stderr, "Error: failed to write vbas\n");
554 void add_body_stream(message_param_t *msg, int fd, int tmpfd)
558 if (!(data = fetch_bytes(fd, msg->res_offset, msg->length))) {
559 fprintf(FCGI_stderr, "Error: fetch_bytes in add_body_stream()\n");
563 if (write(tmpfd, data, msg->length) < 1) {
565 fprintf(FCGI_stderr, "Error: fwrite in add_body_stream()\n");
571 void add_bigendian_bytestream(Byte8_t code, int bytelength, int tmpfd);
573 void add_placeholder_stream(placeholder_param_t *phld, int tmpfd)
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");
580 add_bigendian_bytestream(phld->Flags, 4, tmpfd);
581 add_bigendian_bytestream(phld->OrigID, 8, tmpfd);
583 if (write(tmpfd, phld->OrigBH, phld->OrigBHlen) < 1) {
584 fprintf(FCGI_stderr, "Error: fwrite in add_placeholder_stream()\n");
589 void add_bigendian_bytestream(Byte8_t code, int bytelength, int tmpfd)
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");
605 void print_binarycode(Byte8_t n, int segmentlen)
611 buf[i++] = n % 2 ? '1' : '0';
612 } while ((n = n / 2));
614 for (j = segmentlen - 1; j >= i; j--) {
618 for (j = i - 1, k = 0; j >= 0; j--, k++) {
620 if (!((k + 1) % segmentlen)) {
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);
631 void parse_JPIPstream(Byte_t *JPIPstream, Byte8_t streamlen, OPJ_OFF_T offset,
632 msgqueue_param_t *msgqueue)
634 Byte_t *ptr; /* stream pointer*/
635 message_param_t *msg;
637 Byte8_t class_id, csn;
639 class_id = (Byte8_t) - 1; /* dummy*/
642 while ((Byte8_t)(ptr - JPIPstream) < streamlen) {
643 msg = (message_param_t *)opj_malloc(sizeof(message_param_t));
645 ptr = parse_bin_id_vbas(ptr, &bb, &c, &msg->in_class_id);
647 msg->last_byte = c == 1 ? OPJ_TRUE : OPJ_FALSE;
650 ptr = parse_vbas(ptr, &class_id);
653 msg->class_id = class_id;
656 ptr = parse_vbas(ptr, &csn);
660 ptr = parse_vbas(ptr, &msg->bin_offset);
661 ptr = parse_vbas(ptr, &msg->length);
663 if (msg->class_id % 2) { /* Aux is present only if the id is odd*/
664 ptr = parse_vbas(ptr, &msg->aux);
669 msg->res_offset = ptr - JPIPstream + offset;
673 if (msgqueue->first) {
674 msgqueue->last->next = msg;
676 msgqueue->first = msg;
678 msgqueue->last = msg;
684 void parse_metadata(metadata_param_t *metadata, message_param_t *msg,
687 void parse_metamsg(msgqueue_param_t *msgqueue, Byte_t *stream,
688 Byte8_t streamlen, metadatalist_param_t *metadatalist)
690 message_param_t *msg;
693 if (metadatalist == NULL) {
697 msg = msgqueue->first;
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);
708 placeholder_param_t * parse_phld(Byte_t *datastream, Byte8_t metalength);
710 void parse_metadata(metadata_param_t *metadata, message_param_t *msg,
714 placeholder_param_t *phld;
715 char *boxtype = (char *)(datastream + 4);
719 if (strncmp(boxtype, "phld", 4) == 0) {
720 if (!metadata->placeholderlist) {
721 metadata->placeholderlist = gene_placeholderlist();
724 phld = parse_phld(datastream, msg->length);
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();
734 box = gene_boxbyOffinStream(datastream, msg->res_offset);
735 insert_box_into_list(box, metadata->boxlist);
737 metadata->boxcontents = gene_boxcontents(msg->res_offset, msg->length);
741 placeholder_param_t * parse_phld(Byte_t *datastream, Byte8_t metalength)
743 placeholder_param_t *phld;
745 phld = (placeholder_param_t *)opj_malloc(sizeof(placeholder_param_t));
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);
759 Byte_t * parse_bin_id_vbas(Byte_t *streamptr, Byte_t *bb, Byte_t *c,
760 Byte8_t *in_class_id)
768 *bb = (code >> 5) & 3;
769 *c = (code >> 4) & 1;
771 *in_class_id = code & 15;
775 *in_class_id = (*in_class_id << 7) | (code & 0x7f);
780 Byte_t * parse_vbas(Byte_t *streamptr, Byte8_t *elem)
789 *elem = (*elem << 7) | (code & 0x7f);
795 void delete_message_in_msgqueue(message_param_t **msg,
796 msgqueue_param_t *msgqueue)
798 message_param_t *ptr;
804 if (*msg == msgqueue->first) {
805 msgqueue->first = (*msg)->next;
807 ptr = msgqueue->first;
808 while (ptr->next != *msg) {
812 ptr->next = (*msg)->next;
814 if (*msg == msgqueue->last) {
815 msgqueue->last = ptr;