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.
New data sources can be implemented by overloading the AG_DataSource structure.
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.
FLOATING POINT OPERATIONS
The following routines read and write floating-point numbers in IEEE.754
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.
The AG_ReadStringLen() function reads a string of up to maxLen 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. If non-NULL, the length of the string will be returned to newLen. 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 C string to a data source, in a variable-length encoding. The encoding is a 32-bit strlen(3) followed by the string itself (NUL is not included).
The AG_WriteStringPadded() function writes a C string to a data source, in a fixed-length encoding. The encoding is a 32-bit strlen(3) followed by the string itself (NUL is not included), and possibly extra padding such that the encoding is guaranteed to be length bytes + 4.
On failure, the AG_WriteString() routines raise a data source exception.
INTERNAL DATA SOURCE API
New sources can be implementing by defining a new structure inheriting from
Public members of the AG_DataSource structure include:
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.
|AG_ByteSwap(3), AG_Intro(3), AG_Net(3), AG_Version(3)|
|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.|