123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473 |
- /**
- * Cesium - https://github.com/AnalyticalGraphicsInc/cesium
- *
- * Copyright 2011-2017 Cesium Contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Columbus View (Pat. Pend.)
- *
- * Portions licensed separately.
- * See https://github.com/AnalyticalGraphicsInc/cesium/blob/master/LICENSE.md for full licensing details.
- */
- define(['./when-8d13db60', './Check-70bec281', './RuntimeError-ba10bc3e', './createTaskProcessorWorker', './pako_inflate-8ea163f9'], function (when, Check, RuntimeError, createTaskProcessorWorker, pako_inflate) { 'use strict';
- var compressedMagic = 0x7468dead;
- var compressedMagicSwap = 0xadde6874;
- /**
- * Decodes data that is received from the Google Earth Enterprise server.
- *
- * @param {ArrayBuffer} key The key used during decoding.
- * @param {ArrayBuffer} data The data to be decoded.
- *
- * @private
- */
- function decodeGoogleEarthEnterpriseData(key, data) {
- if (decodeGoogleEarthEnterpriseData.passThroughDataForTesting) {
- return data;
- }
- //>>includeStart('debug', pragmas.debug);
- Check.Check.typeOf.object('key', key);
- Check.Check.typeOf.object('data', data);
- //>>includeEnd('debug');
- var keyLength = key.byteLength;
- if (keyLength === 0 || (keyLength % 4) !== 0) {
- throw new RuntimeError.RuntimeError('The length of key must be greater than 0 and a multiple of 4.');
- }
- var dataView = new DataView(data);
- var magic = dataView.getUint32(0, true);
- if (magic === compressedMagic || magic === compressedMagicSwap) {
- // Occasionally packets don't come back encoded, so just return
- return data;
- }
- var keyView = new DataView(key);
- var dp = 0;
- var dpend = data.byteLength;
- var dpend64 = dpend - (dpend % 8);
- var kpend = keyLength;
- var kp;
- var off = 8;
- // This algorithm is intentionally asymmetric to make it more difficult to
- // guess. Security through obscurity. :-(
- // while we have a full uint64 (8 bytes) left to do
- // assumes buffer is 64bit aligned (or processor doesn't care)
- while (dp < dpend64) {
- // rotate the key each time through by using the offets 16,0,8,16,0,8,...
- off = (off + 8) % 24;
- kp = off;
- // run through one key length xor'ing one uint64 at a time
- // then drop out to rotate the key for the next bit
- while ((dp < dpend64) && (kp < kpend)) {
- dataView.setUint32(dp, dataView.getUint32(dp, true) ^ keyView.getUint32(kp, true), true);
- dataView.setUint32(dp + 4, dataView.getUint32(dp + 4, true) ^ keyView.getUint32(kp + 4, true), true);
- dp += 8;
- kp += 24;
- }
- }
- // now the remaining 1 to 7 bytes
- if (dp < dpend) {
- if (kp >= kpend) {
- // rotate the key one last time (if necessary)
- off = (off + 8) % 24;
- kp = off;
- }
- while (dp < dpend) {
- dataView.setUint8(dp, dataView.getUint8(dp) ^ keyView.getUint8(kp));
- dp++;
- kp++;
- }
- }
- }
- decodeGoogleEarthEnterpriseData.passThroughDataForTesting = false;
- /**
- * @private
- */
- function isBitSet(bits, mask) {
- return ((bits & mask) !== 0);
- }
- // Bitmask for checking tile properties
- var childrenBitmasks = [0x01, 0x02, 0x04, 0x08];
- var anyChildBitmask = 0x0F;
- var cacheFlagBitmask = 0x10; // True if there is a child subtree
- var imageBitmask = 0x40;
- var terrainBitmask = 0x80;
- /**
- * Contains information about each tile from a Google Earth Enterprise server
- *
- * @param {Number} bits Bitmask that contains the type of data and available children for each tile.
- * @param {Number} cnodeVersion Version of the request for subtree metadata.
- * @param {Number} imageryVersion Version of the request for imagery tile.
- * @param {Number} terrainVersion Version of the request for terrain tile.
- * @param {Number} imageryProvider Id of imagery provider.
- * @param {Number} terrainProvider Id of terrain provider.
- *
- * @private
- */
- function GoogleEarthEnterpriseTileInformation(bits, cnodeVersion, imageryVersion, terrainVersion, imageryProvider, terrainProvider) {
- this._bits = bits;
- this.cnodeVersion = cnodeVersion;
- this.imageryVersion = imageryVersion;
- this.terrainVersion = terrainVersion;
- this.imageryProvider = imageryProvider;
- this.terrainProvider = terrainProvider;
- this.ancestorHasTerrain = false; // Set it later once we find its parent
- this.terrainState = undefined;
- }
- /**
- * Creates GoogleEarthEnterpriseTileInformation from an object
- *
- * @param {Object} info Object to be cloned
- * @param {GoogleEarthEnterpriseTileInformation} [result] The object onto which to store the result.
- * @returns {GoogleEarthEnterpriseTileInformation} The modified result parameter or a new GoogleEarthEnterpriseTileInformation instance if none was provided.
- */
- GoogleEarthEnterpriseTileInformation.clone = function(info, result) {
- if (!when.defined(result)) {
- result = new GoogleEarthEnterpriseTileInformation(info._bits, info.cnodeVersion, info.imageryVersion, info.terrainVersion,
- info.imageryProvider, info.terrainProvider);
- } else {
- result._bits = info._bits;
- result.cnodeVersion = info.cnodeVersion;
- result.imageryVersion = info.imageryVersion;
- result.terrainVersion = info.terrainVersion;
- result.imageryProvider = info.imageryProvider;
- result.terrainProvider = info.terrainProvider;
- }
- result.ancestorHasTerrain = info.ancestorHasTerrain;
- result.terrainState = info.terrainState;
- return result;
- };
- /**
- * Sets the parent for the tile
- *
- * @param {GoogleEarthEnterpriseTileInformation} parent Parent tile
- */
- GoogleEarthEnterpriseTileInformation.prototype.setParent = function(parent) {
- this.ancestorHasTerrain = parent.ancestorHasTerrain || this.hasTerrain();
- };
- /**
- * Gets whether a subtree is available
- *
- * @returns {Boolean} true if subtree is available, false otherwise.
- */
- GoogleEarthEnterpriseTileInformation.prototype.hasSubtree = function() {
- return isBitSet(this._bits, cacheFlagBitmask);
- };
- /**
- * Gets whether imagery is available
- *
- * @returns {Boolean} true if imagery is available, false otherwise.
- */
- GoogleEarthEnterpriseTileInformation.prototype.hasImagery = function() {
- return isBitSet(this._bits, imageBitmask);
- };
- /**
- * Gets whether terrain is available
- *
- * @returns {Boolean} true if terrain is available, false otherwise.
- */
- GoogleEarthEnterpriseTileInformation.prototype.hasTerrain = function() {
- return isBitSet(this._bits, terrainBitmask);
- };
- /**
- * Gets whether any children are present
- *
- * @returns {Boolean} true if any children are available, false otherwise.
- */
- GoogleEarthEnterpriseTileInformation.prototype.hasChildren = function() {
- return isBitSet(this._bits, anyChildBitmask);
- };
- /**
- * Gets whether a specified child is available
- *
- * @param {Number} index Index of child tile
- *
- * @returns {Boolean} true if child is available, false otherwise
- */
- GoogleEarthEnterpriseTileInformation.prototype.hasChild = function(index) {
- return isBitSet(this._bits, childrenBitmasks[index]);
- };
- /**
- * Gets bitmask containing children
- *
- * @returns {Number} Children bitmask
- */
- GoogleEarthEnterpriseTileInformation.prototype.getChildBitmask = function() {
- return this._bits & anyChildBitmask;
- };
- // Datatype sizes
- var sizeOfUint16 = Uint16Array.BYTES_PER_ELEMENT;
- var sizeOfInt32 = Int32Array.BYTES_PER_ELEMENT;
- var sizeOfUint32 = Uint32Array.BYTES_PER_ELEMENT;
- var Types = {
- METADATA : 0,
- TERRAIN : 1,
- DBROOT : 2
- };
- Types.fromString = function(s) {
- if (s === 'Metadata') {
- return Types.METADATA;
- } else if (s === 'Terrain') {
- return Types.TERRAIN;
- } else if (s === 'DbRoot') {
- return Types.DBROOT;
- }
- };
- function decodeGoogleEarthEnterprisePacket(parameters, transferableObjects) {
- var type = Types.fromString(parameters.type);
- var buffer = parameters.buffer;
- decodeGoogleEarthEnterpriseData(parameters.key, buffer);
- var uncompressedTerrain = uncompressPacket(buffer);
- buffer = uncompressedTerrain.buffer;
- var length = uncompressedTerrain.length;
- switch (type) {
- case Types.METADATA:
- return processMetadata(buffer, length, parameters.quadKey);
- case Types.TERRAIN:
- return processTerrain(buffer, length, transferableObjects);
- case Types.DBROOT:
- transferableObjects.push(buffer);
- return {
- buffer : buffer
- };
- }
- }
- var qtMagic = 32301;
- function processMetadata(buffer, totalSize, quadKey) {
- var dv = new DataView(buffer);
- var offset = 0;
- var magic = dv.getUint32(offset, true);
- offset += sizeOfUint32;
- if (magic !== qtMagic) {
- throw new RuntimeError.RuntimeError('Invalid magic');
- }
- var dataTypeId = dv.getUint32(offset, true);
- offset += sizeOfUint32;
- if (dataTypeId !== 1) {
- throw new RuntimeError.RuntimeError('Invalid data type. Must be 1 for QuadTreePacket');
- }
- // Tile format version
- var quadVersion = dv.getUint32(offset, true);
- offset += sizeOfUint32;
- if (quadVersion !== 2) {
- throw new RuntimeError.RuntimeError('Invalid QuadTreePacket version. Only version 2 is supported.');
- }
- var numInstances = dv.getInt32(offset, true);
- offset += sizeOfInt32;
- var dataInstanceSize = dv.getInt32(offset, true);
- offset += sizeOfInt32;
- if (dataInstanceSize !== 32) {
- throw new RuntimeError.RuntimeError('Invalid instance size.');
- }
- var dataBufferOffset = dv.getInt32(offset, true);
- offset += sizeOfInt32;
- var dataBufferSize = dv.getInt32(offset, true);
- offset += sizeOfInt32;
- var metaBufferSize = dv.getInt32(offset, true);
- offset += sizeOfInt32;
- // Offset from beginning of packet (instances + current offset)
- if (dataBufferOffset !== (numInstances * dataInstanceSize + offset)) {
- throw new RuntimeError.RuntimeError('Invalid dataBufferOffset');
- }
- // Verify the packets is all there header + instances + dataBuffer + metaBuffer
- if (dataBufferOffset + dataBufferSize + metaBufferSize !== totalSize) {
- throw new RuntimeError.RuntimeError('Invalid packet offsets');
- }
- // Read all the instances
- var instances = [];
- for (var i = 0; i < numInstances; ++i) {
- var bitfield = dv.getUint8(offset);
- ++offset;
- ++offset; // 2 byte align
- var cnodeVersion = dv.getUint16(offset, true);
- offset += sizeOfUint16;
- var imageVersion = dv.getUint16(offset, true);
- offset += sizeOfUint16;
- var terrainVersion = dv.getUint16(offset, true);
- offset += sizeOfUint16;
- // Number of channels stored in the dataBuffer
- offset += sizeOfUint16;
- offset += sizeOfUint16; // 4 byte align
- // Channel type offset into dataBuffer
- offset += sizeOfInt32;
- // Channel version offset into dataBuffer
- offset += sizeOfInt32;
- offset += 8; // Ignore image neighbors for now
- // Data providers
- var imageProvider = dv.getUint8(offset++);
- var terrainProvider = dv.getUint8(offset++);
- offset += sizeOfUint16; // 4 byte align
- instances.push(new GoogleEarthEnterpriseTileInformation(bitfield, cnodeVersion,
- imageVersion, terrainVersion, imageProvider, terrainProvider));
- }
- var tileInfo = [];
- var index = 0;
- function populateTiles(parentKey, parent, level) {
- var isLeaf = false;
- if (level === 4) {
- if (parent.hasSubtree()) {
- return; // We have a subtree, so just return
- }
- isLeaf = true; // No subtree, so set all children to null
- }
- for (var i = 0; i < 4; ++i) {
- var childKey = parentKey + i.toString();
- if (isLeaf) {
- // No subtree so set all children to null
- tileInfo[childKey] = null;
- } else if (level < 4) {
- // We are still in the middle of the subtree, so add child
- // only if their bits are set, otherwise set child to null.
- if (!parent.hasChild(i)) {
- tileInfo[childKey] = null;
- } else {
- if (index === numInstances) {
- console.log('Incorrect number of instances');
- return;
- }
- var instance = instances[index++];
- tileInfo[childKey] = instance;
- populateTiles(childKey, instance, level + 1);
- }
- }
- }
- }
- var level = 0;
- var root = instances[index++];
- if (quadKey === '') {
- // Root tile has data at its root and one less level
- ++level;
- } else {
- tileInfo[quadKey] = root; // This will only contain the child bitmask
- }
- populateTiles(quadKey, root, level);
- return tileInfo;
- }
- function processTerrain(buffer, totalSize, transferableObjects) {
- var dv = new DataView(buffer);
- var offset = 0;
- var terrainTiles = [];
- while (offset < totalSize) {
- // Each tile is split into 4 parts
- var tileStart = offset;
- for (var quad = 0; quad < 4; ++quad) {
- var size = dv.getUint32(offset, true);
- offset += sizeOfUint32;
- offset += size;
- }
- var tile = buffer.slice(tileStart, offset);
- transferableObjects.push(tile);
- terrainTiles.push(tile);
- }
- return terrainTiles;
- }
- var compressedMagic$1 = 0x7468dead;
- var compressedMagicSwap$1 = 0xadde6874;
- function uncompressPacket(data) {
- // The layout of this decoded data is
- // Magic Uint32
- // Size Uint32
- // [GZipped chunk of Size bytes]
- // Pullout magic and verify we have the correct data
- var dv = new DataView(data);
- var offset = 0;
- var magic = dv.getUint32(offset, true);
- offset += sizeOfUint32;
- if (magic !== compressedMagic$1 && magic !== compressedMagicSwap$1) {
- throw new RuntimeError.RuntimeError('Invalid magic');
- }
- // Get the size of the compressed buffer - the endianness depends on which magic was used
- var size = dv.getUint32(offset, (magic === compressedMagic$1));
- offset += sizeOfUint32;
- var compressedPacket = new Uint8Array(data, offset);
- var uncompressedPacket = pako_inflate.pako.inflate(compressedPacket);
- if (uncompressedPacket.length !== size) {
- throw new RuntimeError.RuntimeError('Size of packet doesn\'t match header');
- }
- return uncompressedPacket;
- }
- var decodeGoogleEarthEnterprisePacket$1 = createTaskProcessorWorker(decodeGoogleEarthEnterprisePacket);
- return decodeGoogleEarthEnterprisePacket$1;
- });
|