Rotate.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /**
  2. * Bit rotation operations.
  3. *
  4. * @author n1474335 [n1474335@gmail.com]
  5. * @copyright Crown Copyright 2016
  6. * @license Apache-2.0
  7. *
  8. * @namespace
  9. *
  10. * @todo Support for UTF16
  11. */
  12. var Rotate = {
  13. /**
  14. * @constant
  15. * @default
  16. */
  17. ROTATE_AMOUNT: 1,
  18. /**
  19. * @constant
  20. * @default
  21. */
  22. ROTATE_WHOLE: false,
  23. /**
  24. * Runs rotation operations across the input data.
  25. *
  26. * @private
  27. * @param {byteArray} data
  28. * @param {number} amount
  29. * @param {function} algo - The rotation operation to carry out
  30. * @returns {byteArray}
  31. */
  32. _rot: function(data, amount, algo) {
  33. var result = [];
  34. for (var i = 0; i < data.length; i++) {
  35. var b = data[i];
  36. for (var j = 0; j < amount; j++) {
  37. b = algo(b);
  38. }
  39. result.push(b);
  40. }
  41. return result;
  42. },
  43. /**
  44. * Rotate right operation.
  45. *
  46. * @param {byteArray} input
  47. * @param {Object[]} args
  48. * @returns {byteArray}
  49. */
  50. runRotr: function(input, args) {
  51. if (args[1]) {
  52. return Rotate._rotrWhole(input, args[0]);
  53. } else {
  54. return Rotate._rot(input, args[0], Rotate._rotr);
  55. }
  56. },
  57. /**
  58. * Rotate left operation.
  59. *
  60. * @param {byteArray} input
  61. * @param {Object[]} args
  62. * @returns {byteArray}
  63. */
  64. runRotl: function(input, args) {
  65. if (args[1]) {
  66. return Rotate._rotlWhole(input, args[0]);
  67. } else {
  68. return Rotate._rot(input, args[0], Rotate._rotl);
  69. }
  70. },
  71. /**
  72. * @constant
  73. * @default
  74. */
  75. ROT13_AMOUNT: 13,
  76. /**
  77. * @constant
  78. * @default
  79. */
  80. ROT13_LOWERCASE: true,
  81. /**
  82. * @constant
  83. * @default
  84. */
  85. ROT13_UPPERCASE: true,
  86. /**
  87. * ROT13 operation.
  88. *
  89. * @param {byteArray} input
  90. * @param {Object[]} args
  91. * @returns {byteArray}
  92. */
  93. runRot13: function(input, args) {
  94. var amount = args[2],
  95. output = input,
  96. chr,
  97. rot13Lowercase = args[0],
  98. rot13Upperacse = args[1];
  99. if (amount) {
  100. if (amount < 0) {
  101. amount = 26 - (Math.abs(amount) % 26);
  102. }
  103. for (var i = 0; i < input.length; i++) {
  104. chr = input[i];
  105. if (rot13Upperacse && chr >= 65 && chr <= 90) { // Upper case
  106. chr = (chr - 65 + amount) % 26;
  107. output[i] = chr + 65;
  108. } else if (rot13Lowercase && chr >= 97 && chr <= 122) { // Lower case
  109. chr = (chr - 97 + amount) % 26;
  110. output[i] = chr + 97;
  111. }
  112. }
  113. }
  114. return output;
  115. },
  116. /**
  117. * @constant
  118. * @default
  119. */
  120. ROT47_AMOUNT: 47,
  121. /**
  122. * ROT47 operation.
  123. *
  124. * @author Matt C [matt@artemisbot.pw]
  125. * @param {byteArray} input
  126. * @param {Object[]} args
  127. * @returns {byteArray}
  128. */
  129. runRot47: function(input, args) {
  130. var amount = args[0],
  131. output = input,
  132. chr;
  133. if (amount) {
  134. if (amount < 0) {
  135. amount = 94 - (Math.abs(amount) % 94);
  136. }
  137. for (var i = 0; i < input.length; i++) {
  138. chr = input[i];
  139. if (chr >= 33 && chr <= 126) {
  140. chr = (chr - 33 + amount) % 94;
  141. output[i] = chr + 33;
  142. }
  143. }
  144. }
  145. return output;
  146. },
  147. /**
  148. * Rotate right bitwise op.
  149. *
  150. * @private
  151. * @param {byte} b
  152. * @returns {byte}
  153. */
  154. _rotr: function(b) {
  155. var bit = (b & 1) << 7;
  156. return (b >> 1) | bit;
  157. },
  158. /**
  159. * Rotate left bitwise op.
  160. *
  161. * @private
  162. * @param {byte} b
  163. * @returns {byte}
  164. */
  165. _rotl: function(b) {
  166. var bit = (b >> 7) & 1;
  167. return ((b << 1) | bit) & 0xFF;
  168. },
  169. /**
  170. * Rotates a byte array to the right by a specific amount as a whole, so that bits are wrapped
  171. * from the end of the array to the beginning.
  172. *
  173. * @private
  174. * @param {byteArray} data
  175. * @param {number} amount
  176. * @returns {byteArray}
  177. */
  178. _rotrWhole: function(data, amount) {
  179. var carryBits = 0,
  180. newByte,
  181. result = [];
  182. amount = amount % 8;
  183. for (var i = 0; i < data.length; i++) {
  184. var oldByte = data[i] >>> 0;
  185. newByte = (oldByte >> amount) | carryBits;
  186. carryBits = (oldByte & (Math.pow(2, amount)-1)) << (8-amount);
  187. result.push(newByte);
  188. }
  189. result[0] |= carryBits;
  190. return result;
  191. },
  192. /**
  193. * Rotates a byte array to the left by a specific amount as a whole, so that bits are wrapped
  194. * from the beginning of the array to the end.
  195. *
  196. * @private
  197. * @param {byteArray} data
  198. * @param {number} amount
  199. * @returns {byteArray}
  200. */
  201. _rotlWhole: function(data, amount) {
  202. var carryBits = 0,
  203. newByte,
  204. result = [];
  205. amount = amount % 8;
  206. for (var i = data.length-1; i >= 0; i--) {
  207. var oldByte = data[i];
  208. newByte = ((oldByte << amount) | carryBits) & 0xFF;
  209. carryBits = (oldByte >> (8-amount)) & (Math.pow(2, amount)-1);
  210. result[i] = (newByte);
  211. }
  212. result[data.length-1] = result[data.length-1] | carryBits;
  213. return result;
  214. },
  215. };