Comparing version 1.1.0 to 1.2.0
@@ -13,2 +13,3 @@ "use strict"; | ||
const iconv = require("iconv-lite"); | ||
const path_1 = require("path"); | ||
const field_descriptor_1 = require("./field-descriptor"); | ||
@@ -31,2 +32,3 @@ const options_1 = require("./options"); | ||
this._recordLength = 0; | ||
this._memoPath = ''; | ||
} | ||
@@ -65,8 +67,17 @@ /** Opens an existing DBF file. */ | ||
yield utils_1.read(fd, buffer, 0, 32, 0); | ||
let fileVersion = buffer.readInt8(0); | ||
let fileVersion = buffer.readUInt8(0); | ||
let recordCount = buffer.readInt32LE(4); | ||
let headerLength = buffer.readInt16LE(8); | ||
let recordLength = buffer.readInt16LE(10); | ||
// Ensure the file version is a supported one. | ||
assert(fileVersion === 0x03, `File '${path}' has unknown/unsupported dBase version: ${fileVersion}.`); | ||
let memoPath; | ||
// Ensure the file version is a supported one. Also locate the memo file, if any. | ||
switch (fileVersion) { | ||
case 0x03: | ||
memoPath = undefined; | ||
break; | ||
case 0x83: | ||
memoPath = path.slice(0, -path_1.extname(path).length) + '.dbt'; | ||
break; | ||
default: throw new Error(`File '${path}' has unknown/unsupported dBase version: ${fileVersion}.`); | ||
} | ||
// Parse all field descriptors. | ||
@@ -101,2 +112,3 @@ let fields = []; | ||
result._recordLength = recordLength; | ||
result._memoPath = memoPath; | ||
return result; | ||
@@ -117,3 +129,7 @@ } | ||
// Validate the field metadata. | ||
validateFieldDescriptorss(fields); | ||
validateFieldDescriptors(fields); | ||
// Disallow creation of DBF files with memo fields. | ||
// TODO: Lift this restriction when memo support is fully implemented. | ||
if (fields.some(f => f.type === 'M')) | ||
throw new Error(`Writing to files with memo fields is not supported.`); | ||
// Create the file and create a buffer to write through. | ||
@@ -187,2 +203,3 @@ fd = yield utils_1.open(path, 'wx'); | ||
let fd = 0; | ||
let memoFd = 0; | ||
try { | ||
@@ -194,2 +211,15 @@ // Open the file and prepare to create a buffer to read through. | ||
let buffer = Buffer.alloc(recordLength * recordCountPerBuffer); | ||
// If there is a memo file, open it and get the block size. | ||
// NB: The code below assumes the block size is at offset 4 in the .dbt, and defaults to 512 if all zeros. | ||
// Sources differ about whether the offset is 4 or 6, and no sources mention a default if all zeros. | ||
// However the assumptions here work with our one and only fixture memo file. The format likely differs | ||
// by version. Need more documentation and/or test data to validate or fix these assumptions. | ||
let memoBlockSize = 0; | ||
let memoBuf; | ||
if (dbf._memoPath) { | ||
memoFd = yield utils_1.open(dbf._memoPath, 'r'); | ||
yield utils_1.read(memoFd, buffer, 0, 2, 4); | ||
memoBlockSize = buffer.readInt16BE(0) || 512; | ||
memoBuf = Buffer.alloc(memoBlockSize); | ||
} | ||
// Calculate the file position at which to start reading. | ||
@@ -256,2 +286,25 @@ let currentPosition = dbf._headerLength + recordLength * dbf._recordsRead; | ||
break; | ||
case 'M': // Memo | ||
while (len > 0 && buffer[offset] === 0x20) | ||
++offset, --len; | ||
if (len === 0) { | ||
value = null; | ||
break; | ||
} | ||
let blockIndex = parseInt(substr(offset, len, encoding)); | ||
offset += len; | ||
// Read the memo data from the memo file. | ||
// NB: Some sources indicate that each block has a block header that states the data length. | ||
// Our fixture data doesn't have that - rather, the data is terminated with 0x1A. The format | ||
// likely differs by version. Need more documentation and/or test data to figure this out. | ||
value = ''; | ||
while (true) { | ||
yield utils_1.read(memoFd, memoBuf, 0, memoBlockSize, blockIndex * memoBlockSize); | ||
let eos = memoBuf.indexOf(0x1A); | ||
value += iconv.decode(memoBuf.slice(0, eos === -1 ? memoBlockSize : eos), encoding); | ||
if (eos !== -1) | ||
break; | ||
++blockIndex; | ||
} | ||
break; | ||
default: | ||
@@ -265,4 +318,2 @@ throw new Error(`Type '${field.type}' is not supported`); | ||
} | ||
// Allocate a new buffer, so that all the raw buffer slices created above are not overwritten. | ||
buffer = Buffer.alloc(recordLength * recordCountPerBuffer); | ||
} | ||
@@ -273,5 +324,7 @@ // Return all the records that were read. | ||
finally { | ||
// Close the file. | ||
// Close the file(s). | ||
if (fd) | ||
yield utils_1.close(fd); | ||
if (memoFd) | ||
yield utils_1.close(memoFd); | ||
} | ||
@@ -337,2 +390,6 @@ }); | ||
break; | ||
case 'M': // Memo | ||
// Disallow writing to DBF files with memo fields. | ||
// TODO: Lift this restriction when memo support is fully implemented. | ||
throw new Error(`Writing to files with memo fields is not supported.`); | ||
default: | ||
@@ -364,3 +421,3 @@ throw new Error(`Type '${field.type}' is not supported`); | ||
// Private helper function | ||
function validateFieldDescriptorss(fields) { | ||
function validateFieldDescriptors(fields) { | ||
if (fields.length > 2046) | ||
@@ -367,0 +424,0 @@ throw new Error('Too many fields (maximum is 2046)'); |
@@ -15,3 +15,3 @@ "use strict"; | ||
throw new Error('Type must be a single character'); | ||
if (['C', 'N', 'F', 'L', 'D', 'I'].indexOf(type) === -1) | ||
if (['C', 'N', 'F', 'L', 'D', 'I', 'M'].indexOf(type) === -1) | ||
throw new Error(`Type '${type}' is not supported`); | ||
@@ -33,4 +33,4 @@ // size | ||
throw new Error('Invalid field size (must be 8)'); | ||
if (type === 'I' && size !== 4) | ||
throw new Error('Invalid field size (must be 4)'); | ||
if (type === 'M' && size !== 10) | ||
throw new Error('Invalid field size (must be 10)'); | ||
// decimalPlaces | ||
@@ -37,0 +37,0 @@ if (decs !== undefined && typeof decs !== 'number') |
{ | ||
"name": "dbffile", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"description": "Read and write .dbf (dBase III) files in Node.js", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -7,3 +7,12 @@ # DBFFile | ||
- Supports `C` (string) , `N` (numeric), `F` (float), `I` (integer) , `L` (logical) and `D` (date) field types | ||
- Supported field types: | ||
- `C` (string) | ||
- `N` (numeric) | ||
- `F` (float) | ||
- `I` (integer) | ||
- `L` (logical) | ||
- `D` (date) | ||
- `M` (memo) Note: memo support is experimental/partial, with the following limitations: | ||
- read-only (can't create/write DBF files with memo fields) | ||
- dBase III file version 0x83 only | ||
- Can open an existing .dbf file | ||
@@ -10,0 +19,0 @@ - Can access all field descriptors |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
71484
547
109
1
9