Commit 9af8b832 authored by Tor Lillqvist's avatar Tor Lillqvist

Add GWin32InputStream and GWin32OutputStream classes

Correspond to GUnixInputStream and GUnixOutputStream. No true async
support though. But that is how the Win32 API is, for files not
explicitly opened for so-called overlapped IO.

The API to create these streams takes Win32 HANDLEs. Not file
descriptors, because file descriptors are specific to the C library
used. The user code and GLib might be using different C libraries.

Also add a test program for the new classes, and a gio-windows-2.0.pc
file.
parent 48cd4cbb
......@@ -53,6 +53,7 @@ EXTRA_DIST += \
gthread-2.0.pc.in \
gio-2.0.pc.in \
gio-unix-2.0.pc.in \
gio-windows-2.0.pc.in \
glib-2.0-uninstalled.pc.in \
gobject-2.0-uninstalled.pc.in \
gmodule-2.0-uninstalled.pc.in \
......@@ -108,6 +109,10 @@ if OS_UNIX
pkgconfig_DATA += gio-unix-2.0.pc
endif
if OS_WIN32
pkgconfig_DATA += gio-windows-2.0.pc
endif
$(pkgconfig_DATA): config.status
# install mkinstalldirs for glib-gettextize's benefit
......
......@@ -204,6 +204,10 @@ copy ..\..\..\gio\gvolumemonitor.h $(OutDir)\include\glib-2.0\gio

copy ..\..\..\gio\gzlibcompressor.h $(OutDir)\include\glib-2.0\gio

copy ..\..\..\gio\gzlibdecompressor.h $(OutDir)\include\glib-2.0\gio

mkdir $(OutDir)\include\gio-win32-2.0\gio

copy ..\..\..\gio\gwin32inputstream.h $(OutDir)\include\gio-win32-2.0\gio

copy ..\..\..\gio\gwin32outputstream.h $(OutDir)\include\gio-win32-2.0\gio

mkdir $(OutDir)\lib\glib-2.0\include

copy ..\..\..\glibconfig.h $(OutDir)\lib\glib-2.0\include

......
......@@ -3510,6 +3510,7 @@ gobject-2.0.pc
gobject-2.0-uninstalled.pc
gio-2.0.pc
gio-unix-2.0.pc
gio-windows-2.0.pc
gio-2.0-uninstalled.pc
gio-unix-2.0-uninstalled.pc
glib-zip
......
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: GIO Windows specific APIs
Description: Windows specific headers for glib I/O library
Version: @VERSION@
Requires: gobject-2.0,gmodule-no-export-2.0,gio-2.0
Libs: -L${libdir} -lgio-2.0
Cflags: -I${includedir}/gio-win32-2.0/
......@@ -202,6 +202,15 @@ win32_sources = \
gwin32resolver.h \
gwin32volumemonitor.c \
gwin32volumemonitor.h \
gwin32inputstream.c \
gwin32outputstream.c \
gwin32outputstream.h \
$(NULL)
giowin32includedir=$(includedir)/gio-win32-2.0/gio
giowin32include_HEADERS = \
gwin32inputstream.h \
gwin32outputstream.h \
$(NULL)
endif
......@@ -509,7 +518,7 @@ dist-hook: $(BUILT_EXTRA_DIST) ../build/win32/vs9/gio.vcproj
cp $$d/$$f $(distdir) || exit 1; done
../build/win32/vs9/gio.vcproj: $(top_srcdir)/build/win32/vs9/gio.vcprojin
for F in $(libgio_2_0_la_SOURCES); do \
for F in $(libgio_2_0_la_SOURCES) $(win32_sources); do \
case $$F in \
*.c) echo ' <File RelativePath="..\..\..\gio\'$$F'" />' \
;; \
......
......@@ -611,6 +611,9 @@ g_io_stream_clear_pending
#if IN_FILE(__G_IO_ERROR_C__)
g_io_error_quark
g_io_error_from_errno
#ifdef G_OS_WIN32
g_io_error_from_win32_error
#endif
#endif
#endif
......@@ -827,6 +830,30 @@ g_unix_output_stream_get_fd
#endif
#endif
#if IN_HEADER(__G_WIN32_INPUT_STREAM_H__)
#if IN_FILE(__G_WIN32_INPUT_STREAM_C__)
#ifdef G_OS_WIN32
g_win32_input_stream_get_type G_GNUC_CONST
g_win32_input_stream_new
g_win32_input_stream_set_close_handle
g_win32_input_stream_get_close_handle
g_win32_input_stream_get_handle
#endif /* G_OS_WIN32 */
#endif
#endif
#if IN_HEADER(__G_WIN32_OUTPUT_STREAM_H__)
#if IN_FILE(__G_WIN32_OUTPUT_STREAM_C__)
#ifdef G_OS_WIN32
g_win32_output_stream_get_type G_GNUC_CONST
g_win32_output_stream_new
g_win32_output_stream_set_close_handle
g_win32_output_stream_get_close_handle
g_win32_output_stream_get_handle
#endif /* G_OS_WIN32 */
#endif
#endif
#if IN_HEADER(__G_MOUNT_H__)
#if IN_FILE(__G_MOUNT_C__)
g_mount_get_type G_GNUC_CONST
......
......@@ -206,5 +206,32 @@ g_io_error_from_errno (gint err_no)
}
}
#ifdef G_OS_WIN32
/**
* g_io_error_from_win32_error:
* @error_code: Windows error number.
*
* Converts some common error codes into GIO error codes. The
* fallback value G_IO_ERROR_FAILED is returned for error codes not
* handled.
*
* Returns: #GIOErrorEnum value for the given error number.
*
* Since: 2.26
**/
GIOErrorEnum
g_io_error_from_win32_error (gint error_code)
{
switch (error_code)
{
default:
return G_IO_ERROR_FAILED;
break;
}
}
#endif
#define __G_IO_ERROR_C__
#include "gioaliasdef.c"
......@@ -43,6 +43,10 @@ G_BEGIN_DECLS
GQuark g_io_error_quark (void);
GIOErrorEnum g_io_error_from_errno (gint err_no);
#ifdef G_OS_WIN32
GIOErrorEnum g_io_error_from_win32_error (gint error_code);
#endif
G_END_DECLS
#endif /* __G_IO_ERROR_H__ */
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2006-2010 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* Author: Alexander Larsson <alexl@redhat.com>
* Author: Tor Lillqvist <tml@iki.fi>
*/
#include "config.h"
#include <windows.h>
#include <io.h>
#include <glib.h>
#include "gioerror.h"
#include "gsimpleasyncresult.h"
#include "gwin32inputstream.h"
#include "gcancellable.h"
#include "gasynchelper.h"
#include "glibintl.h"
#include "gioalias.h"
/**
* SECTION:gwin32inputstream
* @short_description: Streaming input operations for Windows file handles
* @include: gio/gwin32inputstream.h
* @see_also: #GInputStream
*
* #GWin32InputStream implements #GInputStream for reading from a
* Windows file handle.
*
* Note that <filename>&lt;gio/gwin32inputstream.h&gt;</filename> belongs
* to the Windows-specific GIO interfaces, thus you have to use the
* <filename>gio-windows-2.0.pc</filename> pkg-config file when using it.
*/
enum {
PROP_0,
PROP_HANDLE,
PROP_CLOSE_HANDLE
};
G_DEFINE_TYPE (GWin32InputStream, g_win32_input_stream, G_TYPE_INPUT_STREAM);
struct _GWin32InputStreamPrivate {
HANDLE handle;
gboolean close_handle;
};
static void g_win32_input_stream_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void g_win32_input_stream_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static gssize g_win32_input_stream_read (GInputStream *stream,
void *buffer,
gsize count,
GCancellable *cancellable,
GError **error);
static gboolean g_win32_input_stream_close (GInputStream *stream,
GCancellable *cancellable,
GError **error);
static void
g_win32_input_stream_finalize (GObject *object)
{
G_OBJECT_CLASS (g_win32_input_stream_parent_class)->finalize (object);
}
static void
g_win32_input_stream_class_init (GWin32InputStreamClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
g_type_class_add_private (klass, sizeof (GWin32InputStreamPrivate));
gobject_class->get_property = g_win32_input_stream_get_property;
gobject_class->set_property = g_win32_input_stream_set_property;
gobject_class->finalize = g_win32_input_stream_finalize;
stream_class->read_fn = g_win32_input_stream_read;
stream_class->close_fn = g_win32_input_stream_close;
/**
* GWin32InputStream:handle:
*
* The handle that the stream reads from.
*
* Since: 2.26
*/
g_object_class_install_property (gobject_class,
PROP_HANDLE,
g_param_spec_pointer ("handle",
P_("File handle"),
P_("The file handle to read from"),
G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
/**
* GWin32InputStream:close-handle:
*
* Whether to close the file handle when the stream is closed.
*
* Since: 2.26
*/
g_object_class_install_property (gobject_class,
PROP_CLOSE_HANDLE,
g_param_spec_boolean ("close-handle",
P_("Close file handle"),
P_("Whether to close the file handle when the stream is closed"),
TRUE,
G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
}
static void
g_win32_input_stream_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GWin32InputStream *win32_stream;
win32_stream = G_WIN32_INPUT_STREAM (object);
switch (prop_id)
{
case PROP_HANDLE:
win32_stream->priv->handle = g_value_get_pointer (value);
break;
case PROP_CLOSE_HANDLE:
win32_stream->priv->close_handle = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
g_win32_input_stream_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GWin32InputStream *win32_stream;
win32_stream = G_WIN32_INPUT_STREAM (object);
switch (prop_id)
{
case PROP_HANDLE:
g_value_set_pointer (value, win32_stream->priv->handle);
break;
case PROP_CLOSE_HANDLE:
g_value_set_boolean (value, win32_stream->priv->close_handle);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
g_win32_input_stream_init (GWin32InputStream *win32_stream)
{
win32_stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (win32_stream,
G_TYPE_WIN32_INPUT_STREAM,
GWin32InputStreamPrivate);
win32_stream->priv->handle = NULL;
win32_stream->priv->close_handle = TRUE;
}
/**
* g_win32_input_stream_new:
* @handle: a Win32 file handle
* @close_fd: %TRUE to close the handle when done
*
* Creates a new #GWin32InputStream for the given @fd.
*
* If @close_handle is %TRUE, the handle will be closed
* when the stream is closed.
*
* Note that "handle" here means a Win32 HANDLE, not a "file descriptor"
* as used in the Windows C libraries.
*
* Returns: a new #GWin32InputStream
**/
GInputStream *
g_win32_input_stream_new (void *handle,
gboolean close_handle)
{
GWin32InputStream *stream;
g_return_val_if_fail (handle != NULL, NULL);
stream = g_object_new (G_TYPE_WIN32_INPUT_STREAM,
"handle", handle,
"close-handle", close_handle,
NULL);
return G_INPUT_STREAM (stream);
}
/**
* g_win32_input_stream_set_close_handle:
* @stream: a #GWin32InputStream
* @close_handle: %TRUE to close the handle when done
*
* Sets whether the handle of @stream shall be closed
* when the stream is closed.
*
* Since: 2.26
*/
void
g_win32_input_stream_set_close_handle (GWin32InputStream *stream,
gboolean close_handle)
{
g_return_if_fail (G_IS_WIN32_INPUT_STREAM (stream));
close_handle = close_handle != FALSE;
if (stream->priv->close_handle != close_handle)
{
stream->priv->close_handle = close_handle;
g_object_notify (G_OBJECT (stream), "close-handle");
}
}
/**
* g_win32_input_stream_get_close_handle:
* @stream: a #GWin32InputStream
*
* Returns whether the handle of @stream will be
* closed when the stream is closed.
*
* Return value: %TRUE if the handle is closed when done
*
* Since: 2.26
*/
gboolean
g_win32_input_stream_get_close_handle (GWin32InputStream *stream)
{
g_return_val_if_fail (G_IS_WIN32_INPUT_STREAM (stream), FALSE);
return stream->priv->close_handle;
}
/**
* g_win32_input_stream_get_handle:
* @stream: a #GWin32InputStream
*
* Return the Windows file handle that the stream reads from.
*
* Return value: The file handle of @stream
*
* Since: 2.26
*/
void *
g_win32_input_stream_get_handle (GWin32InputStream *stream)
{
g_return_val_if_fail (G_IS_WIN32_INPUT_STREAM (stream), NULL);
return stream->priv->handle;
}
static gssize
g_win32_input_stream_read (GInputStream *stream,
void *buffer,
gsize count,
GCancellable *cancellable,
GError **error)
{
GWin32InputStream *win32_stream;
BOOL res;
DWORD nbytes, nread;
win32_stream = G_WIN32_INPUT_STREAM (stream);
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return -1;
if (count > G_MAXINT)
nbytes = G_MAXINT;
else
nbytes = count;
res = ReadFile (win32_stream->priv->handle, buffer, nbytes, &nread, NULL);
if (!res)
{
int errsv = GetLastError ();
gchar *emsg;
if (errsv == ERROR_HANDLE_EOF ||
errsv == ERROR_BROKEN_PIPE)
return 0;
emsg = g_win32_error_message (errsv);
g_set_error (error, G_IO_ERROR,
g_io_error_from_win32_error (errsv),
_("Error reading from handle: %s"),
emsg);
g_free (emsg);
return -1;
}
return nread;
}
static gboolean
g_win32_input_stream_close (GInputStream *stream,
GCancellable *cancellable,
GError **error)
{
GWin32InputStream *win32_stream;
BOOL res;
win32_stream = G_WIN32_INPUT_STREAM (stream);
if (!win32_stream->priv->close_handle)
return TRUE;
res = CloseHandle (win32_stream->priv->handle);
if (!res)
{
int errsv = GetLastError ();
gchar *emsg = g_win32_error_message (errsv);
g_set_error (error, G_IO_ERROR,
g_io_error_from_win32_error (errsv),
_("Error closing handle: %s"),
emsg);
g_free (emsg);
return FALSE;
}
return TRUE;
}
#define __G_WIN32_INPUT_STREAM_C__
#include "gioaliasdef.c"
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2006-2010 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* Author: Alexander Larsson <alexl@redhat.com>
* Author: Tor Lillqvist <tml@iki.fi>
*/
#ifndef __G_WIN32_INPUT_STREAM_H__
#define __G_WIN32_INPUT_STREAM_H__
#include <gio/gio.h>
G_BEGIN_DECLS
#define G_TYPE_WIN32_INPUT_STREAM (g_win32_input_stream_get_type ())
#define G_WIN32_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_WIN32_INPUT_STREAM, GWin32InputStream))
#define G_WIN32_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_WIN32_INPUT_STREAM, GWin32InputStreamClass))
#define G_IS_WIN32_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_WIN32_INPUT_STREAM))
#define G_IS_WIN32_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_WIN32_INPUT_STREAM))
#define G_WIN32_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_WIN32_INPUT_STREAM, GWin32InputStreamClass))
/**
* GWin32InputStream:
*
* Implements #GInputStream for reading from selectable Windows file handles
**/
typedef struct _GWin32InputStream GWin32InputStream;
typedef struct _GWin32InputStreamClass GWin32InputStreamClass;
typedef struct _GWin32InputStreamPrivate GWin32InputStreamPrivate;
struct _GWin32InputStream
{
GInputStream parent_instance;
/*< private >*/
GWin32InputStreamPrivate *priv;
};
struct _GWin32InputStreamClass
{
GInputStreamClass parent_class;
/*< private >*/
/* Padding for future expansion */
void (*_g_reserved1) (void);
void (*_g_reserved2) (void);
void (*_g_reserved3) (void);
void (*_g_reserved4) (void);
void (*_g_reserved5) (void);
};
GType g_win32_input_stream_get_type (void) G_GNUC_CONST;
GInputStream * g_win32_input_stream_new (void *handle,
gboolean close_handle);
void g_win32_input_stream_set_close_handle (GWin32InputStream *stream,
gboolean close_handle);
gboolean g_win32_input_stream_get_close_handle (GWin32InputStream *stream);
void *g_win32_input_stream_get_handle (GWin32InputStream *stream);
G_END_DECLS
#endif /* __G_WIN32_INPUT_STREAM_H__ */
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2006-2010 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* Author: Alexander Larsson <alexl@redhat.com>
* Author: Tor Lillqvist <tml@iki.fi>
*/
#include "config.h"
#include <windows.h>
#include <io.h>
#include <glib.h>
#include <glib/gstdio.h>
#include "gioerror.h"
#include "gwin32outputstream.h"
#include "gcancellable.h"
#include "gsimpleasyncresult.h"
#include "gasynchelper.h"
#include "glibintl.h"
#include "gioalias.h"
/**
* SECTION:gwin32outputstream
* @short_description: Streaming output operations for Windows file handles
* @include: gio/gwin32outputstream.h
* @see_also: #GOutputStream
*
* #GWin32OutputStream implements #GOutputStream for writing to a
* Windows file handle.
*
* Note that <filename>&lt;gio/gwin32outputstream.h&gt;</filename> belongs
* to the Windows-specific GIO interfaces, thus you have to use the
* <filename>gio-windows-2.0.pc</filename> pkg-config file when using it.
*/
enum {
PROP_0,
PROP_HANDLE,
PROP_CLOSE_HANDLE
};
G_DEFINE_TYPE (GWin32OutputStream, g_win32_output_stream, G_TYPE_OUTPUT_STREAM);
struct _GWin32OutputStreamPrivate {
HANDLE handle;
gboolean close_handle;
};
static void g_win32_output_stream_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void g_win32_output_stream_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static gssize g_win32_output_stream_write (GOutputStream *stream,
const void *buffer,
gsize count,
GCancellable *cancellable,
GError **error);
static gboolean g_win32_output_stream_close (GOutputStream *stream,
GCancellable *cancellable,
GError **error);
static void
g_win32_output_stream_finalize (GObject *object)
{
G_OBJECT_CLASS (g_win32_output_stream_parent_class)->finalize (object);
}
static void
g_win32_output_stream_class_init (GWin32OutputStreamClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass);
g_type_class_add_private (klass, sizeof (GWin32OutputStreamPrivate));
gobject_class->get_property = g_win32_output_stream_get_property;
gobject_class->set_property = g_win32_output_stream_set_property;
gobject_class->finalize = g_win32_output_stream_finalize;
stream_class->write_fn = g_win32_output_stream_write;
stream_class->close_fn = g_win32_output_stream_close;
/**
* GWin32OutputStream:handle:
*
* The file handle that the stream writes to.
*
* Since: 2.26
*/
g_object_class_install_property (gobject_class,
PROP_HANDLE,
g_param_spec_pointer ("handle",
P_("File handle"),
P_("The file handle to write to"),
G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
/**
* GWin32OutputStream:close-handle:
*
* Whether to close the file handle when the stream is closed.
*
* Since: 2.26
*/
g_object_class_install_property (gobject_class,
PROP_CLOSE_HANDLE,
g_param_spec_boolean ("close-handle",
P_("Close file handle"),
P_("Whether to close the file handle when the stream is closed"),
TRUE,
G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
}
static void
g_win32_output_stream_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GWin32OutputStream *win32_stream;
win32_stream = G_WIN32_OUTPUT_STREAM (object);
switch (prop_id)
{
case PROP_HANDLE:
win32_stream->priv->handle = g_value_get_pointer (value);
break;
case PROP_CLOSE_HANDLE:
win32_stream->priv->close_handle = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}