giblorb_err_t giblorb_destroy_map( giblorb_map_t *map ) { int ix; if ( !map || !map->chunks || map->inited != giblorb_Inited_Magic ) return giblorb_err_NotAMap; for ( ix = 0; ix < map->numchunks; ix++ ) { giblorb_chunkdesc_t *chu = &( map->chunks[ix] ); if ( chu->ptr ) { giblorb_free( chu->ptr ); chu->ptr = NULL; } } if ( map->chunks ) { giblorb_free( map->chunks ); map->chunks = NULL; } map->numchunks = 0; if ( map->resources ) { giblorb_free( map->resources ); map->resources = NULL; } if ( map->ressorted ) { giblorb_free( map->ressorted ); map->ressorted = NULL; } map->numresources = 0; map->file = NULL; map->inited = 0; giblorb_free( map ); return giblorb_err_None; }
giblorb_err_t giblorb_unload_chunk(giblorb_map_t *map, glui32 chunknum) { giblorb_chunkdesc_t *chu; if (chunknum < 0 || chunknum >= map->numchunks) return giblorb_err_NotFound; chu = &(map->chunks[chunknum]); if (chu->ptr) { giblorb_free(chu->ptr); chu->ptr = NULL; } return giblorb_err_None; }
giblorb_err_t giblorb_unload_chunk(giblorb_map_t *map, glui32 chunknum) { giblorb_chunkdesc_t *chu; // XCode: removed "chunknum < 0" test to shut up compiler warning if (chunknum >= map->numchunks) return giblorb_err_NotFound; chu = &(map->chunks[chunknum]); if (chu->ptr) { giblorb_free(chu->ptr); chu->ptr = NULL; } return giblorb_err_None; }
giblorb_err_t giblorb_create_map(strid_t file, giblorb_map_t **newmap) { giblorb_err_t err; giblorb_map_t *map; glui32 readlen; glui32 nextpos, totallength; giblorb_chunkdesc_t *chunks; int chunks_size, numchunks; char buffer[16]; *newmap = NULL; if (!lib_inited) { err = giblorb_initialize(); if (err) return err; lib_inited = TRUE; } /* First, chew through the file and index the chunks. */ glk_stream_set_position(file, 0, seekmode_Start); readlen = glk_get_buffer_stream(file, buffer, 12); if (readlen != 12) return giblorb_err_Read; if (giblorb_native4(buffer+0) != giblorb_ID_FORM) return giblorb_err_Format; if (giblorb_native4(buffer+8) != giblorb_ID_IFRS) return giblorb_err_Format; totallength = giblorb_native4(buffer+4) + 8; nextpos = 12; chunks_size = 8; numchunks = 0; chunks = (giblorb_chunkdesc_t *)giblorb_malloc(sizeof(giblorb_chunkdesc_t) * chunks_size); while (nextpos < totallength) { glui32 type, len; int chunum; giblorb_chunkdesc_t *chu; glk_stream_set_position(file, nextpos, seekmode_Start); readlen = glk_get_buffer_stream(file, buffer, 8); if (readlen != 8) return giblorb_err_Read; type = giblorb_native4(buffer+0); len = giblorb_native4(buffer+4); if (numchunks >= chunks_size) { chunks_size *= 2; chunks = (giblorb_chunkdesc_t *)giblorb_realloc(chunks, sizeof(giblorb_chunkdesc_t) * chunks_size); } chunum = numchunks; chu = &(chunks[chunum]); numchunks++; chu->type = type; chu->startpos = nextpos; if (type == giblorb_ID_FORM) { chu->datpos = nextpos; chu->len = len+8; } else { chu->datpos = nextpos+8; chu->len = len; } chu->ptr = NULL; chu->auxdatnum = -1; nextpos = nextpos + len + 8; if (nextpos & 1) nextpos++; if (nextpos > totallength) return giblorb_err_Format; } /* The basic IFF structure seems to be ok, and we have a list of chunks. Now we allocate the map structure itself. */ map = (giblorb_map_t *)giblorb_malloc(sizeof(giblorb_map_t)); if (!map) { giblorb_free(chunks); return giblorb_err_Alloc; } map->inited = giblorb_Inited_Magic; map->file = file; map->chunks = chunks; map->numchunks = numchunks; map->resources = NULL; map->ressorted = NULL; map->numresources = 0; /*map->releasenum = 0; map->zheader = NULL; map->resolution = NULL; map->palettechunk = -1; map->palette = NULL; map->auxsound = NULL; map->auxpict = NULL;*/ /* Now we do everything else involved in loading the Blorb file, such as building resource lists. */ err = giblorb_initialize_map(map); if (err) { giblorb_destroy_map(map); return err; } *newmap = map; return giblorb_err_None; }
static giblorb_err_t giblorb_initialize_map( giblorb_map_t *map ) { /* It is important that the map structure be kept valid during this function. If this returns an error, giblorb_destroy_map() will be called. */ int ix, jx; giblorb_result_t chunkres; giblorb_err_t err; char *ptr; glui32 len; glui32 numres; int gotindex = FALSE; for ( ix = 0; ix < map->numchunks; ix++ ) { giblorb_chunkdesc_t *chu = &map->chunks[ix]; switch ( chu->type ) { case giblorb_ID_RIdx: /* Resource index chunk: build the resource list and sort it. */ if ( gotindex ) return giblorb_err_Format; /* duplicate index chunk */ err = giblorb_load_chunk_by_number( map, giblorb_method_Memory, &chunkres, ix ); if ( err ) return err; ptr = chunkres.data.ptr; len = chunkres.length; numres = giblorb_native4( ptr + 0 ); if ( numres ) { int ix2; giblorb_resdesc_t *resources = NULL; giblorb_resdesc_t **ressorted = NULL; if ( len != numres * 12 + 4 ) return giblorb_err_Format; /* bad length field */ resources = (giblorb_resdesc_t *)giblorb_malloc( numres * sizeof( giblorb_resdesc_t ) ); if ( !resources ) { return giblorb_err_Alloc; } ressorted = (giblorb_resdesc_t **)giblorb_malloc( numres * sizeof( giblorb_resdesc_t * ) ); if ( !ressorted ) { giblorb_free( resources ); return giblorb_err_Alloc; } ix2 = 0; for ( jx = 0; jx < numres; jx++ ) { giblorb_resdesc_t *res = &( resources[jx] ); glui32 respos; res->usage = giblorb_native4( ptr + jx * 12 + 4 ); res->resnum = giblorb_native4( ptr + jx * 12 + 8 ); respos = giblorb_native4( ptr + jx * 12 + 12 ); while ( ix2 < map->numchunks && map->chunks[ix2].startpos < respos ) ix2++; if ( ix2 >= map->numchunks || map->chunks[ix2].startpos != respos ) { /* start pos does not match a real chunk */ giblorb_free( resources ); giblorb_free( ressorted ); return giblorb_err_Format; } res->chunknum = ix2; ressorted[jx] = res; } /* Sort a resource list (actually a list of pointers to structures in map->resources.) This makes it easy to find resources by usage and resource number. */ giblorb_qsort( ressorted, numres ); map->numresources = numres; map->resources = resources; map->ressorted = ressorted; } giblorb_unload_chunk( map, ix ); gotindex = TRUE; break; } } return giblorb_err_None; }