123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232 |
- 'use strict';
- const assert = {
- strictEqual(actual, expected, ...args) {
- args = args || [];
- if (actual !== expected) {
- throw new Error(`${actual} (actual) should equal ${expected} (expected): ${[...args].join(' ')}`);
- }
- },
- notStrictEqual(actual, expected, ...args) {
- args = args || [];
- if (actual === expected) {
- throw new Error(`${actual} (actual) should NOT equal ${expected} (expected): ${[...args].join(' ')}`);
- }
- },
- };
- /*
- function dumpBuf(buf) {
- for (let i = 0; i < buf.length; i += 32) {
- const p = [];
- const a = [];
- for (let j = i; j < i + 32 && j < buf.length; ++j) {
- const b = buf[j];
- p.push(b.toString(16).padStart(2, '0'));
- a.push(b >= 32 && b < 128 ? String.fromCharCode(b) : '.');
- if (j % 4 === 3) {
- p.push(' ');
- }
- }
- console.log(i.toString(16).padStart(8, '0'), ':', p.join(''), a.join(''));
- }
- }
- */
- function parse(buf) {
- assert.strictEqual(buf[0], 0x47, 'bad header');
- assert.strictEqual(buf[1], 0x50, 'bad header');
- assert.strictEqual(buf[2], 0, 'unknown version'); // version
- const flags = buf[3];
- const flag_x = (flags >> 5) & 1;
- // const flag_empty_geo = (flags >> 4) & 1; // 1 = empty, 0 non-empty
- const flag_byteOrder = (flags >> 0) & 1; // 1 = little endian, 0 = big
- const flag_envelope = (flags >> 1) & 7;
- assert.strictEqual(flag_x, 0, 'x must be 0');
- const envelopeSizes = [
- 0, // 0: non
- 4, // 1: minx, maxx, miny, maxy
- 6, // 2: minx, maxx, miny, maxy, minz, maxz
- 6, // 3: minx, maxx, miny, maxy, minm, maxm
- 8, // 4: minx, maxx, miny, maxy, minz, maxz, minm, maxm
- ];
- const envelopeSize = envelopeSizes[flag_envelope];
- assert.notStrictEqual(envelopeSize, undefined);
- const headerSize = 8;
- let cursor = headerSize;
- const dataView = new DataView(buf.buffer);
- /*
- const readBE = {
- getDouble() { const v = buf.readDoubleBE(cursor); cursor += 8 ; return v; },
- getFloat() { const v = buf.readFloatBE(cursor); cursor += 4 ; return v; },
- getInt8() { const v = buf.readInt8(cursor); cursor += 1 ; return v; },
- getUint8() { const v = buf.readUInt8(cursor); cursor += 1 ; return v; },
- getInt16() { const v = buf.readInt16BE(cursor); cursor += 2 ; return v; },
- getUint16() { const v = buf.readUInt16BE(cursor); cursor += 2 ; return v; },
- getInt32() { const v = buf.readInt32BE(cursor); cursor += 4 ; return v; },
- getUint32() { const v = buf.readUInt32BE(cursor); cursor += 4 ; return v; },
- };
- const readLE = {
- getDouble() { const v = buf.readDoubleLE(cursor); cursor += 8 ; return v; },
- getFloat() { const v = buf.readFloatLE(cursor); cursor += 4 ; return v; },
- getInt8() { const v = buf.readInt8(cursor); cursor += 1 ; return v; },
- getUint8() { const v = buf.readUInt8(cursor); cursor += 1 ; return v; },
- getInt16() { const v = buf.readInt16LE(cursor); cursor += 2 ; return v; },
- getUint16() { const v = buf.readUInt16LE(cursor); cursor += 2 ; return v; },
- getInt32() { const v = buf.readInt32LE(cursor); cursor += 4 ; return v; },
- getUint32() { const v = buf.readUInt32LE(cursor); cursor += 4 ; return v; },
- };
- */
- let littleEndian;
- const endianStack = [];
- function pushByteOrder(byteOrder) {
- endianStack.push(littleEndian);
- littleEndian = byteOrder;
- }
- function popByteOrder() {
- littleEndian = endianStack.pop();
- }
- const getDouble = () => { const v = dataView.getFloat64(cursor, littleEndian); cursor += 8 ; return v; };
- // const getFloat = () => { const v = dataView.getFloat32(cursor, littleEndian); cursor += 4 ; return v; };
- const getInt8 = () => { const v = dataView.getInt8(cursor); cursor += 1 ; return v; };
- // const getUint8 = () => { const v = dataView.getUint8(cursor, littleEndian); cursor += 1 ; return v; };
- // const getInt16 = () => { const v = dataView.getInt16(cursor, littleEndian); cursor += 2 ; return v; };
- // const getUint16 = () => { const v = dataView.getUint16(cursor, littleEndian); cursor += 2 ; return v; };
- // const getInt32 = () => { const v = dataView.getInt32(cursor, littleEndian); cursor += 4 ; return v; };
- const getUint32 = () => { const v = dataView.getUint32(cursor, littleEndian); cursor += 4 ; return v; };
- pushByteOrder(flag_byteOrder);
- const envelope = [];
- for (let i = 0; i < envelopeSize; ++i) {
- envelope.push(getDouble());
- }
- const primitives = [];
- function getPoints(num) {
- const points = [];
- for (let i = 0; i < num; ++i) {
- points.push(getDouble(), getDouble());
- }
- return points;
- }
- function getRings(num) {
- const rings = [];
- for (let i = 0; i < num; ++i) {
- rings.push(getPoints(getUint32()));
- }
- return rings;
- }
- function pointHandler() {
- return {
- type: 'point',
- point: getPoints(1),
- };
- }
- function lineStringHandler() {
- return {
- type: 'lineString',
- points: getPoints(getUint32()),
- };
- }
- function polygonHandler() {
- return {
- type: 'polygon',
- rings: getRings(getUint32()),
- };
- }
- function multiPointHandler() {
- // WTF?
- const points = [];
- const num = getUint32();
- for (let i = 0; i < num; ++i) {
- pushByteOrder(getInt8());
- const type = getUint32();
- assert.strictEqual(type, 1); // must be point
- points.push(getDouble(), getDouble());
- popByteOrder();
- }
- return {
- type: 'multiPoint',
- points,
- };
- }
- function multiLineStringHandler() {
- // WTF?
- const lineStrings = [];
- const num = getUint32();
- for (let i = 0; i < num; ++i) {
- pushByteOrder(getInt8());
- const type = getUint32();
- assert.strictEqual(type, 2); // must be lineString
- lineStrings.push(getPoints(getUint32()));
- popByteOrder();
- }
- return {
- type: 'multiLineString',
- lineStrings,
- };
- }
- function multiPolygonHandler() {
- // WTF?
- const polygons = [];
- const num = getUint32();
- for (let i = 0; i < num; ++i) {
- pushByteOrder(getInt8());
- const type = getUint32();
- assert.strictEqual(type, 3); // must be polygon
- polygons.push(getRings(getUint32()));
- popByteOrder();
- }
- return {
- type: 'multiPolygon',
- polygons,
- };
- }
- const typeHandlers = [
- undefined, // 0
- pointHandler, // 1
- lineStringHandler, // 2
- polygonHandler, // 3
- multiPointHandler, // 4
- multiLineStringHandler, // 5,
- multiPolygonHandler, // 6,
- ];
- const end = buf.length;
- while (cursor < end) {
- pushByteOrder(getInt8());
- const type = getUint32();
- const handler = typeHandlers[type];
- assert.notStrictEqual(handler, undefined, 'unknown type');
- primitives.push(handler());
- popByteOrder();
- }
- return {
- envelope,
- primitives,
- };
- }
- window.ogcParser = {parse};
|