Fix for 114926. Also fixes for some leaks etc in cspi/spi_streamablecontent.c,
[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
29 /* TODO: factor/wrap Bonobo_Stream dependency to cspi/bonobo */
30
31 struct StreamCacheItem {
32   Bonobo_Stream stream;
33   gchar *mimetype;
34 };
35
36 static gboolean
37 streams_equal_func (gconstpointer a, gconstpointer b)
38 {
39   const struct StreamCacheItem *c1 = a, *c2 = b;
40   return CORBA_Object_is_equivalent (c1->stream, c2->stream, cspi_ev ());
41 }
42
43 static void
44 stream_cache_item_free (gpointer a)
45 {
46   struct StreamCacheItem *cache_item = a;
47
48   cspi_release_unref (cache_item->stream);
49   SPI_freeString (cache_item->mimetype);
50   g_free (cache_item);
51 }
52
53 static GHashTable *streams = NULL;
54
55 GHashTable *
56 get_streams (void) 
57 {
58   if (streams == NULL)
59       streams = g_hash_table_new_full (g_direct_hash, streams_equal_func, 
60                                        NULL, stream_cache_item_free);
61   return streams;
62 }
63
64 static CORBA_long
65 accessible_bonobo_stream_client_seek (const Bonobo_Stream stream,
66                                       CORBA_long offset,
67                                       Bonobo_Stream_SeekType seek_type,
68                                       CORBA_Environment  *opt_ev)
69 {
70         Bonobo_StorageInfo *info;
71         CORBA_Environment  *ev, temp_ev;
72         CORBA_long ret_offset;
73        
74         if (!opt_ev) {
75                 CORBA_exception_init (&temp_ev);
76                 ev = &temp_ev;
77         } else
78                 ev = opt_ev;
79
80         ret_offset = Bonobo_Stream_seek (stream, offset, seek_type, ev);
81         if (BONOBO_EX (ev))
82                 ret_offset = -1;
83
84         if (!opt_ev)
85                 CORBA_exception_free (&temp_ev);
86         
87         return ret_offset;
88 }
89
90 /* internal use only, declared in cspi-private.h */
91 void
92 cspi_streams_close_all (void)
93 {
94   if (streams)
95     {
96       g_hash_table_destroy (streams);
97       streams = NULL;
98     }
99 }
100
101 /**
102  * AccessibleStreamableContent_ref:
103  * @obj: a pointer to the #AccessibleStreamableContent implementor on which to
104  *       operate.
105  *
106  * Increment the reference count for an #AccessibleStreamableContent object.
107  *
108  **/
109 void
110 AccessibleStreamableContent_ref (AccessibleStreamableContent *obj)
111 {
112   cspi_object_ref (obj);
113 }
114
115 /**
116  * AccessibleStreamableContent_unref:
117  * @obj: a pointer to the #AccessibleStreamableContent implementor
118  *       on which to operate. 
119  *
120  * Decrement the reference count for an #AccessibleStreamableContent object.
121  *
122  **/
123 void
124 AccessibleStreamableContent_unref (AccessibleStreamableContent *obj)
125 {
126   cspi_object_unref (obj);
127 }
128
129 /**
130  * AccessibleStreamableContent_getContentTypes:
131  * @obj: a pointer to the #AccessibleStreamableContent implementor on which to operate.
132  *
133  * Get a list of strings containing the content mimetypes available from an
134  *       #AccessibleStreamableContent implementor.
135  *
136  * Returns: an array of strings, terminated by a NULL string, specifying the
137  *       mimetypes for which the streamed content is available.
138  *
139  **/
140
141 char **
142 AccessibleStreamableContent_getContentTypes (AccessibleStreamableContent *obj)
143 {
144   Accessibility_StringSeq *mimeseq;
145   char **content_types;
146   int i;
147
148   mimeseq = Accessibility_StreamableContent_getContentTypes (CSPI_OBJREF (obj),
149                                                              cspi_ev ());
150   cspi_return_val_if_ev ("getContentTypes", NULL); 
151
152   content_types = g_new0 (char *, mimeseq->_length + 1);
153   for (i = 0; i < mimeseq->_length; ++i)
154     content_types[i] = CORBA_string_dup (mimeseq->_buffer[i]);
155   content_types [mimeseq->_length] = NULL;
156   CORBA_free (mimeseq);
157
158   return content_types;
159 }
160
161 void
162 AccessibleStreamableContent_freeContentTypesList (AccessibleStreamableContent *obj,
163                                                   char **content_types)
164 {
165   if (content_types) 
166     {
167       gint i = 0;
168       while (content_types[i])
169         {
170           g_free (content_types[i]);
171           i++;
172         }
173       g_free (content_types);
174     }
175 }
176
177 /**
178  * AccessibleStreamableContent_open:
179  * @obj: a pointer to the #AccessibleStreamableContent implementor on which to operate.
180  * @content_type: a string specifying the content type to retrieve (should match one
181  * of the return strings from #AccessibleStreamableContent_getContentTypes ()).
182  *
183  * Open a streaming connection to an AccessibleStreamableContent implementor,
184  *       of a particular content type
185  *
186  * Returns: #TRUE if successful, #FALSE if unsuccessful.
187  *
188  **/
189 SPIBoolean
190 AccessibleStreamableContent_open (AccessibleStreamableContent *obj,
191                                   const char *content_type)
192 {
193   Bonobo_Stream stream;
194   struct StreamCacheItem *cache;
195   stream = Accessibility_StreamableContent_getContent (CSPI_OBJREF (obj),
196                                                        content_type,
197                                                        cspi_ev ());
198   cspi_return_val_if_ev ("getContent", FALSE); 
199
200   if (stream != CORBA_OBJECT_NIL) {
201     cache = g_new0 (struct StreamCacheItem, 1);
202     cache->stream = stream;
203     cache->mimetype = CORBA_string_dup (content_type);
204     g_hash_table_replace (get_streams (), stream, cache);
205     return TRUE;
206   }
207   return FALSE;
208 }
209
210 /**
211  * AccessibleStreamableContent_close:
212  * @obj: a pointer to the #AccessibleStreamableContent implementor on which to operate.
213  *
214  * Close the current streaming connection to an AccessibleStreamableContent implementor.
215  * This must be called before any subsequent AccessibleStreamableContent_open
216  * calls on the same object.
217  *
218  * Returns: #TRUE if successful, #FALSE if unsuccessful.
219  *
220  **/
221 SPIBoolean
222 AccessibleStreamableContent_close (AccessibleStreamableContent *obj)
223 {
224   if (CSPI_OBJREF (obj) != CORBA_OBJECT_NIL) {
225     if (g_hash_table_remove (get_streams (), CSPI_OBJREF (obj)))
226       return TRUE;
227   }
228   return FALSE;
229 }
230
231 /**
232  * AccessibleStreamableContent_seek:
233  * @obj: a pointer to the #AccessibleStreamableContent implementor on which to operate.
234  * @offset: a long int specifying the offset into the stream.
235  * @seek_type: an enum indicating the seek offset type, may be SEEK_SET,
236  *            SEEK_CUR, SEEK_END (as in the lseek() libc command).
237  *
238  * Cause the current streamable content connection (obtained via
239  *     #AccessibleStreamableContent_open()) to seek to a particular offset in the
240  *     stream.
241  *
242  * Returns: #TRUE if successful, #FALSE if unsuccessful.
243  *
244  **/
245 long int
246 AccessibleStreamableContent_seek (AccessibleStreamableContent *obj,
247                                   long int offset,
248                                   AccessibleStreamableContentSeekType seek_type)
249 {
250   Bonobo_Stream stream;
251   long int ret_offset = 0;
252   struct StreamCacheItem *cached; 
253   Bonobo_Stream_SeekType bonobo_seek_type;
254
255   cached = g_hash_table_lookup (get_streams (), CSPI_OBJREF (obj));
256   if (cached)
257     {
258       stream = cached->stream;
259       if (stream != CORBA_OBJECT_NIL)
260         {
261           guint8 *mem;
262           switch (seek_type) {
263           case SPI_STREAM_SEEK_SET:
264             bonobo_seek_type = Bonobo_Stream_SeekSet; 
265             break;
266           case SPI_STREAM_SEEK_END:
267             bonobo_seek_type = Bonobo_Stream_SeekEnd; 
268             break;
269           case SPI_STREAM_SEEK_CUR:
270           default:
271             bonobo_seek_type = Bonobo_Stream_SeekCur; 
272             break;
273           }
274           /* bonobo-client doesn't wrap seek yet, so we have to. */
275           ret_offset = accessible_bonobo_stream_client_seek (stream, offset, 
276                                                              seek_type, cspi_ev ());
277           cspi_return_val_if_ev ("seek", FALSE);
278         }
279     }
280   return ret_offset;
281 }
282
283 /**
284  * AccessibleStreamableContent_read:
285  * @obj: a pointer to the #AccessibleStreamableContent implementor on which to operate.
286  * @buff: a pointer to a buffer into which the resulting bytes read from the stream
287  *        are to be written.
288  * @nbytes: a long integer indicating the number of bytes to read/write.
289  * @read_type: currently unused, specifies behavior of reads for streamed content
290  *        if blocking is not allowed, etc.
291  *
292  * Copy (read) bytes from the currently open streamable content connection
293  *     to a buffer.  This is a blocking API, in the sense that it does not 
294  *     return until the bytes have been read, or an error condition is 
295  *     detected.
296  *
297  * Returns: an integer indicating the number of bytes read, or -1 on error.
298  *
299  **/
300 SPIBoolean
301 AccessibleStreamableContent_read (AccessibleStreamableContent *obj,
302                                   void *buff,
303                                   long int nbytes,
304                                   unsigned int read_type)
305 {
306   Bonobo_Stream stream;
307   struct StreamCacheItem *cached; 
308   cached = g_hash_table_lookup (get_streams (), CSPI_OBJREF (obj));
309   if (cached)
310     {
311       CORBA_long len_read;
312       stream = cached->stream;
313       if (stream != CORBA_OBJECT_NIL)
314         {
315           guint8 *mem;
316           mem = bonobo_stream_client_read (stream, (size_t) nbytes, &len_read, cspi_ev ());
317           cspi_return_val_if_ev ("read", FALSE);
318           if (mem)
319             {
320               memcpy (buff, mem, len_read);
321               g_free (mem);
322               if ((nbytes == -1) || (len_read == nbytes))
323                 return TRUE;
324             }
325         }
326     }
327   return FALSE;
328 }
329