51 uint32 recordSize, recordCount, firstRecordPos;
52 loadHeader(*dbf, recordSize, recordCount, firstRecordPos);
64 dbf->
seek(firstRecordPos);
79 throw Exception(
"Unknown database version 0x%02X", version);
99 throw Exception(
"Unknown flags 0x%02X", flags);
127 if (field.
offset != (fieldsLength + 1))
128 throw Exception(
"Field offset makes no sense (%d != %d)",
129 field.
offset, fieldsLength + 1);
134 fieldsLength += field.
size;
139 if (recordSize != (fieldsLength + 1))
140 throw Exception(
"Length of all fields does not equal the record size");
144 _pool.push_back(
new byte[recordSize * recordCount]);
147 if (dbf.
read(recordData, recordSize * recordCount) != (recordSize * recordCount))
151 throw Exception(
"Record end marker missing");
157 for (
uint32 i = 0; i < recordCount; i++) {
159 byte *data = recordData + i * recordSize;
167 record.
fields.resize(fieldCount);
168 for (
uint32 j = 0; j < fieldCount; j++) {
250 for (
size_t i = 0; i <
_fields.size(); i++) {
253 const size_t nameLength = std::strlen(field.
name.
c_str());
259 for (
size_t j = 0; j < (10 - nameLength); j++)
282 for (
size_t i = 0; i <
_records.size(); i++) {
287 for (
size_t j = 0; j <
_fields.size(); j++)
300 for (
int i = 0; i < 126; i++)
303 for (
size_t i = 0; i <
_memos.size(); i++)
338 assert(field <
_fields.size());
342 throw Exception(
"Field is not of string type ('%c')", f.type);
355 assert(field <
_fields.size());
368 throw Exception(
"Integer field size != 4 (%d)", f.size);
370 i = READ_LE_UINT32(record.
fields[field]);
373 throw Exception(
"Field is not of int type ('%c')", f.type);
379 assert(field <
_fields.size());
383 throw Exception(
"Field is not of bool type ('%c')", f.type);
386 throw Exception(
"Bool field size != 1 (%d)", f.size);
388 char c = (char) record.
fields[field][0];
390 if ((c ==
't') || (c ==
'T') || (c ==
'y') || (c ==
'Y') || (c ==
'1'))
397 assert(field <
_fields.size());
406 throw Exception(
"Numerical field size > 31 (%d)", f.size);
408 strncpy(n, reinterpret_cast<const char *>(record.
fields[field]), f.size);
411 if (std::sscanf(n,
"%lf", &d) != 1)
417 throw Exception(
"Float field size != 4 (%d)", f.size);
424 throw Exception(
"Double field size != 8 (%d)", f.size);
429 throw Exception(
"Field is not of double type ('%c')", f.type);
435 assert(field <
_fields.size());
439 throw Exception(
"Field is not of date type ('%c')", f.type);
442 throw Exception(
"Date field size != 8 (%d)", f.size);
447 memcpy(tmp, record.
fields[field], MIN<size_t>(f.size,
sizeof(tmp)));
448 tmp[
sizeof(tmp) - 1] =
'\0';
450 uint fieldYear, fieldMonth, fieldDay;
451 if (std::sscanf(tmp,
"%4u%2u%2u", &fieldYear, &fieldMonth, &fieldDay) != 3)
452 throw Exception(
"Failed reading the date");
460 assert(field <
_fields.size());
464 throw Exception(
"Field is not of memo type ('%c')", f.type);
467 if (!
getInt(record.
fields[field], f.size, i) || (i < 1))
470 size_t block = ((
uint32) i) - 1;
472 if (block >=
_memos.size())
475 size_t type = READ_BE_UINT32(
_memos[block] + 0);
476 size_t size = READ_BE_UINT32(
_memos[block] + 4);
478 if ((type != 0x00) && (type != 0x01) && (type != 0x02))
483 size_t dataSize = size;
490 if (block >=
_memos.size())
495 std::memcpy(dataPtr,
_memos[block] + (first ? 8 : 0), n);
687 size_t dataSize = size *
_records.size();
693 for (std::vector<Record>::iterator it =
_records.begin(); it !=
_records.end(); ++it) {
694 it->fields.push_back(data);
713 for (
size_t i = 0; i <
_fields.size(); i++) {
731 throw Exception(
"Field is not of string type ('%c')", f.
type);
733 char *data =
reinterpret_cast<char *
>(r.
fields[field]);
734 char *dataEnd =
reinterpret_cast<char *
>(r.
fields[field]) + f.
size;
738 data += std::strlen(value.
c_str());
740 while (data < dataEnd)
752 char *data =
reinterpret_cast<char *
>(r.
fields[field]);
757 snprintf(data, f.
size,
"%*d", f.
size, value);
766 WRITE_LE_UINT32(data, value);
786 char *data =
reinterpret_cast<char *
>(r.
fields[field]);
788 data[0] = value ?
'T' :
'F';
799 char *data =
reinterpret_cast<char *
>(r.
fields[field]);
823 throw Exception(
"Field is not of double type ('%c')", f.
type);
842 snprintf(tmp,
sizeof(tmp),
"%04u%02u%02u", (
uint) year, (
uint) month, (
uint) day);
858 char *data =
reinterpret_cast<char *
>(r.
fields[field]);
861 std::memset(data, 0x20, f.
size);
868 size_t size = value->
size();
870 size_t block =
_memos.size();
873 size_t startBlock = block + 1;
875 WRITE_BE_UINT32(
_memos[block] , 1);
876 WRITE_BE_UINT32(
_memos[block] + 4, size);
882 if (value->
read(
_memos[block] + (first ? 8 : 0), n) != n)
895 snprintf(data, f.
size,
"%*u", f.
size, (
uint) startBlock);
906 throw Exception(
"Numerical field size > 31 (%u)", (
uint)size);
908 strncpy(n, reinterpret_cast<const char *>(data), size);
911 return std::sscanf(n,
"%d", &i) == 1;
int32 getInt(const Record &record, size_t field) const
static void checkName(const UString &name)
bool getBool(const Record &record, size_t field) const
uint16 readUint16LE()
Read an unsigned 16-bit word stored in little endian (LSB first) order from the stream and return it...
bool deleted
Has this record been deleted?
void loadRecords(SeekableReadStream &dbf, uint32 recordSize, uint32 recordCount)
uint32 readUint32LE()
Read an unsigned 32-bit word stored in little endian (LSB first) order from the stream and return it...
virtual void flush()
Commit any buffered data to the underlying channel or storage medium; unbuffered streams can use the ...
A class holding an UTF-8 string.
virtual size_t seek(ptrdiff_t offset, Origin whence=kOriginBegin)=0
Sets the stream position indicator for the stream.
PointerType release()
Returns the plain pointer value and releases ScopedPtr.
const std::vector< Record > & getRecords() const
A date/time object, storing a specific point in time.
size_t addFieldInt(const UString &name)
virtual bool eos() const =0
Returns true if a read failed because the stream has been reached.
void deleteRecord(size_t record)
Implementing the reading stream interfaces for plain memory blocks.
size_t getRecordCount() const
void saveMemos(WriteStream &fpt) const
double convertIEEEDouble(uint64 data)
Convert a uint64 holding the bit pattern of a 64-bit IEEE 754 double precision floating point value i...
Exception that provides a stack of explanations.
void saveHeader(WriteStream &dbf) const
A simple scoped smart pointer template.
Utility functions for manipulating date and time.
Basic exceptions to throw.
utf8::iterator< std::string::const_iterator > iterator
const char * c_str() const
Return the (utf8 encoded) string data.
void writeUint16BE(uint16 value)
void saveFields(WriteStream &dbf) const
size_t addFieldDate(const UString &name)
uint16 readUint16BE()
Read an unsigned 16-bit word stored in big endian (MSB first) order from the stream and return it...
size_t addFieldBool(const UString &name)
virtual size_t skip(ptrdiff_t offset)
Skip the specified number of bytes, adding that offset to the current position in the stream...
Basic writing stream interfaces.
size_t addFieldNumber(const UString &name, uint8 size, uint8 decimals)
void setDate(size_t record, size_t field, uint16 year, uint8 month, uint8 day)
size_t addFieldMemo(const UString &name)
virtual size_t read(void *dataPtr, size_t dataSize)=0
Read data from the stream.
Simple memory based 'stream', which implements the ReadStream interface for a plain memory block...
Utility functions for working with differing string encodings.
void writeUint16LE(uint16 value)
void loadFields(SeekableReadStream &dbf, uint32 recordSize)
const Exception kReadError("Read error")
Exception when reading from a stream failed.
A database in FoxPro format.
virtual size_t write(const void *dataPtr, size_t dataSize)=0
Write data into the stream.
void writeByte(byte value)
virtual size_t size() const =0
Obtains the total size of the stream, measured in bytes.
std::vector< Record > _records
void save(WriteStream *dbf, WriteStream *cdx=0, WriteStream *fpt=0) const
Generic interface for a writable data stream.
void setMemo(size_t record, size_t field, SeekableReadStream *value=0)
double getDouble(const Record &record, size_t field) const
Seek from the current position of the stream.
void saveRecords(WriteStream &dbf) const
PtrList< byte, DeallocatorArray > _pool
Plain, unextended ASCII (7bit clean).
void setString(size_t record, size_t field, const UString &value)
PointerType get() const
Returns the plain pointer value.
void getDate(uint16 &year, uint8 &month, uint8 &day) const
Return the year, month (1..12) and day (1..31) in the Gregorian calendar.
static bool isASCII(uint32 c)
Is the character an ASCII character?
float convertIEEEFloat(uint32 data)
Convert a uint32 holding the bit pattern of a 32-bit IEEE 754 single precision floating point value i...
void loadHeader(SeekableReadStream &dbf, uint32 &recordSize, uint32 &recordCount, uint32 &firstRecordPos)
SeekableReadStream * getMemo(const Record &record, size_t field) const
Coordinated Universal Time (UTC).
const std::vector< Field > & getFields() const
PtrVector< byte, DeallocatorArray > _memos
UString getString(const Record &record, size_t field) const
void getDate(const Record &record, size_t field, uint16 &year, uint8 &month, uint8 &day)
size_t addFieldString(const UString &name, uint8 size)
std::vector< Field > _fields
void status(const char *s,...)
size_t getFieldCount() const
void getLastUpdate(uint16 &lastUpdateYear, uint8 &lastUpdateMonth, uint8 &lastUpdateDay) const
UString readStringFixed(SeekableReadStream &stream, Encoding encoding, size_t length)
Read length bytes as a string with the given encoding out of a stream.
void writeUint32BE(uint32 value)
void load(SeekableReadStream *dbf, SeekableReadStream *cdx=0, SeekableReadStream *fpt=0)
std::vector< byte * > fields
Raw field data.
void setDouble(size_t record, size_t field, double value)
void setBool(size_t record, size_t field, bool value)
Interface for a seekable & readable data stream.
void writeUint32LE(uint32 value)
void addField(uint8 size)
void setInt(size_t record, size_t field, int32 value)
byte readByte()
Read an unsigned byte from the stream and return it.
void loadMemos(SeekableReadStream &fpt)