Fix caching the last accessed entry number when removing a entry.
[L-SMASH.git] / utils.c
blob98ece81d6b104da94bda75e4fc7bf589e482eb3d
1 /*****************************************************************************
2 * utils.c:
3 *****************************************************************************
4 * Copyright (C) 2010 L-SMASH project
6 * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 *****************************************************************************/
21 /* This file is available under an ISC license. */
23 #include "internal.h" /* must be placed first */
25 #include <stdlib.h>
26 #include <string.h>
28 #include "utils.h"
30 uint64_t lsmash_bs_get_pos( lsmash_bs_t *bs )
32 return bs->pos;
35 void lsmash_bs_empty( lsmash_bs_t *bs )
37 if( !bs )
38 return;
39 memset( bs->data, 0, bs->alloc );
40 bs->store = 0;
41 bs->pos = 0;
44 void lsmash_bs_free( lsmash_bs_t *bs )
46 if( bs->data )
47 free( bs->data );
48 bs->data = NULL;
49 bs->alloc = 0;
50 bs->store = 0;
51 bs->pos = 0;
54 void lsmash_bs_alloc( lsmash_bs_t *bs, uint64_t size )
56 if( bs->error )
57 return;
58 uint64_t alloc = size + (1<<16);
59 uint8_t *data;
60 if( !bs->data )
61 data = malloc( alloc );
62 else if( bs->alloc < size )
63 data = realloc( bs->data, alloc );
64 else
65 return;
66 if( !data )
68 lsmash_bs_free( bs );
69 bs->error = 1;
70 return;
72 bs->data = data;
73 bs->alloc = alloc;
76 /*---- bitstream writer ----*/
77 void lsmash_bs_put_byte( lsmash_bs_t *bs, uint8_t value )
79 lsmash_bs_alloc( bs, bs->store + 1 );
80 if( bs->error )
81 return;
82 bs->data[bs->store ++] = value;
85 void lsmash_bs_put_bytes( lsmash_bs_t *bs, void *value, uint32_t size )
87 if( !size )
88 return;
89 lsmash_bs_alloc( bs, bs->store + size );
90 if( bs->error )
91 return;
92 memcpy( bs->data + bs->store, value, size );
93 bs->store += size;
96 void lsmash_bs_put_be16( lsmash_bs_t *bs, uint16_t value )
98 lsmash_bs_put_byte( bs, (uint8_t)((value>>8)&0xff) );
99 lsmash_bs_put_byte( bs, (uint8_t)(value&0xff) );
102 void lsmash_bs_put_be24( lsmash_bs_t *bs, uint32_t value )
104 lsmash_bs_put_byte( bs, (uint8_t)((value>>16)&0xff) );
105 lsmash_bs_put_be16( bs, (uint16_t)(value&0xffff) );
108 void lsmash_bs_put_be32( lsmash_bs_t *bs, uint32_t value )
110 lsmash_bs_put_be16( bs, (uint16_t)((value>>16)&0xffff) );
111 lsmash_bs_put_be16( bs, (uint16_t)(value&0xffff) );
114 void lsmash_bs_put_be64( lsmash_bs_t *bs, uint64_t value )
116 lsmash_bs_put_be32( bs, (uint32_t)((value>>32)&0xffffffff) );
117 lsmash_bs_put_be32( bs, (uint32_t)(value&0xffffffff) );
120 void lsmash_bs_put_byte_from_64( lsmash_bs_t *bs, uint64_t value )
122 lsmash_bs_put_byte( bs, (uint8_t)(value&0xff) );
125 void lsmash_bs_put_be16_from_64( lsmash_bs_t *bs, uint64_t value )
127 lsmash_bs_put_be16( bs, (uint16_t)(value&0xffff) );
130 void lsmash_bs_put_be24_from_64( lsmash_bs_t *bs, uint64_t value )
132 lsmash_bs_put_be24( bs, (uint32_t)(value&0xffffff) );
135 void lsmash_bs_put_be32_from_64( lsmash_bs_t *bs, uint64_t value )
137 lsmash_bs_put_be32( bs, (uint32_t)(value&0xffffffff) );
140 int lsmash_bs_write_data( lsmash_bs_t *bs )
142 if( !bs )
143 return -1;
144 if( !bs->store || !bs->data )
145 return 0;
146 if( bs->error || !bs->stream || fwrite( bs->data, 1, bs->store, bs->stream ) != bs->store )
148 lsmash_bs_free( bs );
149 bs->error = 1;
150 return -1;
152 bs->written += bs->store;
153 bs->store = 0;
154 return 0;
157 lsmash_bs_t* lsmash_bs_create( char* filename )
159 lsmash_bs_t* bs = malloc( sizeof(lsmash_bs_t) );
160 if( !bs )
161 return NULL;
162 memset( bs, 0, sizeof(lsmash_bs_t) );
163 if( filename && (bs->stream = fopen( filename, "wb" )) == NULL )
165 free( bs );
166 return NULL;
168 return bs;
171 void lsmash_bs_cleanup( lsmash_bs_t *bs )
173 if( !bs )
174 return;
175 if( bs->stream )
176 fclose( bs->stream );
177 lsmash_bs_free( bs );
178 free( bs );
181 void* lsmash_bs_export_data( lsmash_bs_t *bs, uint32_t* length )
183 if( !bs || !bs->data || bs->store == 0 || bs->error )
184 return NULL;
185 void* buf = malloc( bs->store );
186 if( !buf )
187 return NULL;
188 memcpy( buf, bs->data, bs->store );
189 if( length )
190 *length = bs->store;
191 return buf;
193 /*---- ----*/
195 /*---- bitstream reader ----*/
196 uint8_t lsmash_bs_get_byte( lsmash_bs_t *bs )
198 if( bs->error || !bs->data )
199 return 0;
200 if( bs->pos + 1 > bs->store )
202 lsmash_bs_free( bs );
203 bs->error = 1;
204 return 0;
206 return bs->data[bs->pos ++];
209 uint8_t *lsmash_bs_get_bytes( lsmash_bs_t *bs, uint32_t size )
211 if( bs->error || !size )
212 return NULL;
213 uint8_t *value = malloc( size );
214 if( !value || bs->pos + size > bs->store )
216 lsmash_bs_free( bs );
217 bs->error = 1;
218 return NULL;
220 memcpy( value, bs->data + bs->pos, size );
221 bs->pos += size;
222 return value;
225 uint16_t lsmash_bs_get_be16( lsmash_bs_t *bs )
227 uint16_t value = lsmash_bs_get_byte( bs );
228 return (value<<8) | lsmash_bs_get_byte( bs );
231 uint32_t lsmash_bs_get_be24( lsmash_bs_t *bs )
233 uint32_t value = lsmash_bs_get_byte( bs );
234 return (value<<16) | lsmash_bs_get_be16( bs );
237 uint32_t lsmash_bs_get_be32( lsmash_bs_t *bs )
239 uint32_t value = lsmash_bs_get_be16( bs );
240 return (value<<16) | lsmash_bs_get_be16( bs );
243 uint64_t lsmash_bs_get_be64( lsmash_bs_t *bs )
245 uint64_t value = lsmash_bs_get_be32( bs );
246 return (value<<32) | lsmash_bs_get_be32( bs );
249 uint64_t lsmash_bs_get_byte_to_64( lsmash_bs_t *bs )
251 return lsmash_bs_get_byte( bs );
254 uint64_t lsmash_bs_get_be16_to_64( lsmash_bs_t *bs )
256 return lsmash_bs_get_be16( bs );
259 uint64_t lsmash_bs_get_be24_to_64( lsmash_bs_t *bs )
261 return lsmash_bs_get_be24( bs );
264 uint64_t lsmash_bs_get_be32_to_64( lsmash_bs_t *bs )
266 return lsmash_bs_get_be32( bs );
269 int lsmash_bs_read_data( lsmash_bs_t *bs, uint32_t size )
271 if( !bs )
272 return -1;
273 if( !size )
274 return 0;
275 lsmash_bs_alloc( bs, bs->store + size );
276 if( bs->error || !bs->stream )
278 lsmash_bs_free( bs );
279 bs->error = 1;
280 return -1;
282 uint64_t read_size = fread( bs->data + bs->store, 1, size, bs->stream );
283 if( read_size != size && !feof( bs->stream ) )
285 bs->error = 1;
286 return -1;
288 bs->store += read_size;
289 return 0;
292 int lsmash_bs_import_data( lsmash_bs_t *bs, void* data, uint32_t length )
294 if( !bs || bs->error || !data || length == 0 )
295 return -1;
296 lsmash_bs_alloc( bs, bs->store + length );
297 if( bs->error || !bs->data ) /* means, failed to alloc. */
299 lsmash_bs_free( bs );
300 return -1;
302 memcpy( bs->data + bs->store, data, length );
303 bs->store += length;
304 return 0;
306 /*---- ----*/
308 /*---- bitstream ----*/
309 void lsmash_bits_init( lsmash_bits_t* bits, lsmash_bs_t *bs )
311 debug_if( !bits || !bs )
312 return;
313 bits->bs = bs;
314 bits->store = 0;
315 bits->cache = 0;
318 lsmash_bits_t* lsmash_bits_create( lsmash_bs_t *bs )
320 debug_if( !bs )
321 return NULL;
322 lsmash_bits_t* bits = (lsmash_bits_t*)malloc( sizeof(lsmash_bits_t) );
323 if( !bits )
324 return NULL;
325 lsmash_bits_init( bits, bs );
326 return bits;
329 #define BITS_IN_BYTE 8
330 void lsmash_bits_put_align( lsmash_bits_t *bits )
332 debug_if( !bits )
333 return;
334 if( !bits->store )
335 return;
336 lsmash_bs_put_byte( bits->bs, bits->cache << ( BITS_IN_BYTE - bits->store ) );
339 void lsmash_bits_get_align( lsmash_bits_t *bits )
341 debug_if( !bits )
342 return;
343 bits->store = 0;
344 bits->cache = 0;
347 /* Must be used ONLY for bits struct created with isom_create_bits.
348 Otherwise, just free() the bits struct. */
349 void lsmash_bits_cleanup( lsmash_bits_t *bits )
351 debug_if( !bits )
352 return;
353 free( bits );
356 /* we can change value's type to unsigned int for 64-bit operation if needed. */
357 static inline uint8_t lsmash_bits_mask_lsb8( uint32_t value, uint32_t width )
359 return (uint8_t)( value & ~( ~0U << width ) );
362 /* We can change value's type to unsigned int for 64-bit operation if needed. */
363 void lsmash_bits_put( lsmash_bits_t *bits, uint32_t value, uint32_t width )
365 debug_if( !bits || !width )
366 return;
367 if( bits->store )
369 if( bits->store + width < BITS_IN_BYTE )
371 /* cache can contain all of value's bits. */
372 bits->cache <<= width;
373 bits->cache |= lsmash_bits_mask_lsb8( value, width );
374 bits->store += width;
375 return;
377 /* flush cache with value's some leading bits. */
378 uint32_t free_bits = BITS_IN_BYTE - bits->store;
379 bits->cache <<= free_bits;
380 bits->cache |= lsmash_bits_mask_lsb8( value >> (width -= free_bits), free_bits );
381 lsmash_bs_put_byte( bits->bs, bits->cache );
382 bits->store = 0;
383 bits->cache = 0;
385 /* cache is empty here. */
386 /* byte unit operation. */
387 while( width > BITS_IN_BYTE )
388 lsmash_bs_put_byte( bits->bs, (uint8_t)(value >> (width -= BITS_IN_BYTE)) );
389 /* bit unit operation for residual. */
390 if( width )
392 bits->cache = lsmash_bits_mask_lsb8( value, width );
393 bits->store = width;
397 /* We can change value's type to unsigned int for 64-bit operation if needed. */
398 uint32_t lsmash_bits_get( lsmash_bits_t *bits, uint32_t width )
400 debug_if( !bits || !width )
401 return 0;
402 uint32_t value = 0;
403 if( bits->store )
405 if( bits->store >= width )
407 /* cache contains all of bits required. */
408 bits->store -= width;
409 return lsmash_bits_mask_lsb8( bits->cache >> bits->store, width );
411 /* fill value's leading bits with cache's residual. */
412 value = lsmash_bits_mask_lsb8( bits->cache, bits->store );
413 width -= bits->store;
414 bits->store = 0;
415 bits->cache = 0;
417 /* cache is empty here. */
418 /* byte unit operation. */
419 while( width > BITS_IN_BYTE )
421 value <<= BITS_IN_BYTE;
422 width -= BITS_IN_BYTE;
423 value |= lsmash_bs_get_byte( bits->bs );
425 /* bit unit operation for residual. */
426 if( width )
428 bits->cache = lsmash_bs_get_byte( bits->bs );
429 bits->store = BITS_IN_BYTE - width;
430 value <<= width;
431 value |= lsmash_bits_mask_lsb8( bits->cache >> bits->store, width );
433 return value;
436 /****
437 bitstream with bytestream for adhoc operation
438 ****/
440 lsmash_bits_t* lsmash_bits_adhoc_create()
442 lsmash_bs_t* bs = lsmash_bs_create( NULL ); /* no file writing */
443 if( !bs )
444 return NULL;
445 lsmash_bits_t* bits = lsmash_bits_create( bs );
446 if( !bits )
448 lsmash_bs_cleanup( bs );
449 return NULL;
451 return bits;
454 void lsmash_bits_adhoc_cleanup( lsmash_bits_t* bits )
456 if( !bits )
457 return;
458 lsmash_bs_cleanup( bits->bs );
459 lsmash_bits_cleanup( bits );
462 void* lsmash_bits_export_data( lsmash_bits_t* bits, uint32_t* length )
464 lsmash_bits_put_align( bits );
465 return lsmash_bs_export_data( bits->bs, length );
468 int lsmash_bits_import_data( lsmash_bits_t* bits, void* data, uint32_t length )
470 return lsmash_bs_import_data( bits->bs, data, length );
472 /*---- ----*/
474 /*---- list ----*/
475 void lsmash_init_entry_list( lsmash_entry_list_t *list )
477 list->head = NULL;
478 list->tail = NULL;
479 list->last_accessed_entry = NULL;
480 list->last_accessed_number = 0;
481 list->entry_count = 0;
484 lsmash_entry_list_t *lsmash_create_entry_list( void )
486 lsmash_entry_list_t *list = malloc( sizeof(lsmash_entry_list_t) );
487 if( !list )
488 return NULL;
489 lsmash_init_entry_list( list );
490 return list;
493 int lsmash_add_entry( lsmash_entry_list_t *list, void *data )
495 if( !list )
496 return -1;
497 lsmash_entry_t *entry = malloc( sizeof(lsmash_entry_t) );
498 if( !entry )
499 return -1;
500 entry->next = NULL;
501 entry->prev = list->tail;
502 entry->data = data;
503 if( list->head )
504 list->tail->next = entry;
505 else
506 list->head = entry;
507 list->tail = entry;
508 list->entry_count += 1;
509 return 0;
512 int lsmash_remove_entry_direct( lsmash_entry_list_t *list, lsmash_entry_t *entry, void* eliminator )
514 if( !entry )
515 return -1;
516 if( !eliminator )
517 eliminator = free;
518 lsmash_entry_t *next = entry->next;
519 lsmash_entry_t *prev = entry->prev;
520 if( entry == list->head )
521 list->head = next;
522 else
523 prev->next = next;
524 if( entry == list->tail )
525 list->tail = prev;
526 else
527 next->prev = prev;
528 if( entry->data )
529 ((lsmash_entry_data_eliminator)eliminator)( entry->data );
530 if( entry == list->last_accessed_entry )
532 if( next )
533 list->last_accessed_entry = next;
534 else if( prev )
536 list->last_accessed_entry = prev;
537 list->last_accessed_number -= 1;
539 else
541 list->last_accessed_entry = NULL;
542 list->last_accessed_number = 0;
545 else
547 /* We can't know the current entry number immediately,
548 * so discard the last accessed entry info because time is wasted to know it. */
549 list->last_accessed_entry = NULL;
550 list->last_accessed_number = 0;
552 free( entry );
553 list->entry_count -= 1;
554 return 0;
557 int lsmash_remove_entry( lsmash_entry_list_t *list, uint32_t entry_number, void* eliminator )
559 lsmash_entry_t *entry = lsmash_get_entry( list, entry_number );
560 return lsmash_remove_entry_direct( list, entry, eliminator );
563 void lsmash_remove_entries( lsmash_entry_list_t *list, void* eliminator )
565 if( !list )
566 return;
567 if( !eliminator )
568 eliminator = free;
569 for( lsmash_entry_t *entry = list->head; entry; )
571 lsmash_entry_t *next = entry->next;
572 if( entry->data )
573 ((lsmash_entry_data_eliminator)eliminator)( entry->data );
574 free( entry );
575 entry = next;
577 lsmash_init_entry_list( list );
580 void lsmash_remove_list( lsmash_entry_list_t *list, void* eliminator )
582 if( !list )
583 return;
584 lsmash_remove_entries( list, eliminator );
585 free( list );
588 lsmash_entry_t *lsmash_get_entry( lsmash_entry_list_t *list, uint32_t entry_number )
590 if( !list || !entry_number || entry_number > list->entry_count )
591 return NULL;
592 int shortcut = 1;
593 lsmash_entry_t *entry = NULL;
594 if( list->last_accessed_entry )
596 if( entry_number == list->last_accessed_number )
597 entry = list->last_accessed_entry;
598 else if( entry_number == list->last_accessed_number + 1 )
599 entry = list->last_accessed_entry->next;
600 else if( entry_number == list->last_accessed_number - 1 )
601 entry = list->last_accessed_entry->prev;
602 else
603 shortcut = 0;
605 else
606 shortcut = 0;
607 if( !shortcut )
609 if( entry_number <= (list->entry_count >> 1) )
611 /* Look for from the head. */
612 uint32_t distance_plus_one = entry_number;
613 for( entry = list->head; entry && --distance_plus_one; entry = entry->next );
615 else
617 /* Look for from the tail. */
618 uint32_t distance = list->entry_count - entry_number;
619 for( entry = list->tail; entry && distance--; entry = entry->prev );
622 if( entry )
624 list->last_accessed_entry = entry;
625 list->last_accessed_number = entry_number;
627 return entry;
630 void *lsmash_get_entry_data( lsmash_entry_list_t *list, uint32_t entry_number )
632 lsmash_entry_t *entry = lsmash_get_entry( list, entry_number );
633 return entry ? entry->data : NULL;
635 /*---- ----*/
637 /*---- type ----*/
638 double lsmash_fixed2double( uint64_t value, int frac_width )
640 return value / (double)(1ULL << frac_width);
643 float lsmash_int2float32( uint32_t value )
645 return (union {uint32_t i; float f;}){value}.f;
648 double lsmash_int2float64( uint64_t value )
650 return (union {uint64_t i; double d;}){value}.d;
652 /*---- ----*/
654 /*---- allocator ----*/
655 void *lsmash_memdup( void *src, size_t size )
657 if( !size )
658 return NULL;
659 void *dst = malloc( size );
660 if( !dst )
661 return NULL;
662 memcpy( dst, src, size );
663 return dst;