is_simh.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /*-
  2. * Copyright (c) 2023 Christos Zoulas
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  15. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  16. * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  17. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
  18. * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  19. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  20. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  21. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  22. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  23. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  24. * POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. /*
  27. * Parse SIM-H tape files
  28. * http://simh.trailing-edge.com/docs/simh_magtape.pdf
  29. */
  30. #ifndef TEST
  31. #include "file.h"
  32. #ifndef lint
  33. FILE_RCSID("@(#)$File: is_simh.c,v 1.10 2023/07/27 19:39:55 christos Exp $")
  34. #endif
  35. #include <string.h>
  36. #include <stddef.h>
  37. #include "magic.h"
  38. #else
  39. #include <stdint.h>
  40. #include <sys/types.h>
  41. #include <string.h>
  42. #include <stddef.h>
  43. #define CAST(a, b) (a)(b)
  44. #endif
  45. #ifdef DEBUG
  46. #include <stdio.h>
  47. #define DPRINTF(fmt, ...) printf(fmt, __VA_ARGS__)
  48. #else
  49. #define DPRINTF(fmt, ...)
  50. #endif
  51. /*
  52. * if SIMH_TAPEMARKS == 0:
  53. * check all the records and tapemarks
  54. * otherwise:
  55. * check only up-to the number of tapemarks specified
  56. */
  57. #ifndef SIMH_TAPEMARKS
  58. #define SIMH_TAPEMARKS 10
  59. #endif
  60. typedef union {
  61. char s[4];
  62. uint32_t u;
  63. } myword;
  64. static myword simh_bo;
  65. #define NEED_SWAP (simh_bo.u == CAST(uint32_t, 0x01020304))
  66. /*
  67. * swap an int
  68. */
  69. static uint32_t
  70. swap4(uint32_t sv)
  71. {
  72. myword d, s;
  73. s.u = sv;
  74. d.s[0] = s.s[3];
  75. d.s[1] = s.s[2];
  76. d.s[2] = s.s[1];
  77. d.s[3] = s.s[0];
  78. return d.u;
  79. }
  80. static uint32_t
  81. getlen(const unsigned char **uc)
  82. {
  83. uint32_t n;
  84. memcpy(&n, *uc, sizeof(n));
  85. *uc += sizeof(n);
  86. if (NEED_SWAP)
  87. n = swap4(n);
  88. if (n == 0xffffffff) /* check for End of Medium */
  89. return n;
  90. n &= 0x00ffffff; /* keep only the record len */
  91. if (n & 1)
  92. n++;
  93. return n;
  94. }
  95. static int
  96. simh_parse(const unsigned char *uc, const unsigned char *ue)
  97. {
  98. uint32_t nbytes, cbytes;
  99. const unsigned char *orig_uc = uc;
  100. size_t nt = 0, nr = 0;
  101. (void)memcpy(simh_bo.s, "\01\02\03\04", 4);
  102. while (ue - uc >= CAST(ptrdiff_t, sizeof(nbytes))) {
  103. nbytes = getlen(&uc);
  104. if ((nt > 0 || nr > 0) && nbytes == 0xFFFFFFFF)
  105. /* EOM after at least one record or tapemark */
  106. break;
  107. if (nbytes == 0) {
  108. nt++; /* count tapemarks */
  109. #if SIMH_TAPEMARKS
  110. if (nt == SIMH_TAPEMARKS)
  111. break;
  112. #endif
  113. continue;
  114. }
  115. /* handle a data record */
  116. uc += nbytes;
  117. if (ue - uc < CAST(ptrdiff_t, sizeof(nbytes)))
  118. break;
  119. cbytes = getlen(&uc);
  120. if (nbytes != cbytes)
  121. return 0;
  122. nr++;
  123. }
  124. if (nt * sizeof(uint32_t) == CAST(size_t, uc - orig_uc))
  125. return 0; /* All examined data was tapemarks (0) */
  126. if (nr == 0) /* No records */
  127. return 0;
  128. return 1;
  129. }
  130. #ifndef TEST
  131. int
  132. file_is_simh(struct magic_set *ms, const struct buffer *b)
  133. {
  134. const unsigned char *uc = CAST(const unsigned char *, b->fbuf);
  135. const unsigned char *ue = uc + b->flen;
  136. int mime = ms->flags & MAGIC_MIME;
  137. if ((ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION)) != 0)
  138. return 0;
  139. if (!simh_parse(uc, ue))
  140. return 0;
  141. if (mime == MAGIC_MIME_ENCODING)
  142. return 1;
  143. if (mime) {
  144. if (file_printf(ms, "application/SIMH-tape-data") == -1)
  145. return -1;
  146. return 1;
  147. }
  148. if (file_printf(ms, "SIMH tape data") == -1)
  149. return -1;
  150. return 1;
  151. }
  152. #else
  153. #include <sys/types.h>
  154. #include <sys/stat.h>
  155. #include <stdio.h>
  156. #include <fcntl.h>
  157. #include <unistd.h>
  158. #include <stdlib.h>
  159. #include <stdint.h>
  160. #include <err.h>
  161. int
  162. main(int argc, char *argv[])
  163. {
  164. int fd;
  165. struct stat st;
  166. unsigned char *p;
  167. if ((fd = open(argv[1], O_RDONLY)) == -1)
  168. err(EXIT_FAILURE, "Can't open `%s'", argv[1]);
  169. if (fstat(fd, &st) == -1)
  170. err(EXIT_FAILURE, "Can't stat `%s'", argv[1]);
  171. if ((p = CAST(char *, malloc(st.st_size))) == NULL)
  172. err(EXIT_FAILURE, "Can't allocate %jd bytes",
  173. (intmax_t)st.st_size);
  174. if (read(fd, p, st.st_size) != st.st_size)
  175. err(EXIT_FAILURE, "Can't read %jd bytes",
  176. (intmax_t)st.st_size);
  177. printf("is simh %d\n", simh_parse(p, p + st.st_size));
  178. return 0;
  179. }
  180. #endif