2018-11-10 21:22:57 -08:00
|
|
|
/* ScummVM - Graphic Adventure Engine
|
|
|
|
*
|
|
|
|
* ScummVM is the legal property of its developers, whose names
|
|
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
|
|
* file distributed with this source distribution.
|
|
|
|
*
|
|
|
|
* This program is free software{} you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation{} either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY{} without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program{} if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2018-11-13 19:47:07 -08:00
|
|
|
#include "glk/blorb.h"
|
2018-11-10 21:22:57 -08:00
|
|
|
|
2018-11-13 20:05:59 -08:00
|
|
|
namespace Glk {
|
2018-11-10 21:22:57 -08:00
|
|
|
|
|
|
|
#define giblorb_Inited_Magic 0xB7012BEDU
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Describes one chunk of the Blorb file.
|
|
|
|
*/
|
|
|
|
struct giblorb_chunkdesc_struct {
|
|
|
|
glui32 type;
|
|
|
|
glui32 len;
|
|
|
|
glui32 startpos; ///< start of chunk header
|
|
|
|
glui32 datpos; ///< start of data (either startpos or startpos+8)
|
|
|
|
|
2018-11-16 20:38:25 -08:00
|
|
|
byte *ptr; ///< pointer to malloc'd data, if loaded
|
2018-11-10 21:22:57 -08:00
|
|
|
int auxdatnum; ///< entry in the auxsound/auxpict array; -1 if none. This only applies to chunks that represent resources;
|
|
|
|
};
|
|
|
|
typedef giblorb_chunkdesc_struct giblorb_chunkdesc_t;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Describes one resource in the Blorb file.
|
|
|
|
*/
|
|
|
|
struct giblorb_resdesc_struct {
|
|
|
|
glui32 usage;
|
|
|
|
glui32 resnum;
|
|
|
|
glui32 chunknum;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Holds the complete description of an open Blorb file.
|
|
|
|
*/
|
|
|
|
struct giblorb_map_struct {
|
|
|
|
glui32 inited; ///< holds giblorb_Inited_Magic if the map structure is valid
|
|
|
|
|
|
|
|
uint numchunks;
|
|
|
|
giblorb_chunkdesc_t *chunks; ///< list of chunk descriptors
|
|
|
|
|
|
|
|
int numresources;
|
|
|
|
giblorb_resdesc_t *resources; ///< list of resource descriptors
|
|
|
|
giblorb_resdesc_t **ressorted; ///< list of pointers to descriptors in map->resources -- sorted by usage and resource number.
|
|
|
|
};
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
Blorb::Blorb(const Common::String &filename, InterpreterType interpType) :
|
|
|
|
Common::Archive(), _interpType(interpType), _map(nullptr) {
|
|
|
|
if (!_file.open(filename))
|
|
|
|
error("Could not open blorb file");
|
|
|
|
|
|
|
|
if (create_map() != giblorb_err_None)
|
|
|
|
error("Could not parse blorb file");
|
|
|
|
}
|
|
|
|
|
|
|
|
Blorb::~Blorb() {
|
|
|
|
for (uint ix = 0; ix < _map->numchunks; ix++) {
|
|
|
|
giblorb_chunkdesc_t *chu = &(_map->chunks[ix]);
|
|
|
|
if (chu->ptr) {
|
|
|
|
delete chu->ptr;
|
|
|
|
chu->ptr = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_map->chunks) {
|
|
|
|
delete[] _map->chunks;
|
|
|
|
_map->chunks = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
_map->numchunks = 0;
|
|
|
|
|
|
|
|
if (_map->resources) {
|
|
|
|
delete[] _map->resources;
|
|
|
|
_map->resources = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_map->ressorted) {
|
|
|
|
delete[] _map->ressorted;
|
|
|
|
_map->ressorted = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
_map->numresources = 0;
|
|
|
|
_map->inited = 0;
|
|
|
|
|
|
|
|
delete _map;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Blorb::hasFile(const Common::String &name) const {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Blorb::listMatchingMembers(Common::ArchiveMemberList &list, const Common::String &pattern) const {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Blorb::listMembers(Common::ArchiveMemberList &list) const {
|
|
|
|
return 0;
|
2018-11-10 21:22:57 -08:00
|
|
|
}
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
const Common::ArchiveMemberPtr Blorb::getMember(const Common::String &name) const {
|
|
|
|
return Common::ArchiveMemberPtr();
|
|
|
|
}
|
|
|
|
|
|
|
|
Common::SeekableReadStream *Blorb::createReadStreamForMember(const Common::String &name) const {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
giblorb_err_t Blorb::create_map() {
|
2018-11-10 21:22:57 -08:00
|
|
|
giblorb_err_t err;
|
|
|
|
giblorb_map_t *map;
|
|
|
|
glui32 readlen;
|
|
|
|
glui32 nextpos, totallength;
|
|
|
|
giblorb_chunkdesc_t *chunks;
|
|
|
|
int chunks_size, numchunks;
|
|
|
|
char buffer[16];
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
// First, chew through the file and index the chunks
|
|
|
|
_file.seek(0);
|
2018-11-10 21:22:57 -08:00
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
readlen = _file.read(buffer, 12);
|
2018-11-10 21:22:57 -08:00
|
|
|
if (readlen != 12)
|
2018-11-18 22:32:27 -08:00
|
|
|
return giblorb_err_Format;
|
2018-11-10 21:22:57 -08:00
|
|
|
|
|
|
|
if (READ_BE_INT32(buffer + 0) != giblorb_ID_FORM)
|
|
|
|
return giblorb_err_Format;
|
|
|
|
if (READ_BE_INT32(buffer + 8) != giblorb_ID_IFRS)
|
|
|
|
return giblorb_err_Format;
|
|
|
|
|
|
|
|
totallength = READ_BE_INT32(buffer + 4) + 8;
|
|
|
|
nextpos = 12;
|
|
|
|
|
|
|
|
chunks_size = 8;
|
|
|
|
numchunks = 0;
|
|
|
|
chunks = new giblorb_chunkdesc_t[chunks_size];
|
|
|
|
|
|
|
|
while (nextpos < totallength) {
|
|
|
|
glui32 type, len;
|
|
|
|
int chunum;
|
|
|
|
giblorb_chunkdesc_t *chu;
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
_file.seek(nextpos);
|
2018-11-10 21:22:57 -08:00
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
readlen = _file.read(buffer, 8);
|
2018-11-10 21:22:57 -08:00
|
|
|
if (readlen != 8) {
|
|
|
|
delete[] chunks;
|
|
|
|
return giblorb_err_Read;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = READ_BE_INT32(buffer + 0);
|
|
|
|
len = READ_BE_INT32(buffer + 4);
|
|
|
|
|
|
|
|
if (numchunks >= chunks_size) {
|
|
|
|
chunks_size *= 2;
|
|
|
|
chunks = new 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 = nullptr;
|
|
|
|
chu->auxdatnum = -1;
|
|
|
|
|
|
|
|
nextpos = nextpos + len + 8;
|
|
|
|
if (nextpos & 1)
|
|
|
|
nextpos++;
|
|
|
|
|
|
|
|
if (nextpos > totallength) {
|
|
|
|
delete[] chunks;
|
|
|
|
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.
|
2018-11-18 22:32:27 -08:00
|
|
|
_map = new giblorb_map_t();
|
|
|
|
if (!_map) {
|
2018-11-10 21:22:57 -08:00
|
|
|
delete[] chunks;
|
|
|
|
return giblorb_err_Alloc;
|
|
|
|
}
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
_map->inited = giblorb_Inited_Magic;
|
|
|
|
_map->chunks = chunks;
|
|
|
|
_map->numchunks = numchunks;
|
|
|
|
_map->resources = nullptr;
|
|
|
|
_map->ressorted = nullptr;
|
|
|
|
_map->numresources = 0;
|
2018-11-10 21:22:57 -08:00
|
|
|
|
|
|
|
// Now we do everything else involved in loading the Blorb file,
|
|
|
|
// such as building resource lists.
|
2018-11-18 22:32:27 -08:00
|
|
|
err = initialize_map();
|
|
|
|
if (err)
|
2018-11-10 21:22:57 -08:00
|
|
|
return err;
|
|
|
|
|
|
|
|
return giblorb_err_None;
|
|
|
|
}
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
giblorb_err_t Blorb::initialize_map() {
|
2018-11-10 21:22:57 -08:00
|
|
|
// It is important that the map structure be kept valid during this function.
|
|
|
|
// If this returns an error, giblorb_destroy_map() will be called.
|
|
|
|
uint ix, jx;
|
|
|
|
giblorb_result_t chunkres;
|
|
|
|
giblorb_err_t err;
|
|
|
|
char *ptr;
|
|
|
|
glui32 len;
|
|
|
|
glui32 numres;
|
|
|
|
int gotindex = false;
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
for (ix = 0; ix < _map->numchunks; ix++) {
|
|
|
|
giblorb_chunkdesc_t *chu = &_map->chunks[ix];
|
2018-11-10 21:22:57 -08:00
|
|
|
|
|
|
|
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
|
2018-11-18 22:32:27 -08:00
|
|
|
err = load_chunk_by_number(giblorb_method_Memory, &chunkres, ix);
|
2018-11-10 21:22:57 -08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
ptr = (char *)chunkres.data.ptr;
|
|
|
|
len = chunkres.length;
|
|
|
|
numres = READ_BE_INT32(ptr + 0);
|
|
|
|
|
|
|
|
if (numres) {
|
|
|
|
uint ix2;
|
|
|
|
giblorb_resdesc_t *resources;
|
|
|
|
giblorb_resdesc_t **ressorted;
|
|
|
|
|
|
|
|
if (len != numres * 12 + 4)
|
|
|
|
return giblorb_err_Format; // bad length field
|
|
|
|
|
|
|
|
resources = new giblorb_resdesc_t[numres];
|
|
|
|
ressorted = new giblorb_resdesc_t *[numres];
|
|
|
|
if (!ressorted || !resources) {
|
|
|
|
delete[] resources;
|
|
|
|
delete[] ressorted;
|
|
|
|
return giblorb_err_Alloc;
|
|
|
|
}
|
|
|
|
|
|
|
|
ix2 = 0;
|
|
|
|
for (jx = 0; jx < numres; jx++) {
|
|
|
|
giblorb_resdesc_t *res = &(resources[jx]);
|
|
|
|
glui32 respos;
|
|
|
|
|
|
|
|
res->usage = READ_BE_INT32(ptr + jx * 12 + 4);
|
|
|
|
res->resnum = READ_BE_INT32(ptr + jx * 12 + 8);
|
|
|
|
respos = READ_BE_INT32(ptr + jx * 12 + 12);
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
while (ix2 < _map->numchunks
|
|
|
|
&& _map->chunks[ix2].startpos < respos)
|
2018-11-10 21:22:57 -08:00
|
|
|
ix2++;
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
if (ix2 >= _map->numchunks
|
|
|
|
|| _map->chunks[ix2].startpos != respos) {
|
2018-11-10 21:22:57 -08:00
|
|
|
delete[] resources;
|
|
|
|
delete[] ressorted;
|
|
|
|
return giblorb_err_Format; // start pos does not match a real chunk
|
|
|
|
}
|
|
|
|
|
|
|
|
res->chunknum = ix2;
|
|
|
|
|
|
|
|
ressorted[jx] = res;
|
|
|
|
}
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
// Sort a resource list (actually a list of pointers to structures in _map->resources.)
|
2018-11-10 21:22:57 -08:00
|
|
|
// This makes it easy to find resources by usage and resource number.
|
2018-11-18 22:32:27 -08:00
|
|
|
qsort(ressorted, numres);
|
2018-11-10 21:22:57 -08:00
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
_map->numresources = numres;
|
|
|
|
_map->resources = resources;
|
|
|
|
_map->ressorted = ressorted;
|
2018-11-10 21:22:57 -08:00
|
|
|
}
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
unload_chunk(ix);
|
2018-11-10 21:22:57 -08:00
|
|
|
gotindex = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return giblorb_err_None;
|
|
|
|
}
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
void Blorb::qsort(giblorb_resdesc_t **list, size_t len) {
|
2018-11-10 21:22:57 -08:00
|
|
|
int ix, jx, res;
|
|
|
|
giblorb_resdesc_t *tmpptr, *pivot;
|
|
|
|
|
|
|
|
if (len < 6) {
|
|
|
|
// The list is short enough for a bubble-sort.
|
|
|
|
for (jx = len - 1; jx>0; jx--) {
|
|
|
|
for (ix = 0; ix<jx; ix++) {
|
|
|
|
res = sortsplot(list[ix], list[ix + 1]);
|
|
|
|
if (res > 0) {
|
|
|
|
tmpptr = list[ix];
|
|
|
|
list[ix] = list[ix + 1];
|
|
|
|
list[ix + 1] = tmpptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Split the list.
|
|
|
|
pivot = list[len / 2];
|
|
|
|
ix = 0;
|
|
|
|
jx = len;
|
|
|
|
for (;;) {
|
|
|
|
while (ix < jx - 1 && sortsplot(list[ix], pivot) < 0)
|
|
|
|
ix++;
|
|
|
|
while (ix < jx - 1 && sortsplot(list[jx - 1], pivot) > 0)
|
|
|
|
jx--;
|
|
|
|
if (ix >= jx - 1)
|
|
|
|
break;
|
|
|
|
tmpptr = list[ix];
|
|
|
|
list[ix] = list[jx - 1];
|
|
|
|
list[jx - 1] = tmpptr;
|
|
|
|
}
|
|
|
|
ix++;
|
|
|
|
// Sort the halves.
|
2018-11-18 22:32:27 -08:00
|
|
|
qsort(list + 0, ix);
|
|
|
|
qsort(list + ix, len - ix);
|
2018-11-10 21:22:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
giblorb_resdesc_t *Blorb::bsearch(giblorb_resdesc_t *sample,
|
2018-11-10 21:22:57 -08:00
|
|
|
giblorb_resdesc_t **list, int len) {
|
|
|
|
int top, bot, val, res;
|
|
|
|
|
|
|
|
bot = 0;
|
|
|
|
top = len;
|
|
|
|
|
|
|
|
while (bot < top) {
|
|
|
|
val = (top + bot) / 2;
|
|
|
|
res = sortsplot(list[val], sample);
|
|
|
|
if (res == 0)
|
|
|
|
return list[val];
|
|
|
|
if (res < 0) {
|
|
|
|
bot = val + 1;
|
|
|
|
} else {
|
|
|
|
top = val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Blorb::sortsplot(giblorb_resdesc_t *v1, giblorb_resdesc_t *v2) {
|
|
|
|
if (v1->usage < v2->usage)
|
|
|
|
return -1;
|
|
|
|
if (v1->usage > v2->usage)
|
|
|
|
return 1;
|
|
|
|
if (v1->resnum < v2->resnum)
|
|
|
|
return -1;
|
|
|
|
if (v1->resnum > v2->resnum)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
giblorb_err_t Blorb::load_chunk_by_type(glui32 method, giblorb_result_t *res, glui32 chunktype, glui32 count) {
|
2018-11-10 21:22:57 -08:00
|
|
|
uint ix;
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
for (ix = 0; ix < _map->numchunks; ix++) {
|
|
|
|
if (_map->chunks[ix].type == chunktype) {
|
2018-11-10 21:22:57 -08:00
|
|
|
if (count == 0)
|
|
|
|
break;
|
|
|
|
count--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
if (ix >= _map->numchunks) {
|
2018-11-10 21:22:57 -08:00
|
|
|
return giblorb_err_NotFound;
|
|
|
|
}
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
return load_chunk_by_number(method, res, ix);
|
2018-11-10 21:22:57 -08:00
|
|
|
}
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
giblorb_err_t Blorb::load_chunk_by_number(glui32 method, giblorb_result_t *res, glui32 chunknum) {
|
2018-11-10 21:22:57 -08:00
|
|
|
giblorb_chunkdesc_t *chu;
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
if (chunknum >= _map->numchunks)
|
2018-11-10 21:22:57 -08:00
|
|
|
return giblorb_err_NotFound;
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
chu = &(_map->chunks[chunknum]);
|
2018-11-10 21:22:57 -08:00
|
|
|
|
|
|
|
switch (method) {
|
|
|
|
case giblorb_method_DontLoad:
|
|
|
|
// do nothing
|
|
|
|
break;
|
|
|
|
|
|
|
|
case giblorb_method_FilePos:
|
|
|
|
res->data.startpos = chu->datpos;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case giblorb_method_Memory:
|
|
|
|
if (!chu->ptr) {
|
|
|
|
glui32 readlen;
|
|
|
|
byte *dat = new byte[chu->len];
|
|
|
|
|
|
|
|
if (!dat)
|
|
|
|
return giblorb_err_Alloc;
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
_file.seek(chu->datpos);
|
2018-11-10 21:22:57 -08:00
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
readlen = _file.read(dat, chu->len);
|
2018-11-10 21:22:57 -08:00
|
|
|
if (readlen != chu->len)
|
|
|
|
return giblorb_err_Read;
|
|
|
|
|
|
|
|
chu->ptr = dat;
|
|
|
|
}
|
|
|
|
|
|
|
|
res->data.ptr = chu->ptr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
res->chunknum = chunknum;
|
|
|
|
res->length = chu->len;
|
|
|
|
res->chunktype = chu->type;
|
|
|
|
|
|
|
|
return giblorb_err_None;
|
|
|
|
}
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
giblorb_err_t Blorb::unload_chunk(glui32 chunknum) {
|
2018-11-10 21:22:57 -08:00
|
|
|
giblorb_chunkdesc_t *chu;
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
if (chunknum >= _map->numchunks)
|
2018-11-10 21:22:57 -08:00
|
|
|
return giblorb_err_NotFound;
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
chu = &(_map->chunks[chunknum]);
|
2018-11-10 21:22:57 -08:00
|
|
|
|
|
|
|
if (chu->ptr) {
|
|
|
|
delete chu->ptr;
|
|
|
|
chu->ptr = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return giblorb_err_None;
|
|
|
|
}
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
giblorb_err_t Blorb::load_resource(glui32 method, giblorb_result_t *res, glui32 usage, glui32 resnum) {
|
2018-11-10 21:22:57 -08:00
|
|
|
giblorb_resdesc_t sample;
|
|
|
|
giblorb_resdesc_t *found;
|
|
|
|
|
|
|
|
sample.usage = usage;
|
|
|
|
sample.resnum = resnum;
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
found = bsearch(&sample, _map->ressorted, _map->numresources);
|
2018-11-10 21:22:57 -08:00
|
|
|
|
|
|
|
if (!found)
|
|
|
|
return giblorb_err_NotFound;
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
return load_chunk_by_number(method, res, found->chunknum);
|
2018-11-10 21:22:57 -08:00
|
|
|
}
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
giblorb_err_t Blorb::count_resources(glui32 usage, glui32 *num, glui32 *min, glui32 *max) {
|
2018-11-10 21:22:57 -08:00
|
|
|
int ix;
|
|
|
|
int count;
|
|
|
|
glui32 val;
|
|
|
|
glui32 minval, maxval;
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
minval = 0;
|
|
|
|
maxval = 0;
|
|
|
|
|
2018-11-18 22:32:27 -08:00
|
|
|
for (ix = 0; ix<_map->numresources; ix++) {
|
|
|
|
if (_map->resources[ix].usage == usage) {
|
|
|
|
val = _map->resources[ix].resnum;
|
2018-11-10 21:22:57 -08:00
|
|
|
if (count == 0) {
|
|
|
|
count++;
|
|
|
|
minval = val;
|
|
|
|
maxval = val;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
count++;
|
|
|
|
if (val < minval)
|
|
|
|
minval = val;
|
|
|
|
if (val > maxval)
|
|
|
|
maxval = val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (num)
|
|
|
|
*num = count;
|
|
|
|
if (min)
|
|
|
|
*min = minval;
|
|
|
|
if (max)
|
|
|
|
*max = maxval;
|
|
|
|
|
|
|
|
return giblorb_err_None;
|
|
|
|
}
|
|
|
|
|
2018-11-13 20:05:59 -08:00
|
|
|
} // End of namespace Glk
|