将数值编码为字母数字代码(反向解码功能) [英] Encoding numerical values into alphanumeric code (reversing decoding function)

查看:141
本文介绍了将数值编码为字母数字代码(反向解码功能)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个将CS:GO十字线代码解码为键值对象的函数。

I have a function decoding CS:GO crosshair codes into key value object.

(以前我问过有关如何从CS:GO解码共享代码的问题此处

(Previously I asked question about how to decode share codes from CS:GO Here)

如何将其从解码这些值转换为将它们编码为共享代码

函数解码共享代码:

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
// }

因此以下值:

{
  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
}

应编码为: 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}$/;

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

我还发现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


推荐答案

使用提供的信息,很难创建一个内编码器,因为编码的位数比您指定的来源多得多。该代码足够大,可以容纳18个字节。您解码仅使用其中的14个,甚至不使用所有这些。 (对我而言)最有趣的是,未说明字节13的最低有效位。

With the information provided, it would be difficult to impossible to create an endcoder, because there are a lot more encoded bits than you have specified a source for. The code is big enough for 18 bytes. You decoding only uses 14 of them, and not even all of those. Most interesting (to me) is that the least significant bit of byte 13 is unaccounted for.

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

Even if you come up with reasonable default values for most of these, you have to figure out how to compute byte 0, which appears to be some kind of checksum.

这篇关于将数值编码为字母数字代码(反向解码功能)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆