/* * $Id$ * * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium * Copyright (c) 2002-2014, Professor Benoit Macq * Copyright (c) 2010-2011, Kaori Hagihara * Copyright (c) 2011, Lucian Corlaciu, GSoC * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #else #include #endif #include "msgqueue_manager.h" #include "metadata_manager.h" #include "index_manager.h" #include "opj_inttypes.h" #ifdef SERVER #include "fcgi_stdio.h" #define logstream FCGI_stdout #else #define FCGI_stdout stdout #define FCGI_stderr stderr #define logstream stderr #endif /*SERVER*/ msgqueue_param_t * gene_msgqueue(OPJ_BOOL stateless, cachemodel_param_t *cachemodel) { msgqueue_param_t *msgqueue; msgqueue = (msgqueue_param_t *)opj_malloc(sizeof(msgqueue_param_t)); msgqueue->first = NULL; msgqueue->last = NULL; msgqueue->stateless = stateless; msgqueue->cachemodel = cachemodel; return msgqueue; } void delete_msgqueue(msgqueue_param_t **msgqueue) { message_param_t *ptr, *next; if (!(*msgqueue)) { return; } ptr = (*msgqueue)->first; while (ptr) { next = ptr->next; opj_free(ptr); ptr = next; } if ((*msgqueue)->stateless && (*msgqueue)->cachemodel) { delete_cachemodel(&((*msgqueue)->cachemodel)); } opj_free(*msgqueue); } void print_msgqueue(msgqueue_param_t *msgqueue) { message_param_t *ptr; static const char *message_class[] = { "Precinct", "Ext-Prec", "TileHead", "non", "Tile", "Ext-Tile", "Main", "non", "Meta" }; if (!msgqueue) { return; } fprintf(logstream, "message queue:\n"); ptr = msgqueue->first; while (ptr) { fprintf(logstream, "\t class_id: %" PRId64 " %s\n", ptr->class_id, message_class[ptr->class_id]); fprintf(logstream, "\t in_class_id: %" PRId64 "\n", ptr->in_class_id); fprintf(logstream, "\t csn: %" PRId64 "\n", ptr->csn); fprintf(logstream, "\t bin_offset: %#" PRIx64 "\n", ptr->bin_offset); fprintf(logstream, "\t length: %#" PRIx64 "\n", ptr->length); if (ptr->class_id % 2) { fprintf(logstream, "\t aux: %" PRId64 "\n", ptr->aux); } fprintf(logstream, "\t last_byte: %d\n", ptr->last_byte); if (ptr->phld) { print_placeholder(ptr->phld); } else { fprintf(logstream, "\t res_offset: %#" PRIx64 "\n", ptr->res_offset); } fprintf(logstream, "\n"); ptr = ptr->next; } } void enqueue_message(message_param_t *msg, msgqueue_param_t *msgqueue); void enqueue_mainheader(msgqueue_param_t *msgqueue) { cachemodel_param_t *cachemodel; target_param_t *target; index_param_t *codeidx; message_param_t *msg; cachemodel = msgqueue->cachemodel; target = cachemodel->target; codeidx = target->codeidx; msg = (message_param_t *)opj_malloc(sizeof(message_param_t)); msg->last_byte = OPJ_TRUE; msg->in_class_id = 0; msg->class_id = MAINHEADER_MSG; assert(target->csn >= 0); msg->csn = (Byte8_t)target->csn; msg->bin_offset = 0; msg->length = codeidx->mhead_length; msg->aux = 0; /* non exist*/ msg->res_offset = codeidx->offset; msg->phld = NULL; msg->next = NULL; enqueue_message(msg, msgqueue); cachemodel->mhead_model = OPJ_TRUE; } void enqueue_tileheader(int tile_id, msgqueue_param_t *msgqueue) { cachemodel_param_t *cachemodel; target_param_t *target; index_param_t *codeidx; message_param_t *msg; cachemodel = msgqueue->cachemodel; target = cachemodel->target; codeidx = target->codeidx; if (!cachemodel->th_model[ tile_id]) { msg = (message_param_t *)opj_malloc(sizeof(message_param_t)); msg->last_byte = OPJ_TRUE; assert(tile_id >= 0); msg->in_class_id = (Byte8_t)tile_id; msg->class_id = TILE_HEADER_MSG; assert(target->csn >= 0); msg->csn = (Byte8_t)target->csn; msg->bin_offset = 0; msg->length = codeidx->tileheader[tile_id]->tlen - 2; /* SOT marker segment is removed*/ msg->aux = 0; /* non exist*/ msg->res_offset = codeidx->offset + (OPJ_OFF_T)get_elemOff(codeidx->tilepart, 0, (Byte8_t)tile_id) + 2; /* skip SOT marker seg*/ msg->phld = NULL; msg->next = NULL; enqueue_message(msg, msgqueue); cachemodel->th_model[ tile_id] = OPJ_TRUE; } } void enqueue_tile(Byte4_t tile_id, int level, msgqueue_param_t *msgqueue) { cachemodel_param_t *cachemodel; target_param_t *target; OPJ_BOOL *tp_model; Byte8_t numOftparts; /* num of tile parts par tile*/ Byte8_t numOftiles; index_param_t *codeidx; faixbox_param_t *tilepart; message_param_t *msg; Byte8_t binOffset, binLength, class_id; Byte8_t i; cachemodel = msgqueue->cachemodel; target = cachemodel->target; codeidx = target->codeidx; tilepart = codeidx->tilepart; numOftparts = get_nmax(tilepart); numOftiles = get_m(tilepart); class_id = (numOftparts == 1) ? TILE_MSG : EXT_TILE_MSG; if (/*tile_id < 0 ||*/ numOftiles <= (Byte8_t)tile_id) { fprintf(FCGI_stderr, "Error, Invalid tile-id %d\n", tile_id); return; } tp_model = &cachemodel->tp_model[ tile_id * numOftparts]; binOffset = 0; for (i = 0; i < numOftparts - (Byte8_t)level; i++) { binLength = get_elemLen(tilepart, i, tile_id); if (!tp_model[i]) { msg = (message_param_t *)opj_malloc(sizeof(message_param_t)); msg->last_byte = (i == numOftparts - 1); msg->in_class_id = tile_id; msg->class_id = class_id; assert(target->csn >= 0); msg->csn = (Byte8_t)target->csn; msg->bin_offset = binOffset; msg->length = binLength; msg->aux = numOftparts - i; msg->res_offset = codeidx->offset + (OPJ_OFF_T)get_elemOff(tilepart, i, tile_id)/*-1*/; msg->phld = NULL; msg->next = NULL; enqueue_message(msg, msgqueue); tp_model[i] = OPJ_TRUE; } binOffset += binLength; } } void enqueue_precinct(int seq_id, int tile_id, int comp_id, int layers, msgqueue_param_t *msgqueue) { cachemodel_param_t *cachemodel; index_param_t *codeidx; faixbox_param_t *precpacket; message_param_t *msg; Byte8_t nmax, binOffset, binLength; int layer_id, numOflayers; cachemodel = msgqueue->cachemodel; codeidx = cachemodel->target->codeidx; precpacket = codeidx->precpacket[ comp_id]; numOflayers = codeidx->COD.numOflayers; nmax = get_nmax(precpacket); assert(nmax < INT_MAX); if (layers < 0) { layers = numOflayers; } assert(tile_id >= 0); binOffset = 0; for (layer_id = 0; layer_id < layers; layer_id++) { binLength = get_elemLen(precpacket, (Byte8_t)(seq_id * numOflayers + layer_id), (Byte8_t)tile_id); if (!cachemodel->pp_model[comp_id][tile_id * (int)nmax + seq_id * numOflayers + layer_id]) { msg = (message_param_t *)opj_malloc(sizeof(message_param_t)); msg->last_byte = (layer_id == (numOflayers - 1)); msg->in_class_id = comp_precinct_id(tile_id, comp_id, seq_id, codeidx->SIZ.Csiz, (int)codeidx->SIZ.XTnum * (int) codeidx->SIZ.YTnum); msg->class_id = PRECINCT_MSG; msg->csn = (Byte8_t)cachemodel->target->csn; msg->bin_offset = binOffset; msg->length = binLength; msg->aux = 0; msg->res_offset = codeidx->offset + (OPJ_OFF_T)get_elemOff(precpacket, (Byte8_t)(seq_id * numOflayers + layer_id), (Byte8_t)tile_id); msg->phld = NULL; msg->next = NULL; enqueue_message(msg, msgqueue); cachemodel->pp_model[comp_id][tile_id * (int)nmax + seq_id * numOflayers + layer_id] = OPJ_TRUE; } binOffset += binLength; } } /* MM FIXME: each params is coded on int, this is really not clear from the specs what it should be */ Byte8_t comp_precinct_id(int t, int c, int s, int num_components, int num_tiles) { return (Byte8_t)(t + (c + s * num_components) * num_tiles); } void enqueue_box(Byte8_t meta_id, boxlist_param_t *boxlist, msgqueue_param_t *msgqueue, Byte8_t *binOffset); void enqueue_phld(Byte8_t meta_id, placeholderlist_param_t *phldlist, msgqueue_param_t *msgqueue, Byte8_t *binOffset); void enqueue_boxcontents(Byte8_t meta_id, boxcontents_param_t *boxcontents, msgqueue_param_t *msgqueue, Byte8_t *binOffset); void enqueue_metadata(Byte8_t meta_id, msgqueue_param_t *msgqueue) { metadatalist_param_t *metadatalist; metadata_param_t *metadata; Byte8_t binOffset; metadatalist = msgqueue->cachemodel->target->codeidx->metadatalist; metadata = search_metadata(meta_id, metadatalist); if (!metadata) { fprintf(FCGI_stderr, "Error: metadata-bin %" PRIu64 " not found\n", meta_id); return; } binOffset = 0; if (metadata->boxlist) { enqueue_box(meta_id, metadata->boxlist, msgqueue, &binOffset); } if (metadata->placeholderlist) { enqueue_phld(meta_id, metadata->placeholderlist, msgqueue, &binOffset); } if (metadata->boxcontents) { enqueue_boxcontents(meta_id, metadata->boxcontents, msgqueue, &binOffset); } msgqueue->last->last_byte = OPJ_TRUE; } message_param_t * gene_metamsg(Byte8_t meta_id, Byte8_t binoffset, Byte8_t length, OPJ_OFF_T res_offset, placeholder_param_t *phld, Byte8_t csn); void enqueue_box(Byte8_t meta_id, boxlist_param_t *boxlist, msgqueue_param_t *msgqueue, Byte8_t *binOffset) { box_param_t *box; message_param_t *msg; box = boxlist->first; assert(msgqueue->cachemodel->target->csn >= 0); while (box) { msg = gene_metamsg(meta_id, *binOffset, box->length, box->offset, NULL, (Byte8_t)msgqueue->cachemodel->target->csn); enqueue_message(msg, msgqueue); *binOffset += box->length; box = box->next; } } void enqueue_phld(Byte8_t meta_id, placeholderlist_param_t *phldlist, msgqueue_param_t *msgqueue, Byte8_t *binOffset) { placeholder_param_t *phld; message_param_t *msg; phld = phldlist->first; assert(msgqueue->cachemodel->target->csn >= 0); while (phld) { msg = gene_metamsg(meta_id, *binOffset, phld->LBox, 0, phld, (Byte8_t)msgqueue->cachemodel->target->csn); enqueue_message(msg, msgqueue); *binOffset += phld->LBox; phld = phld->next; } } void enqueue_boxcontents(Byte8_t meta_id, boxcontents_param_t *boxcontents, msgqueue_param_t *msgqueue, Byte8_t *binOffset) { message_param_t *msg; assert(msgqueue->cachemodel->target->csn >= 0); msg = gene_metamsg(meta_id, *binOffset, boxcontents->length, boxcontents->offset, NULL, (Byte8_t)msgqueue->cachemodel->target->csn); enqueue_message(msg, msgqueue); *binOffset += boxcontents->length; } message_param_t * gene_metamsg(Byte8_t meta_id, Byte8_t binOffset, Byte8_t length, OPJ_OFF_T res_offset, placeholder_param_t *phld, Byte8_t csn) { message_param_t *msg; msg = (message_param_t *)opj_malloc(sizeof(message_param_t)); msg->last_byte = OPJ_FALSE; msg->in_class_id = meta_id; msg->class_id = METADATA_MSG; msg->csn = csn; msg->bin_offset = binOffset; msg->length = length; msg->aux = 0; /* non exist*/ msg->res_offset = res_offset; msg->phld = phld; msg->next = NULL; return msg; } void enqueue_message(message_param_t *msg, msgqueue_param_t *msgqueue) { if (msgqueue->first) { msgqueue->last->next = msg; } else { msgqueue->first = msg; } msgqueue->last = msg; } void add_bin_id_vbas_stream(Byte_t bb, Byte_t c, Byte8_t in_class_id, int tmpfd); void add_vbas_stream(Byte8_t code, int tmpfd); void add_body_stream(message_param_t *msg, int fd, int tmpfd); void add_placeholder_stream(placeholder_param_t *phld, int tmpfd); void recons_stream_from_msgqueue(msgqueue_param_t *msgqueue, int tmpfd) { message_param_t *msg; Byte8_t class_id, csn; Byte_t bb, c; if (!(msgqueue)) { return; } msg = msgqueue->first; class_id = (Byte8_t) - 1; csn = (Byte8_t) - 1; while (msg) { if (msg->csn == csn) { if (msg->class_id == class_id) { bb = 1; } else { bb = 2; class_id = msg->class_id; } } else { bb = 3; class_id = msg->class_id; csn = msg->csn; } c = msg->last_byte ? 1 : 0; add_bin_id_vbas_stream(bb, c, msg->in_class_id, tmpfd); if (bb >= 2) { add_vbas_stream(class_id, tmpfd); } if (bb == 3) { add_vbas_stream(csn, tmpfd); } add_vbas_stream(msg->bin_offset, tmpfd); add_vbas_stream(msg->length, tmpfd); if (msg->class_id % 2) { /* Aux is present only if the id is odd*/ add_vbas_stream(msg->aux, tmpfd); } if (msg->phld) { add_placeholder_stream(msg->phld, tmpfd); } else { add_body_stream(msg, msgqueue->cachemodel->target->fd, tmpfd); } msg = msg->next; } } void add_vbas_with_bytelen_stream(Byte8_t code, int bytelength, int tmpfd); void print_binarycode(Byte8_t n, int segmentlen); void add_bin_id_vbas_stream(Byte_t bb, Byte_t c, Byte8_t in_class_id, int tmpfd) { int bytelength; Byte8_t tmp; /* A.2.3 In-class identifiers */ /* 7k-3bits, where k is the number of bytes in the VBAS*/ bytelength = 1; tmp = in_class_id >> 4; while (tmp) { bytelength ++; tmp >>= 7; } in_class_id |= (Byte8_t)((((bb & 3) << 5) | (c & 1) << 4) << (( bytelength - 1) * 7)); add_vbas_with_bytelen_stream(in_class_id, bytelength, tmpfd); } void add_vbas_stream(Byte8_t code, int tmpfd) { int bytelength; Byte8_t tmp; bytelength = 1; tmp = code; while (tmp >>= 7) { bytelength ++; } add_vbas_with_bytelen_stream(code, bytelength, tmpfd); } void add_vbas_with_bytelen_stream(Byte8_t code, int bytelength, int tmpfd) { int n; Byte8_t seg; n = bytelength - 1; while (n >= 0) { seg = (code >> (n * 7)) & 0x7f; if (n) { seg |= 0x80; } if (write(tmpfd, (Byte4_t *)&seg, 1) != 1) { fprintf(FCGI_stderr, "Error: failed to write vbas\n"); return; } n--; } } void add_body_stream(message_param_t *msg, int fd, int tmpfd) { Byte_t *data; if (!(data = fetch_bytes(fd, msg->res_offset, msg->length))) { fprintf(FCGI_stderr, "Error: fetch_bytes in add_body_stream()\n"); return; } if (write(tmpfd, data, msg->length) < 1) { opj_free(data); fprintf(FCGI_stderr, "Error: fwrite in add_body_stream()\n"); return; } opj_free(data); } void add_bigendian_bytestream(Byte8_t code, int bytelength, int tmpfd); void add_placeholder_stream(placeholder_param_t *phld, int tmpfd) { add_bigendian_bytestream(phld->LBox, 4, tmpfd); if (write(tmpfd, phld->TBox, 4) < 1) { fprintf(FCGI_stderr, "Error: fwrite in add_placeholder_stream()\n"); return; } add_bigendian_bytestream(phld->Flags, 4, tmpfd); add_bigendian_bytestream(phld->OrigID, 8, tmpfd); if (write(tmpfd, phld->OrigBH, phld->OrigBHlen) < 1) { fprintf(FCGI_stderr, "Error: fwrite in add_placeholder_stream()\n"); return; } } void add_bigendian_bytestream(Byte8_t code, int bytelength, int tmpfd) { int n; Byte8_t seg; n = bytelength - 1; while (n >= 0) { seg = (code >> (n * 8)) & 0xff; if (write(tmpfd, (Byte4_t *)&seg, 1) != 1) { fprintf(FCGI_stderr, "ERROR: failed to write bigendian_bytestream\n"); return; } n--; } } void print_binarycode(Byte8_t n, int segmentlen) { char buf[256]; int i = 0, j, k; do { buf[i++] = n % 2 ? '1' : '0'; } while ((n = n / 2)); for (j = segmentlen - 1; j >= i; j--) { putchar('0'); } for (j = i - 1, k = 0; j >= 0; j--, k++) { putchar(buf[j]); if (!((k + 1) % segmentlen)) { printf(" "); } } printf("\n"); } Byte_t * parse_bin_id_vbas(Byte_t *streamptr, Byte_t *bb, Byte_t *c, Byte8_t *in_class_id); Byte_t * parse_vbas(Byte_t *streamptr, Byte8_t *elem); void parse_JPIPstream(Byte_t *JPIPstream, Byte8_t streamlen, OPJ_OFF_T offset, msgqueue_param_t *msgqueue) { Byte_t *ptr; /* stream pointer*/ message_param_t *msg; Byte_t bb, c; Byte8_t class_id, csn; class_id = (Byte8_t) - 1; /* dummy*/ csn = (Byte8_t) - 1; ptr = JPIPstream; while ((Byte8_t)(ptr - JPIPstream) < streamlen) { msg = (message_param_t *)opj_malloc(sizeof(message_param_t)); ptr = parse_bin_id_vbas(ptr, &bb, &c, &msg->in_class_id); msg->last_byte = c == 1 ? OPJ_TRUE : OPJ_FALSE; if (bb >= 2) { ptr = parse_vbas(ptr, &class_id); } msg->class_id = class_id; if (bb == 3) { ptr = parse_vbas(ptr, &csn); } msg->csn = csn; ptr = parse_vbas(ptr, &msg->bin_offset); ptr = parse_vbas(ptr, &msg->length); if (msg->class_id % 2) { /* Aux is present only if the id is odd*/ ptr = parse_vbas(ptr, &msg->aux); } else { msg->aux = 0; } msg->res_offset = ptr - JPIPstream + offset; msg->phld = NULL; msg->next = NULL; if (msgqueue->first) { msgqueue->last->next = msg; } else { msgqueue->first = msg; } msgqueue->last = msg; ptr += msg->length; } } void parse_metadata(metadata_param_t *metadata, message_param_t *msg, Byte_t *stream); void parse_metamsg(msgqueue_param_t *msgqueue, Byte_t *stream, Byte8_t streamlen, metadatalist_param_t *metadatalist) { message_param_t *msg; (void)streamlen; if (metadatalist == NULL) { return; } msg = msgqueue->first; while (msg) { if (msg->class_id == METADATA_MSG) { metadata_param_t *metadata = gene_metadata(msg->in_class_id, NULL, NULL, NULL); insert_metadata_into_list(metadata, metadatalist); parse_metadata(metadata, msg, stream + msg->res_offset); } msg = msg->next; } } placeholder_param_t * parse_phld(Byte_t *datastream, Byte8_t metalength); void parse_metadata(metadata_param_t *metadata, message_param_t *msg, Byte_t *datastream) { box_param_t *box; placeholder_param_t *phld; char *boxtype = (char *)(datastream + 4); msg->phld = NULL; if (strncmp(boxtype, "phld", 4) == 0) { if (!metadata->placeholderlist) { metadata->placeholderlist = gene_placeholderlist(); } phld = parse_phld(datastream, msg->length); msg->phld = phld; insert_placeholder_into_list(phld, metadata->placeholderlist); } else if (isalpha(boxtype[0]) && isalpha(boxtype[1]) && (isalnum(boxtype[2]) || isspace(boxtype[2])) && (isalpha(boxtype[3]) || isspace(boxtype[3]))) { if (!metadata->boxlist) { metadata->boxlist = gene_boxlist(); } box = gene_boxbyOffinStream(datastream, msg->res_offset); insert_box_into_list(box, metadata->boxlist); } else { metadata->boxcontents = gene_boxcontents(msg->res_offset, msg->length); } } placeholder_param_t * parse_phld(Byte_t *datastream, Byte8_t metalength) { placeholder_param_t *phld; phld = (placeholder_param_t *)opj_malloc(sizeof(placeholder_param_t)); phld->LBox = big4(datastream); strncpy(phld->TBox, "phld", 4); phld->Flags = big4(datastream + 8); phld->OrigID = big8(datastream + 12); phld->OrigBHlen = (Byte_t)(metalength - 20); phld->OrigBH = (Byte_t *)opj_malloc(phld->OrigBHlen); memcpy(phld->OrigBH, datastream + 20, phld->OrigBHlen); phld->next = NULL; return phld; } Byte_t * parse_bin_id_vbas(Byte_t *streamptr, Byte_t *bb, Byte_t *c, Byte8_t *in_class_id) { Byte_t code; Byte_t *ptr; ptr = streamptr; code = *(ptr++); *bb = (code >> 5) & 3; *c = (code >> 4) & 1; *in_class_id = code & 15; while (code >> 7) { code = *(ptr++); *in_class_id = (*in_class_id << 7) | (code & 0x7f); } return ptr; } Byte_t * parse_vbas(Byte_t *streamptr, Byte8_t *elem) { Byte_t code; Byte_t *ptr; *elem = 0; ptr = streamptr; do { code = *(ptr++); *elem = (*elem << 7) | (code & 0x7f); } while (code >> 7); return ptr; } void delete_message_in_msgqueue(message_param_t **msg, msgqueue_param_t *msgqueue) { message_param_t *ptr; if (!(*msg)) { return; } if (*msg == msgqueue->first) { msgqueue->first = (*msg)->next; } else { ptr = msgqueue->first; while (ptr->next != *msg) { ptr = ptr->next; } ptr->next = (*msg)->next; if (*msg == msgqueue->last) { msgqueue->last = ptr; } } opj_free(*msg); }