IO Interface
------------

GFXprim implements an I/O interface which is used by all image loaders.

The purpose of the interface is:

* Make it easy to load and save images from/into memory buffers
* Fast and clean containers (ZIP for example) implementation
  (zlib deflate could feed data directly into a memory based IO stream)

The I/O interface is defined by a structure with callbacks.

[source,c]
-------------------------------------------------------------------------------
#include <loaders/gp_io.h>
/* or */
#include <gfxprim.h>

/*
 * Values are 1:1 with constants passed to lseek()
 */
enum GP_IOWhence {
        GP_IO_SEEK_SET = 0,
        GP_IO_SEEK_CUR = 1,
        GP_IO_SEEK_END = 2,
};


typedef struct GP_IO {
        ssize_t (*Read)(struct GP_IO *self, void *buf, size_t size);
        ssize_t (*Write)(struct GP_IO *self, void *buf, size_t size);
        off_t (*Seek)(struct GP_IO *self, off_t off, enum GP_IOWhence whence);
        int (*Close)(struct GP_IO *self);

        off_t mark;
        char priv[];
} GP_IO;
-------------------------------------------------------------------------------

The fields of the I/O stream structure are mostly self describing. The 'Seek'
behaves exactly as 'lseek(2)', the 'Read' as 'read(2)' and the 'Write' as
'write(2)'.

The 'mark' and 'priv' are private fields that shall not be touched by user.

An IO reader must implement at least 'Read', 'Seek' (at least able to seek
forward to skip some data) and 'Close'.

An IO writer must implement at least 'Write' and 'Close'.

Return value from the 'Seek' is a value of current offset in the stream (after
the seek has been done) or in case of failure '(off_t)-1'.

Return value from 'Read' or 'Write' is a number of bytes read/written or in
case of failure a negative number (-1).

Return value from 'Close' is zero on success and non-zero on IO failure.

NOTE: Make sure errno is set if any of the operations has failed.

[source,c]
-------------------------------------------------------------------------------
#include <loaders/gp_io.h>
/* or */
#include <gfxprim.h>

ssize_t GP_IORead(GP_IO *io, void *buf, size_t size);
-------------------------------------------------------------------------------

This is a wrapper to 'io->Read()'.

Reads at most 'size' bytes from an 'IO' stream and stores them into the
buffer. Returns number of bytes read.

On failure negative value is returned and errno is set.


[source,c]
-------------------------------------------------------------------------------
#include <loaders/gp_io.h>
/* or */
#include <gfxprim.h>

int GP_IOFill(GP_IO *io, void *buf, size_t size);
-------------------------------------------------------------------------------

Similar to 'GP_IORead()' but either reads the whole buffer or fails.

Returns zero on success and non-zero on failure.


[source,c]
-------------------------------------------------------------------------------
#include <loaders/gp_io.h>
/* or */
#include <gfxprim.h>

ssize_t GP_IOWrite(GP_IO *io, void *buf, size_t size);
-------------------------------------------------------------------------------

This is a wrapper to 'io->Write()'.

Writes at most 'size' bytes from an 'IO' stream and stores them into the
buffer. Returns number of bytes read.

On failure negative value is returned and errno is set.


[source,c]
-------------------------------------------------------------------------------
#include <loaders/gp_io.h>
/* or */
#include <gfxprim.h>

int GP_IOFlush(GP_IO *io, void *buf, size_t size);
-------------------------------------------------------------------------------

Similar to 'GP_IOWrite()' but either writes the whole buffer or fails.

Returns zero on success and non-zero on failure.

[source,c]
-------------------------------------------------------------------------------
#include <loaders/gp_io.h>
/* or */
#include <gfxprim.h>

int GP_IOPrintF(GP_IO *io, const char *fmt, ...);
-------------------------------------------------------------------------------

Printf-like function for an I/O stream.

Returns zero on success and non-zero on failure.

[source,c]
-------------------------------------------------------------------------------
#include <loaders/gp_io.h>
/* or */
#include <gfxprim.h>

int GP_IOClose(GP_IO *io);
-------------------------------------------------------------------------------

This is a wrapper to 'io->Close()'.

Finalizes reading/writing, closes file descriptors (in case of file IO), frees
memory buffers.

Returns zero on success, non-zero on I/O failure and errno is set.


[source,c]
-------------------------------------------------------------------------------
#include <loaders/gp_io.h>
/* or */
#include <gfxprim.h>

enum GP_IOWhence {
	GP_IO_SEEK_SET = 0,
	GP_IO_SEEK_CUR = 1,
	GP_IO_SEEK_END = 2,
};

off_t GP_IOSeek(GP_IO *io, off_t off, enum GP_IOWhence whence);
-------------------------------------------------------------------------------

This is a wrapper to 'io->Seek()'.


Returns '(off_t)-1' on failure and errno is set.

Generally not all read I/O streams are seekable back (zlib/rle decompression
streams, etc.) but all streams should be able to seek to the start of the
stream, to the end and forward.

.Most common errno values
|==============================================================================
| 'EINVAL' | Invalid 'whence' or 'off' points outside the stream.
| 'ENOSYS' | Operation not supported, combination of 'whence' and 'off' points
             inside the stream (is valid) but action cannot be done.
|==============================================================================

[source,c]
-------------------------------------------------------------------------------
#include <loaders/gp_io.h>
/* or */
#include <gfxprim.h>

off_t GP_IOTell(GP_IO *io);
-------------------------------------------------------------------------------

Wrapper to 'GP_IOSeek()', returns current position in I/O stream.


[source,c]
-------------------------------------------------------------------------------
#include <loaders/gp_io.h>
/* or */
#include <gfxprim.h>

off_t GP_IORewind(GP_IO *io)
-------------------------------------------------------------------------------

Wrapper to 'GP_IOSeek()', rewinds to the start of the I/O stream.

Returns zero on success, non-zero on failure and errno is set.


[source,c]
-------------------------------------------------------------------------------
#include <loaders/gp_io.h>
/* or */
#include <gfxprim.h>

GP_IO *GP_IOMem(void *buf, size_t size, void (*free)(void *));
-------------------------------------------------------------------------------

Creates an read-only I/O from a memory buffer.

Returns initialized I/O or in case of failure NULL and errno is set.

The 'buf' is pointer to the start of the buffer, the 'size' is size in bytes.

The 'free()' callback if not NULL is called with the start of the buffer as
an argument on 'IOClose()'.

TIP: See link:example_memory_io.html[memory I/O example].


[source,c]
-------------------------------------------------------------------------------
#include <loaders/gp_io.h>
/* or */
#include <gfxprim.h>

enum GP_IOFileMode {
        GP_IO_RDONLY = 0x00,
        GP_IO_WRONLY = 0x01,
        GP_IO_RDWR = 0x02,
};

GP_IO *GP_IOFile(const char *path, enum GP_IOFileMode mode);
-------------------------------------------------------------------------------

Creates an IO stream from a file.

Returns a pointer to initialized I/O stream, or in case of failure NULL and
errno is set.

[source,c]
-------------------------------------------------------------------------------
#include <loaders/gp_io.h>
/* or */
#include <gfxprim.h>

GP_IO *GP_IOSubIO(GP_IO *pio, size_t size);
-------------------------------------------------------------------------------

Creates an readable I/O on the top of an existing readable I/O.

The stream position in the parent I/O is advanced when reading or seeking the
sub I/O.

The sub I/O is limited to an interval starting at current position and can
advance size bytes at max; then it behaves like the stream has ended i.e.
'GP_IORead()' returns zero.

You can seek in the resulting I/O if:

* The parent I/O is seekable

* The the combination of 'off' and 'whence' fits inside the sub I/O

WARNING: If you combine reading or seeking in the parent I/O and sub I/O the
         result is undefined.

[source,c]
-------------------------------------------------------------------------------
#include <loaders/gp_io.h>
/* or */
#include <gfxprim.h>

GP_IO *GP_IOWBuffer(GP_IO *io, size_t bsize);
-------------------------------------------------------------------------------

Creates write buffered I/O on the top of an existing I/O.

Generally you should create a buffered I/O if you are about to write data a
few bytes at the time.

If 'bsize' is zero default size is choosen.

TIP: See link:example_loader_registration.html[example buffered I/O usage].
