You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
251 lines
7.8 KiB
251 lines
7.8 KiB
2 years ago
|
(function(window,undefined){
|
||
|
|
||
|
if(window.document && window.Worker){
|
||
|
var worker = new Worker(host+"js/tools/shapefileToGeoJson/dbf.js")
|
||
|
|
||
|
var DBF = function(url, callback){
|
||
|
var
|
||
|
w = this._worker = worker,
|
||
|
t = this
|
||
|
|
||
|
w.onmessage = function(e){
|
||
|
t.data = e.data
|
||
|
if (callback) callback(e.data);
|
||
|
};
|
||
|
|
||
|
w.postMessage(url)
|
||
|
}
|
||
|
|
||
|
window["DBF"] = DBF
|
||
|
return
|
||
|
}
|
||
|
|
||
|
var IN_WORKER = !window.document
|
||
|
if (IN_WORKER) {
|
||
|
importScripts('stream.js')
|
||
|
onmessage = function(e){
|
||
|
new DBF(e.data);
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var
|
||
|
DBASE_LEVEL = {
|
||
|
"3": "dBASE Level 5",
|
||
|
"4": "dBase Level 7"
|
||
|
},
|
||
|
DBASE_FIELD_TYPE = {
|
||
|
"N": "Number",
|
||
|
"C": "Character", // binary
|
||
|
"L": "Logical",
|
||
|
"D": "Date",
|
||
|
"M": "Memo", // binary
|
||
|
"F": "Floating point",
|
||
|
"B": "Binary",
|
||
|
"G": "General",
|
||
|
"P": "Picture",
|
||
|
"Y": "Currency",
|
||
|
"T": "DateTime",
|
||
|
"I": "Integer",
|
||
|
"V": "VariField",
|
||
|
"X": "Variant",
|
||
|
"@": "Timestamp",
|
||
|
"O": "Double",
|
||
|
"+": "Autoincrement", // (dBase Level 7)
|
||
|
"O": "Double", // (dBase Level 7)
|
||
|
"@": "Timestamp" // (dBase Level 7)
|
||
|
}
|
||
|
|
||
|
var DBF = function(url, callback){
|
||
|
if (!!url.lastModifiedDate)
|
||
|
this.handleFile(url, callback);
|
||
|
else
|
||
|
this.handleUri(url, callback);
|
||
|
}
|
||
|
|
||
|
DBF.prototype = {
|
||
|
constructor: DBF,
|
||
|
handleFile: function(file, callback) {
|
||
|
this.callback = callback;
|
||
|
|
||
|
if (!!window.FileReader) {
|
||
|
var reader = new FileReader();
|
||
|
} else {
|
||
|
var reader = new FileReaderSync();
|
||
|
}
|
||
|
|
||
|
reader.onload = (function(that){
|
||
|
return function(e){
|
||
|
that.onFileLoad(e.target.result)
|
||
|
}
|
||
|
})(this);
|
||
|
|
||
|
if (!!window.FileReader) {
|
||
|
reader.readAsBinaryString(file);
|
||
|
} else {
|
||
|
this.onFileLoad(reader.readAsBinaryString(file));
|
||
|
}
|
||
|
},
|
||
|
onFileLoad: function(data) {
|
||
|
this.stream = new Gordon.Stream(data)
|
||
|
|
||
|
this.readFileHeader()
|
||
|
this.readFieldDescriptions()
|
||
|
this.readRecords()
|
||
|
|
||
|
this._postMessage()
|
||
|
},
|
||
|
handleUri: function(url, callback) {
|
||
|
var xhr = new XMLHttpRequest();
|
||
|
|
||
|
xhr.open("GET", url, false)
|
||
|
//xhr.overrideMimeType("text/plain; charset=UTF-8")
|
||
|
|
||
|
xhr.send()
|
||
|
|
||
|
if(200 != xhr.status)
|
||
|
throw "Unable to load " + url + " status: " + xhr.status
|
||
|
|
||
|
this.stream = new Gordon.Stream(xhr.responseText)
|
||
|
this.callback = callback
|
||
|
|
||
|
this.readFileHeader()
|
||
|
this.readFieldDescriptions()
|
||
|
this.readRecords()
|
||
|
|
||
|
this._postMessage()
|
||
|
},
|
||
|
_postMessage: function() {
|
||
|
var data = {
|
||
|
header: this.header,
|
||
|
fields: this.fields,
|
||
|
records: this.records
|
||
|
}
|
||
|
if (IN_WORKER) postMessage(data)
|
||
|
else if (this.callback) this.callback(data)
|
||
|
},
|
||
|
readFileHeader: function(){
|
||
|
var s = this.stream,
|
||
|
header = this.header = {},
|
||
|
date = new Date;
|
||
|
|
||
|
header.version = DBASE_LEVEL[s.readSI8()]
|
||
|
|
||
|
// Date of last update; in YYMMDD format. Each byte contains the number as a binary. YY is added to a base of 1900 decimal to determine the actual year. Therefore, YY has possible values from 0x00-0xFF, which allows for a range from 1900-2155.
|
||
|
date.setUTCFullYear(1900 + s.readSI8())
|
||
|
date.setUTCMonth(s.readSI8())
|
||
|
date.setUTCDate(s.readSI8())
|
||
|
|
||
|
header.lastUpdated = date
|
||
|
|
||
|
// Number of records in file
|
||
|
header.numRecords = s.readSI32()
|
||
|
|
||
|
// Position of first data record
|
||
|
header.firstRecordPosition = s.readSI16()
|
||
|
|
||
|
// Length of one data record, including delete flag
|
||
|
header.recordLength = s.readSI16()
|
||
|
|
||
|
// Reserved; filled with zeros
|
||
|
s.offset += 16
|
||
|
|
||
|
/*
|
||
|
Table flags:
|
||
|
0x01 file has a structural .cdx
|
||
|
0x02 file has a Memo field
|
||
|
0x04 file is a database (.dbc)
|
||
|
This byte can contain the sum of any of the above values. For example, the value 0x03 indicates the table has a structural .cdx and a Memo field.
|
||
|
*/
|
||
|
header.flags = s.readSI8()
|
||
|
|
||
|
// Code page mark
|
||
|
header.codePageMark = s.readSI8()
|
||
|
|
||
|
// Reserved; filled with zeros.
|
||
|
s.offset += 2
|
||
|
|
||
|
},
|
||
|
readFieldDescriptions: function(){
|
||
|
var s = this.stream,
|
||
|
fields = [],
|
||
|
field
|
||
|
|
||
|
while (s.readSI8() != 0x0D) {
|
||
|
s.offset--
|
||
|
field = {}
|
||
|
|
||
|
// Field name with a maximum of 10 characters. If less than 10, it is padded with null characters (0x00).
|
||
|
field.name = s.readString(11).replace(/\u0000/g,"")
|
||
|
|
||
|
field.type = DBASE_FIELD_TYPE[s.readString(1)]
|
||
|
|
||
|
// Displacement of field in record
|
||
|
field.fieldDisplacement = s.readSI32()
|
||
|
|
||
|
// Length of field (in bytes)
|
||
|
field.fieldLength = s.readUI8()
|
||
|
|
||
|
// Number of decimal places
|
||
|
field.decimals = s.readSI8()
|
||
|
|
||
|
/*
|
||
|
Field flags:
|
||
|
0x01 System Column (not visible to user)
|
||
|
0x02 Column can store null values
|
||
|
0x04 Binary column (for CHAR and MEMO only)
|
||
|
0x06 (0x02+0x04) When a field is NULL and binary (Integer, Currency, and Character/Memo fields)
|
||
|
0x0C Column is autoincrementing
|
||
|
*/
|
||
|
field.flags = s.readSI8()
|
||
|
|
||
|
// Value of autoincrement Next value
|
||
|
field.autoincrementNextValue = s.readSI32()
|
||
|
|
||
|
// Value of autoincrement Step value
|
||
|
field.autoincrementStepValue = s.readSI8()
|
||
|
|
||
|
// Reserved
|
||
|
s.offset += 8
|
||
|
|
||
|
fields.push(field)
|
||
|
}
|
||
|
|
||
|
this.fields = fields
|
||
|
|
||
|
},
|
||
|
readRecords: function(){
|
||
|
var s = this.stream,
|
||
|
numRecords = this.header.numRecords,
|
||
|
recordsOffset = this.header.firstRecordPosition,
|
||
|
recordSize = this.header.recordLength,
|
||
|
fields = this.fields,
|
||
|
numFields = fields.length,
|
||
|
records = [],
|
||
|
field, record
|
||
|
|
||
|
for (var index = 0; index < numRecords; index++) {
|
||
|
s.offset = recordsOffset + index * recordSize
|
||
|
|
||
|
record = {}
|
||
|
|
||
|
// Data records begin with a delete flag byte. If this byte is an ASCII space (0x20), the record is not deleted. If the first byte is an asterisk (0x2A), the record is deleted
|
||
|
record._isDeleted = s.readSI8() == 42
|
||
|
|
||
|
for(var i = 0; i < numFields; i++){
|
||
|
field = fields[i]
|
||
|
record[field.name] = s.readString(field.fieldLength).trim();
|
||
|
}
|
||
|
|
||
|
records.push(record);
|
||
|
}
|
||
|
|
||
|
this.records = records
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
window["DBF"] = DBF;
|
||
|
|
||
|
})(self);
|
||
|
|