Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 additions & 0 deletions dbase-level-7.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
var createDecoder = require('./decoder');
function dbfHeader(data) {
var out = {};
out.lastUpdated = new Date(data.readUInt8(1) + 1900, data.readUInt8(2), data.readUInt8(3));
out.records = data.readUInt32LE(4);
out.headerLen = data.readUInt16LE(8);
out.recLen = data.readUInt16LE(10);
return out;
}

function dbfRowHeader(data, headerLen, decoder) {
var out = [];
var offset = 68;

while (offset < headerLen) {
var columna = {
name: decoder(data.slice(offset, offset + 32)),
dataType: String.fromCharCode(data.readUInt8(offset + 32)),
len: data.readUInt8(offset + 33),
decimal: data.readUInt8(offset + 34),
mdx: data.readUInt8(offset + 37) == 0x01,
autoInc: data.readUInt32LE(offset + 40)
}

out.push(columna);

if (data.readUInt8(offset + 30) === 13) {
break;
} else {
offset += 48;
}
}
return out;
}

function rowFuncs(buffer, offset, len, type, decoder) {
var data = buffer.slice(offset, offset + len);


var textData = decoder(data);

//console.log('textData', textData, type, offset, len)

switch (type) {
case '+':

var negative = (data[0] & 0x80) == 0x00
var lastPart = (data[0] & 0x7F)

var buffer2 = Buffer.alloc(len, data)
buffer2[0] = lastPart

return buffer2.readUInt32BE(0)


case 'N':
case 'F':
case 'O':
return parseFloat(textData, 10);
case 'D':
return new Date(textData.slice(0, 4), parseInt(textData.slice(4, 6), 10) - 1, textData.slice(6, 8));
case 'L':
return textData.toLowerCase() === 'y' || textData.toLowerCase() === 't';
default:
return textData;
}
}

function parseRow(buffer, offset, rowHeaders, decoder) {
var out = {};
var i = 0;
var len = rowHeaders.length;
var field;
var header;
var deleted;
deleted = buffer.readUInt8(offset) == 0x2A
offset++
out['@deleted'] = deleted
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok so this is a field that's going to be showing up in records, if it's deleted shouldn't it actually just skip this record?


while (i < len) {

header = rowHeaders[i];
field = rowFuncs(buffer, offset, header.len, header.dataType, decoder);
offset += header.len;
if (typeof field !== 'undefined') {
out[header.name] = field;
}
i++;
}

return out;
}

module.exports = function(buffer, encoding) {
var decoder = createDecoder(encoding);
var header = dbfHeader(buffer);

var rowHeaders = dbfRowHeader(buffer, header.headerLen - 1, decoder);

var offset = header.headerLen//((rowHeaders.length + 1) << 5) + 2;
var recLen = header.recLen;
var records = header.records;
var out = [];

for (var i = 0; i < records; i++, offset += recLen) {
out.push(parseRow(buffer, offset, rowHeaders, decoder));
}

return out;
};
36 changes: 32 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
var createDecoder = require('./decoder');
var parseLevel7 = require('./dbase-level-7')
var parseVisualFoxpro = require('./visual-foxpro')

function dbfHeader(data) {
var out = {};

switch(data[0]) {
case 0x03:
out.dBaseVersion = 'level5'
break
case 0x04:
out.dBaseVersion = 'level7'
break
case 0x30:
out.dBaseVersion = 'visual_foxpro'
break
}

out.lastUpdated = new Date(data.readUInt8(1) + 1900, data.readUInt8(2), data.readUInt8(3));
out.records = data.readUInt32LE(4);
out.headerLen = data.readUInt16LE(8);
out.recLen = data.readUInt16LE(10);

return out;
}

Expand Down Expand Up @@ -65,16 +82,27 @@ function parseRow(buffer, offset, rowHeaders, decoder) {
module.exports = function(buffer, encoding) {
var decoder = createDecoder(encoding);
var header = dbfHeader(buffer);

switch(header.dBaseVersion) {
case 'level7':
return parseLevel7.apply(this, arguments)
case 'visual_foxpro':
return parseVisualFoxpro.apply(this, arguments)
}

var decoder = createDecoder(encoding);
var header = dbfHeader(buffer);

var rowHeaders = dbfRowHeader(buffer, header.headerLen - 1, decoder);

var offset = ((rowHeaders.length + 1) << 5) + 2;
var offset = header.headerLen//((rowHeaders.length + 1) << 5) + 2;
var recLen = header.recLen;
var records = header.records;
var out = [];
while (records) {

for (var i = 0; i < records; i++, offset += recLen) {
out.push(parseRow(buffer, offset, rowHeaders, decoder));
offset += recLen;
records--;
}

return out;
};
Binary file added tickets.dbf
Binary file not shown.
94 changes: 94 additions & 0 deletions visual-foxpro.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
var createDecoder = require('./decoder');
var parseLevel7 = require('./dbase-level-7')

function dbfHeader(data) {
var out = {};

out.lastUpdated = new Date(data.readUInt8(1) + 1900, data.readUInt8(2), data.readUInt8(3));
out.records = data.readUInt32LE(4);
out.headerLen = data.readUInt16LE(8);
out.recLen = data.readUInt16LE(10);

return out;
}

function dbfRowHeader(data, headerLen, decoder) {
var out = [];
var offset = 32;
while (offset < headerLen) {
out.push({
name: decoder(data.slice(offset, offset + 11)),
dataType: String.fromCharCode(data.readUInt8(offset + 11)),
len: data.readUInt8(offset + 16),
decimal: data.readUInt8(offset + 17)
});
if (data.readUInt8(offset + 32) === 13) {
break;
} else {
offset += 32;
}
}
return out;
}

function rowFuncs(buffer, offset, len, type, decoder) {
var data = buffer.slice(offset, offset + len);
var textData = decoder(data);
switch (type) {
case 'N':
case 'F':
case 'O':
return parseFloat(textData, 10);
case 'D':
return new Date(textData.slice(0, 4), parseInt(textData.slice(4, 6), 10) - 1, textData.slice(6, 8));
case 'L':
return textData.toLowerCase() === 'y' || textData.toLowerCase() === 't';
case 'Y':
return data.readUIntLE(0, 8) / 10000
default:
return textData;
}
}

function parseRow(buffer, offset, rowHeaders, decoder) {
var out = {};
var i = 0;
var len = rowHeaders.length;
var field;
var header;
deleted = buffer.readUInt8(offset) == 0x2A
offset++
out['@deleted'] = deleted
while (i < len) {
header = rowHeaders[i];
field = rowFuncs(buffer, offset, header.len, header.dataType, decoder);
offset += header.len;
if (typeof field !== 'undefined') {
out[header.name] = field;
}
i++;
}
return out;
}

module.exports = function(buffer, encoding) {
var decoder = createDecoder(encoding);
var header = dbfHeader(buffer);

if (header.dBaseVersion === 'level7') {
return parseLevel7.apply(this, arguments)
}

var rowHeaders = dbfRowHeader(buffer, header.headerLen - 1, decoder);

var offset = header.headerLen//((rowHeaders.length + 1) << 5) + 2;
var recLen = header.recLen;
var records = header.records;
var out = [];

for (var i = 0; i < records; i++, offset += recLen) {
out.push(parseRow(buffer, offset, rowHeaders, decoder));
}

return out;
};
Loading