Last active
February 17, 2019 10:32
-
-
Save lvsecoto/b1b2ce762b382a5cec28733e2e2e60dc to your computer and use it in GitHub Desktop.
计算Google翻译请求中的TK值 参考 https://github.com/guyrotem/google-translate-server/blob/master/scripts/hash/tk-hash.js Java版本
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.List; | |
public class TKCalculateUtils { | |
public static long hexCharAsNumber(char c) { | |
if (c >= 'a') { | |
return c - 87; | |
} else { | |
return Long.valueOf(String.valueOf(c)); | |
} | |
} | |
public static long normalizeHash(long encondindRound2) { | |
if (encondindRound2 < 0) { | |
encondindRound2 = (encondindRound2 & 0x7fffffffL) + 0x80000000L; | |
} | |
return encondindRound2 % 1000000L; | |
} | |
public static List<Long> transformQuery(String query) { | |
List<Long> result = new ArrayList<>(); | |
for (int i = 0; i < query.length(); i++) { | |
char c = query.charAt(i); | |
if (c < 128) { | |
result.add((long) c); // 0{l[6-0]} | |
} else if (c < 2048) { | |
result.add(c >> 6 | 0xC0L); // 110{l[10-6]} | |
result.add(c & 0x3F | 0x80L); // 10{l[5-0]} | |
} else if (0xD800L == (c & 0xFC00L) && c + 1 < query.length() && 0xDC00L == (query.charAt(i + 1) & 0xFC00L)) { | |
// that's pretty rare... (avoid ovf?) | |
c = (char) ((1 << 16) + ((c & 0x03FF) << 10) + (query.charAt(++i) & 0x03FF)); | |
result.add(c >> 18 | 0xF0L); // 111100{l[9-8*]} | |
result.add(c >> 12 & 0x3FL | 0x80L); // 10{l[7*-2]} | |
result.add(c & 0x3FL | 0x80L); // 10{(l+1)[5-0]} | |
} else { | |
result.add(c >> 12 | 0xE0L); // 1110{l[15-12]} | |
result.add(c >> 6 & 0x3FL | 0x80L); // 10{l[11-6]} | |
result.add(c & 0x3FL | 0x80L); // 10{l[5-0]} | |
} | |
} | |
return result; | |
} | |
public static long shiftLeftOrRightThenSumOrXor(List<String> opArray, long num) { | |
for (String opString : opArray) { | |
char op1 = opString.charAt(1); // '+' | '-' ~ SUM | XOR | |
char op2 = opString.charAt(0); // '+' | '^' ~ SLL | SRL | |
char xd = opString.charAt(2); // [0-9a-f] | |
long shiftAmount = hexCharAsNumber(xd); | |
long mask = (op1 == '+') ? num >>> shiftAmount : num << shiftAmount; | |
num = (op2 == '+') ? (num + mask & 0xffffffffL) : (num ^ mask); | |
} | |
return num; | |
} | |
/* | |
/ EXAMPLE: | |
/ | |
/ INPUT: query: 'hola', windowTkk: '409837.2120040981' | |
/ OUTPUT: '70528.480109' | |
/ | |
*/ | |
public static String calcHash(String query, String windowTkk) { | |
// STEP 1: spread the the query char codes on a byte-array, 1-3 bytes per char | |
List<Long> bytesArray = transformQuery(query); | |
// STEP 2: starting with TKK index, add the array from last step one-by-one, and do 2 rounds of shift+add/xor | |
String[] d = windowTkk.split("\\."); | |
long tkkIndex = Long.valueOf(d[0]); | |
long tkkKey = Long.valueOf(d[1]); | |
long acc = tkkIndex; | |
for (Long current : bytesArray) { | |
acc += current; | |
acc = shiftLeftOrRightThenSumOrXor(Arrays.asList("+-a", "^+6"), acc); | |
} | |
long encondingRound1 = acc; | |
// STEP 3: apply 3 rounds of shift+add/xor and XOR with they TKK key | |
long encondingRound2 = shiftLeftOrRightThenSumOrXor(Arrays.asList("+-3", "^+b", "+-f"), encondingRound1) ^ tkkKey; | |
// STEP 4: Normalize to 2s complement & format | |
long normalizedResult = normalizeHash(encondingRound2); | |
return normalizedResult + "." + (normalizedResult ^ tkkIndex); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.junit.Test; | |
import static cn.lskiot.lsapp.TKCalculateUtils.*; | |
import static com.google.common.truth.Truth.assertThat; | |
import static java.util.Arrays.asList; | |
public class TKCalculateUtilsTest { | |
@Test | |
public void testHexCharAsNumber() { | |
assertThat(hexCharAsNumber('3')).isEqualTo(3); | |
assertThat(hexCharAsNumber('a')).isEqualTo(10); | |
} | |
@Test | |
public void testTransformQuery() { | |
assertThat(transformQuery("123ABCabc我")).isEqualTo(asList(49L, 50L, 51L, 65L, 66L, 67L, 97L, 98L, 99L, 230L, 136L, 145L)); | |
} | |
@Test | |
public void testNormalizeHash() { | |
assertThat(normalizeHash(8134240)).isEqualTo(134240); | |
} | |
@Test | |
public void testShiftLeftOrRightThenSumOrXor() { | |
assertThat(shiftLeftOrRightThenSumOrXor(asList("+-a", "^+9"), 12)).isEqualTo(12308); | |
} | |
@Test | |
public void testCalcHash() { | |
assertThat(calcHash("hola", "409837.2120040981")).isEqualTo("70528.480109"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment