| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 | 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);  if (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 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;export default decodeGoogleEarthEnterpriseData;
 |