85b3a948290d0d2dd3c9c59215842ae2bf3ccd15
[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     assert( (OPJ_OFF_T)box->length >= 0);
74     pos += (OPJ_OFF_T)box->length;
75     
76     if( !boxlist)
77       boxlist = gene_boxlist();
78     insert_box_into_list( box, boxlist);
79   }while( pos < offset+(OPJ_OFF_T)length);
80
81   return boxlist;
82 }
83
84 box_param_t * gene_boxbyOffset( int fd, OPJ_OFF_T offset)
85 {
86   Byte_t *data;
87   Byte8_t boxlen;
88   Byte_t headlen;
89   char *boxtype;
90   box_param_t *box;
91
92   /* read LBox and TBox*/
93   if(!(data = fetch_bytes( fd, offset, 8))){
94     fprintf( FCGI_stderr, "Error: error in gene_boxbyOffset( %d, %" PRId64 ")\n", fd, offset);
95     return NULL;
96   }
97   
98   headlen = 8;
99   boxlen = (Byte8_t)big4(data);
100   boxtype = (char *)(data+4);  
101
102   /* box type constraint*/
103   if( !isalpha(boxtype[0]) || !isalpha(boxtype[1]) ||
104       (!isalnum(boxtype[2])&&!isspace(boxtype[2])) ||
105       (!isalpha(boxtype[3])&&!isspace(boxtype[3]))){
106     free( data);
107     return NULL;
108   }
109   
110   if( boxlen == 1){
111     Byte_t *data2;
112     headlen = 16;
113     /* read XLBox*/
114     if((data2 = fetch_bytes( fd, offset+8, 8))){
115       boxlen = big8(data2);
116       free(data2);
117     }
118     else{
119       fprintf( FCGI_stderr, "Error: error in gene_boxbyOffset( %d, %" PRId64 ")\n", fd, offset);
120       free( data);
121       return NULL;
122     }
123   }
124   box = (box_param_t *)malloc( sizeof( box_param_t));
125   box->fd = fd;
126   box->offset = offset;
127   box->headlen = headlen;
128   box->length = boxlen;
129   strncpy( box->type, boxtype, 4);
130   box->next = NULL;
131   free( data);
132   return box;
133 }
134
135 box_param_t * gene_boxbyOffinStream( Byte_t *stream, OPJ_OFF_T offset)
136 {
137   Byte8_t boxlen;
138   Byte_t headlen;
139   char *boxtype;
140   box_param_t *box;
141
142   /* read LBox and TBox*/
143   headlen = 8;
144   boxlen = (Byte8_t)big4( stream);
145   boxtype = (char *)( stream+4);  
146
147   /* box type constraint*/
148   if( !isalpha(boxtype[0]) || !isalpha(boxtype[1]) ||
149       (!isalnum(boxtype[2])&&!isspace(boxtype[2])) ||
150       (!isalpha(boxtype[3])&&!isspace(boxtype[3]))){
151     return NULL;
152   }
153   
154   if( boxlen == 1){
155     headlen = 16;
156     boxlen = big8( stream+8); /* read XLBox*/
157   }
158   box = (box_param_t *)malloc( sizeof( box_param_t));
159   box->fd = -1;
160   box->offset = offset;
161   box->headlen = headlen;
162   box->length = boxlen;
163   strncpy( box->type, boxtype, 4);
164   box->next = NULL;
165
166   return box;
167 }
168
169
170 box_param_t * gene_boxbyType( int fd, OPJ_OFF_T offset, OPJ_SIZE_T length, const char TBox[])
171 {
172   OPJ_OFF_T pos;
173   Byte_t *data;
174   Byte8_t boxlen;
175   Byte_t headlen;
176   char *boxtype;
177   box_param_t *foundbox;
178
179   
180   if( length==0){ /* set the max length*/
181     if( get_filesize( fd) <= offset )
182       return NULL;
183     assert( get_filesize( fd) > offset );
184     assert( offset >= 0 );
185     length = (OPJ_SIZE_T)(get_filesize( fd) - offset);
186   }
187
188   pos = offset;
189   assert( pos >= 0 );
190   assert( (OPJ_OFF_T)length >= 0 );
191   while( pos < offset+(OPJ_OFF_T)length-7){ /* LBox+TBox-1=7*/
192     
193     /* read LBox and TBox*/
194     if((data = fetch_bytes( fd, pos, 8))){
195       headlen = 8;
196       boxlen = (Byte8_t)big4(data);
197       boxtype = (char *)(data+4);
198
199       if( boxlen == 1){
200         Byte_t *data2;
201         headlen = 16;
202         /* read XLBox*/
203         if((data2 = fetch_bytes( fd, pos+8, 8))){
204           boxlen = big8(data2);
205           free(data2);
206         }
207         else{
208           fprintf( FCGI_stderr, "Error: error in gene_boxbyType( %d, %" PRId64 ", %" PRId64 ", %s)\n", fd, offset, length, TBox);
209           return NULL;
210         }
211       }
212       if( strncmp ( boxtype, TBox, 4) == 0){
213         foundbox = (box_param_t *)malloc( sizeof( box_param_t));
214         foundbox->fd = fd;
215         foundbox->offset = pos;
216         foundbox->headlen = headlen;
217         foundbox->length = boxlen;
218         strncpy( foundbox->type, TBox, 4);
219         foundbox->next = NULL;
220         free( data);
221         return foundbox;
222       }
223       free( data);
224     }
225     else{
226       fprintf( FCGI_stderr, "Error: error in gene_boxbyType( %d, %" PRId64 ", %" PRId64 ", %s)\n", fd, offset, length, TBox);
227       return NULL;
228     }
229     assert( ((Byte8_t)pos+boxlen)>=(Byte8_t)pos);
230     pos+= (OPJ_OFF_T)boxlen;
231   }
232   fprintf( FCGI_stderr, "Error: Box %s not found\n", TBox);
233
234   return NULL;
235 }
236
237 box_param_t * gene_boxbyTypeinStream( Byte_t *stream, OPJ_OFF_T offset, OPJ_SIZE_T length, const char TBox[])
238 {
239   OPJ_OFF_T pos;
240   Byte_t *data;
241   Byte8_t boxlen;
242   Byte_t headlen;
243   char *boxtype;
244   box_param_t *foundbox;
245
246   pos = offset;
247   assert( pos >= 0 );
248   assert( (OPJ_OFF_T)length >= 0 );
249   while( pos < offset+(OPJ_OFF_T)(length)-7){ /* LBox+TBox-1=7*/
250     
251     /* read LBox and TBox*/
252     data = stream + pos;
253     headlen = 8;
254     boxlen = (Byte8_t)big4(data);
255     boxtype = (char *)(data+4);
256    
257     if( boxlen == 1){
258       /* read XLBox*/
259       headlen = 16;
260       boxlen = big8( data+8);
261     }
262
263     if( strncmp ( boxtype, TBox, 4) == 0){
264       foundbox = (box_param_t *)malloc( sizeof( box_param_t));
265       foundbox->fd = -1;
266       foundbox->offset = pos;
267       foundbox->headlen = headlen;
268       foundbox->length = boxlen;
269       strncpy( foundbox->type, TBox, 4);
270       foundbox->next = NULL;
271       return foundbox;
272     }
273     assert( ((Byte8_t)pos+boxlen)>=(Byte8_t)pos);
274     pos+= (OPJ_OFF_T)boxlen;
275   }
276   fprintf( FCGI_stderr, "Error: Box %s not found\n", TBox);
277   
278   return NULL;
279 }
280
281 box_param_t * gene_childboxbyOffset( box_param_t *superbox, OPJ_OFF_T offset)
282 {
283   return gene_boxbyOffset( superbox->fd, get_DBoxoff( superbox)+offset);
284 }
285
286 box_param_t * gene_childboxbyType( box_param_t *superbox, OPJ_OFF_T offset, const char TBox[])
287 {
288   OPJ_SIZE_T DBOXlen = get_DBoxlen(superbox);
289   assert( offset >= 0 );
290   if( DBOXlen < (OPJ_SIZE_T)offset )
291     {
292     fprintf( FCGI_stderr, "Error: Impossible happen %lu < %ld\n", DBOXlen, offset);
293     return NULL;
294     }
295   return gene_boxbyType( superbox->fd, get_DBoxoff( superbox)+offset, DBOXlen-(OPJ_SIZE_T)offset, TBox);
296 }
297
298 OPJ_OFF_T get_DBoxoff( box_param_t *box)
299 {
300   return box->offset+box->headlen;
301 }
302
303 OPJ_SIZE_T get_DBoxlen( box_param_t *box)
304 {
305   return box->length - box->headlen;
306 }
307
308 Byte_t * fetch_headbytes( box_param_t *box)
309 {
310   return fetch_bytes( box->fd, box->offset, box->headlen);
311 }
312
313 Byte_t * fetch_DBoxbytes( box_param_t *box, OPJ_OFF_T offset, OPJ_SIZE_T size)
314 {
315   return fetch_bytes( box->fd, get_DBoxoff( box)+offset, size);
316 }
317
318 Byte_t fetch_DBox1byte( box_param_t *box, OPJ_OFF_T offset)
319 {
320   return fetch_1byte( box->fd, get_DBoxoff( box)+offset);
321 }
322
323 Byte2_t fetch_DBox2bytebigendian( box_param_t *box, OPJ_OFF_T offset)
324 {
325   return fetch_2bytebigendian( box->fd, get_DBoxoff( box)+offset);
326 }
327
328 Byte4_t fetch_DBox4bytebigendian( box_param_t *box, OPJ_OFF_T offset)
329 {
330   return fetch_4bytebigendian( box->fd, get_DBoxoff( box)+offset);
331 }
332
333 Byte8_t fetch_DBox8bytebigendian( box_param_t *box, OPJ_OFF_T offset)
334 {
335   return fetch_8bytebigendian( box->fd, get_DBoxoff( box)+offset);
336 }
337
338 box_param_t * search_box( const char type[], boxlist_param_t *boxlist)
339 {
340   box_param_t *foundbox;
341
342   foundbox = boxlist->first;
343   
344   while( foundbox != NULL){
345     
346     if( strncmp( type, foundbox->type, 4) == 0)
347       return foundbox;
348       
349     foundbox = foundbox->next;
350   }
351   fprintf( FCGI_stderr, "Error: Box %s not found\n", type);
352
353   return NULL;
354 }
355
356 void print_box( box_param_t *box)
357 {
358   fprintf( logstream, "box info:\n"
359            "\t type: %.4s\n"
360            "\t offset: %" PRId64 " %#" PRIx64 "\n" 
361            "\t header length: %d\n"
362      "\t length: %" PRId64 " %#" PRIx64 "\n", box->type, box->offset, 
363      box->offset, box->headlen, box->length, box->length);
364 }
365
366 void print_allbox( boxlist_param_t *boxlist)
367 {
368   box_param_t *ptr;
369
370   if( !boxlist)
371     return;
372
373   ptr = boxlist->first;
374   if( !ptr)
375     fprintf( logstream, "no box\n");
376
377   fprintf( logstream, "all box info: \n");
378   while( ptr != NULL){
379     print_box( ptr);
380     ptr=ptr->next;
381   }
382 }
383
384 void delete_box_in_list( box_param_t **box, boxlist_param_t *boxlist)
385 {
386   box_param_t *ptr;
387
388   if( *box == boxlist->first)
389     boxlist->first = (*box)->next;
390   else{
391     ptr = boxlist->first;
392     while( ptr->next != *box){
393       ptr=ptr->next;
394     }
395     ptr->next = (*box)->next;
396     
397     if( *box == boxlist->last)
398       boxlist->last = ptr;
399   }
400   free( *box);
401 }
402
403 void delete_box_in_list_by_type( const char type[], boxlist_param_t *boxlist)
404 {
405   box_param_t *box;
406
407   box = search_box( type, boxlist);
408   delete_box_in_list( &box, boxlist);
409 }
410
411 void delete_boxlist( boxlist_param_t **boxlist)
412 {
413   box_param_t *boxPtr, *boxNext;
414
415   if(!(*boxlist))
416     return;
417   
418   boxPtr = (*boxlist)->first;
419   while( boxPtr != NULL){
420     boxNext=boxPtr->next;
421     free( boxPtr);
422     boxPtr=boxNext;
423   }
424   free( *boxlist);
425 }
426
427 void insert_box_into_list( box_param_t *box, boxlist_param_t *boxlist)
428 {
429   if( boxlist->first)
430     boxlist->last->next = box;
431   else
432     boxlist->first = box;
433   boxlist->last = box;
434 }