X-Git-Url: https://git.stderr.nl/gitweb?p=projects%2Fchimara%2Fchimara.git;a=blobdiff_plain;f=libchimara%2Fstream.c;h=0b1e2d8952c8fe34c0d638fe1094a4aba0ed1e28;hp=f9a6cf5bf4cea649c405ff7382dc8a5767276707;hb=7cbc2c68d146433b1d438d60406ca05e14a523ce;hpb=ea1acbd0ed1f4ee7b7a8cd65412f6213ccf62094 diff --git a/libchimara/stream.c b/libchimara/stream.c index f9a6cf5..0b1e2d8 100644 --- a/libchimara/stream.c +++ b/libchimara/stream.c @@ -1,10 +1,13 @@ +#include #include "stream.h" #include "fileref.h" #include "magic.h" +#include "gi_blorb.h" #include #include #include #include +#include #include "chimara-glk-private.h" extern GPrivate *glk_data_key; @@ -516,8 +519,58 @@ glk_stream_open_file_uni(frefid_t fileref, glui32 fmode, glui32 rock) strid_t glk_stream_open_resource(glui32 filenum, glui32 rock) { - g_warning("Not implemented"); - return NULL; + /* Adapted from CheapGlk */ + strid_t str; + gboolean isbinary; + giblorb_err_t err; + giblorb_result_t res; + giblorb_map_t *map = giblorb_get_resource_map(); + if(map == NULL) { + WARNING(_("Could not create resource stream, because there was no " + "resource map.")); + return NULL; /* Not running from a blorb file */ + } + + err = giblorb_load_resource(map, giblorb_method_Memory, &res, giblorb_ID_Data, filenum); + if(err) { + WARNING_S(_("Could not create resource stream, because the resource " + "could not be loaded"), giblorb_get_error_message(err)); + return 0; /* Not found, or some other error */ + } + + /* We'll use the in-memory copy of the chunk data as the basis for + our new stream. It's important to not call chunk_unload() until + the stream is closed (and we won't). + + This will be memory-hoggish for giant data chunks, but I don't + expect giant data chunks at this point. A more efficient model + would be to use the file on disk, but this requires some hacking + into the file stream code (we'd need to open a new FILE*) and + I don't feel like doing that. */ + + if(res.chunktype == giblorb_ID_TEXT) + isbinary = FALSE; + else if(res.chunktype == giblorb_ID_BINA) + isbinary = TRUE; + else { + WARNING(_("Could not create resource stream, because chunk was of " + "unknown type.")); + return NULL; /* Unknown chunk type */ + } + + str = stream_new_common(rock); + str->type = STREAM_TYPE_RESOURCE; + str->file_mode = filemode_Read; + str->binary = isbinary; + + if (res.data.ptr && res.length) { + str->buffer = res.data.ptr; + str->mark = 0; + str->buflen = res.length; + str->endmark = str->buflen; + } + + return str; } /** @@ -542,8 +595,16 @@ glk_stream_open_resource(glui32 filenum, glui32 rock) strid_t glk_stream_open_resource_uni(glui32 filenum, glui32 rock) { - g_warning("Not implemented"); - return NULL; + /* Adapted from CheapGlk */ + /* We have been handed an array of bytes. (They're big-endian + four-byte chunks, or perhaps a UTF-8 byte sequence, rather than + native-endian four-byte integers). So we drop it into str->buffer, + rather than str->ubuffer -- we'll have to do the translation in the + get() functions. */ + strid_t str = glk_stream_open_resource(filenum, rock); + if(str != NULL) + str->unicode = TRUE; + return str; } /** @@ -592,6 +653,12 @@ glk_stream_close(strid_t str, stream_result_t *result) IO_WARNING( "Failed to close file", str->filename, g_strerror(errno) ); g_free(str->filename); break; + + case STREAM_TYPE_RESOURCE: + /* Shouldn't free the chunk; someone else might be using it. It will + be freed when the resource map is freed. */ + break; + default: ILLEGAL_PARAM("Unknown stream type: %u", str->type); return;