AG_DataSource
—
agar data source access
The AG_DataSource
structure provides a generic interface
to different data sources. Built-in sources include
AG_FileSource for files,
AG_CoreSource for fixed-size memory,
AG_AutoCoreSource for automatically-allocated memory and
AG_ConstCoreSource for read-only memory.
AG_NetSocketSource for
AG_Net(3)
sockets.
New data sources can be implemented by overloading the
AG_DataSource
structure.
AG_DataSource *
AG_OpenFile
(const
char *path, const char
*mode);
AG_DataSource *
AG_OpenFileHandle
(FILE
*f);
AG_DataSource *
AG_OpenCore
(void
*p, size_t
size);
AG_DataSource *
AG_OpenConstCore
(const
void *p, size_t
size);
AG_DataSource *
AG_OpenAutoCore
(void);
AG_DataSource *
AG_OpenNetSocket
(AG_NetSocket
*ns);
void
AG_CloseDataSource
(AG_DataSource
*ds);
int
AG_Read
(AG_DataSource
*ds, void *buf,
size_t size);
int
AG_ReadAt
(AG_DataSource
*ds, void *buf,
size_t size,
off_t pos);
int
AG_Write
(AG_DataSource
*ds, const void
*buf, size_t
size);
int
AG_WriteAt
(AG_DataSource
*ds, const void
*buf, size_t size,
off_t pos);
int
AG_ReadP
(AG_DataSource
*ds, void *buf,
size_t size,
size_t *nRead);
int
AG_ReadAtP
(AG_DataSource
*ds, void *buf,
size_t size,
off_t pos,
size_t *nRead);
int
AG_WriteP
(AG_DataSource
*ds, const void
*buf, size_t size,
size_t *nWrote);
int
AG_WriteAtP
(AG_DataSource
*ds, const void
*buf, size_t size,
off_t pos,
size_t *nWrote);
off_t
AG_Tell
(AG_DataSource
*ds);
int
AG_Seek
(AG_DataSource
*ds, off_t offs,
enum ag_seek_mode
mode);
void
AG_LockDataSource
(AG_DataSource
*ds);
void
AG_UnlockDataSource
(AG_DataSource
*ds);
void
AG_SetByteOrder
(AG_DataSource
*ds, enum ag_byte_order
order);
void
AG_SetSourceDebug
(AG_DataSource
*ds, int
enable);
void
AG_DataSourceInit
(AG_DataSource
*ds);
void
AG_DataSourceDestroy
(AG_DataSource
*ds);
void
AG_DataSourceSetErrorFn
(AG_DataSource
*ds, void (*fn)(AG_Event
*), const char
*fmt, ...);
void
AG_DataSourceError
(AG_DataSource
*ds, const char
*fmt, ...);
int
AG_DataSourceRealloc
(AG_CoreSource
*dsCore, size_t
size);
The AG_OpenFile
() function opens the file
at path, where mode is a
fopen(3)
style mode string. AG_OpenFileHandle
() creates a new
data source for a previously opened file.
The AG_OpenCore
() and
AG_OpenConstCore
() functions create new data sources
referencing the region of memory p of
size bytes.
AG_OpenAutoCore
() creates a new data
source using dynamically-allocated memory (accessible as the
data member of the structure).
AG_OpenNetSocket
() creates a new data
source using a network socket (see
AG_Net(3)).
The AG_CloseDataSource
() function closes
the data source, freeing any data allocated by the
AG_DataSource
layer (such as the
data buffer allocated by
AG_OpenAutoCore
()). For network sockets opened with
AG_OpenNetSocket
(), the underlying socket is left
open.
AG_Read
() reads size
bytes from the data source into the destination buffer
buf. AG_Write
() writes
size bytes from the source buffer
buf to the destination data source.
AG_ReadAt
() and AG_WriteAt
()
allow a source/target position (byte offset) to be specified. These
functions all return 0 on success or -1 if an error has occured. Partial
transfers are treated as errors.
The AG_ReadP
(),
AG_WriteP
(), AG_ReadAtP
()
and AG_WriteAtP
() variants do not treat partial
reads or writes as errors, returning the total number of bytes transferred
into the nRead or nWrote
argument (if not NULL). Depending on the underlying data source, a byte
count of 0 may indicate either an end-of-file condition or a closed
socket.
AG_Tell
() returns the current position in
the data source. If the underlying data source does not support this
operation, a value of 0 is returned.
AG_Seek
() seeks to the given position in
the data source. Acceptable values for mode include
AG_SEEK_SET
(relative to data start),
AG_SEEK_CUR
(relative to current position),
AG_SEEK_END
(relative to data end).
The AG_LockDataSource
() and
AG_UnlockDataSource
() functions acquire and release
the exclusive lock protecting this data source, and are no-ops if thread
support is disabled.
AG_SetByteOrder
() configures the byte
order to be used by integer read/write operations. Accepted parameters are
AG_BYTEORDER_BE
for big-endian and
AG_BYTEORDER_LE
for little-endian. To determine the
byte order of the current architecture, you can use the standard
AG_BYTEORDER
define (which evaluates to
AG_BIG_ENDIAN
or
AG_LITTLE_ENDIAN
).
AG_SetSourceDebug
() enables or disables
the inclusion of debugging information in the archive. Debugging information
allows type-safety checking at the primitive data level, at the cost of an
increased archive size due to the additional metadata that must be
encoded.
The AG_DataSourceInit
() and
AG_DataSourceDestroy
() functions are used when
implementing new data source types. They are used internally by the
AG_Open*
() and AG_Close*
()
functions.
AG_DataSourceSetErrorFn
() configures an
alternate handler routine for data source exceptions (which can occur when
using routines such as AG_ReadUint32
(), for example
on I/O error). From the handler routine, a pointer to the
AG_DataSource can be retrieved using
AG_SELF
, and the error message is retrieved using
AG_STRING(1)
. The default exception handler simply
calls
AG_FatalError(3).
The AG_DataSourceError
() function raises a
data source error, with the optional error message string. It is intended
for use in custom I/O routines which do not return an error status. If
fmt is NULL, the error is obtained from
AG_GetError(3).
The AG_DataSourceRealloc
() routine
explicitely resizes the buffer of a data source previously created with
AG_OpenAutoCore
(). While the buffer is already
resized automatically as data is written to the source, setting an explicit
buffer size may be desirable in some situations.
The following functions read and write integer values using the byte order
specified for the data source.
Uint8
AG_ReadUint8
(AG_DataSource
*ds);
int
AG_ReadUint8v
(AG_DataSource
*ds, Uint8 *v);
Sint8
AG_ReadSint8
(AG_DataSource
*ds);
int
AG_ReadSint8v
(AG_DataSource
*ds, Sint8 *v);
Uint16
AG_ReadUint16
(AG_DataSource
*ds);
int
AG_ReadUint16v
(AG_DataSource
*ds, Uint16
*v);
Sint16
AG_ReadSint16
(AG_DataSource
*ds);
int
AG_ReadSint16v
(AG_DataSource
*ds, Sint16
*v);
Uint32
AG_ReadUint32
(AG_DataSource
*ds);
int
AG_ReadUint32v
(AG_DataSource
*ds, Uint32
*v);
Sint32
AG_ReadSint32
(AG_DataSource
*ds);
int
AG_ReadSint32
(AG_DataSource
*ds, Sint32
*v);
Uint64
AG_ReadUint64
(AG_DataSource
*ds);
int
AG_ReadUint64v
(AG_DataSource
*ds, Uint64
*v);
Sint64
AG_ReadSint64
(AG_DataSource
*ds);
int
AG_ReadSint64v
(AG_DataSource
*ds, Sint64
*v);
void
AG_WriteUint8
(AG_DataSource
*ds, Uint8
value);
int
AG_WriteUint8v
(AG_DataSource
*ds, const Uint8
*value);
void
AG_WriteSint8
(AG_DataSource
*ds, Sint8
value);
int
AG_WriteSint8v
(AG_DataSource
*ds, const Sint8
*value);
void
AG_WriteUint16
(AG_DataSource
*ds, Uint16
value);
int
AG_WriteUint16v
(AG_DataSource
*ds, const Uint16
*value);
void
AG_WriteSint16
(AG_DataSource
*ds, Sint16
value);
int
AG_WriteSint16v
(AG_DataSource
*ds, const Sint16
*value);
void
AG_WriteUint32
(AG_DataSource
*ds, Uint32
value);
int
AG_WriteUint32v
(AG_DataSource
*ds, const Uint32
*value);
void
AG_WriteSint32
(AG_DataSource
*ds, Sint32
value);
int
AG_WriteSint32v
(AG_DataSource
*ds, const Sint32
*value);
void
AG_WriteUint64
(AG_DataSource
*ds, Uint64
value);
int
AG_WriteUint64v
(AG_DataSource
*ds, const Uint64
*value);
void
AG_WriteSint64
(AG_DataSource
*ds, Sint64
value);
int
AG_WriteSint64v
(AG_DataSource
*ds, const Sint64
*value);
void
AG_WriteUint8At
(AG_DataSource
*ds, Uint8 value,
off_t offs);
void
AG_WriteSint8At
(AG_DataSource
*ds, Sint8 value,
off_t offs);
void
AG_WriteUint16At
(AG_DataSource
*ds, Uint16 value,
off_t offs);
void
AG_WriteSint16At
(AG_DataSource
*ds, Sint16 value,
off_t offs);
void
AG_WriteUint32At
(AG_DataSource
*ds, Uint32 value,
off_t offs);
void
AG_WriteSint32At
(AG_DataSource
*ds, Sint32 value,
off_t offs);
void
AG_WriteUint64At
(AG_DataSource
*ds, Uint64 value,
off_t offs);
void
AG_WriteSint64At
(AG_DataSource
*ds, Sint64 value,
off_t offs);
The AG_Read[SU]intN
() functions read and
return an integer value of N bits from the data source. The
AG_Read[SU]intNv
() variants write the value to the
specified pointer.
The AG_Write[SU]intN
() functions write an
integer value of N bits to the data source. The
AG_Write[SU]intNv
() variants accept a pointer
argument.
The AG_Write[SU]intNAt
() variants write
the integer to the specified position in the data source.
All AG_Read*v
() functions return 0 on
success and -1 on failure, without raising any exceptions. The other
functions will raise a data source exception if an failuer (e.g., an I/O
error) occured.
The 64-bit types are only available if
HAVE_64BIT
is defined.
The following routines read and write floating-point numbers in IEEE.754
representation.
float
AG_ReadFloat
(AG_DataSource
*ds);
int
AG_ReadFloatv
(AG_DataSource
*ds, float *f);
double
AG_ReadDouble
(AG_DataSource
*ds);
int
AG_ReadDoublev
(AG_DataSource
*ds, double
*f);
long double
AG_ReadLongDouble
(AG_DataSource
*ds);
int
AG_ReadLongDouble
(AG_DataSource
*ds, long double
*f);
void
AG_WriteFloat
(AG_DataSource
*ds, float f);
int
AG_WriteFloatv
(AG_DataSource
*ds, float *f);
void
AG_WriteFloatAt
(AG_DataSource
*ds, float f,
off_t pos);
void
AG_WriteDouble
(AG_DataSource
*ds, double f);
int
AG_WriteDoublev
(AG_DataSource
*ds, double
*f);
void
AG_WriteDoubleAt
(AG_DataSource
*ds, double f,
off_t pos);
void
AG_WriteLongDouble
(AG_DataSource
*ds, long double
f);
int
AG_WriteLongDoublev
(AG_DataSource
*ds, long double
*f);
void
AG_WriteLongDoubleAt
(AG_DataSource
*ds, long double f,
off_t pos);
AG_ReadFloat
(),
AG_ReadDouble
() and
AG_ReadLongDouble
() read a floating-point value from
the data source.
AG_WriteFloat
(),
AG_WriteDouble
() and
AG_WriteLongDouble
() write a floating-point value to
the data source. The AG_Write*At
() variants write
the value at a given position.
All AG_Read*v
() functions return 0 on
success and -1 on failure, without raising any exceptions. The other
functions will raise a data source exception if an failuer (e.g., an I/O
error) occured.
The long double functions are available only
if HAVE_LONG_DOUBLE
is defined.
The following functions read and write arbitrary strings, and are commonly used
for text. The encoding of the strings is simply an unsigned 32-bit integer
byte count, followed by the string. The encoding may or may not include a
terminating NUL.
char *
AG_ReadStringLen
(AG_DataSource
*ds, size_t
maxsize);
int
AG_ReadStringLenv
(AG_DataSource
*ds, size_t
maxsize, char
**s);
char *
AG_ReadString
(AG_DataSource
*ds);
int
AG_ReadStringv
(AG_DataSource
*ds, char **s);
char *
AG_ReadNulStringLen
(AG_DataSource
*ds, size_t
maxsize);
char *
AG_ReadNulString
(AG_DataSource
*ds);
size_t
AG_CopyString
(char
*buf, AG_DataSource
*ds, size
buf_size);
size_t
AG_CopyNulString
(char
*buf, AG_DataSource
*ds, size
buf_size);
void
AG_SkipString
(AG_DataSource
*ds);
void
AG_WriteString
(AG_DataSource
*ds, const char
*s);
int
AG_WriteStringv
(AG_DataSource
*ds, const char
*s);
The AG_ReadStringLen
() function reads a
string of up to maxsize bytes and returns a
dynamically allocated, NUL-terminated copy of the string.
AG_ReadString
() implicitely limits the string to
AG_LOAD_STRING_MAX
bytes. Both functions will raise
a data source exception on error.
The AG_ReadStringLenv
() and
AG_ReadStringv
() variants accept a pointer
s to an existing, valid string buffer which will be
reallocated to fit the new string. Both functions will return -1 (without
raising a data source exception) on failure. If a low-level I/O error occurs
after the buffer is reallocated, the string at s will
be truncated to zero-length.
AG_CopyString
() copies the string directly
into a fixed-size buffer buf of
buf_size bytes and NUL-terminates it.
AG_CopyString
() returns the number of bytes that
would have been copied were buf_size unlimited. If an
error occurs, a data source exception is raised.
The AG_ReadNulString
(),
AG_ReadNulStringLen
() and
AG_CopyNulString
() variants handle strings where the
encoding includes the NUL-termination. These functions do not perform type
checking are mostly useful when reading non-Agar generated data files.
The AG_SkipString
() routine skips over the
string at the current position in the buffer.
The AG_WriteString
() function writes a
string to a data source, where the encoding is not NUL-terminated. If an
error occurs, a data source exception is raised. The
AG_WriteStringv
() variant returns 0 on success and
-1 on failure, without raising exceptions.
New sources can be implementing by defining a new structure inheriting from
AG_DataSource.
Public members of the AG_DataSource
structure include:
typedef struct ag_data_source {
AG_Mutex lock; /* Lock on all operations */
enum ag_byte_order byte_order; /* Byte order of source */
size_t wrLast; /* Last write count (bytes) */
size_t rdLast; /* Last read count (bytes) */
size_t wrTotal; /* Total write count (bytes) */
size_t rdTotal; /* Total read count (bytes) */
AG_IOStatus (*read)(struct ag_data_source *, void *buf,
size_t size, size_t *rv);
AG_IOStatus (*read_at)(struct ag_data_source *, void *buf,
size_t size, off_t pos, size_t *rv);
AG_IOStatus (*write)(struct ag_data_source *, const void *buf,
size_t size, size_t *rv);
AG_IOStatus (*write_at)(struct ag_data_source *, const void *buf,
size_t size, off_t pos, size_t *rv);
off_t (*tell)(struct ag_data_source *);
int (*seek)(struct ag_data_source *, off_t offs,
enum ag_seek_mode mode);
void (*close)(struct ag_data_source *);
} AG_DataSource;
The byte_order setting affects integer read
operations.
The wrLast, rdLast,
wrTotal and rdTotal fields keep
count of the read/written bytes, and are automatically incremented by the
generic AG_DataSource
calls.
The read operation reads
size bytes from the data source and into
buf, returning the total number of bytes read into
rv. The read_at variant reads
data at a specified offset.
The write operation writes
size bytes from buf to the data
source, returning the total number of bytes written into
rv. The write_at variant writes
the data at a specified offset.
tell returns the current offset.
seek moves to the specified offset and
returns 0 on success and -1 on failure.
close closes the data source.
A similar interface called ‘AG_Netbuf’ first appeared in Agar 1.0.
The current AG_DataSource
interface appeared in Agar
1.3. Exception handling and error-checking variants of the primitive I/O
routines appeared in Agar 1.3.3. The interface to network sockets appeared in
Agar 1.5.0.