Merge branch 'glk-074'
authorPhilip Chimento <philip.chimento@gmail.com>
Sun, 12 Feb 2012 12:58:18 +0000 (13:58 +0100)
committerPhilip Chimento <philip.chimento@gmail.com>
Sun, 12 Feb 2012 12:58:18 +0000 (13:58 +0100)
libchimara/fileref.c
libchimara/fileref.h
libchimara/gestalt.c
libchimara/glkunix.c
libchimara/stream.c
libchimara/stream.h
libchimara/strio.c
tests/externalfile.ulx
tests/glulxercise.ui
tests/resstreamtest.gblorb [new file with mode: 0644]

index 3db89a2445cbcb204dc64709a75ff38a3f095540..d4f2043dc454fc322c627844d22f168060b47e61 100644 (file)
 
 extern GPrivate *glk_data_key;
 
-/* Internal function: create a fileref using the given parameters. */
+/* Internal function: create a fileref using the given parameters. If @basename
+is NULL, compute a basename from @filename. */
 frefid_t
-fileref_new(gchar *filename, glui32 rock, glui32 usage, glui32 orig_filemode)
+fileref_new(char *filename, char *basename, glui32 rock, glui32 usage, glui32 orig_filemode)
 {
        g_return_val_if_fail(filename != NULL, NULL);
 
@@ -27,6 +28,10 @@ fileref_new(gchar *filename, glui32 rock, glui32 usage, glui32 orig_filemode)
                f->disprock = (*glk_data->register_obj)(f, gidisp_Class_Fileref);
        
        f->filename = g_strdup(filename);
+       if(basename)
+               f->basename = g_strdup(basename);
+       else
+               f->basename = g_path_get_basename(filename);
        f->usage = usage;
        f->orig_filemode = orig_filemode;
        
@@ -50,8 +55,8 @@ fileref_close_common(frefid_t fref)
                fref->disprock.ptr = NULL;
        }
        
-       if(fref->filename)
-               g_free(fref->filename);
+       g_free(fref->filename);
+       g_free(fref->basename);
        
        fref->magic = MAGIC_FREE;
        g_free(fref);
@@ -147,7 +152,8 @@ glk_fileref_create_temp(glui32 usage, glui32 rock)
                return NULL;
        }
        
-       frefid_t f = fileref_new(filename, rock, usage, filemode_Write);
+       /* Pass a basename of "" to ensure that this file can't be repurposed */
+       frefid_t f = fileref_new(filename, "", rock, usage, filemode_Write);
        g_free(filename);
        return f;
 }
@@ -261,6 +267,48 @@ glk_fileref_create_by_prompt(glui32 usage, glui32 fmode, glui32 rock)
                        return NULL;
        }
        
+       /* Set up a file filter with suggested extensions */
+       GtkFileFilter *filter = gtk_file_filter_new();
+       switch(usage & fileusage_TypeMask)
+       {
+               case fileusage_Data:
+                       gtk_file_filter_set_name(filter, _("Data files (*.glkdata)"));
+                       gtk_file_filter_add_pattern(filter, "*.glkdata");
+                       break;
+               case fileusage_SavedGame:
+                       gtk_file_filter_set_name(filter, _("Saved games (*.glksave)"));
+                       gtk_file_filter_add_pattern(filter, "*.glksave");
+                       break;
+               case fileusage_InputRecord:
+                       gtk_file_filter_set_name(filter, _("Text files (*.txt)"));
+                       gtk_file_filter_add_pattern(filter, "*.txt");
+                       break;
+               case fileusage_Transcript:
+                       gtk_file_filter_set_name(filter, _("Transcript files (*.txt)"));
+                       gtk_file_filter_add_pattern(filter, "*.txt");
+                       break;
+               default:
+                       ILLEGAL_PARAM("Unknown file usage: %u", usage);
+                       gdk_threads_leave();
+                       return NULL;
+       }
+       gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(chooser), filter);
+
+       /* Add a "text mode" filter for text files */
+       if((usage & fileusage_TypeMask) == fileusage_InputRecord || (usage & fileusage_TypeMask) == fileusage_Transcript)
+       {
+               filter = gtk_file_filter_new();
+               gtk_file_filter_set_name(filter, _("All text files"));
+               gtk_file_filter_add_mime_type(filter, "text/plain");
+               gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(chooser), filter);
+       }
+
+       /* Add another non-restricted filter */
+       filter = gtk_file_filter_new();
+       gtk_file_filter_set_name(filter, _("All files"));
+       gtk_file_filter_add_pattern(filter, "*");
+       gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(chooser), filter);
+
        if(glk_data->current_dir)
                gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser), glk_data->current_dir);
        
@@ -271,7 +319,7 @@ glk_fileref_create_by_prompt(glui32 usage, glui32 fmode, glui32 rock)
                return NULL;
        }
        gchar *filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(chooser) );
-       frefid_t f = fileref_new(filename, rock, usage, fmode);
+       frefid_t f = fileref_new(filename, NULL, rock, usage, fmode);
        g_free(filename);
        gtk_widget_destroy(chooser);
 
@@ -391,8 +439,47 @@ glk_fileref_create_by_name(glui32 usage, char *name, glui32 rock)
        ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
        
        /* Do any string-munging here to remove illegal Latin-1 characters from 
-       filename. On ext3, the only illegal characters are '/' and '\0'. */
-       g_strdelimit(name, "/", '_');
+       filename. On ext3, the only illegal characters are '/' and '\0', but the Glk
+       spec calls for removing any other tricky characters. */
+       char *buf = g_malloc(strlen(name));
+       char *ptr, *filename, *extension;
+       int len;
+       for(ptr = name, len = 0; *ptr && *ptr != '.'; ptr++)
+       {
+               switch(*ptr)
+               {
+                       case '"': case '\\': case '/': case '>': case '<':
+                       case ':': case '|':     case '?': case '*':
+                               break;
+                       default:
+                               buf[len++] = *ptr;
+               }
+       }
+       buf[len] = '\0';
+
+       /* If there is nothing left, make the name "null" */
+       if(len == 0) {
+               strcpy(buf, "null");
+               len = strlen(buf);
+       }
+
+       switch(usage & fileusage_TypeMask)
+       {
+               case fileusage_Data:
+                       extension = ".glkdata";
+                       break;
+               case fileusage_SavedGame:
+                       extension = ".glksave";
+                       break;
+               case fileusage_InputRecord:
+               case fileusage_Transcript:
+                       extension = ".txt";
+                       break;
+               default:
+                       ILLEGAL_PARAM("Unknown file usage: %u", usage);
+                       return NULL;
+       }
+       filename = g_strconcat(buf, extension, NULL);
        
        /* Find out what encoding filenames are in */
        const gchar **charsets; /* Do not free */
@@ -400,8 +487,7 @@ glk_fileref_create_by_name(glui32 usage, char *name, glui32 rock)
 
        /* Convert name to that encoding */
        GError *error = NULL;
-       gchar *osname = g_convert(name, -1, charsets[0], "ISO-8859-1", NULL, NULL,
-               &error);
+       char *osname = g_convert(filename, -1, charsets[0], "ISO-8859-1", NULL, NULL, &error);
        if(osname == NULL)
        {
                WARNING_S("Error during latin1->filename conversion", error->message);
@@ -415,8 +501,9 @@ glk_fileref_create_by_name(glui32 usage, char *name, glui32 rock)
                path = g_strdup(osname);
        g_free(osname);
        
-       frefid_t f = fileref_new(path, rock, usage, filemode_ReadWrite);
+       frefid_t f = fileref_new(path, buf, rock, usage, filemode_ReadWrite);
        g_free(path);
+       g_free(buf);
        return f;
 }
 
@@ -455,7 +542,7 @@ frefid_t
 glk_fileref_create_from_fileref(glui32 usage, frefid_t fref, glui32 rock)
 {
        VALID_FILEREF(fref, return NULL);
-       return fileref_new(fref->filename, rock, usage, fref->orig_filemode);
+       return fileref_new(fref->filename, fref->basename, rock, usage, fref->orig_filemode);
 }
 
 /**
index c2d8f4666b2124e94f860804a8f96dac3e39a982..03ab4fe94fcd99c5cc98f8eb7ba1da9c0af3aca7 100644 (file)
@@ -22,10 +22,11 @@ struct glk_fileref_struct
        /* Fileref parameters */
        gchar *filename; /* Always stored in the default filename encoding, not
                UTF8 or Latin-1 */
+       char *basename; /* Name from which real filename was derived */
        glui32 orig_filemode; /* Used to check if the user gets a fileref in read
                mode and then tries to open it in write mode */
        glui32 usage;
 };
 
-G_GNUC_INTERNAL frefid_t fileref_new(gchar *filename, glui32 rock, glui32 usage, glui32 orig_filemode);
+G_GNUC_INTERNAL frefid_t fileref_new(char *filename, char *basename, glui32 rock, glui32 usage, glui32 orig_filemode);
 #endif
index 55ff57c797bd210340c8189db253213a0d7f2288..1dad9d94bf8c173b62f6ff906691f159e565ee70 100644 (file)
@@ -123,6 +123,7 @@ glk_gestalt_ext(glui32 sel, glui32 val, glui32 *arr, glui32 arrlen)
                case gestalt_UnicodeNorm:
                case gestalt_LineInputEcho:
                case gestalt_LineTerminators:
+               case gestalt_ResourceStream:
                        return 1;
 
                /* Capabilities supported if compiled with GStreamer */
@@ -138,8 +139,7 @@ glk_gestalt_ext(glui32 sel, glui32 val, glui32 *arr, glui32 arrlen)
 #endif
                        
                /* Unsupported capabilities */
-               case gestalt_ResourceStream:
-                       return 0;
+                       /* None! */
 
                /* Selector not supported */    
                default:
index 284fc1cd19f74f8f5df9ba622e4feaf26af68a83..ddaf84806c2bed15a65252bab4e9a83c0d4f0164 100644 (file)
@@ -36,7 +36,7 @@ glkunix_stream_open_pathname_gen(char *pathname, glui32 writemode, glui32 textmo
        g_return_val_if_fail(pathname, NULL);
        g_return_val_if_fail(strlen(pathname) > 0, NULL);
 
-       frefid_t fileref = fileref_new(pathname, rock,
+       frefid_t fileref = fileref_new(pathname, NULL, rock,
                textmode? fileusage_TextMode : fileusage_BinaryMode,
                writemode? filemode_Write : filemode_Read);
        return file_stream_new(fileref, writemode? filemode_Write : filemode_Read, rock, FALSE);
@@ -67,7 +67,7 @@ glkunix_stream_open_pathname(char *pathname, glui32 textmode, glui32 rock)
        g_return_val_if_fail(pathname, NULL);
        g_return_val_if_fail(strlen(pathname) > 0, NULL);
 
-       frefid_t fileref = fileref_new(pathname, rock, textmode? fileusage_TextMode : fileusage_BinaryMode, filemode_Read);
+       frefid_t fileref = fileref_new(pathname, NULL, rock, textmode? fileusage_TextMode : fileusage_BinaryMode, filemode_Read);
        return file_stream_new(fileref, filemode_Read, rock, FALSE);
 }
 
@@ -190,4 +190,4 @@ parse_command_line(glkunix_argumentlist_t glkunix_arguments[], int argc, char *a
        g_slist_free(arglist);
        
        return TRUE;
-}
\ No newline at end of file
+}
index f9a6cf5bf4cea649c405ff7382dc8a5767276707..0b1e2d8952c8fe34c0d638fe1094a4aba0ed1e28 100644 (file)
@@ -1,10 +1,13 @@
+#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;
@@ -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;
index 7ff7618c61ef44dc78a75ebc1b60033f45c81718..33497ceb2d11f36b17cc1afedde5b59cc66fe7e4 100644 (file)
@@ -12,7 +12,8 @@ enum StreamType
 {
        STREAM_TYPE_WINDOW,
        STREAM_TYPE_MEMORY,
-       STREAM_TYPE_FILE
+       STREAM_TYPE_FILE,
+       STREAM_TYPE_RESOURCE
 };
 
 /**
@@ -36,18 +37,20 @@ struct glk_stream_struct
        enum StreamType type;
        /* Specific to window stream: the window this stream is connected to */
        winid_t window;
-       /* For memory and file streams */
+       /* For memory, file, and resource streams */
        gboolean unicode;
-       /* Specific to memory streams */
-       gchar *buffer;
+       /* For file and resource streams */
+       gboolean binary;
+       /* For memory and resource streams */
+       char *buffer;
        glui32 *ubuffer;
        glui32 mark;
        glui32 endmark;
        glui32 buflen;
+       /* Specific to memory streams */
        gidispatch_rock_t buffer_rock;
        /* Specific to file streams */
        FILE *file_pointer;
-       gboolean binary;
        gchar *filename; /* Displayable filename in UTF-8 for error handling */
        glui32 lastop; /* 0, filemode_Write, or filemode_Read */
 
index 41146f24fd6613bb159cc7d653093bcbaf5f5835..d8dda82a00627d273e705ffd8cf3e0ec2ed0fbf0 100644 (file)
@@ -1,3 +1,4 @@
+#include <config.h>
 #include "charset.h"
 #include "magic.h"
 #include "stream.h"
@@ -6,6 +7,7 @@
 #include <string.h>
 #include <glib.h>
 #include <glib/gstdio.h>
+#include <glib/gi18n-lib.h>
 
 /* Internal function: ensure that an fseek() is called on a file pointer in
  between reading and writing operations, and vice versa. This will only come up
@@ -346,6 +348,9 @@ write_buffer_to_stream(strid_t str, gchar *buf, glui32 len)
                        
                        str->write_count += len;
                        break;
+               case STREAM_TYPE_RESOURCE:
+                       ILLEGAL(_("Writing to a resource stream is illegal."));
+                       break;
                default:
                        ILLEGAL_PARAM("Unknown stream type: %u", str->type);
        }
@@ -444,6 +449,9 @@ write_buffer_to_stream_uni(strid_t str, glui32 *buf, glui32 len)
                        
                        str->write_count += len;
                        break;
+               case STREAM_TYPE_RESOURCE:
+                       ILLEGAL(_("Writing to a resource stream is illegal."));
+                       break;
                default:
                        ILLEGAL_PARAM("Unknown stream type: %u", str->type);
        }
@@ -623,6 +631,58 @@ read_utf8_char_from_file(strid_t str)
        return charresult;
 }
 
+/* Internal function: Read one UTF-8 character, which may be more than one byte,
+from a memory stream @str, and return it as a Unicode code point. */
+static glsi32
+read_utf8_char_from_buffer(strid_t str)
+{
+       size_t foo;
+       gunichar charresult = (gunichar)-2;
+       char *buffer = str->buffer + str->mark;
+       size_t maxlen = str->buflen - str->mark;
+
+       if(maxlen == 0)
+               return -1;
+
+       for(foo = 1; foo <= maxlen; foo++)
+       {
+               charresult = g_utf8_get_char_validated(buffer, foo);
+               /* charresult is -1 if invalid, -2 if incomplete, and the
+               Unicode code point otherwise */
+               if(charresult != (gunichar)-2)
+                       break;
+       }
+       str->mark += foo;
+       str->read_count++;
+
+       /* Return -1 on EOS */
+       if(charresult == (gunichar)-2)
+               return -1;
+       /* Silently return unknown characters as 0xFFFD, Replacement Character */
+       if(charresult == (gunichar)-1)
+               return 0xFFFD;
+       return charresult;
+}
+
+/* Internal function: Read one big-endian four-byte character from memory and
+return it as a Unicode code point, or -1 on EOF */
+static glsi32
+read_ucs4be_char_from_buffer(strid_t str)
+{
+       glui32 ch = str->buffer[str->mark++];
+       if(str->mark >= str->buflen)
+               return -1;
+       ch = (ch << 8) | (str->buffer[str->mark++] & 0xFF);
+       if(str->mark >= str->buflen)
+               return -1;
+       ch = (ch << 8) | (str->buffer[str->mark++] & 0xFF);
+       if(str->mark >= str->buflen)
+               return -1;
+       ch = (ch << 8) | (str->buffer[str->mark++] & 0xFF);
+       str->read_count++;
+       return ch;
+}
+
 /* Internal function: Tell whether this code point is a Unicode newline. The
 file pointer and eight-bit flag are included in case the newline is a CR 
 (U+000D). If the next character is LF (U+000A) then it also belongs to the
@@ -653,6 +713,18 @@ get_char_stream_common(strid_t str)
 {
        switch(str->type)
        {
+               case STREAM_TYPE_RESOURCE:
+                       if(str->unicode)
+                       {
+                               if(!str->buffer || str->mark >= str->buflen)
+                                       return -1;
+                               if(str->binary)
+                                       /* Cheap big-endian stream */
+                                       return read_ucs4be_char_from_buffer(str);
+                               /* slightly less cheap UTF8 stream */
+                               return read_utf8_char_from_buffer(str);
+                       }
+                       /* for text streams, fall through to memory case */
                case STREAM_TYPE_MEMORY:
                        if(str->unicode)
                        {
@@ -785,6 +857,24 @@ glk_get_buffer_stream(strid_t str, char *buf, glui32 len)
        
        switch(str->type)
        {
+               case STREAM_TYPE_RESOURCE:
+               {
+                       int copycount = 0;
+                       if(str->unicode)
+                       {
+                               while(copycount < len && str->buffer && str->mark < str->buflen)
+                               {
+                                       glui32 ch;
+                                       if(str->binary)
+                                               ch = read_ucs4be_char_from_buffer(str);
+                                       else
+                                               ch = read_utf8_char_from_buffer(str);
+                                       buf[copycount++] = (ch > 0xFF)? '?' : (char)ch;
+                               }
+                               return copycount;
+                       }
+                       /* for text streams, fall through to memory case */
+               }
                case STREAM_TYPE_MEMORY:
                {
                        int copycount = 0;
@@ -884,6 +974,24 @@ glk_get_buffer_stream_uni(strid_t str, glui32 *buf, glui32 len)
        
        switch(str->type)
        {
+               case STREAM_TYPE_RESOURCE:
+               {
+                       int copycount = 0;
+                       if(str->unicode)
+                       {
+                               while(copycount < len && str->buffer && str->mark < str->buflen)
+                               {
+                                       glui32 ch;
+                                       if(str->binary)
+                                               ch = read_ucs4be_char_from_buffer(str);
+                                       else
+                                               ch = read_utf8_char_from_buffer(str);
+                                       buf[copycount++] = ch;
+                               }
+                               return copycount;
+                       }
+                       /* for text streams, fall through to memory case */
+               }
                case STREAM_TYPE_MEMORY:
                {
                        int copycount = 0;
@@ -992,6 +1100,40 @@ glk_get_line_stream(strid_t str, char *buf, glui32 len)
 
        switch(str->type)
        {
+               case STREAM_TYPE_RESOURCE:
+               {
+                       int copycount = 0;
+                       if(str->unicode)
+                       {
+                               /* Do it character-by-character */
+                               while(copycount < len - 1 && str->buffer && str->mark < str->buflen)
+                               {
+                                       glsi32 ch;
+                                       if(str->binary)
+                                               ch = read_ucs4be_char_from_buffer(str);
+                                       else
+                                               ch = read_utf8_char_from_buffer(str);
+                                       /* Check for Unicode newline; slightly different than
+                                       in file streams */
+                                       if(ch == 0x0A || ch == 0x85 || ch == 0x0C || ch == 0x2028 || ch == 0x2029)
+                                       {
+                                               buf[copycount++] = '\n';
+                                               break;
+                                       }
+                                       if(ch == 0x0D)
+                                       {
+                                               if(str->buffer[str->mark] == 0x0A)
+                                                       str->mark++; /* skip past next newline */
+                                               buf[copycount++] = '\n';
+                                               break;
+                                       }
+                                       buf[copycount++] = (ch > 0xFF)? '?' : (char)ch;
+                               }
+                               buf[copycount] = '\0';
+                               return copycount;
+                       }
+                       /* for text streams, fall through to the memory case */
+               }
                case STREAM_TYPE_MEMORY:
                {
                        int copycount = 0;
@@ -1129,6 +1271,40 @@ glk_get_line_stream_uni(strid_t str, glui32 *buf, glui32 len)
 
        switch(str->type)
        {
+               case STREAM_TYPE_RESOURCE:
+               {
+                       int copycount = 0;
+                       if(str->unicode)
+                       {
+                               /* Do it character-by-character */
+                               while(copycount < len - 1 && str->buffer && str->mark < str->buflen) 
+                               {
+                                       glsi32 ch;
+                                       if(str->binary)
+                                               ch = read_ucs4be_char_from_buffer(str);
+                                       else
+                                               ch = read_utf8_char_from_buffer(str);
+                                       /* Check for Unicode newline; slightly different than
+                                       in file streams */
+                                       if(ch == 0x0A || ch == 0x85 || ch == 0x0C || ch == 0x2028 || ch == 0x2029)
+                                       {
+                                               buf[copycount++] = '\n';
+                                               break;
+                                       }
+                                       if(ch == 0x0D)
+                                       {
+                                               if(str->ubuffer[str->mark] == 0x0A)
+                                                       str->mark++; /* skip past next newline */
+                                               buf[copycount++] = '\n';
+                                               break;
+                                       }
+                                       buf[copycount++] = ch;
+                               }
+                               buf[copycount] = '\0';
+                               return copycount;
+                       }
+                       /* for text streams, fall through to the memory case */
+               }
                case STREAM_TYPE_MEMORY:
                {
                        int copycount = 0;
@@ -1297,6 +1473,7 @@ glk_stream_get_position(strid_t str)
        switch(str->type)
        {
                case STREAM_TYPE_MEMORY:
+               case STREAM_TYPE_RESOURCE:
                        return str->mark;
                case STREAM_TYPE_FILE:
                        return ftell(str->file_pointer);
@@ -1346,6 +1523,7 @@ glk_stream_set_position(strid_t str, glsi32 pos, glui32 seekmode)
        
        switch(str->type)
        {
+               case STREAM_TYPE_RESOURCE:
                case STREAM_TYPE_MEMORY:
                        switch(seekmode)
                        {
index 7f0b40e98a4109ce7429cee79bf6e7480000d3c7..91f66cec99c6fba127d4b56b3a38dc8f5d65c9ad 100644 (file)
Binary files a/tests/externalfile.ulx and b/tests/externalfile.ulx differ
index 264de510b067ebc6b772ce904dad126bfb5e5502..1cb21a434181fb5146d4b444dfd9eaf176e5bccf 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <interface>
-  <!-- interface-requires gtk+ 2.12 -->
+  <requires lib="gtk+" version="2.16"/>
   <!-- interface-naming-policy project-wide -->
   <object class="GtkWindow" id="window">
     <property name="border_width">6</property>
         <col id="0" translatable="yes">MemStreamTest</col>
         <col id="1">memstreamtest.ulx</col>
       </row>
+      <row>
+        <col id="0" translatable="yes">ResStreamTest</col>
+        <col id="1">resstreamtest.gblorb</col>
+      </row>
       <row>
         <col id="0" translatable="yes">UniCaseTest</col>
         <col id="1">unicasetest.ulx</col>
diff --git a/tests/resstreamtest.gblorb b/tests/resstreamtest.gblorb
new file mode 100644 (file)
index 0000000..123c0ac
Binary files /dev/null and b/tests/resstreamtest.gblorb differ