2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2001, 2002 Sun Microsystems Inc.,
6 * Copyright 2001, 2002 Ximian, Inc.
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.
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.
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.
25 #include <cspi/spi-private.h>
27 #define CORBA_BLOCK_SIZE 65536 /* see libbonobo, dunno where this is officially dictated */
30 struct StreamCacheItem {
31 Accessibility_ContentStream stream;
36 streams_equal_func (gconstpointer a, gconstpointer b)
38 const struct StreamCacheItem *c1 = a, *c2 = b;
39 return CORBA_Object_is_equivalent (c1->stream, c2->stream, cspi_ev ());
43 stream_cache_item_free (gpointer a)
45 struct StreamCacheItem *cache_item = a;
47 cspi_release_unref (cache_item->stream);
48 SPI_freeString (cache_item->mimetype);
52 static GHashTable *streams = NULL;
58 streams = g_hash_table_new_full (g_direct_hash, streams_equal_func,
59 NULL, stream_cache_item_free);
64 accessible_content_stream_client_seek (const Accessibility_ContentStream stream,
66 Accessibility_ContentStream_SeekType seek_type,
67 CORBA_Environment *opt_ev)
69 CORBA_Environment *ev, temp_ev;
70 CORBA_long ret_offset;
73 CORBA_exception_init (&temp_ev);
78 ret_offset = Accessibility_ContentStream_seek (stream, offset, seek_type, ev);
83 CORBA_exception_free (&temp_ev);
89 accessible_content_stream_client_read (const Accessibility_ContentStream stream,
91 CORBA_long *length_read,
92 CORBA_Environment *ev)
98 g_return_val_if_fail (ev != NULL, NULL);
108 mem = g_try_malloc (length);
110 CORBA_exception_set_system (ev, ex_CORBA_NO_MEMORY,
117 for (pos = 0; pos < length;) {
118 Accessibility_ContentStream_iobuf *buf;
121 len = (pos + CORBA_BLOCK_SIZE < length) ?
122 CORBA_BLOCK_SIZE : length - pos;
124 Accessibility_ContentStream_read (stream, len, &buf, ev);
126 if (BONOBO_EX (ev) || !buf)
129 if (buf->_length > 0) {
130 memcpy (mem + pos, buf->_buffer, 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)
137 g_warning ("Buffer length %d", buf->_length);
140 *length_read += buf->_length;
152 /* internal use only, declared in cspi-private.h */
154 cspi_streams_close_all (void)
159 g_hash_table_destroy (streams);
163 g_warning ("Streams not implemented yet");
169 * AccessibleStreamableContent_ref:
170 * @obj: a pointer to the #AccessibleStreamableContent implementor on which to
173 * Increment the reference count for an #AccessibleStreamableContent object.
178 AccessibleStreamableContent_ref (AccessibleStreamableContent *obj)
180 cspi_object_ref (obj);
184 * AccessibleStreamableContent_unref:
185 * @obj: a pointer to the #AccessibleStreamableContent implementor
186 * on which to operate.
188 * Decrement the reference count for an #AccessibleStreamableContent object.
193 AccessibleStreamableContent_unref (AccessibleStreamableContent *obj)
195 cspi_object_unref (obj);
199 * AccessibleStreamableContent_getContentTypes:
200 * @obj: a pointer to the #AccessibleStreamableContent implementor on which to operate.
202 * Get a list of strings containing the content mimetypes available from an
203 * #AccessibleStreamableContent implementor.
207 * Returns: an array of strings, terminated by a NULL string, specifying the
208 * mimetypes for which the streamed content is available.
213 AccessibleStreamableContent_getContentTypes (AccessibleStreamableContent *obj)
215 Accessibility_StringSeq *mimeseq;
216 char **content_types;
219 g_return_val_if_fail (obj != NULL, NULL);
221 mimeseq = Accessibility_StreamableContent_getContentTypes (CSPI_OBJREF (obj),
223 cspi_return_val_if_ev ("getContentTypes", NULL);
224 content_types = g_new0 (char *, mimeseq->_length + 1);
225 for (i = 0; i < mimeseq->_length; ++i)
226 content_types[i] = g_strdup (mimeseq->_buffer[i]);
227 content_types [mimeseq->_length] = NULL;
228 CORBA_free (mimeseq);
230 return content_types;
233 * AccessibleStreamableContent_freeContentTypesList:
234 * @obj: the AccessibleStreamableContent implementor on which to operate.
235 * @content_types: a list of content types previously returned by
236 * #AccessibleStreamableContent_getContentTypes.
238 * Free the memory associated with a call to #AccessibleStreamableContent_getContentTypes, once
239 * the result has been used.
244 AccessibleStreamableContent_freeContentTypesList (AccessibleStreamableContent *obj,
245 char **content_types)
250 while (content_types[i])
252 g_free (content_types[i]);
255 g_free (content_types);
260 * AccessibleStreamableContent_open:
261 * @obj: a pointer to the #AccessibleStreamableContent implementor on which to operate.
262 * @content_type: a string specifying the content type to retrieve (should match one
263 * of the return strings from #AccessibleStreamableContent_getContentTypes ()).
265 * Open a streaming connection to an AccessibleStreamableContent implementor,
266 * of a particular content type. Note that a client may only have one
267 * open stream per streamable interface instance in the current
272 * Returns: #TRUE if successful, #FALSE if unsuccessful.
276 AccessibleStreamableContent_open (AccessibleStreamableContent *obj,
277 const char *content_type)
279 Accessibility_ContentStream stream;
280 struct StreamCacheItem *cache;
281 stream = Accessibility_StreamableContent_getStream (CSPI_OBJREF (obj),
284 cspi_return_val_if_ev ("getContent", FALSE);
286 if (stream != CORBA_OBJECT_NIL) {
287 cache = g_new0 (struct StreamCacheItem, 1);
288 cache->stream = stream;
289 cache->mimetype = CORBA_string_dup (content_type);
291 g_hash_table_replace (get_streams (), CSPI_OBJREF (obj), cache);
293 * This limits us to one concurrent stream per streamable interface
294 * for a given client.
295 * It might be reasonable for a client to open more than one stream
296 * to content, in different mime-types, at the same time.
305 * AccessibleStreamableContent_close:
306 * @obj: a pointer to the #AccessibleStreamableContent implementor on which to operate.
308 * Close the current streaming connection to an AccessibleStreamableContent implementor.
309 * This must be called before any subsequent AccessibleStreamableContent_open
310 * calls on the same object.
314 * Returns: #TRUE if successful, #FALSE if unsuccessful.
318 AccessibleStreamableContent_close (AccessibleStreamableContent *obj)
320 if (CSPI_OBJREF (obj) != CORBA_OBJECT_NIL) {
321 if (g_hash_table_remove (get_streams (), CSPI_OBJREF (obj)))
328 * AccessibleStreamableContent_seek:
329 * @obj: a pointer to the #AccessibleStreamableContent implementor on which to operate.
330 * @offset: a long int specifying the offset into the stream.
331 * @seek_type: an enum indicating the seek offset type, may be SEEK_SET,
332 * SEEK_CUR, SEEK_END (as in the lseek() libc command).
334 * Cause the current streamable content connection (obtained via
335 * #AccessibleStreamableContent_open()) to seek to a particular offset in the
340 * Returns: #TRUE if successful, #FALSE if unsuccessful.
344 AccessibleStreamableContent_seek (AccessibleStreamableContent *obj,
346 AccessibleStreamableContentSeekType seek_type)
348 Accessibility_ContentStream stream;
349 long int ret_offset = 0;
350 struct StreamCacheItem *cached;
351 Accessibility_ContentStream_SeekType content_seek_type;
353 cached = g_hash_table_lookup (get_streams (), CSPI_OBJREF (obj));
356 stream = cached->stream;
357 if (stream != CORBA_OBJECT_NIL)
360 case SPI_STREAM_SEEK_SET:
361 content_seek_type = Accessibility_ContentStream_SEEK_SET;
363 case SPI_STREAM_SEEK_END:
364 content_seek_type = Accessibility_ContentStream_SEEK_END;
366 case SPI_STREAM_SEEK_CUR:
368 content_seek_type = Accessibility_ContentStream_SEEK_CURRENT;
371 ret_offset = accessible_content_stream_client_seek (stream, offset,
372 content_seek_type, cspi_ev ());
373 cspi_return_val_if_ev ("seek", FALSE);
380 * AccessibleStreamableContent_read:
381 * @obj: a pointer to the #AccessibleStreamableContent implementor on which to operate.
382 * @buff: a pointer to a buffer into which the resulting bytes read from the stream
384 * @nbytes: a long integer indicating the number of bytes to read/write.
385 * @read_type: currently unused, specifies behavior of reads for streamed content
386 * if blocking is not allowed, etc.
388 * Copy (read) bytes from the currently open streamable content connection
389 * to a buffer. This is a blocking API, in the sense that it does not
390 * return until the bytes have been read, or an error condition is
395 * Returns: an integer indicating the number of bytes read, or -1 on error.
399 AccessibleStreamableContent_read (AccessibleStreamableContent *obj,
402 unsigned int read_type)
404 Accessibility_ContentStream stream;
405 struct StreamCacheItem *cached;
406 cached = g_hash_table_lookup (get_streams (), CSPI_OBJREF (obj));
409 CORBA_long len_read = 0;
410 stream = cached->stream;
411 if (stream != CORBA_OBJECT_NIL)
415 mem = accessible_content_stream_client_read (stream, (size_t) nbytes, &len_read, cspi_ev ());
416 cspi_return_val_if_ev ("read", FALSE);
419 memcpy (buff, mem, len_read);
421 if ((nbytes == -1) || (len_read == nbytes))
426 else g_message ("no matching stream was opened...");