ce520640fe69b1aef1b9d309e48d3097b2f5807e
[openjpeg.git] / src / lib / openjpip / box_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  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <ctype.h>
35 #include <assert.h>
36 #include "box_manager.h"
37 #include "opj_inttypes.h"
38
39 #ifdef SERVER
40 #include "fcgi_stdio.h"
41 #define logstream FCGI_stdout
42 #else
43 #define FCGI_stdout stdout
44 #define FCGI_stderr stderr
45 #define logstream stderr
46 #endif /*SERVER*/
47
48 boxlist_param_t * gene_boxlist(void)
49 {
50     boxlist_param_t *boxlist;
51
52     boxlist = (boxlist_param_t *)malloc(sizeof(boxlist_param_t));
53
54     boxlist->first = NULL;
55     boxlist->last  = NULL;
56
57     return boxlist;
58 }
59
60 boxlist_param_t * get_boxstructure(int fd, OPJ_OFF_T offset, OPJ_SIZE_T length)
61 {
62     boxlist_param_t *boxlist;
63     box_param_t *box;
64     OPJ_OFF_T pos;
65
66     boxlist = NULL;
67     pos = offset;
68     assert((OPJ_OFF_T)length >= 0);
69     do {
70         if (!(box = gene_boxbyOffset(fd, pos))) {
71             break;
72         }
73
74         assert((OPJ_OFF_T)box->length >= 0);
75         pos += (OPJ_OFF_T)box->length;
76
77         if (!boxlist) {
78             boxlist = gene_boxlist();
79         }
80         insert_box_into_list(box, boxlist);
81     } while (pos < offset + (OPJ_OFF_T)length);
82
83     return boxlist;
84 }
85
86 box_param_t * gene_boxbyOffset(int fd, OPJ_OFF_T offset)
87 {
88     Byte_t *data;
89     Byte8_t boxlen;
90     Byte_t headlen;
91     char *boxtype;
92     box_param_t *box;
93
94     /* read LBox and TBox*/
95     if (!(data = fetch_bytes(fd, offset, 8))) {
96         fprintf(FCGI_stderr, "Error: error in gene_boxbyOffset( %d, %" PRId64 ")\n", fd,
97                 offset);
98         return NULL;
99     }
100
101     headlen = 8;
102     boxlen = (Byte8_t)big4(data);
103     boxtype = (char *)(data + 4);
104
105     /* box type constraint*/
106     if (!isalpha(boxtype[0]) || !isalpha(boxtype[1]) ||
107             (!isalnum(boxtype[2]) && !isspace(boxtype[2])) ||
108             (!isalpha(boxtype[3]) && !isspace(boxtype[3]))) {
109         free(data);
110         return NULL;
111     }
112
113     if (boxlen == 1) {
114         Byte_t *data2;
115         headlen = 16;
116         /* read XLBox*/
117         if ((data2 = fetch_bytes(fd, offset + 8, 8))) {
118             boxlen = big8(data2);
119             free(data2);
120         } else {
121             fprintf(FCGI_stderr, "Error: error in gene_boxbyOffset( %d, %" PRId64 ")\n", fd,
122                     offset);
123             free(data);
124             return NULL;
125         }
126     }
127     box = (box_param_t *)malloc(sizeof(box_param_t));
128     box->fd = fd;
129     box->offset = offset;
130     box->headlen = headlen;
131     box->length = boxlen;
132     strncpy(box->type, boxtype, 4);
133     box->next = NULL;
134     free(data);
135     return box;
136 }
137
138 box_param_t * gene_boxbyOffinStream(Byte_t *stream, OPJ_OFF_T offset)
139 {
140     Byte8_t boxlen;
141     Byte_t headlen;
142     char *boxtype;
143     box_param_t *box;
144
145     /* read LBox and TBox*/
146     headlen = 8;
147     boxlen = (Byte8_t)big4(stream);
148     boxtype = (char *)(stream + 4);
149
150     /* box type constraint*/
151     if (!isalpha(boxtype[0]) || !isalpha(boxtype[1]) ||
152             (!isalnum(boxtype[2]) && !isspace(boxtype[2])) ||
153             (!isalpha(boxtype[3]) && !isspace(boxtype[3]))) {
154         return NULL;
155     }
156
157     if (boxlen == 1) {
158         headlen = 16;
159         boxlen = big8(stream + 8); /* read XLBox*/
160     }
161     box = (box_param_t *)malloc(sizeof(box_param_t));
162     box->fd = -1;
163     box->offset = offset;
164     box->headlen = headlen;
165     box->length = boxlen;
166     strncpy(box->type, boxtype, 4);
167     box->next = NULL;
168
169     return box;
170 }
171
172
173 box_param_t * gene_boxbyType(int fd, OPJ_OFF_T offset, OPJ_SIZE_T length,
174                              const char TBox[])
175 {
176     OPJ_OFF_T pos;
177     Byte_t *data;
178     Byte8_t boxlen;
179     Byte_t headlen;
180     char *boxtype;
181     box_param_t *foundbox;
182
183
184     if (length == 0) { /* set the max length*/
185         if (get_filesize(fd) <= offset) {
186             return NULL;
187         }
188         assert(get_filesize(fd) > offset);
189         assert(offset >= 0);
190         length = (OPJ_SIZE_T)(get_filesize(fd) - offset);
191     }
192
193     pos = offset;
194     assert(pos >= 0);
195     assert((OPJ_OFF_T)length >= 0);
196     while (pos < offset + (OPJ_OFF_T)length - 7) { /* LBox+TBox-1=7*/
197
198         /* read LBox and TBox*/
199         if ((data = fetch_bytes(fd, pos, 8))) {
200             headlen = 8;
201             boxlen = (Byte8_t)big4(data);
202             boxtype = (char *)(data + 4);
203
204             if (boxlen == 1) {
205                 Byte_t *data2;
206                 headlen = 16;
207                 /* read XLBox*/
208                 if ((data2 = fetch_bytes(fd, pos + 8, 8))) {
209                     boxlen = big8(data2);
210                     free(data2);
211                 } else {
212                     fprintf(FCGI_stderr, "Error: error in gene_boxbyType( %d, %" PRId64 ", %" PRId64
213                             ", %s)\n", fd, offset, length, TBox);
214                     return NULL;
215                 }
216             }
217             if (strncmp(boxtype, TBox, 4) == 0) {
218                 foundbox = (box_param_t *)malloc(sizeof(box_param_t));
219                 foundbox->fd = fd;
220                 foundbox->offset = pos;
221                 foundbox->headlen = headlen;
222                 foundbox->length = boxlen;
223                 strncpy(foundbox->type, TBox, 4);
224                 foundbox->next = NULL;
225                 free(data);
226                 return foundbox;
227             }
228             free(data);
229         } else {
230             fprintf(FCGI_stderr, "Error: error in gene_boxbyType( %d, %" PRId64 ", %" PRId64
231                     ", %s)\n", fd, offset, length, TBox);
232             return NULL;
233         }
234         assert(((Byte8_t)pos + boxlen) >= (Byte8_t)pos);
235         pos += (OPJ_OFF_T)boxlen;
236     }
237     fprintf(FCGI_stderr, "Error: Box %s not found\n", TBox);
238
239     return NULL;
240 }
241
242 box_param_t * gene_boxbyTypeinStream(Byte_t *stream, OPJ_OFF_T offset,
243                                      OPJ_SIZE_T length, const char TBox[])
244 {
245     OPJ_OFF_T pos;
246     Byte_t *data;
247     Byte8_t boxlen;
248     Byte_t headlen;
249     char *boxtype;
250     box_param_t *foundbox;
251
252     pos = offset;
253     assert(pos >= 0);
254     assert((OPJ_OFF_T)length >= 0);
255     while (pos < offset + (OPJ_OFF_T)(length) - 7) { /* LBox+TBox-1=7*/
256
257         /* read LBox and TBox*/
258         data = stream + pos;
259         headlen = 8;
260         boxlen = (Byte8_t)big4(data);
261         boxtype = (char *)(data + 4);
262
263         if (boxlen == 1) {
264             /* read XLBox*/
265             headlen = 16;
266             boxlen = big8(data + 8);
267         }
268
269         if (strncmp(boxtype, TBox, 4) == 0) {
270             foundbox = (box_param_t *)malloc(sizeof(box_param_t));
271             foundbox->fd = -1;
272             foundbox->offset = pos;
273             foundbox->headlen = headlen;
274             foundbox->length = boxlen;
275             strncpy(foundbox->type, TBox, 4);
276             foundbox->next = NULL;
277             return foundbox;
278         }
279         assert(((Byte8_t)pos + boxlen) >= (Byte8_t)pos);
280         pos += (OPJ_OFF_T)boxlen;
281     }
282     fprintf(FCGI_stderr, "Error: Box %s not found\n", TBox);
283
284     return NULL;
285 }
286
287 box_param_t * gene_childboxbyOffset(box_param_t *superbox, OPJ_OFF_T offset)
288 {
289     return gene_boxbyOffset(superbox->fd, get_DBoxoff(superbox) + offset);
290 }
291
292 box_param_t * gene_childboxbyType(box_param_t *superbox, OPJ_OFF_T offset,
293                                   const char TBox[])
294 {
295     OPJ_SIZE_T DBOXlen = get_DBoxlen(superbox);
296     assert(offset >= 0);
297     if (DBOXlen < (OPJ_SIZE_T)offset) {
298         fprintf(FCGI_stderr, "Error: Impossible happen %lu < %ld\n", DBOXlen, offset);
299         return NULL;
300     }
301     return gene_boxbyType(superbox->fd, get_DBoxoff(superbox) + offset,
302                           DBOXlen - (OPJ_SIZE_T)offset, TBox);
303 }
304
305 OPJ_OFF_T get_DBoxoff(box_param_t *box)
306 {
307     return box->offset + box->headlen;
308 }
309
310 OPJ_SIZE_T get_DBoxlen(box_param_t *box)
311 {
312     return box->length - box->headlen;
313 }
314
315 Byte_t * fetch_headbytes(box_param_t *box)
316 {
317     return fetch_bytes(box->fd, box->offset, box->headlen);
318 }
319
320 Byte_t * fetch_DBoxbytes(box_param_t *box, OPJ_OFF_T offset, OPJ_SIZE_T size)
321 {
322     return fetch_bytes(box->fd, get_DBoxoff(box) + offset, size);
323 }
324
325 Byte_t fetch_DBox1byte(box_param_t *box, OPJ_OFF_T offset)
326 {
327     return fetch_1byte(box->fd, get_DBoxoff(box) + offset);
328 }
329
330 Byte2_t fetch_DBox2bytebigendian(box_param_t *box, OPJ_OFF_T offset)
331 {
332     return fetch_2bytebigendian(box->fd, get_DBoxoff(box) + offset);
333 }
334
335 Byte4_t fetch_DBox4bytebigendian(box_param_t *box, OPJ_OFF_T offset)
336 {
337     return fetch_4bytebigendian(box->fd, get_DBoxoff(box) + offset);
338 }
339
340 Byte8_t fetch_DBox8bytebigendian(box_param_t *box, OPJ_OFF_T offset)
341 {
342     return fetch_8bytebigendian(box->fd, get_DBoxoff(box) + offset);
343 }
344
345 box_param_t * search_box(const char type[], boxlist_param_t *boxlist)
346 {
347     box_param_t *foundbox;
348
349     foundbox = boxlist->first;
350
351     while (foundbox != NULL) {
352
353         if (strncmp(type, foundbox->type, 4) == 0) {
354             return foundbox;
355         }
356
357         foundbox = foundbox->next;
358     }
359     fprintf(FCGI_stderr, "Error: Box %s not found\n", type);
360
361     return NULL;
362 }
363
364 void print_box(box_param_t *box)
365 {
366     fprintf(logstream, "box info:\n"
367             "\t type: %.4s\n"
368             "\t offset: %" PRId64 " %#" PRIx64 "\n"
369             "\t header length: %d\n"
370             "\t length: %" PRId64 " %#" PRIx64 "\n", box->type, box->offset,
371             box->offset, box->headlen, box->length, box->length);
372 }
373
374 void print_allbox(boxlist_param_t *boxlist)
375 {
376     box_param_t *ptr;
377
378     if (!boxlist) {
379         return;
380     }
381
382     ptr = boxlist->first;
383     if (!ptr) {
384         fprintf(logstream, "no box\n");
385     }
386
387     fprintf(logstream, "all box info: \n");
388     while (ptr != NULL) {
389         print_box(ptr);
390         ptr = ptr->next;
391     }
392 }
393
394 void delete_box_in_list(box_param_t **box, boxlist_param_t *boxlist)
395 {
396     box_param_t *ptr;
397
398     if (*box == boxlist->first) {
399         boxlist->first = (*box)->next;
400     } else {
401         ptr = boxlist->first;
402         while (ptr->next != *box) {
403             ptr = ptr->next;
404         }
405         ptr->next = (*box)->next;
406
407         if (*box == boxlist->last) {
408             boxlist->last = ptr;
409         }
410     }
411     free(*box);
412 }
413
414 void delete_box_in_list_by_type(const char type[], boxlist_param_t *boxlist)
415 {
416     box_param_t *box;
417
418     box = search_box(type, boxlist);
419     delete_box_in_list(&box, boxlist);
420 }
421
422 void delete_boxlist(boxlist_param_t **boxlist)
423 {
424     box_param_t *boxPtr, *boxNext;
425
426     if (!(*boxlist)) {
427         return;
428     }
429
430     boxPtr = (*boxlist)->first;
431     while (boxPtr != NULL) {
432         boxNext = boxPtr->next;
433         free(boxPtr);
434         boxPtr = boxNext;
435     }
436     free(*boxlist);
437 }
438
439 void insert_box_into_list(box_param_t *box, boxlist_param_t *boxlist)
440 {
441     if (boxlist->first) {
442         boxlist->last->next = box;
443     } else {
444         boxlist->first = box;
445     }
446     boxlist->last = box;
447 }