Hexdump.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /* globals app */
  2. /**
  3. * Hexdump operations.
  4. *
  5. * @author n1474335 [n1474335@gmail.com]
  6. * @copyright Crown Copyright 2016
  7. * @license Apache-2.0
  8. *
  9. * @namespace
  10. */
  11. var Hexdump = {
  12. /**
  13. * @constant
  14. * @default
  15. */
  16. WIDTH: 16,
  17. /**
  18. * @constant
  19. * @default
  20. */
  21. UPPER_CASE: false,
  22. /**
  23. * @constant
  24. * @default
  25. */
  26. INCLUDE_FINAL_LENGTH: false,
  27. /**
  28. * To Hexdump operation.
  29. *
  30. * @param {byteArray} input
  31. * @param {Object[]} args
  32. * @returns {string}
  33. */
  34. runTo: function(input, args) {
  35. var length = args[0] || Hexdump.WIDTH;
  36. var upperCase = args[1];
  37. var includeFinalLength = args[2];
  38. var output = "", padding = 2;
  39. for (var i = 0; i < input.length; i += length) {
  40. var buff = input.slice(i, i+length);
  41. var hexa = "";
  42. for (var j = 0; j < buff.length; j++) {
  43. hexa += Utils.hex(buff[j], padding) + " ";
  44. }
  45. var lineNo = Utils.hex(i, 8);
  46. if (upperCase) {
  47. hexa = hexa.toUpperCase();
  48. lineNo = lineNo.toUpperCase();
  49. }
  50. output += lineNo + " " +
  51. Utils.padRight(hexa, (length*(padding+1))) +
  52. " |" + Utils.padRight(Utils.printable(Utils.byteArrayToChars(buff)), buff.length) + "|\n";
  53. if (includeFinalLength && i+buff.length === input.length) {
  54. output += Utils.hex(i+buff.length, 8) + "\n";
  55. }
  56. }
  57. return output.slice(0, -1);
  58. },
  59. /**
  60. * From Hexdump operation.
  61. *
  62. * @param {string} input
  63. * @param {Object[]} args
  64. * @returns {byteArray}
  65. */
  66. runFrom: function(input, args) {
  67. var output = [],
  68. regex = /^\s*(?:[\dA-F]{4,16}:?)?\s*((?:[\dA-F]{2}\s){1,8}(?:\s|[\dA-F]{2}-)(?:[\dA-F]{2}\s){1,8}|(?:[\dA-F]{2}\s|[\dA-F]{4}\s)+)/igm,
  69. block, line;
  70. while ((block = regex.exec(input))) {
  71. line = Utils.fromHex(block[1].replace(/-/g, " "));
  72. for (var i = 0; i < line.length; i++) {
  73. output.push(line[i]);
  74. }
  75. }
  76. // Is this a CyberChef hexdump or is it from a different tool?
  77. var width = input.indexOf("\n");
  78. var w = (width - 13) / 4;
  79. // w should be the specified width of the hexdump and therefore a round number
  80. if (Math.floor(w) !== w || input.indexOf("\r") !== -1 || output.indexOf(13) !== -1) {
  81. app.options.attemptHighlight = false;
  82. }
  83. return output;
  84. },
  85. /**
  86. * Highlight to hexdump
  87. *
  88. * @param {Object[]} pos
  89. * @param {number} pos[].start
  90. * @param {number} pos[].end
  91. * @param {Object[]} args
  92. * @returns {Object[]} pos
  93. */
  94. highlightTo: function(pos, args) {
  95. // Calculate overall selection
  96. var w = args[0] || 16,
  97. width = 14 + (w*4),
  98. line = Math.floor(pos[0].start / w),
  99. offset = pos[0].start % w,
  100. start = 0,
  101. end = 0;
  102. pos[0].start = line*width + 10 + offset*3;
  103. line = Math.floor(pos[0].end / w);
  104. offset = pos[0].end % w;
  105. if (offset === 0) {
  106. line--;
  107. offset = w;
  108. }
  109. pos[0].end = line*width + 10 + offset*3 - 1;
  110. // Set up multiple selections for bytes
  111. var startLineNum = Math.floor(pos[0].start / width);
  112. var endLineNum = Math.floor(pos[0].end / width);
  113. if (startLineNum === endLineNum) {
  114. pos.push(pos[0]);
  115. } else {
  116. start = pos[0].start;
  117. end = (startLineNum+1) * width - w - 5;
  118. pos.push({ start: start, end: end });
  119. while (end < pos[0].end) {
  120. startLineNum++;
  121. start = startLineNum * width + 10;
  122. end = (startLineNum+1) * width - w - 5;
  123. if (end > pos[0].end) end = pos[0].end;
  124. pos.push({ start: start, end: end });
  125. }
  126. }
  127. // Set up multiple selections for ASCII
  128. var len = pos.length, lineNum = 0;
  129. start = 0;
  130. end = 0;
  131. for (var i = 1; i < len; i++) {
  132. lineNum = Math.floor(pos[i].start / width);
  133. start = (((pos[i].start - (lineNum * width)) - 10) / 3) + (width - w -2) + (lineNum * width);
  134. end = (((pos[i].end + 1 - (lineNum * width)) - 10) / 3) + (width - w -2) + (lineNum * width);
  135. pos.push({ start: start, end: end });
  136. }
  137. return pos;
  138. },
  139. /**
  140. * Highlight from hexdump
  141. *
  142. * @param {Object[]} pos
  143. * @param {number} pos[].start
  144. * @param {number} pos[].end
  145. * @param {Object[]} args
  146. * @returns {Object[]} pos
  147. */
  148. highlightFrom: function(pos, args) {
  149. var w = args[0] || 16;
  150. var width = 14 + (w*4);
  151. var line = Math.floor(pos[0].start / width);
  152. var offset = pos[0].start % width;
  153. if (offset < 10) { // In line number section
  154. pos[0].start = line*w;
  155. } else if (offset > 10+(w*3)) { // In ASCII section
  156. pos[0].start = (line+1)*w;
  157. } else { // In byte section
  158. pos[0].start = line*w + Math.floor((offset-10)/3);
  159. }
  160. line = Math.floor(pos[0].end / width);
  161. offset = pos[0].end % width;
  162. if (offset < 10) { // In line number section
  163. pos[0].end = line*w;
  164. } else if (offset > 10+(w*3)) { // In ASCII section
  165. pos[0].end = (line+1)*w;
  166. } else { // In byte section
  167. pos[0].end = line*w + Math.ceil((offset-10)/3);
  168. }
  169. return pos;
  170. },
  171. };