+/**
+ * glk_put_buffer:
+ * @buf: An array of characters in Latin-1 encoding.
+ * @len: Length of @buf.
+ *
+ * Prints a block of characters to the current stream. It is exactly equivalent
+ * to:
+ * |[
+ * for (i = 0; i < @len; i++)
+ * #glk_put_char(@buf[i]);
+ * ]|
+ * However, it may be more efficient.
+ */
+void
+glk_put_buffer(char *buf, glui32 len)
+{
+ VALID_STREAM(glk_data->current_stream, return);
+ glk_put_buffer_stream(glk_data->current_stream, buf, len);
+}
+
+/**
+ * glk_put_buffer_uni:
+ * @buf: An array of Unicode code points.
+ * @len: Length of @buf.
+ *
+ * Prints a block of Unicode characters to the current stream. It is equivalent
+ * to a series of glk_put_char_uni() calls.
+ */
+void
+glk_put_buffer_uni(glui32 *buf, glui32 len)
+{
+ VALID_STREAM(glk_data->current_stream, return);
+ glk_put_buffer_stream_uni(glk_data->current_stream, buf, len);
+}
+
+/**
+ * glk_stream_open_memory:
+ * @buf: An allocated buffer, or %NULL.
+ * @buflen: Length of @buf.
+ * @fmode: Mode in which the buffer will be opened. Must be one of
+ * #filemode_Read, #filemode_Write, or #filemode_ReadWrite.
+ * @rock: The new stream's rock value.
+ *
+ * Opens a stream which reads from or writes to a space in memory. @buf points
+ * to the buffer where output will be read from or written to. @buflen is the
+ * length of the buffer.
+ *
+ * Unicode values (characters greater than 255) cannot be written to the buffer.
+ * If you try, they will be stored as 0x3F (<code>"?"</code>) characters.
+ *
+ * Returns: the new stream, or %NULL on error.
+ */
+strid_t
+glk_stream_open_memory(char *buf, glui32 buflen, glui32 fmode, glui32 rock)
+{
+ g_return_val_if_fail(fmode != filemode_WriteAppend, NULL);
+
+ strid_t str = stream_new_common(rock, fmode, STREAM_TYPE_MEMORY);
+ str->buffer = buf;
+ str->mark = 0;
+ str->buflen = buflen;
+ str->unicode = FALSE;
+ return str;
+}
+
+/**
+ * glk_stream_open_memory_uni:
+ * @buf: An allocated buffer, or %NULL.
+ * @buflen: Length of @buf.
+ * @fmode: Mode in which the buffer will be opened. Must be one of
+ * #filemode_Read, #filemode_Write, or #filemode_ReadWrite.
+ * @rock: The new stream's rock value.
+ *
+ * Works just like glk_stream_open_memory(), except that the buffer is an array
+ * of 32-bit words, instead of bytes. This allows you to write and read any
+ * Unicode character. The @buflen is the number of words, not the number of
+ * bytes.
+ *
+ * Returns: the new stream, or %NULL on error.
+ */
+strid_t
+glk_stream_open_memory_uni(glui32 *buf, glui32 buflen, glui32 fmode, glui32 rock)
+{
+ g_return_val_if_fail(fmode != filemode_WriteAppend, NULL);
+
+ strid_t str = stream_new_common(rock, fmode, STREAM_TYPE_MEMORY);
+ str->ubuffer = buf;
+ str->mark = 0;
+ str->buflen = buflen;
+ str->unicode = TRUE;
+ return str;
+}
+
+/* Internal function: create a stream using the given parameters. */
+static strid_t
+file_stream_new(frefid_t fileref, glui32 fmode, glui32 rock, gboolean unicode)
+{
+ VALID_FILEREF(fileref, return NULL);
+
+ gchar *modestr;
+ /* Binary mode is 0x000, text mode 0x100 */
+ gboolean binary = !(fileref->usage & fileusage_TextMode);
+ switch(fmode)
+ {
+ case filemode_Read:
+ if(!g_file_test(fileref->filename, G_FILE_TEST_EXISTS)) {
+ ILLEGAL_PARAM("Tried to open a nonexistent file, '%s', in read mode", fileref->filename);
+ return NULL;