preprocess.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /*
  2. * Inspired by the shp.js , dbf.js by Mano Marks
  3. *
  4. * I found there were something wrong to show chinese characters from DBF file,
  5. * so i added some code that is needed to deal with this problem.
  6. *
  7. * Created by Gipong <sheu781230@gmail.com>
  8. *
  9. */
  10. var geojsonData = {};
  11. // Shapefile parser, following the specification at
  12. // http://www.esri.com/library/whitepapers/pdfs/shapefile.pdf
  13. SHP = {
  14. NULL: 0,
  15. POINT: 1,
  16. POLYLINE: 3,
  17. POLYGON: 5
  18. };
  19. SHP.getShapeName = function(id) {
  20. for (name in this) {
  21. if (id === this[name]) {
  22. return name;
  23. }
  24. }
  25. };
  26. SHPParser = function() {};
  27. SHPParser.load = function(url, callback, returnData) {
  28. var xhr = new XMLHttpRequest();
  29. xhr.open('GET', url);
  30. xhr.responseType = 'arraybuffer';
  31. xhr.onload = function() {
  32. geojsonData['shp'] = new SHPParser().parse(xhr.response,url);
  33. callback(geojsonData['shp'], returnData);
  34. URL.revokeObjectURL(url);
  35. };
  36. xhr.onerror = onerror;
  37. xhr.send(null);
  38. };
  39. SHPParser.prototype.parse = function(arrayBuffer,url) {
  40. var o = {},
  41. dv = new DataView(arrayBuffer),
  42. idx = 0;
  43. o.fileName = url;
  44. o.fileCode = dv.getInt32(idx, false);
  45. if (o.fileCode != 0x0000270a) {
  46. throw (new Error("Unknown file code: " + o.fileCode));
  47. }
  48. idx += 6*4;
  49. o.wordLength = dv.getInt32(idx, false);
  50. o.byteLength = o.wordLength * 2;
  51. idx += 4;
  52. o.version = dv.getInt32(idx, true);
  53. idx += 4;
  54. o.shapeType = dv.getInt32(idx, true);
  55. idx += 4;
  56. o.minX = dv.getFloat64(idx, true);
  57. o.minY = dv.getFloat64(idx+8, true);
  58. o.maxX = dv.getFloat64(idx+16, true);
  59. o.maxY = dv.getFloat64(idx+24, true);
  60. o.minZ = dv.getFloat64(idx+32, true);
  61. o.maxZ = dv.getFloat64(idx+40, true);
  62. o.minM = dv.getFloat64(idx+48, true);
  63. o.maxM = dv.getFloat64(idx+56, true);
  64. idx += 8*8;
  65. o.records = [];
  66. while (idx < o.byteLength) {
  67. var record = {};
  68. record.number = dv.getInt32(idx, false);
  69. idx += 4;
  70. record.length = dv.getInt32(idx, false);
  71. idx += 4;
  72. try {
  73. record.shape = this.parseShape(dv, idx, record.length);
  74. } catch(e) {
  75. console.log(e, record);
  76. }
  77. idx += record.length * 2;
  78. o.records.push(record);
  79. }
  80. return o;
  81. };
  82. SHPParser.prototype.parseShape = function(dv, idx, length) {
  83. var i=0,
  84. c=null,
  85. shape = {};
  86. shape.type = dv.getInt32(idx, true);
  87. idx += 4;
  88. var byteLen = length * 2;
  89. switch (shape.type) {
  90. case SHP.NULL: // Null
  91. break;
  92. case SHP.POINT: // Point (x,y)
  93. shape.content = {
  94. x: dv.getFloat64(idx, true),
  95. y: dv.getFloat64(idx+8, true)
  96. };
  97. break;
  98. case SHP.POLYLINE: // Polyline (MBR, partCount, pointCount, parts, points)
  99. case SHP.POLYGON: // Polygon (MBR, partCount, pointCount, parts, points)
  100. c = shape.content = {
  101. minX: dv.getFloat64(idx, true),
  102. minY: dv.getFloat64(idx+8, true),
  103. maxX: dv.getFloat64(idx+16, true),
  104. maxY: dv.getFloat64(idx+24, true),
  105. parts: new Int32Array(dv.getInt32(idx+32, true)),
  106. points: new Float64Array(dv.getInt32(idx+36, true)*2)
  107. };
  108. idx += 40;
  109. for (i=0; i<c.parts.length; i++) {
  110. c.parts[i] = dv.getInt32(idx, true);
  111. idx += 4;
  112. }
  113. for (i=0; i<c.points.length; i++) {
  114. c.points[i] = dv.getFloat64(idx, true);
  115. idx += 8;
  116. }
  117. break;
  118. case 8: // MultiPoint (MBR, pointCount, points)
  119. case 11: // PointZ (X, Y, Z, M)
  120. case 13: // PolylineZ
  121. case 15: // PolygonZ
  122. case 18: // MultiPointZ
  123. case 21: // PointM (X, Y, M)
  124. case 23: // PolylineM
  125. case 25: // PolygonM
  126. case 28: // MultiPointM
  127. case 31: // MultiPatch
  128. throw new Error("Shape type not supported: "
  129. + shape.type + ':' +
  130. + SHP.getShapeName(shape.type));
  131. default:
  132. throw new Error("Unknown shape type at " + (idx-4) + ': ' + shape.type);
  133. }
  134. return shape;
  135. };
  136. /**
  137. * @fileoverview Parses a .dbf file based on the xbase standards as documented
  138. * here: http://www.clicketyclick.dk/databases/xbase/format/dbf.html
  139. * @author Mano Marks
  140. */
  141. // Creates global namespace.
  142. DBF = {};
  143. DBFParser = function() {};
  144. DBFParser.load = function(url, encoding, callback, returnData) {
  145. var xhr = new XMLHttpRequest();
  146. xhr.open('GET', url);
  147. xhr.responseType = 'arraybuffer';
  148. xhr.onload = function() {
  149. var xhrText = new XMLHttpRequest();
  150. var xhrTextResponse = '';
  151. xhrText.open('GET', url);
  152. xhrText.overrideMimeType('text/plain; charset='+encoding);
  153. xhrText.onload = function() {
  154. geojsonData['dbf'] = new DBFParser().parse(xhr.response,url,xhrText.responseText,encoding);
  155. callback(geojsonData['dbf'], returnData);
  156. URL.revokeObjectURL(url);
  157. };
  158. xhrText.send();
  159. };
  160. xhr.onerror = onerror;
  161. xhr.send(null);
  162. };
  163. DBFParser.prototype.parse = function(arrayBuffer,src,response,encoding) {
  164. var o = {},
  165. dv = new DataView(arrayBuffer),
  166. idx = 0,
  167. offset;
  168. switch(encoding.toLowerCase()) {
  169. case "big5": offset = 2; break;
  170. case "iso-8859-1": offset = 1; break;
  171. default: offset = 3;
  172. }
  173. o.fileName = src;
  174. o.version = dv.getInt8(idx, false);
  175. idx += 1;
  176. o.year = dv.getUint8(idx) + 1900;
  177. idx += 1;
  178. o.month = dv.getUint8(idx);
  179. idx += 1;
  180. o.day = dv.getUint8(idx);
  181. idx += 1;
  182. o.numberOfRecords = dv.getInt32(idx, true);
  183. idx += 4;
  184. o.bytesInHeader = dv.getInt16(idx, true);
  185. idx += 2;
  186. o.bytesInRecord = dv.getInt16(idx, true);
  187. idx += 2;
  188. //reserved bytes
  189. idx += 2;
  190. o.incompleteTransation = dv.getUint8(idx);
  191. idx += 1;
  192. o.encryptionFlag = dv.getUint8(idx);
  193. idx += 1;
  194. // skip free record thread for LAN only
  195. idx += 4;
  196. // reserved for multi-user dBASE in dBASE III+
  197. idx += 8;
  198. o.mdxFlag = dv.getUint8(idx);
  199. idx += 1;
  200. o.languageDriverId = dv.getUint8(idx);
  201. idx += 1;
  202. // reserved bytes
  203. idx += 2;
  204. o.fields = [];
  205. var response_handler = response.split('\r');
  206. if(response_handler.length > 2) {
  207. response_handler.pop();
  208. responseHeader = response_handler.join('\r');
  209. responseHeader = responseHeader.slice(32, responseHeader.length);
  210. } else {
  211. responseHeader = response_handler[0];
  212. responseHeader = responseHeader.slice(32, responseHeader.length);
  213. offset = 2;
  214. }
  215. var charString = [],
  216. count = 0,
  217. index = 0,
  218. sum = (responseHeader.length+1)/32;
  219. while(responseHeader.length > 0) {
  220. while(count < 10) {
  221. try {
  222. if( encodeURIComponent(responseHeader[z]).match(/%[A-F\d]{2}/g) ) {
  223. if( encodeURIComponent(responseHeader[z]).match(/%[A-F\d]{2}/g).length > 1 ) {
  224. count += offset;
  225. z++;
  226. } else {
  227. count += 1;
  228. z++;
  229. }
  230. } else {
  231. count += 1;
  232. z++;
  233. }
  234. } catch(error) { // avoid malformed URI
  235. count += 1;
  236. z++;
  237. }
  238. }
  239. charString.push(responseHeader.slice(0, 10).replace(/\0/g, ''))
  240. responseHeader = responseHeader.slice(32, responseHeader.length);
  241. }
  242. while (true) {
  243. var field = {},
  244. nameArray = [];
  245. for (var i = 0, z=0; i < 10; i++) {
  246. var letter = dv.getUint8(idx);
  247. if (letter != 0) nameArray.push(String.fromCharCode(letter));
  248. idx += 1;
  249. }
  250. field.name = charString[index++];
  251. idx += 1;
  252. field.type = String.fromCharCode(dv.getUint8(idx));
  253. idx += 1;
  254. // Skip field data address
  255. idx += 4;
  256. field.fieldLength = dv.getUint8(idx);
  257. idx += 1;
  258. //field.decimalCount = dv.getUint8(idx);
  259. idx += 1;
  260. // Skip reserved bytes multi-user dBASE.
  261. idx += 2;
  262. field.workAreaId = dv.getUint8(idx);
  263. idx += 1;
  264. // Skip reserved bytes multi-user dBASE.
  265. idx += 2;
  266. field.setFieldFlag = dv.getUint8(idx);
  267. idx += 1;
  268. // Skip reserved bytes.
  269. idx += 7;
  270. field.indexFieldFlag = dv.getUint8(idx);
  271. idx += 1;
  272. o.fields.push(field);
  273. var test = dv.getUint8(idx);
  274. // Checks for end of field descriptor array. Valid .dbf files will have this
  275. // flag.
  276. if (dv.getUint8(idx) == 0x0D) break;
  277. }
  278. idx += 1;
  279. o.fieldpos = idx;
  280. o.records = [];
  281. responseText = response.split('\r')[response.split('\r').length-1];
  282. for (var i = 0; i < o.numberOfRecords; i++) {
  283. responseText = responseText.slice(1, responseText.length);
  284. var record = {};
  285. for (var j = 0; j < o.fields.length; j++) {
  286. var charString = [],
  287. count = 0,
  288. z = 0;
  289. while(count < o.fields[j].fieldLength) {
  290. try {
  291. if( encodeURIComponent(responseText[z]).match(/%[A-F\d]{2}/g) ) {
  292. if( encodeURIComponent(responseText[z]).match(/%[A-F\d]{2}/g).length > 1 ) {
  293. count += offset;
  294. z++;
  295. check = 1;
  296. } else {
  297. count += 1;
  298. z++;
  299. }
  300. } else {
  301. count += 1;
  302. z++;
  303. }
  304. } catch(error) { // avoid malformed URI
  305. count += 1;
  306. z++;
  307. }
  308. }
  309. charString.push(responseText.slice(0, z).replace(/\0/g, ''));
  310. responseText = responseText.slice(z, responseText.length);
  311. if(charString.join('').trim().match(/\d{1}\.\d{11}e\+\d{3}/g)) {
  312. record[o.fields[j].name] = parseFloat(charString.join('').trim());
  313. } else {
  314. record[o.fields[j].name] = charString.join('').trim();
  315. }
  316. }
  317. o.records.push(record);
  318. }
  319. return o;
  320. };