X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=libchimara%2Fstream.c;h=46a2efc5cb077b8af39d54c86427d1c497178490;hb=refs%2Fheads%2Fgtk3;hp=96ab73fb08dcc97c8857541c0d91bafedbe7b33b;hpb=bea353f718967322136bfe95b04d1de02084671a;p=projects%2Fchimara%2Fchimara.git diff --git a/libchimara/stream.c b/libchimara/stream.c index 96ab73f..46a2efc 100644 --- a/libchimara/stream.c +++ b/libchimara/stream.c @@ -1,20 +1,23 @@ +#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; +extern GPrivate glk_data_key; /* Internal function: create a stream with a specified rock value */ strid_t stream_new_common(glui32 rock) { - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); - + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); + strid_t str = g_new0(struct glk_stream_struct, 1); str->magic = MAGIC_STREAM; str->rock = rock; @@ -33,7 +36,7 @@ stream_new_common(glui32 rock) void stream_close_common(strid_t str, stream_result_t *result) { - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); if(glk_data->unregister_obj) { @@ -82,7 +85,7 @@ glk_stream_iterate(strid_t str, glui32 *rockptr) { VALID_STREAM_OR_NULL(str, return NULL); - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); GList *retnode; if(str == NULL) @@ -128,8 +131,8 @@ glk_stream_set_current(strid_t str) { VALID_STREAM_OR_NULL(str, return); - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); - + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); + if(str != NULL && str->file_mode == filemode_Read) { ILLEGAL("Cannot set current stream to non output stream"); @@ -149,7 +152,7 @@ glk_stream_set_current(strid_t str) strid_t glk_stream_get_current() { - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); return glk_data->current_stream; } @@ -164,7 +167,7 @@ glk_stream_get_current() void glk_put_char(unsigned char ch) { - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); VALID_STREAM(glk_data->current_stream, return); glk_put_char_stream(glk_data->current_stream, ch); } @@ -180,7 +183,7 @@ glk_put_char(unsigned char ch) void glk_put_char_uni(glui32 ch) { - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); VALID_STREAM(glk_data->current_stream, return); glk_put_char_stream_uni(glk_data->current_stream, ch); } @@ -200,7 +203,7 @@ glk_put_char_uni(glui32 ch) void glk_put_string(char *s) { - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); VALID_STREAM(glk_data->current_stream, return); glk_put_string_stream(glk_data->current_stream, s); } @@ -216,7 +219,7 @@ glk_put_string(char *s) void glk_put_string_uni(glui32 *s) { - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); VALID_STREAM(glk_data->current_stream, return); glk_put_string_stream_uni(glk_data->current_stream, s); } @@ -237,7 +240,7 @@ glk_put_string_uni(glui32 *s) void glk_put_buffer(char *buf, glui32 len) { - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); VALID_STREAM(glk_data->current_stream, return); glk_put_buffer_stream(glk_data->current_stream, buf, len); } @@ -253,7 +256,7 @@ glk_put_buffer(char *buf, glui32 len) void glk_put_buffer_uni(glui32 *buf, glui32 len) { - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); VALID_STREAM(glk_data->current_stream, return); glk_put_buffer_stream_uni(glk_data->current_stream, buf, len); } @@ -289,7 +292,7 @@ glk_stream_open_memory(char *buf, glui32 buflen, glui32 fmode, glui32 rock) if(buf && buflen) { - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); str->buffer = buf; str->buflen = buflen; if(glk_data->register_arr) @@ -328,7 +331,7 @@ glk_stream_open_memory_uni(glui32 *buf, glui32 buflen, glui32 fmode, glui32 rock if(buf && buflen) { - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); str->ubuffer = buf; str->buflen = buflen; if(glk_data->register_arr) @@ -488,6 +491,122 @@ glk_stream_open_file_uni(frefid_t fileref, glui32 fmode, glui32 rock) return file_stream_new(fileref, fmode, rock, TRUE); } +/** + * glk_stream_open_resource: + * @filenum: Resource chunk number to open. + * @rock: The new stream's rock value. + * + * Open the given data resource for reading (only), as a normal stream. + * + * + * Note that there is no notion of file usage — the resource does not + * have to be specified as saved game or whatever. + * + * + * If no resource chunk of the given number exists, the open function returns + * %NULL. + * + * As with file streams, a binary resource stream reads the resource as bytes. A + * text resource stream reads characters encoded as Latin-1. + * + * When reading from a resource stream, newlines are not remapped, even if they + * normally would be when reading from a text file on the host OS. If you read a + * line (glk_get_line_stream() or glk_get_line_stream_uni()), a Unix newline + * (0x0A) terminates the line. + * + * Returns: the new stream, or %NULL. + */ +strid_t +glk_stream_open_resource(glui32 filenum, glui32 rock) +{ + /* 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; +} + +/** + * glk_stream_open_resource_uni: + * @filenum: Resource chunk number to open. + * @rock: The new stream's rock value. + * + * Open the given data resource for reading (only), as a Unicode stream. See + * glk_stream_open_resource() for more information. + * + * As with file streams, a binary resource stream reads the resource as + * four-byte (big-endian) words. A text resource stream reads characters encoded + * as UTF-8. + * + * + * Thus, the difference between text and binary resources is only important + * when opened as a Unicode stream. + * + * + * Returns: the new stream, or %NULL. + */ +strid_t +glk_stream_open_resource_uni(glui32 filenum, glui32 rock) +{ + /* 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; +} + /** * glk_stream_close: * @str: Stream to close. @@ -518,7 +637,7 @@ glk_stream_close(strid_t str, stream_result_t *result) case STREAM_TYPE_MEMORY: { - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); if(glk_data->unregister_arr) { if(str->unicode) @@ -534,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;