Changes to introspection generation to remove DOCTYPE and XML
[platform/core/uifw/at-spi2-atk.git] / cspi / spi_streamablecontent.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2001, 2002 Sun Microsystems Inc.,
6  * Copyright 2001, 2002 Ximian, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #include <string.h>
25 #include <libbonobo.h>
26 #include <cspi/spi-private.h>
27
28 #define CORBA_BLOCK_SIZE 65536 /* see libbonobo, dunno where this is officially dictated */
29
30 struct StreamCacheItem {
31   Accessibility_ContentStream stream;
32   gchar *mimetype;
33 };
34
35 static gboolean
36 streams_equal_func (gconstpointer a, gconstpointer b)
37 {
38   const struct StreamCacheItem *c1 = a, *c2 = b;
39   return CORBA_Object_is_equivalent (c1->stream, c2->stream, cspi_ev ());
40 }
41
42 static void
43 stream_cache_item_free (gpointer a)
44 {
45   struct StreamCacheItem *cache_item = a;
46
47   cspi_release_unref (cache_item->stream);
48   SPI_freeString (cache_item->mimetype);
49   g_free (cache_item);
50 }
51
52 static GHashTable *streams = NULL;
53
54 static GHashTable *
55 get_streams (void) 
56 {
57   if (streams == NULL)
58       streams = g_hash_table_new_full (g_direct_hash, streams_equal_func, 
59                                        NULL, stream_cache_item_free);
60   return streams;
61 }
62
63 static CORBA_long
64 accessible_content_stream_client_seek (const Accessibility_ContentStream stream,
65                                       CORBA_long offset,
66                                       Accessibility_ContentStream_SeekType seek_type,
67                                       CORBA_Environment  *opt_ev)
68 {
69         CORBA_Environment  *ev, temp_ev;
70         CORBA_long ret_offset;
71        
72         if (!opt_ev) {
73                 CORBA_exception_init (&temp_ev);
74                 ev = &temp_ev;
75         } else
76                 ev = opt_ev;
77
78         ret_offset = Accessibility_ContentStream_seek (stream, offset, seek_type, ev);
79         if (BONOBO_EX (ev))
80                 ret_offset = -1;
81
82         if (!opt_ev)
83                 CORBA_exception_free (&temp_ev);
84         
85         return ret_offset;
86 }
87
88 static guint8*
89 accessible_content_stream_client_read (const Accessibility_ContentStream stream,
90                                        const size_t size,
91                                        CORBA_long *length_read,
92                                        CORBA_Environment  *ev)
93 {
94         size_t  pos;
95         guint8 *mem;
96         size_t  length;
97
98         g_return_val_if_fail (ev != NULL, NULL);
99
100         if (length_read)
101                 *length_read = size;
102
103         length = size;
104
105         if (length == 0)
106                 return NULL;
107
108         mem = g_try_malloc (length);
109         if (!mem) {
110                 CORBA_exception_set_system (ev, ex_CORBA_NO_MEMORY,
111                                             CORBA_COMPLETED_NO);
112                 return NULL;
113         }
114
115         *length_read = 0;
116
117         for (pos = 0; pos < length;) {
118                 Accessibility_ContentStream_iobuf *buf;
119                 CORBA_long           len;
120
121                 len = (pos + CORBA_BLOCK_SIZE < length) ?
122                         CORBA_BLOCK_SIZE : length - pos;
123
124                 Accessibility_ContentStream_read (stream, len, &buf, ev);
125
126                 if (BONOBO_EX (ev) || !buf)
127                         goto io_error;
128
129                 if (buf->_length > 0) {
130                         memcpy (mem + pos, buf->_buffer, buf->_length);
131                         pos += buf->_length;
132                         *length_read += buf->_length;
133                         /* we assume a short read equals EOF ... is that right? */
134                         if (buf->_length < len || *length_read == size)
135                             return mem;
136                 } else {
137                         g_warning ("Buffer length %d", buf->_length);
138                         goto io_error;
139                 }
140                 *length_read += buf->_length;
141
142                 CORBA_free (buf);
143         }
144
145         return mem;
146
147  io_error:
148         return NULL;
149 }
150
151 /* internal use only, declared in cspi-private.h */
152 void
153 cspi_streams_close_all (void)
154 {
155   if (streams)
156     {
157       g_hash_table_destroy (streams);
158       streams = NULL;
159     }
160 }
161
162 /**
163  * AccessibleStreamableContent_ref:
164  * @obj: a pointer to the #AccessibleStreamableContent implementor on which to
165  *       operate.
166  *
167  * Increment the reference count for an #AccessibleStreamableContent object.
168  *
169  * @Since: AT-SPI 1.4
170  **/
171 void
172 AccessibleStreamableContent_ref (AccessibleStreamableContent *obj)
173 {
174   cspi_object_ref (obj);
175 }
176
177 /**
178  * AccessibleStreamableContent_unref:
179  * @obj: a pointer to the #AccessibleStreamableContent implementor
180  *       on which to operate. 
181  *
182  * Decrement the reference count for an #AccessibleStreamableContent object.
183  *
184  * @Since: AT-SPI 1.4
185  **/
186 void
187 AccessibleStreamableContent_unref (AccessibleStreamableContent *obj)
188 {
189   cspi_object_unref (obj);
190 }
191
192 /**
193  * AccessibleStreamableContent_getContentTypes:
194  * @obj: a pointer to the #AccessibleStreamableContent implementor on which to operate.
195  *
196  * Get a list of strings containing the content mimetypes available from an
197  *       #AccessibleStreamableContent implementor.
198  *
199  * @Since: AT-SPI 1.4
200  *
201  * Returns: an array of strings, terminated by a NULL string, specifying the
202  *       mimetypes for which the streamed content is available.
203  *
204  **/
205
206 char **
207 AccessibleStreamableContent_getContentTypes (AccessibleStreamableContent *obj)
208 {
209   Accessibility_StringSeq *mimeseq;
210   char **content_types;
211   int i;
212
213   g_return_val_if_fail (obj != NULL, NULL);
214
215   mimeseq = Accessibility_StreamableContent_getContentTypes (CSPI_OBJREF (obj),
216                                                              cspi_ev ());
217   cspi_return_val_if_ev ("getContentTypes", NULL); 
218   content_types = g_new0 (char *, mimeseq->_length + 1);
219   for (i = 0; i < mimeseq->_length; ++i)
220     content_types[i] = g_strdup (mimeseq->_buffer[i]);
221   content_types [mimeseq->_length] = NULL;
222   CORBA_free (mimeseq);
223   
224   return content_types;
225 }
226 /**
227 * AccessibleStreamableContent_freeContentTypesList:
228 * @obj: the AccessibleStreamableContent implementor on which to operate.
229 * @content_types: a list of content types previously returned by 
230 *     #AccessibleStreamableContent_getContentTypes.
231 *
232 * Free the memory associated with a call to #AccessibleStreamableContent_getContentTypes, once 
233 * the result has been used.
234 *
235 * Since: AT-SPI 1.4
236 **/
237 void
238 AccessibleStreamableContent_freeContentTypesList (AccessibleStreamableContent *obj,
239                                                   char **content_types)
240 {
241   if (content_types) 
242     {
243       gint i = 0;
244       while (content_types[i])
245         {
246           g_free (content_types[i]);
247           i++;
248         }
249       g_free (content_types);
250     }
251 }
252
253 /**
254  * AccessibleStreamableContent_open:
255  * @obj: a pointer to the #AccessibleStreamableContent implementor on which to operate.
256  * @content_type: a string specifying the content type to retrieve (should match one
257  * of the return strings from #AccessibleStreamableContent_getContentTypes ()).
258  *
259  * Open a streaming connection to an AccessibleStreamableContent implementor,
260  *       of a particular content type.  Note that a client may only have one
261  *       open stream per streamable interface instance in the current 
262  *       implementation.
263  *
264  * @Since: AT-SPI 1.4
265  *
266  * Returns: #TRUE if successful, #FALSE if unsuccessful.
267  *
268  **/
269 SPIBoolean
270 AccessibleStreamableContent_open (AccessibleStreamableContent *obj,
271                                   const char *content_type)
272 {
273   Accessibility_ContentStream stream;
274   struct StreamCacheItem *cache;
275   stream = Accessibility_StreamableContent_getStream (CSPI_OBJREF (obj),
276                                                       content_type,
277                                                       cspi_ev ());
278   cspi_return_val_if_ev ("getContent", FALSE); 
279
280   if (stream != CORBA_OBJECT_NIL) {
281     cache = g_new0 (struct StreamCacheItem, 1);
282     cache->stream = stream;
283     cache->mimetype = CORBA_string_dup (content_type);
284
285     g_hash_table_replace (get_streams (), CSPI_OBJREF (obj), cache);
286     /* FIXME 
287      * This limits us to one concurrent stream per streamable interface
288      * for a given client.
289      * It might be reasonable for a client to open more than one stream
290      * to content, in different mime-types, at the same time.
291      */
292
293     return TRUE;
294   }
295   return FALSE;
296 }
297
298 /**
299  * AccessibleStreamableContent_close:
300  * @obj: a pointer to the #AccessibleStreamableContent implementor on which to operate.
301  *
302  * Close the current streaming connection to an AccessibleStreamableContent implementor.
303  * This must be called before any subsequent AccessibleStreamableContent_open
304  * calls on the same object.
305  * 
306  * @Since: AT-SPI 1.4
307  *
308  * Returns: #TRUE if successful, #FALSE if unsuccessful.
309  *
310  **/
311 SPIBoolean
312 AccessibleStreamableContent_close (AccessibleStreamableContent *obj)
313 {
314   if (CSPI_OBJREF (obj) != CORBA_OBJECT_NIL) {
315     if (g_hash_table_remove (get_streams (), CSPI_OBJREF (obj)))
316       return TRUE;
317   }
318   return FALSE;
319 }
320
321 /**
322  * AccessibleStreamableContent_seek:
323  * @obj: a pointer to the #AccessibleStreamableContent implementor on which to operate.
324  * @offset: a long int specifying the offset into the stream.
325  * @seek_type: an enum indicating the seek offset type, may be SEEK_SET,
326  *            SEEK_CUR, SEEK_END (as in the lseek() libc command).
327  *
328  * Cause the current streamable content connection (obtained via
329  *     #AccessibleStreamableContent_open()) to seek to a particular offset in the
330  *     stream.
331  *
332  * @Since: AT-SPI 1.4
333  *
334  * Returns: #TRUE if successful, #FALSE if unsuccessful.
335  *
336  **/
337 long int
338 AccessibleStreamableContent_seek (AccessibleStreamableContent *obj,
339                                   long int offset,
340                                   AccessibleStreamableContentSeekType seek_type)
341 {
342   Accessibility_ContentStream stream;
343   long int ret_offset = 0;
344   struct StreamCacheItem *cached; 
345   Accessibility_ContentStream_SeekType content_seek_type;
346
347   cached = g_hash_table_lookup (get_streams (), CSPI_OBJREF (obj));
348   if (cached)
349     {
350       stream = cached->stream;
351       if (stream != CORBA_OBJECT_NIL)
352         {
353           switch (seek_type) {
354           case SPI_STREAM_SEEK_SET:
355             content_seek_type = Accessibility_ContentStream_SEEK_SET; 
356             break;
357           case SPI_STREAM_SEEK_END:
358             content_seek_type = Accessibility_ContentStream_SEEK_END; 
359             break;
360           case SPI_STREAM_SEEK_CUR:
361           default:
362             content_seek_type = Accessibility_ContentStream_SEEK_CURRENT; 
363             break;
364           }
365           ret_offset = accessible_content_stream_client_seek (stream, offset, 
366                                                              content_seek_type, cspi_ev ());
367           cspi_return_val_if_ev ("seek", FALSE);
368         }
369     }
370   return ret_offset;
371 }
372
373 /**
374  * AccessibleStreamableContent_read:
375  * @obj: a pointer to the #AccessibleStreamableContent implementor on which to operate.
376  * @buff: a pointer to a buffer into which the resulting bytes read from the stream
377  *        are to be written.
378  * @nbytes: a long integer indicating the number of bytes to read/write.
379  * @read_type: currently unused, specifies behavior of reads for streamed content
380  *        if blocking is not allowed, etc.
381  *
382  * Copy (read) bytes from the currently open streamable content connection
383  *     to a buffer.  This is a blocking API, in the sense that it does not 
384  *     return until the bytes have been read, or an error condition is 
385  *     detected.
386  *
387  * @Since: AT-SPI 1.4
388  *
389  * Returns: an integer indicating the number of bytes read, or -1 on error.
390  *
391  **/
392 SPIBoolean
393 AccessibleStreamableContent_read (AccessibleStreamableContent *obj,
394                                   void *buff,
395                                   long int nbytes,
396                                   unsigned int read_type)
397 {
398   Accessibility_ContentStream stream;
399   struct StreamCacheItem *cached; 
400   cached = g_hash_table_lookup (get_streams (), CSPI_OBJREF (obj));
401   if (cached)
402     {
403       CORBA_long len_read = 0;
404       stream = cached->stream;
405       if (stream != CORBA_OBJECT_NIL)
406         {
407           guint8 *mem;
408
409           mem = accessible_content_stream_client_read (stream, (size_t) nbytes, &len_read, cspi_ev ());
410           cspi_return_val_if_ev ("read", FALSE);
411           if (mem)
412             {
413               memcpy (buff, mem, len_read);
414               g_free (mem);
415               if ((nbytes == -1) || (len_read == nbytes))
416                 return TRUE;
417             }
418         }
419     }
420   else g_message ("no matching stream was opened...");
421   return FALSE;
422 }
423