"Initial commit to Gerrit"
[profile/ivi/libgsf.git] / gsf-win32 / gsf-input-win32.c
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * gsf-input-win32.c:
4  *
5  * Copyright (C) 2003-2004 Dom Lachowicz <cinamod@hotmail.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of version 2.1 of the GNU Lesser General Public
9  * License as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
19  * USA
20  */
21
22 #include <gsf-config.h>
23 #include <gsf-win32/gsf-input-win32.h>
24 #include <gsf/gsf-input-impl.h>
25 #include <gsf/gsf-impl-utils.h>
26 #include <string.h>
27
28 struct _GsfInputIStream {
29         GsfInput input;
30         IStream * stream;
31         guint8   *buf;
32         size_t   buf_size;
33 };
34
35 typedef struct {
36         GsfInputClass input_class;
37 } GsfInputIStreamClass;
38
39 #define NEED_ISTREAM_MACROS
40
41 #ifdef NEED_ISTREAM_MACROS
42 #define IStream_AddRef(This) (This)->lpVtbl->AddRef(This)
43 #define IStream_Clone(This,ppstm) (This)->lpVtbl->Clone(This,ppstm)
44 #define IStream_Read(This,pv,cb,pcbRead) (This)->lpVtbl->Read(This,pv,cb,pcbRead)
45 #define IStream_Release(This) (This)->lpVtbl->Release(This)
46 #define IStream_Seek(This,dlibMove,dwOrigin,plibNewPosition) (This)->lpVtbl->Seek(This,dlibMove,dwOrigin,plibNewPosition)
47 #define IStream_Stat(This,pstatstg,grfStatFlag) (This)->lpVtbl->Stat(This,pstatstg,grfStatFlag)
48 #endif
49
50 gchar * gsf_win32_hresult_to_utf8 (HRESULT hr);
51
52 gchar *
53 gsf_win32_hresult_to_utf8 (HRESULT hr)
54 {
55         void * pMsgBuf;
56         gchar * utf8_msg;
57
58         if (SUCCEEDED (hr))
59                 return NULL;
60
61         FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr,
62                                         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&pMsgBuf, 0, NULL);
63
64         utf8_msg = g_locale_to_utf8 ((char const *)pMsgBuf, -1, NULL, NULL, NULL);
65         if (utf8_msg == NULL)
66                 utf8_msg = g_strdup ("!SUCCEEDED (hr)");
67
68         LocalFree(pMsgBuf);
69
70         return utf8_msg;
71 }
72
73 static void
74 hresult_to_gerror (HRESULT hr, GError ** err)
75 {
76         if (err) {
77                 gchar * msg;
78
79                 msg = gsf_win32_hresult_to_utf8 (hr);
80
81                 if (msg) {
82                         *err = g_error_new (gsf_input_error_id (), 0, msg);
83                         g_free (msg);
84                 }
85         }
86 }
87
88 static char *
89 lpwstr_to_utf8 (LPWSTR str)
90 {
91         if (str)
92                 return g_utf16_to_utf8 (str, -1, NULL, NULL, NULL);
93         return NULL;
94 }
95
96 /**
97  * gsf_input_istream_new :
98  * @stream   : IStream stream
99  * @err      : optionally %NULL.
100  *
101  * Returns: a new input object or %NULL.
102  **/
103 GsfInput *
104 gsf_input_istream_new (IStream * stream, GError **err)
105 {
106         GsfInputIStream *input;
107         STATSTG statbuf;
108         HRESULT hr;
109         char * name;
110
111         if (stream == NULL) {
112                 if (err != NULL)
113                         *err = g_error_new (gsf_input_error_id (), 0,
114                                             "stream is NULL");
115                 return NULL;
116         }
117
118         if (FAILED (hr = IStream_Stat (stream, &statbuf, STATFLAG_DEFAULT))) {
119                 hresult_to_gerror (hr, err);
120                 return NULL;
121         }
122
123         input = g_object_new (GSF_INPUT_ISTREAM_TYPE, NULL);
124         if (G_UNLIKELY (NULL == input)) {
125                 IStream_Release (stream);
126                 return NULL;
127         }
128
129         input->stream = stream;
130         input->buf  = NULL;
131         input->buf_size = 0;
132
133         IStream_AddRef (input->stream);
134
135         /* LowPart and HiPart are the low and high 32 bit UINT parts. The MSDN documentation
136            says to use QuadPart if your compiler supports 64 bit ints. gsf_off_t is a gint64 value.
137            http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winprog/winprog/large_integer_str.asp
138          */
139         gsf_input_set_size (GSF_INPUT (input), (gsf_off_t) statbuf.cbSize.QuadPart);
140
141         name = lpwstr_to_utf8 (statbuf.pwcsName);
142         if (name) {
143                 gsf_input_set_name (GSF_INPUT (input), name);
144                 g_free (name);
145         }
146
147         return GSF_INPUT(input);
148 }
149
150 static void
151 gsf_input_istream_finalize (GObject *obj)
152 {
153         GObjectClass *parent_class;
154         GsfInputIStream *input = (GsfInputIStream *)obj;
155
156         IStream_Release (input->stream);
157         input->stream = NULL;
158
159         if (input->buf != NULL) {
160                 g_free (input->buf);
161                 input->buf  = NULL;
162                 input->buf_size = 0;
163         }
164
165         parent_class = g_type_class_peek (GSF_INPUT_TYPE);
166         if (parent_class && parent_class->finalize)
167                 parent_class->finalize (obj);
168 }
169
170 static GsfInput *
171 gsf_input_istream_dup (GsfInput *src_input, GError **err)
172 {
173         GsfInputIStream const *src = (GsfInputIStream *)src_input;
174         GsfInput *dst;
175         HRESULT hr;
176         IStream * clone;
177
178         g_return_val_if_fail (src_input != NULL, NULL);
179         g_return_val_if_fail (src->stream != NULL, NULL);
180
181         if (SUCCEEDED (hr = IStream_Clone (src->stream, &clone))) {
182                 dst = gsf_input_istream_new (clone, NULL);
183                 IStream_Release (clone); /* gsf_input_istream_new() adds a ref */
184                 return dst;
185         }
186
187         hresult_to_gerror (hr, err);
188         return NULL;
189 }
190
191 static guint8 const *
192 gsf_input_istream_read (GsfInput *input, size_t num_bytes,
193                         guint8 *buffer)
194 {
195         GsfInputIStream *istm = GSF_INPUT_ISTREAM (input);
196         HRESULT hr;
197         ULONG nread, total_read = 0;
198
199         g_return_val_if_fail (istm != NULL, NULL);
200         g_return_val_if_fail (istm->stream != NULL, NULL);
201
202         if (buffer == NULL) {
203                 if (istm->buf_size < num_bytes) {
204                         istm->buf_size = num_bytes;
205                         g_free (istm->buf);
206                         istm->buf = g_new (guint8, istm->buf_size);
207                 }
208                 buffer = istm->buf;
209         }
210
211         while (1)
212             {
213                     hr = IStream_Read (istm->stream, (buffer + total_read), (ULONG)(num_bytes - total_read), &nread);
214
215                     if (SUCCEEDED (hr)) {
216                             total_read += nread;
217                             if ((size_t) total_read == num_bytes) {
218                                     return buffer;
219                             }
220                     } else
221                             break;
222             }
223
224         g_warning ("IStream read failed\n");
225         return NULL;
226 }
227
228 static gboolean
229 gsf_input_istream_seek (GsfInput *input, gsf_off_t offset, GSeekType whence)
230 {
231         GsfInputIStream *istm = GSF_INPUT_ISTREAM (input);
232         DWORD dwhence;
233
234         g_return_val_if_fail (istm != NULL, TRUE);
235         g_return_val_if_fail (istm->stream != NULL, TRUE);
236
237         switch (whence) {
238         case G_SEEK_SET :
239                 dwhence = STREAM_SEEK_SET;
240                 break;
241         case G_SEEK_CUR :
242                 dwhence = STREAM_SEEK_CUR;
243                 break;
244         case G_SEEK_END :
245                 dwhence = STREAM_SEEK_END;
246                 break;
247         default:
248                 return TRUE;
249         }
250
251         if(SUCCEEDED (IStream_Seek (istm->stream, *(LARGE_INTEGER *) &offset, dwhence, NULL)))
252                 return FALSE;
253         return TRUE;
254 }
255
256 static void
257 gsf_input_istream_init (GObject *obj)
258 {
259         GsfInputIStream *istm = GSF_INPUT_ISTREAM (obj);
260
261         istm->stream = NULL;
262         istm->buf  = NULL;
263         istm->buf_size = 0;
264 }
265
266 static void
267 gsf_input_istream_class_init (GObjectClass *gobject_class)
268 {
269         GsfInputClass *input_class = GSF_INPUT_CLASS (gobject_class);
270
271         gobject_class->finalize = gsf_input_istream_finalize;
272         input_class->Dup        = gsf_input_istream_dup;
273         input_class->Read       = gsf_input_istream_read;
274         input_class->Seek       = gsf_input_istream_seek;
275 }
276
277 GSF_CLASS (GsfInputIStream, gsf_input_istream,
278            gsf_input_istream_class_init, gsf_input_istream_init, GSF_INPUT_TYPE)
279
280 /***************************************************************************/
281 /***************************************************************************/