All files / engine/Source/Core decodeGoogleEarthEnterpriseData.js

97.22% Statements 35/36
81.25% Branches 13/16
100% Functions 1/1
97.22% Lines 35/36

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94      1x 1x                     10x 2x       8x 7x     6x 6x 4x         2x 2x 2x         2x   2x 2x 2x 2x   2x             2x   6x 6x       6x 256x         256x         256x 256x         2x 2x   2x 2x     2x 2x 2x 2x         1x    
import Check from "./Check.js";
import RuntimeError from "./RuntimeError.js";
 
const compressedMagic = 0x7468dead;
const 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.typeOf.object("key", key);
  Check.typeOf.object("data", data);
  //>>includeEnd('debug');
 
  const keyLength = key.byteLength;
  if (keyLength === 0 || keyLength % 4 !== 0) {
    throw new RuntimeError(
      "The length of key must be greater than 0 and a multiple of 4.",
    );
  }
 
  const dataView = new DataView(data);
  const magic = dataView.getUint32(0, true);
  Iif (magic === compressedMagic || magic === compressedMagicSwap) {
    // Occasionally packets don't come back encoded, so just return
    return data;
  }
 
  const keyView = new DataView(key);
 
  let dp = 0;
  const dpend = data.byteLength;
  const dpend64 = dpend - (dpend % 8);
  const kpend = keyLength;
  let kp;
  let 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 offsets 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
  Eif (dp < dpend) {
    Eif (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;
export default decodeGoogleEarthEnterpriseData;