;;; google-translate-tk.el --- functions for generation `tk' ;;; parameter. ;; Copyright (C) 2012 Oleksandr Manzyuk ;; Author: Oleksandr Manzyuk ;; Maintainer: Andrey Tykhonov ;; URL: https://github.com/atykhonov/google-translate ;; Version: 0.11.18 ;; Keywords: convenience ;; Contributors: ;; Tassilo Horn ;; Bernard Hurley ;; Chris Bilson ;; Takumi Kinjo ;; momomo5717 ;; This file is NOT part of GNU Emacs. ;; This is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This file is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;; This file contains functions for generation `tk' parameter which is ;; required to make a valid request to the Google Translate. ;;; Code: (require 'cl-lib) (require 'google-translate-backend) (defvar google-translate--bit-v-len 32) (defvar google-translate--tkk-url "http://translate.google.com/") (defun google-translate--bit-v-2comp (v) "Return the two's complement of V." (let* ((vc (vconcat v)) (len (length vc))) ;; Complement of v (cl-loop for i from 0 below len do (aset vc i (logxor (aref vc i) 1))) ;; vc = complement of v + 1 (cl-loop for i downfrom (1- len) to 0 do (aset vc i (logxor (aref vc i) 1)) when (> (aref vc i) 0) return nil) vc)) (defun google-translate--number-to-bit-v (n) "Return a bit vector from N." (if (< n 0) (google-translate--bit-v-2comp (google-translate--number-to-bit-v (abs n))) (let ((v (make-vector google-translate--bit-v-len 0))) (cl-loop for i downfrom (1- google-translate--bit-v-len) to 0 with q when (< n 1) return nil do (setq q (ffloor (* n 0.5))) (aset v i (floor (- n (* 2.0 q)))) (setq n q)) v))) (defun google-translate--bit-v-to-number (v) "Return a floating-point number from V." (if (and (> (aref v 0) 0) ;; Exclude [1 0 ... 0] (cl-loop for i from 1 below google-translate--bit-v-len thereis (> (aref v i) 0))) (- (google-translate--bit-v-to-number (google-translate--bit-v-2comp v))) (funcall (if (> (aref v 0) 0) #'- #'+) (cl-reduce (lambda (acc e) (+ (* acc 2.0) e)) v :initial-value 0.0)))) (defun google-translate--logfn (fn n1 n2) "Helper function for logical FN." (let ((v1 (google-translate--number-to-bit-v n1)) (v2 (google-translate--number-to-bit-v n2)) (v (make-vector google-translate--bit-v-len 0))) (cl-loop for i from 0 below google-translate--bit-v-len do (aset v i (funcall fn (aref v1 i) (aref v2 i)))) (google-translate--bit-v-to-number v))) (defun google-translate--logand (n1 n2) "Return a floating-point number from N1 and N2." (google-translate--logfn #'logand n1 n2)) (defun google-translate--logxor (n1 n2) "Return a floating-point number from N1 and N2." (google-translate--logfn #'logxor n1 n2)) (defun google-translate--lsh (n d) "Return a floating-point number. Shift the bits in N to the left or rihgt D places. D is an integer." (let ((v (google-translate--number-to-bit-v n)) (v-result (make-vector google-translate--bit-v-len 0))) (if (< d 0) ;; Shift Right Logical ;; [x0 x1 ... xn-d ... xn] => [0 ... 0 x0 x1 ... xn-d] (cl-loop for i from (abs d) below google-translate--bit-v-len for j from 0 do (aset v-result i (aref v j))) ;; Shift Left Logical ;; [x0 x1 ... xd ... xn] => [xd ... xn 0 ... 0] (cl-loop for i from d below google-translate--bit-v-len for j from 0 do (aset v-result j (aref v i)))) (google-translate--bit-v-to-number v-result))) (defun google-translate--search-tkk () "Search TKK." (let ((start nil) (tkk nil) (nums '())) (setq start (search-forward ",tkk:'")) (search-forward "',") (backward-char 2) (setq tkk (buffer-substring start (point))) (setq nums (split-string tkk "\\.")) (list (string-to-number (car nums)) (string-to-number (car (cdr nums)))))) (defun google-translate--get-b-d1 () "Return a list of b and d1 for `google-translate--gen-tk'." (let ((url-request-extra-headers '(("Connection" . "close")))) (with-temp-buffer (save-excursion (google-translate-backend-retrieve google-translate--tkk-url)) (google-translate--search-tkk)))) (defun google-translate--gen-rl (a b) (cl-loop for c from 0 below (- (length b) 2) by 3 for d = (aref b (+ c 2)) do (setq d (if (>= d ?a) (- d 87) (- d ?0))) (setq d (if (= (aref b (1+ c)) ?+) (google-translate--lsh a (- d)) (google-translate--lsh a d))) (setq a (if (= (aref b c) ?+) (google-translate--logand (+ a d) 4294967295.0) (google-translate--logxor a d)))) a) (defun google-translate--gen-tk (text &optional b-d1) (setq b-d1 (or b-d1 (google-translate--get-b-d1))) (let* ((b (cl-first b-d1)) (d1 (cl-second b-d1)) (ub "+-3^+b+-f") (vb "+-a^+6") (a (cl-reduce (lambda (a e) (google-translate--gen-rl (+ a e) vb)) (encode-coding-string text 'utf-8) :initial-value b))) (setq a (google-translate--gen-rl a ub)) (setq a (google-translate--logxor a d1)) (when (< a 0) ;; (abs a) + 2^31 (setq a (+ (google-translate--logand a 2147483647.0) 2147483648.0))) (setq a (ffloor (mod a 1e6))) (format "%s.%s" (car (split-string (number-to-string a) "\\.")) (car (split-string (number-to-string (google-translate--logxor a b)) "\\."))))) (provide 'google-translate-tk) ;;; google-translate-tk.el ends here