void FoxPro::setMemo(size_t record, size_t field, SeekableReadStream *value) { assert((record < _records.size()) && (field < _fields.size())); Record &r = _records[record]; Field &f = _fields[field]; if (f.type != kTypeMemo) throw Exception("Field is not of memo type ('%c')", f.type); char *data = (char *) r.fields[field]; if (!value) { memset(data, 0x20, f.size); updateUpdate(); return; } value->seek(0); size_t size = value->size(); size_t block = _memos.size(); _memos.push_back(new byte[_memoBlockSize]); size_t startBlock = block + 1; WRITE_BE_UINT32(_memos[block] , 1); WRITE_BE_UINT32(_memos[block] + 4, size); bool first = true; while (size > 0) { size_t n = MIN<size_t>(size, _memoBlockSize - (first ? 8 : 0)); if (value->read(_memos[block] + (first ? 8 : 0), n) != n) throw Exception(kReadError); size -= n; block += 1; if (size > 0) _memos.push_back(new byte[_memoBlockSize]); first = false; } if (f.decimals != 0) snprintf(data, f.size, "%*u", f.size, (uint) startBlock); else snprintf(data, f.size, "%*.*f", f.size, f.decimals, (double) startBlock); updateUpdate(); }
void FoxPro::setDouble(size_t record, size_t field, double value) { assert((record < _records.size()) && (field < _fields.size())); Record &r = _records[record]; Field &f = _fields[field]; char *data = (char *) r.fields[field]; if (f.type == kTypeNumber) { if (f.decimals != 0) snprintf(data, f.size, "%*d", f.size, (int32) value); else snprintf(data, f.size, "%*.*f", f.size, f.decimals, value); } else if (f.type == kTypeFloat) { if (f.size != 4) throw Exception("Float field size != 4 (%d)", f.size); WRITE_LE_UINT32(data, convertIEEEFloat((float) value)); } else if (f.type == kTypeDouble) { if (f.size != 8) throw Exception("Double field size != 8 (%d)", f.size); WRITE_LE_UINT64(data, convertIEEEDouble(value)); } else throw Exception("Field is not of double type ('%c')", f.type); updateUpdate(); }
void FoxPro::setInt(size_t record, size_t field, int32 value) { assert((record < _records.size()) && (field < _fields.size())); Record &r = _records[record]; Field &f = _fields[field]; char *data = (char *) r.fields[field]; if (f.type == kTypeNumber) { if (f.decimals != 0) snprintf(data, f.size, "%*d", f.size, value); else snprintf(data, f.size, "%*.*f", f.size, f.decimals, (double) value); } else if (f.type == kTypeInteger) { if (f.size != 4) throw Exception("Integer field size != 4 (%d)", f.size); WRITE_LE_UINT32(data, value); } else throw Exception("Field is not of int type ('%c')", f.type); updateUpdate(); }
size_t FoxPro::addFieldMemo(const UString &name) { size_t offset = 1; if (!_fields.empty()) offset = _fields.back().offset + _fields.back().size; _fields.push_back(Field()); Field &field = _fields.back(); field.name = name; field.type = kTypeMemo; field.offset = offset; field.size = 10; field.decimals = 0; field.flags = 0; field.autoIncNext = 0; field.autoIncStep = 0; addField(field.size); updateUpdate(); _hasMemo = true; return _fields.size() - 1; }
void FoxPro::deleteRecord(size_t record) { assert(record < _records.size()); _records[record].deleted = true; updateUpdate(); // TODO: Deleting a record should also mark any memo fields in that // record as free. They should be reused when adding a memo // field of equals or less size. }
void FoxPro::setDate(size_t record, size_t field, uint16 year, uint8 month, uint8 day) { assert((record < _records.size()) && (field < _fields.size())); Record &r = _records[record]; Field &f = _fields[field]; if (f.type != kTypeDate) throw Exception("Field is not of date type ('%c')", f.type); char *data = reinterpret_cast<char *>(r.fields[field]); snprintf(data, 8, "%04u%02u%02u", (uint) year, (uint) month, (uint) day); updateUpdate(); }
void FoxPro::setDate(size_t record, size_t field, const date &value) { assert((record < _records.size()) && (field < _fields.size())); Record &r = _records[record]; Field &f = _fields[field]; if (f.type != kTypeDate) throw Exception("Field is not of date type ('%c')", f.type); char *data = (char *) r.fields[field]; snprintf(data, 8, "%04d%02d%02d", (int) value.year(), (int) value.month(), (int) value.day()); updateUpdate(); }
void FoxPro::setBool(size_t record, size_t field, bool value) { assert((record < _records.size()) && (field < _fields.size())); Record &r = _records[record]; Field &f = _fields[field]; if (f.type != kTypeBool) throw Exception("Field is not of bool type ('%c')", f.type); if (f.size != 1) throw Exception("Bool field size != 1 (%d)", f.size); char *data = (char *) r.fields[field]; data[0] = value ? 'T' : 'F'; updateUpdate(); }
void FoxPro::setString(size_t record, size_t field, const UString &value) { assert((record < _records.size()) && (field < _fields.size())); Record &r = _records[record]; Field &f = _fields[field]; if (f.type != kTypeString) throw Exception("Field is not of string type ('%c')", f.type); char *data = (char *) r.fields[field]; char *dataEnd = (char *) r.fields[field] + f.size; strncpy(data, value.c_str(), f.size); data += strlen(value.c_str()); while (data < dataEnd) *dataEnd++ = 0x20; updateUpdate(); }
size_t FoxPro::addFieldNumber(const UString &name, uint8 size, uint8 decimals) { size_t offset = 1; if (!_fields.empty()) offset = _fields.back().offset + _fields.back().size; _fields.push_back(Field()); Field &field = _fields.back(); field.name = name; field.type = kTypeNumber; field.offset = offset; field.size = size; field.decimals = decimals; field.flags = 0; field.autoIncNext = 0; field.autoIncStep = 0; addField(field.size); updateUpdate(); return _fields.size() - 1; }
size_t FoxPro::addRecord() { _records.push_back(Record()); Record &record = _records.back(); record.deleted = false; if (!_fields.empty()) { size_t dataSize = _fields.back().offset + _fields.back().size; _pool.push_back(new byte[dataSize]); byte *data = _pool.back(); record.fields.resize(_fields.size()); for (size_t i = 0; i < _fields.size(); i++) { record.fields[i] = data; data += _fields[i].size; } } updateUpdate(); return _records.size() - 1; }
FoxPro::FoxPro() : _hasIndex(false), _hasMemo(false), _memoBlockSize(512) { updateUpdate(); }