[cairo] Implementing cairo_read_func_t/cairo_write_func_t properly

Bernhard Fischer bf at abenteuerland.at
Sat Jan 2 13:27:08 PST 2016

On Saturday 02 January 2016 13:01:39 Bill Spitzak wrote:
> On 01/01/2016 01:42 AM, Lawrence D'Oliveiro wrote:
> > On Fri, 01 Jan 2016 10:32:59 +0100, Bernhard Fischer wrote:
> >> cairo_..._stream() are stream reading functions. This is that it does
> >> not know in advance how many bytes are available in the file.
> > 
> > That’s not how they work. Cairo uses them to read known file formats.
> > If it doesn’t get the number of bytes it expects, then there is
> > something wrong with the file.
> No, he is right, this is a problem.
> A lot of libraries that accept such read/write functions are assuming
> they have to do buffering themselves, as the intention is for the
> functions to be the system read/write which are only efficient for large
> blocks.
> At the point the library is calling the function to read, it is just
> trying to refill it's input buffer. It will pass the size of that
> buffer, but it wants to detect where the EOF is if it lands inside the
> buffer.
> I think the api has to be changed to return number of bytes read, and a
> negative number for eof.

The return value should be the number of bytes read and on eof it is something 
between 0 and length. If it is called again at/after eof it returns 0 again. A 
negative value (-1) is only returned in case of error (but not EOF). This is 
exactly like read(3) behaves.
That's one variant. I implemented such a function with a new type in my JPEG 

typedef ssize_t (*cairo_read_func_len_t) (void *closure, unsigned char *data, 
unsigned int length);

A different approach is to do it with a pointer to the length variable which is 
set to the total length at the call and is modified by the stream reader 
function to the actual read length, similar to what is done by accept(2).
In this case the return value could again be cairo_status_t which is a more 
"Cairo-style" manner:

typedef cairo_status_t (*cairo_read_func_len_t) (void *closure, unsigned char 
*data, unsigned int *length);


More information about the cairo mailing list