Javascript 将数值编码为字母数字代码(反向解码功能)
我有一个解码CS的函数:将十字线代码转换成键值对象 (之前我问了一个关于如何从CS:GO解码共享代码的问题) 如何将这些值从解码转换为编码为由字母数字字符组成的“共享代码”? 功能解码共享码: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
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…等)生成的代码相同,因此可能会有所帮助。