hexify.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2018 K. Lange
  5. *
  6. * hexify - Convert binary to hex.
  7. *
  8. * This is based on the output of xxd.
  9. * Does NOT a hex-to-bin option - something to consider.
  10. */
  11. #include <stdio.h>
  12. #include <ctype.h>
  13. #include <errno.h>
  14. #include <unistd.h>
  15. #include <string.h>
  16. void print_line(unsigned char * buf, unsigned int width, unsigned int sizer, unsigned int offset) {
  17. fprintf(stdout, "%08x: ", sizer);
  18. for (unsigned int i = 0; i < width; ) {
  19. if (i >= offset) {
  20. fprintf(stdout, " ");
  21. } else {
  22. fprintf(stdout, "%02x", buf[i]);
  23. }
  24. i++;
  25. if (i == width) break; /* in case of odd width */
  26. if (i >= offset) {
  27. fprintf(stdout, " ");
  28. } else {
  29. fprintf(stdout, "%02x ", buf[i]);
  30. }
  31. i++;
  32. }
  33. fprintf(stdout, " ");
  34. for (unsigned int i = 0; i < width; i++) {
  35. if (i >= offset) {
  36. fprintf(stdout, " ");
  37. } else {
  38. if (isprint(buf[i])) {
  39. fprintf(stdout, "%c", buf[i]);
  40. } else {
  41. fprintf(stdout, ".");
  42. }
  43. }
  44. }
  45. fprintf(stdout, "\n");
  46. }
  47. static int stoih(int w, char c[w], unsigned int *out) {
  48. *out = 0;
  49. for (int i = 0; i < w; ++i) {
  50. (*out) <<= 4;
  51. if (c[i] >= '0' && c[i] <= '9') {
  52. *out |= (c[i] - '0');
  53. } else if (c[i] >= 'A' && c[i] <= 'F') {
  54. *out |= (c[i] - 'A' + 0xA);
  55. } else if (c[i] >= 'a' && c[i] <= 'f') {
  56. *out |= (c[i] - 'a' + 0xA);
  57. } else {
  58. *out = 0;
  59. return 1;
  60. }
  61. }
  62. return 0;
  63. }
  64. int main(int argc, char * argv[]) {
  65. unsigned int width = 16; /* TODO make configurable */
  66. int opt;
  67. int direction = 0;
  68. while ((opt = getopt(argc, argv, "?w:d")) != -1) {
  69. switch (opt) {
  70. default:
  71. case '?':
  72. fprintf(stderr, "%s: convert to/from hexadecimal dump\n", argv[0]);
  73. return 1;
  74. case 'w':
  75. width = atoi(optarg);
  76. break;
  77. case 'd':
  78. direction = 1;
  79. break;
  80. }
  81. }
  82. FILE * f;
  83. char * name;
  84. if (optind < argc) {
  85. f = fopen(argv[optind], "r");
  86. name = argv[optind];
  87. if (!f) {
  88. fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno));
  89. }
  90. } else {
  91. name = "[stdin]";
  92. f = stdin;
  93. }
  94. if (direction == 0) {
  95. /* Convert to hexadecimal */
  96. unsigned int sizer = 0;
  97. unsigned int offset = 0;
  98. unsigned char buf[width];
  99. while (!feof(f)) {
  100. unsigned int r = fread(buf+offset, 1, width-offset, f);
  101. offset += r;
  102. if (offset == width) {
  103. print_line(buf, width, sizer, offset);
  104. offset = 0;
  105. sizer += width;
  106. }
  107. }
  108. if (offset != 0) {
  109. print_line(buf, width, sizer, offset);
  110. }
  111. } else {
  112. /* Convert from hexify's output format */
  113. unsigned int eoffset = 0;
  114. unsigned int lineno = 1;
  115. while (!feof(f)) {
  116. /* Read offset */
  117. char offset_bytes[8];
  118. fread(&offset_bytes, 1, 8, f);
  119. /* Convert offset for verification */
  120. unsigned int offset;
  121. if (stoih(8, offset_bytes, &offset)) {
  122. fprintf(stderr, "%s: %s: syntax error (bad offset) on line %d\n", argv[0], name, lineno);
  123. fprintf(stderr, "offset bytes: %8s\n", offset_bytes);
  124. return 1;
  125. }
  126. if (offset != eoffset) {
  127. fprintf(stderr, "%s: %s: offset mismatch on line %d\n", argv[0], name, lineno);
  128. fprintf(stderr, "expected 0x%x, got 0x%x\n", offset, eoffset);
  129. return 1;
  130. }
  131. /* Read ": " */
  132. char tmp[2];
  133. fread(&tmp, 1, 2, f);
  134. if (tmp[0] != ':' || tmp[1] != ' ') {
  135. fprintf(stderr, "%s: %s: syntax error (unexpected characters after offset) on line %d\n", argv[0], name, lineno);
  136. return 1;
  137. }
  138. /* Read [width] characters */
  139. for (unsigned int i = 0; i < width; ) {
  140. unsigned int byte = 0;
  141. for (unsigned int j = 0; i < width && j < 2; ++j, ++i) {
  142. fread(&tmp, 1, 2, f);
  143. if (tmp[0] == ' ' && tmp[1] == ' ') {
  144. /* done; return */
  145. return 0;
  146. }
  147. if (stoih(2, tmp, &byte)) {
  148. fprintf(stderr, "%s: %s: syntax error (bad byte) on line %d\n", argv[0], name, lineno);
  149. fprintf(stderr, "byte bytes: %2s\n", tmp);
  150. return 1;
  151. }
  152. fwrite(&byte, 1, 1, stdout);
  153. }
  154. /* Read space */
  155. fread(&tmp, 1, 1, f);
  156. if (tmp[0] != ' ') {
  157. fprintf(stderr, "%s: %s: syntax error (unexpected characters after byte) on line %d\n", argv[0], name, lineno);
  158. fprintf(stderr, "unexpected character: %c\n", tmp[0]);
  159. return 1;
  160. }
  161. }
  162. fread(&tmp, 1, 1, f);
  163. if (tmp[0] != ' ') {
  164. fprintf(stderr, "%s: %s: syntax error (unexpected characters after bytes) on line %d\n", argv[0], name, lineno);
  165. }
  166. /* Read correct number of characters, plus line feed */
  167. char tmp2[width+2];
  168. fread(&tmp2, 1, width+1, f);
  169. tmp2[width+1] = '\0';
  170. if (tmp2[width] != '\n') {
  171. fprintf(stderr, "%s: %s: syntax error: expected end of line, got garbage on line %d\n", argv[0], name, lineno);
  172. fprintf(stderr, "eol data: %s\n", tmp2);
  173. }
  174. lineno++;
  175. eoffset += width;
  176. }
  177. }
  178. return 0;
  179. }