Javascript 将数值编码为字母数字代码(反向解码功能)

Javascript 将数值编码为字母数字代码(反向解码功能),javascript,node.js,encoding,byte,decoding,Javascript,Node.js,Encoding,Byte,Decoding,我有一个解码CS的函数:将十字线代码转换成键值对象 (之前我问了一个关于如何从CS:GO解码共享代码的问题) 如何将这些值从解码转换为编码为由字母数字字符组成的“共享代码”? 功能解码共享码: const BigNumber = require("bignumber.js"); // Intentionally no 0 and 1 number in DICTIONARY const DICTIONARY = "ABCDEFGHJKLMNOPQRSTUVWXYZ

我有一个解码CS的函数:将十字线代码转换成键值对象

(之前我问了一个关于如何从CS:GO解码共享代码的问题)

如何将这些值从解码转换为编码为由字母数字字符组成的“共享代码”?

功能解码共享码:

const BigNumber = require("bignumber.js");

// Intentionally no 0 and 1 number in DICTIONARY
const DICTIONARY = "ABCDEFGHJKLMNOPQRSTUVWXYZabcdefhijkmnopqrstuvwxyz23456789";
const DICTIONARY_LENGTH = DICTIONARY.length;
const SHARECODE_PATTERN = /CSGO(-?[\w]{5}){5}$/;

const bigNumberToByteArray = big => {
  const str = big.toString(16).padStart(36, "0");
  const bytes = [];

  for (let i = 0; i < str.length; i += 2) {
    bytes.push(parseInt(str.slice(i, i + 2), 16));
  }

  return bytes;
}

const parseBytes = bytes => {
  return {
    cl_crosshairgap: Int8Array.of(bytes[2])[0] / 10.0,

    cl_crosshair_outlinethickness: (bytes[3] & 7) / 2.0,

    cl_crosshaircolor_r: bytes[4],
    cl_crosshaircolor_g: bytes[5],
    cl_crosshaircolor_b: bytes[6],
    cl_crosshairalpha: bytes[7],
    cl_crosshair_dynamic_splitdist: bytes[8],

    cl_fixedcrosshairgap: Int8Array.of(bytes[9])[0] / 10.0,

    cl_crosshaircolor: bytes[10] & 7,
    cl_crosshair_drawoutline: bytes[10] & 8 ? 1 : 0,
    cl_crosshair_dynamic_splitalpha_innermod: ((bytes[10] & 0xF0) >> 4) / 10.0,

    cl_crosshair_dynamic_splitalpha_outermod: (bytes[11] & 0xF) / 10.0,
    cl_crosshair_dynamic_maxdist_splitratio: ((bytes[11] & 0xF0) >> 4) / 10.0,

    cl_crosshairthickness: (bytes[12] & 0x3F) / 10.0,

    cl_crosshairstyle: (bytes[13] & 0xE) >> 1,
    cl_crosshairdot: bytes[13] & 0x10 ? 1 : 0,
    cl_crosshairgap_useweaponvalue: bytes[13] & 0x20 ? 1 : 0,
    cl_crosshairusealpha: bytes[13] & 0x40 ? 1 : 0,
    cl_crosshair_t: bytes[13] & 0x80 ? 1 : 0,

    cl_crosshairsize: (((bytes[15] & 0x1f) << 8) + bytes[14]) / 10.0
  };
}

const decode = shareCode => {
  if (!shareCode.match(SHARECODE_PATTERN)) {
    throw new Error('Invalid share code');
  }

  shareCode = shareCode.replace(/CSGO|-/g, '');
  const chars = Array.from(shareCode).reverse();
  let big = new BigNumber(0);

  for (let i = 0; i < chars.length; i++) {
    big = big.multipliedBy(DICTIONARY_LENGTH).plus(DICTIONARY.indexOf(chars[i]));
  }
  
  return parseBytes(bigNumberToByteArray(big));
}

console.log(decode('CSGO-O4Jsi-V36wY-rTMGK-9w7qF-jQ8WB'))
// OUTPUT:
// {
//   cl_crosshairgap: 1,
//   cl_crosshair_outlinethickness: 1.5,
//   cl_crosshaircolor_r: 50,
//   cl_crosshaircolor_g: 250,
//   cl_crosshaircolor_b: 84,
//   cl_crosshairalpha: 200,
//   cl_crosshair_dynamic_splitdist: 127,
//   cl_fixedcrosshairgap: -10,
//   cl_crosshaircolor: 5,
//   cl_crosshair_drawoutline: 0,
//   cl_crosshair_dynamic_splitalpha_innermod: 0.6,
//   cl_crosshair_dynamic_splitalpha_outermod: 0.8,
//   cl_crosshair_dynamic_maxdist_splitratio: 0.3,
//   cl_crosshairthickness: 4.1,
//   cl_crosshairstyle: 2,
//   cl_crosshairdot: 1,
//   cl_crosshairgap_useweaponvalue: 0,
//   cl_crosshairusealpha: 0,
//   cl_crosshair_t: 1,
//   cl_crosshairsize: 33
// }
const BigNumber = require("bignumber.js");

// Intentionally no 0 and 1 number in DICTIONARY
const DICTIONARY = "ABCDEFGHJKLMNOPQRSTUVWXYZabcdefhijkmnopqrstuvwxyz23456789";
const DICTIONARY_LENGTH = DICTIONARY.length;
const SHARECODE_PATTERN = /CSGO(-?[\w]{5}){5}$/;

function bytesToHex(bytes) {
  return Array.from(bytes, (byte) => {
    return ('0' + (byte & 0xff).toString(16)).slice(-2);
  }).join('');
}

function bigNumberToByteArray(big) {
  const str = big.toString(16).padStart(36, '0');
  const bytes = [];
  for (let i = 0; i < str.length; i += 2) {
    bytes.push(parseInt(str.slice(i, i + 2), 16));
  }

  return bytes;
}

function longToBytesBE(high, low) {
  return [
    (high >>> 24) & 0xff,
    (high >>> 16) & 0xff,
    (high >>> 8) & 0xff,
    high & 0xff,
    (low >>> 24) & 0xff,
    (low >>> 16) & 0xff,
    (low >>> 8) & 0xff,
    low & 0xff,
  ];
}

function int16ToBytes(number) {
  return [(number & 0x0000ff00) >> 8, number & 0x000000ff];
}

function bytesToInt32(bytes) {
  let number = 0;
  for (let i = 0; i < bytes.length; i++) {
    number += bytes[i];
    if (i < bytes.length - 1) {
      number = number << 8;
    }
  }

  return number;
}

function bigNumberToByteArray(big) {
  const str = big.toString(16).padStart(36, "0");
  const bytes = [];
  for (let i = 0; i < str.length; i += 2) {
    bytes.push(parseInt(str.slice(i, i + 2), 16));
  }

  return bytes;
}

const encode = (matchId, reservationId, tvPort) => {
  const matchBytes = longToBytesBE(matchId.high, matchId.low).reverse();
  const reservationBytes = longToBytesBE(reservationId.high, reservationId.low).reverse();
  const tvBytes = int16ToBytes(tvPort).reverse();
  const bytes = Array.prototype.concat(matchBytes, reservationBytes, tvBytes);
  const bytesHex = bytesToHex(bytes);
  let total = new BigNumber(bytesHex, 16);

  // This part would probably be identical
  let c = '';
  let rem = new BigNumber(0);
  for (let i = 0; i < 25; i++) {
    rem = total.mod(DICTIONARY_LENGTH);
    c += DICTIONARY[rem.integerValue(BigNumber.ROUND_FLOOR).toNumber()];
    total = total.div(DICTIONARY_LENGTH);
  }

  return `CSGO-${c.substr(0, 5)}-${c.substr(5, 5)}-${c.substr(10, 5)}-${c.substr(15, 5)}-${c.substr(20, 5)}`;
};

console.log(encode(
  {
    low: -2147483492, high: 752192506
  },
  {
    low: 143, high: 752193760
  },
  55788
));

// OUTPUT:
// CSGO-GADqf-jjyJ8-cSP2r-smZRo-TO2xK
应编码为:
CSGO-O4Jsi-V36wY-rTMGK-9w7qF-jQ8WB

函数编码匹配共享代码,这可能是编码十字线代码的基础:

const BigNumber = require("bignumber.js");

// Intentionally no 0 and 1 number in DICTIONARY
const DICTIONARY = "ABCDEFGHJKLMNOPQRSTUVWXYZabcdefhijkmnopqrstuvwxyz23456789";
const DICTIONARY_LENGTH = DICTIONARY.length;
const SHARECODE_PATTERN = /CSGO(-?[\w]{5}){5}$/;

const bigNumberToByteArray = big => {
  const str = big.toString(16).padStart(36, "0");
  const bytes = [];

  for (let i = 0; i < str.length; i += 2) {
    bytes.push(parseInt(str.slice(i, i + 2), 16));
  }

  return bytes;
}

const parseBytes = bytes => {
  return {
    cl_crosshairgap: Int8Array.of(bytes[2])[0] / 10.0,

    cl_crosshair_outlinethickness: (bytes[3] & 7) / 2.0,

    cl_crosshaircolor_r: bytes[4],
    cl_crosshaircolor_g: bytes[5],
    cl_crosshaircolor_b: bytes[6],
    cl_crosshairalpha: bytes[7],
    cl_crosshair_dynamic_splitdist: bytes[8],

    cl_fixedcrosshairgap: Int8Array.of(bytes[9])[0] / 10.0,

    cl_crosshaircolor: bytes[10] & 7,
    cl_crosshair_drawoutline: bytes[10] & 8 ? 1 : 0,
    cl_crosshair_dynamic_splitalpha_innermod: ((bytes[10] & 0xF0) >> 4) / 10.0,

    cl_crosshair_dynamic_splitalpha_outermod: (bytes[11] & 0xF) / 10.0,
    cl_crosshair_dynamic_maxdist_splitratio: ((bytes[11] & 0xF0) >> 4) / 10.0,

    cl_crosshairthickness: (bytes[12] & 0x3F) / 10.0,

    cl_crosshairstyle: (bytes[13] & 0xE) >> 1,
    cl_crosshairdot: bytes[13] & 0x10 ? 1 : 0,
    cl_crosshairgap_useweaponvalue: bytes[13] & 0x20 ? 1 : 0,
    cl_crosshairusealpha: bytes[13] & 0x40 ? 1 : 0,
    cl_crosshair_t: bytes[13] & 0x80 ? 1 : 0,

    cl_crosshairsize: (((bytes[15] & 0x1f) << 8) + bytes[14]) / 10.0
  };
}

const decode = shareCode => {
  if (!shareCode.match(SHARECODE_PATTERN)) {
    throw new Error('Invalid share code');
  }

  shareCode = shareCode.replace(/CSGO|-/g, '');
  const chars = Array.from(shareCode).reverse();
  let big = new BigNumber(0);

  for (let i = 0; i < chars.length; i++) {
    big = big.multipliedBy(DICTIONARY_LENGTH).plus(DICTIONARY.indexOf(chars[i]));
  }
  
  return parseBytes(bigNumberToByteArray(big));
}

console.log(decode('CSGO-O4Jsi-V36wY-rTMGK-9w7qF-jQ8WB'))
// OUTPUT:
// {
//   cl_crosshairgap: 1,
//   cl_crosshair_outlinethickness: 1.5,
//   cl_crosshaircolor_r: 50,
//   cl_crosshaircolor_g: 250,
//   cl_crosshaircolor_b: 84,
//   cl_crosshairalpha: 200,
//   cl_crosshair_dynamic_splitdist: 127,
//   cl_fixedcrosshairgap: -10,
//   cl_crosshaircolor: 5,
//   cl_crosshair_drawoutline: 0,
//   cl_crosshair_dynamic_splitalpha_innermod: 0.6,
//   cl_crosshair_dynamic_splitalpha_outermod: 0.8,
//   cl_crosshair_dynamic_maxdist_splitratio: 0.3,
//   cl_crosshairthickness: 4.1,
//   cl_crosshairstyle: 2,
//   cl_crosshairdot: 1,
//   cl_crosshairgap_useweaponvalue: 0,
//   cl_crosshairusealpha: 0,
//   cl_crosshair_t: 1,
//   cl_crosshairsize: 33
// }
const BigNumber = require("bignumber.js");

// Intentionally no 0 and 1 number in DICTIONARY
const DICTIONARY = "ABCDEFGHJKLMNOPQRSTUVWXYZabcdefhijkmnopqrstuvwxyz23456789";
const DICTIONARY_LENGTH = DICTIONARY.length;
const SHARECODE_PATTERN = /CSGO(-?[\w]{5}){5}$/;

function bytesToHex(bytes) {
  return Array.from(bytes, (byte) => {
    return ('0' + (byte & 0xff).toString(16)).slice(-2);
  }).join('');
}

function bigNumberToByteArray(big) {
  const str = big.toString(16).padStart(36, '0');
  const bytes = [];
  for (let i = 0; i < str.length; i += 2) {
    bytes.push(parseInt(str.slice(i, i + 2), 16));
  }

  return bytes;
}

function longToBytesBE(high, low) {
  return [
    (high >>> 24) & 0xff,
    (high >>> 16) & 0xff,
    (high >>> 8) & 0xff,
    high & 0xff,
    (low >>> 24) & 0xff,
    (low >>> 16) & 0xff,
    (low >>> 8) & 0xff,
    low & 0xff,
  ];
}

function int16ToBytes(number) {
  return [(number & 0x0000ff00) >> 8, number & 0x000000ff];
}

function bytesToInt32(bytes) {
  let number = 0;
  for (let i = 0; i < bytes.length; i++) {
    number += bytes[i];
    if (i < bytes.length - 1) {
      number = number << 8;
    }
  }

  return number;
}

function bigNumberToByteArray(big) {
  const str = big.toString(16).padStart(36, "0");
  const bytes = [];
  for (let i = 0; i < str.length; i += 2) {
    bytes.push(parseInt(str.slice(i, i + 2), 16));
  }

  return bytes;
}

const encode = (matchId, reservationId, tvPort) => {
  const matchBytes = longToBytesBE(matchId.high, matchId.low).reverse();
  const reservationBytes = longToBytesBE(reservationId.high, reservationId.low).reverse();
  const tvBytes = int16ToBytes(tvPort).reverse();
  const bytes = Array.prototype.concat(matchBytes, reservationBytes, tvBytes);
  const bytesHex = bytesToHex(bytes);
  let total = new BigNumber(bytesHex, 16);

  // This part would probably be identical
  let c = '';
  let rem = new BigNumber(0);
  for (let i = 0; i < 25; i++) {
    rem = total.mod(DICTIONARY_LENGTH);
    c += DICTIONARY[rem.integerValue(BigNumber.ROUND_FLOOR).toNumber()];
    total = total.div(DICTIONARY_LENGTH);
  }

  return `CSGO-${c.substr(0, 5)}-${c.substr(5, 5)}-${c.substr(10, 5)}-${c.substr(15, 5)}-${c.substr(20, 5)}`;
};

console.log(encode(
  {
    low: -2147483492, high: 752192506
  },
  {
    low: 143, high: 752193760
  },
  55788
));

// OUTPUT:
// CSGO-GADqf-jjyJ8-cSP2r-smZRo-TO2xK
const BigNumber=require(“BigNumber.js”);
//字典中没有0和1数字
const DICTIONARY=“ABCDEFGHJKLMNOPQRSTUVWXYZABCDFHIJKMNOPQRSTUVWXYZ23456789”;
const DICTIONARY_LENGTH=DICTIONARY.LENGTH;
constShareCode_PATTERN=/CSGO(-?[\w]{5}){5}$/;
函数bytesToHex(字节){
返回数组。从(字节,(字节)=>{
返回('0'+(字节和0xff).toString(16)).slice(-2);
}).加入(“”);
}
函数bigNumberToByteArray(大){
const str=big.toString(16).padStart(36,'0');
常量字节=[];
对于(设i=0;i>>24)和0xff,
(高>>>16)和0xff,
(高>>>8)和0xff,
高&0xff,
(低>>>24)和0xff,
(低>>>16)和0xff,
(低>>>8)和0xff,
低&0xff,
];
}
函数int16ToBytes(数字){
返回[(数字&0x0000ff00)>>8,数字&0x000000ff];
}
函数ByTestPoint32(字节){
设数=0;
for(设i=0;i
我还发现Python代码也在做同样的事情(使用“匹配代码”,包含更少的编码值)-我知道这是JS的问题,包括这一点只是为了识别相似性

import re
 
dictionary = "ABCDEFGHJKLMNOPQRSTUVWXYZabcdefhijkmnopqrstuvwxyz23456789"

def _swap_endianness(number):
    result = 0
 
    for n in range(0, 144, 8):
        result = (result << 8) + ((number >> n) & 0xFF)
 
    return result

def encode(matchid, outcomeid, token):
    a = _swap_endianness((token << 128) | (outcomeid << 64) | matchid)
 
    code = ''
    for _ in range(25):
        a, r = divmod(a, len(dictionary))
        code += dictionary[r]
 
    return "CSGO-%s-%s-%s-%s-%s" % (code[:5], code[5:10], code[10:15], code[15:20], code[20:])
    
print(encode(250, 34, 10))
# CSGO-t4kTW-mcVyA-TcReG-hviRe-pXNtQ
重新导入
dictionary=“ABCDEFGHJKLMNOPQRSTUVXYZABCDFHIJKMNOPQRSTUVXYZ23456789”
定义交换终止(编号):
结果=0
对于范围(0、144、8)内的n:
结果=(结果>n)&0xFF)
返回结果
def编码(匹配ID、输出ID、令牌):

a=\u swap\u endianness((token根据所提供的信息,很难创建一个端编码器,因为编码的位比您指定的源多得多。代码足够大,可以容纳18个字节。您解码只使用14个,甚至不是所有的。最有趣的是(对我来说)字节13的最低有效位未被计算


即使您为其中的大多数设置了合理的默认值,您也必须弄清楚如何计算字节0,这似乎是某种校验和。

我添加了对匹配代码进行编码的质疑函数。带有循环的部分,以及在其中使用divmod可能会解释“校验和”如果我理解正确,请告诉我字节编码为共享代码的方式。如果有帮助,请告诉我,我添加的编码匹配代码(要编码的值较少)的函数生成的结构与从20个值(CSGO-xxxxx-xxxxx…等)生成的代码相同,因此可能会有所帮助。