Permalink
Browse files

got rid of all the manual binary offset tracking with a simple wrapper

  • Loading branch information...
RandomEtc committed Nov 24, 2009
1 parent 9f4801f commit 28cebb818436b54ae4c022a287748d7d9d71b35b
Showing with 257 additions and 194 deletions.
  1. +3 −2 README
  2. +64 −0 binary.js → binaryajax.js
  3. +70 −0 binarywrapper.js
  4. +5 −4 dbf.html
  5. +60 −79 dbf.js
  6. +2 −1 index.html
  7. +51 −107 shapefile.js
  8. +2 −1 shp.html
View
5 README
@@ -1,9 +1,8 @@
A binary shapefile loader and canvas-based renderer, for javascript. Many caveats:
Seems best in Safari... times out in IE and in Firefox 3.5 with large files.
-Does the dumbest thing possible and reads entire shp and dbf files in one go..
+Does the dumbest thing possible and reads entire shp and dbf files in one go.
Error checking is strange (needs testing with more known-good files).
-Manually increments byte array offsets instead of being smart.
Implies that it's a good idea to load large binary files over the network.
Doesn't do anything much apart from proof of concept.
@@ -13,6 +12,8 @@ http://code.google.com/p/explorercanvas/ is used for IE support
binaryajax.js is under MPL and was extended to support parsing doubles
+binarywrapper.js is new, to keep track of binary offsets and endianness
+
dbf.js and shapefile.js are close relatives of the vanrijkom-libs code and as such are LGPL v2 as well
excanvas.js is under Apache License 2.0
@@ -1,3 +1,67 @@
+var BinaryFileWrapper = function(binFile) {
+
+ this.position = 0;
+ this.bigEndian = true;
+
+ this.getByte = function() {
+ var byte = binFile.getByteAt(this.position);
+ this.position++;
+ return byte;
+ }
+
+ this.getLength = function() {
+ return binFile.getLength();
+ }
+
+ this.getSByte = function() {
+ var sbyte = binFile.getSByteAt(this.position);
+ this.position++;
+ return sbyte;
+ }
+
+ this.getShort = function() {
+ var short = binFile.getShortAt(this.position, this.bigEndian);
+ this.position += 2;
+ return short;
+ }
+
+ this.getSShort = function() {
+ var sshort = binFile.getSShortAt(this.position, this.bigEndian);
+ this.position += 2;
+ return sshort;
+ }
+
+ this.getLong = function() {
+ var l = binFile.getLongAt(this.position, this.bigEndian);
+ this.position += 4;
+ return l;
+ }
+
+ this.getSLong = function() {
+ var l = binFile.getSLongAt(this.position, this.bigEndian);
+ this.position += 4;
+ return l;
+ }
+
+ this.getString = function(iLength) {
+ var s = binFile.getStringAt(this.position, iLength);
+ this.position += iLength;
+ return s;
+ }
+
+ this.getDouble = function() {
+ var d = binFile.getDoubleAt(this.position, this.bigEndian);
+ this.position += 8;
+ return d;
+ }
+
+ this.getChar = function() {
+ var c = binFile.getCharAt(this.position);
+ this.position++;
+ return c;
+ }
+};
+
/*
* Binary Ajax 0.1.7
* Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com, http://blog.nihilogic.dk/
View
@@ -0,0 +1,70 @@
+//
+// stateful helper for binaryajax.js's BinaryFile class
+//
+// modelled on Flash's ByteArray, mostly, although some names
+// (int/short/long) differ in definition
+//
+
+function BinaryFileWrapper(binFile) {
+
+ this.position = 0;
+ this.bigEndian = true;
+
+ this.getByte = function() {
+ var byte = binFile.getByteAt(this.position);
+ this.position++;
+ return byte;
+ }
+
+ this.getLength = function() {
+ return binFile.getLength();
+ }
+
+ this.getSByte = function() {
+ var sbyte = binFile.getSByteAt(this.position);
+ this.position++;
+ return sbyte;
+ }
+
+ this.getShort = function() {
+ var short = binFile.getShortAt(this.position, this.bigEndian);
+ this.position += 2;
+ return short;
+ }
+
+ this.getSShort = function() {
+ var sshort = binFile.getSShortAt(this.position, this.bigEndian);
+ this.position += 2;
+ return sshort;
+ }
+
+ this.getLong = function() {
+ var l = binFile.getLongAt(this.position, this.bigEndian);
+ this.position += 4;
+ return l;
+ }
+
+ this.getSLong = function() {
+ var l = binFile.getSLongAt(this.position, this.bigEndian);
+ this.position += 4;
+ return l;
+ }
+
+ this.getString = function(iLength) {
+ var s = binFile.getStringAt(this.position, iLength);
+ this.position += iLength;
+ return s;
+ }
+
+ this.getDouble = function() {
+ var d = binFile.getDoubleAt(this.position, this.bigEndian);
+ this.position += 8;
+ return d;
+ }
+
+ this.getChar = function() {
+ var c = binFile.getCharAt(this.position);
+ this.position++;
+ return c;
+ }
+}
View
@@ -1,7 +1,8 @@
<html>
<head>
<title>Javascript DBF Loader</title>
-<script type="text/javascript" src="binary.js"></script>
+<script type="text/javascript" src="binaryajax.js"></script>
+<script type="text/javascript" src="binarywrapper.js"></script>
<script type="text/javascript" src="dbf.js"></script>
<script type="text/javascript">
@@ -20,12 +21,12 @@
if (window.console && window.console.log) console.log('got data, parsing dbf');
- var dbf = new DbfHeader(binFile);
+ var dbf = new DbfFile(binFile);
if (window.console && window.console.log) console.log(dbf);
- for (var i = 0; i < dbf.recordCount; i++) {
- var record = getRecord(binFile, dbf, i);
+ for (var i = 0; i < dbf.header.recordCount; i++) {
+ var record = dbf.records[i];
if (window.console && window.console.log) console.log(record);
}
}
View
139 dbf.js
@@ -1,140 +1,121 @@
// ported from http://code.google.com/p/vanrijkom-flashlibs/ under LGPL v2.1
-function DbfFile(src) {
+function DbfFile(binFile) {
+
+ this.src = new BinaryFileWrapper(binFile);
+
var t1 = new Date().getTime();
- this.header = new DbfHeader(src);
+ this.header = new DbfHeader(this.src);
var t2 = new Date().getTime();
if (window.console && window.console.log) console.log('parsed dbf header in ' + (t2-t1) + ' ms');
t1 = new Date().getTime();
+ // TODO: could maybe be smarter about this and only parse these on demand
this.records = [];
for (var i = 0; i < this.header.recordCount; i++) {
- var record = getRecord(src, this.header, i);
+ var record = this.getRecord(i);
this.records.push(record);
}
t2 = new Date().getTime();
if (window.console && window.console.log) console.log('parsed dbf records in ' + (t2-t1) + ' ms');
}
+DbfFile.prototype.getRecord = function(index) {
+ if (index > this.header.recordCount)
+ throw(new DbfError("",DbfError.ERROR_OUTOFBOUNDS));
+
+ this.src.position = this.header.recordsOffset + index * this.header.recordSize;
+ this.src.bigEndian = false;
+
+ return new DbfRecord(this.src, this.header);
+}
-function DbfHeader(src) {
- var binState = { offset: 0, bigEndian: true };
+function DbfHeader(src) {
// endian:
- binState.bigEndian = false;
-
- this.version = src.getSByteAt(binState.offset, binState.bigEndian);
- binState.offset += 1;
- this.updateYear = 1900+src.getByteAt(binState.offset, binState.bigEndian);
- binState.offset += 1;
- this.updateMonth = src.getByteAt(binState.offset, binState.bigEndian);
- binState.offset += 1;
- this.updateDay = src.getByteAt(binState.offset, binState.bigEndian);
- binState.offset += 1;
- this.recordCount = src.getLongAt(binState.offset, binState.bigEndian);
- binState.offset += 4;
- this.headerSize = src.getShortAt(binState.offset, binState.bigEndian);
- binState.offset += 2;
- this.recordSize = src.getShortAt(binState.offset, binState.bigEndian);
- binState.offset += 2;
+ src.bigEndian = false;
+
+ this.version = src.getSByte();
+ this.updateYear = 1900+src.getByte();
+ this.updateMonth = src.getByte();
+ this.updateDay = src.getByte();
+ this.recordCount = src.getLong();
+ this.headerSize = src.getShort();
+ this.recordSize = src.getShort();
//skip 2:
- binState.offset += 2;
+ src.position += 2;
- this.incompleteTransaction = src.getByteAt(binState.offset, binState.bigEndian);
- binState.offset += 1;
- this.encrypted = src.getByteAt(binState.offset, binState.bigEndian);
- binState.offset += 1;
+ this.incompleteTransaction = src.getByte();
+ this.encrypted = src.getByte();
// skip 12:
- binState.offset += 12;
+ src.position += 12;
- this.mdx = src.getByteAt(binState.offset, binState.bigEndian);
- binState.offset += 1;
- this.language = src.getByteAt(binState.offset, binState.bigEndian);
- binState.offset += 1;
+ this.mdx = src.getByte();
+ this.language = src.getByte();
// skip 2;
- binState.offset += 2;
+ src.position += 2;
// iterate field descriptors:
this.fields = [];
- while (src.getSByteAt(binState.offset, binState.bigEndian) != 0x0D){
- this.fields.push(new DbfField(src, binState));
+ while (src.getSByte() != 0x0D){
+ src.position -= 1;
+ this.fields.push(new DbfField(src));
}
this.recordsOffset = this.headerSize+1;
-}
+}
-function readZeroTermANSIString(src, binState) {
- var r = "";
- var b;
- while (b = src.getByteAt(binState.offset, binState.bigEndian)) {
- binState.offset += 1;
- r+= String.fromCharCode(b);
- }
- binState.offset += 1;
- return r;
-}
-
+function DbfField(src) {
-function DbfField(src, binState) {
-
- this.name = readZeroTermANSIString(src, binState);
+ this.name = this.readZeroTermANSIString(src);
// fixed length: 10, so:
- binState.offset += (10-this.name.length);
+ src.position += (10-this.name.length);
- this.type = src.getByteAt(binState.offset, binState.bigEndian);
- binState.offset += 1;
- this.address = src.getLongAt(binState.offset, binState.bigEndian);
- binState.offset += 4;
- this.length = src.getByteAt(binState.offset, binState.bigEndian);
- binState.offset += 1;
- this.decimals = src.getByteAt(binState.offset, binState.bigEndian);
- binState.offset += 1;
+ this.type = src.getByte();
+ this.address = src.getLong();
+ this.length = src.getByte();
+ this.decimals = src.getByte();
// skip 2:
- binState.offset += 2;
+ src.position += 2;
- this.id = src.getByteAt(binState.offset, binState.bigEndian);
- binState.offset += 1;
+ this.id = src.getByte();
// skip 2:
- binState.offset += 2;
+ src.position += 2;
- this.setFlag = src.getByteAt(binState.offset, binState.bigEndian);
- binState.offset += 1;
+ this.setFlag = src.getByte();
// skip 7:
- binState.offset += 7;
+ src.position += 7;
- this.indexFlag = src.getByteAt(binState.offset, binState.bigEndian);
- binState.offset += 1;
+ this.indexFlag = src.getByte();
}
-
-function getRecord(src, header, index) {
- if (index > header.recordCount)
- throw(new DbfError("",DbfError.ERROR_OUTOFBOUNDS));
-
- var binState = { bigEndian: false,
- offset: header.recordsOffset + index * header.recordSize };
- return new DbfRecord(src, header, binState);
+DbfField.prototype.readZeroTermANSIString = function(src) {
+ var r = "";
+ var b;
+ while (b = src.getByte()) {
+ r+= String.fromCharCode(b);
+ }
+ return r;
}
-function DbfRecord(src, header, binState) {
- this.offset = binState.offset;
+function DbfRecord(src, header) {
+ this.offset = src.position;
this.values = {}
for (var i = 0; i < header.fields.length; i++) {
var field = header.fields[i];
- this.values[field.name] = src.getStringAt(binState.offset, field.length);
- binState.offset += field.length;
+ this.values[field.name] = src.getString(field.length);
}
}
View
@@ -1,7 +1,8 @@
<html>
<head>
<title>Javascript Shapefile and DBF Loader</title>
-<script type="text/javascript" src="binary.js"></script>
+<script type="text/javascript" src="binaryajax.js"></script>
+<script type="text/javascript" src="binarywrapper.js"></script>
<script type="text/javascript" src="shapefile.js"></script>
<script type="text/javascript" src="dbf.js"></script>
<!--[if IE]><script src="excanvas.js"></script><![endif]-->
Oops, something went wrong.

0 comments on commit 28cebb8

Please sign in to comment.