+#include <config.h>
#include "stream.h"
#include "fileref.h"
#include "magic.h"
+#include "gi_blorb.h"
#include <errno.h>
#include <stdio.h>
#include <glib.h>
#include <glib/gstdio.h>
+#include <glib/gi18n-lib.h>
#include "chimara-glk-private.h"
extern GPrivate *glk_data_key;
str->file_mode = fmode;
str->type = STREAM_TYPE_MEMORY;
str->mark = 0;
+ str->endmark = 0;
str->unicode = FALSE;
if(buf && buflen)
str->file_mode = fmode;
str->type = STREAM_TYPE_MEMORY;
str->mark = 0;
+ str->endmark = 0;
str->unicode = TRUE;
if(buf && buflen)
{
VALID_FILEREF(fileref, return NULL);
- gchar *modestr;
+ const gchar *modestr;
/* Binary mode is 0x000, text mode 0x100 */
gboolean binary = !(fileref->usage & fileusage_TextMode);
switch(fmode)
ILLEGAL_PARAM("Tried to open a nonexistent file, '%s', in read mode", fileref->filename);
return NULL;
}
- modestr = g_strdup(binary? "rb" : "r");
+ modestr = binary? "rb" : "r";
break;
case filemode_Write:
- modestr = g_strdup(binary? "wb" : "w");
+ modestr = binary? "wb" : "w";
break;
case filemode_WriteAppend:
case filemode_ReadWrite:
IO_WARNING( "Error opening file", fileref->filename, g_strerror(errno) );
return NULL;
}
- modestr = g_strdup(binary? "r+b" : "r+");
+ modestr = binary? "r+b" : "r+";
}
break;
default:
}
FILE *fp = g_fopen(fileref->filename, modestr);
- g_free(modestr);
if(fp == NULL) {
IO_WARNING( "Error opening file", fileref->filename, g_strerror(errno) );
return NULL;
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><para>
+ * Note that there is no notion of file usage — the resource does not
+ * have to be specified as <quote>saved game</quote> or whatever.
+ * </para></note>
+ *
+ * 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.
+ *
+ * <note><para>
+ * Thus, the difference between text and binary resources is only important
+ * when opened as a Unicode stream.
+ * </para></note>
+ *
+ * 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.
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;