Coverage Report

Created: 2025-08-28 06:53

/src/file/src/is_simh.c
Line
Count
Source (jump to first uncovered line)
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
/*
28
 * Parse SIM-H tape files
29
 * http://simh.trailing-edge.com/docs/simh_magtape.pdf
30
 */
31
32
#ifndef TEST
33
#include "file.h"
34
35
#ifndef lint
36
FILE_RCSID("@(#)$File: is_simh.c,v 1.11 2025/05/31 23:31:45 christos Exp $")
37
#endif
38
39
#include <string.h>
40
#include <stddef.h>
41
#include "magic.h"
42
#else
43
#include <stdint.h>
44
#include <sys/types.h>
45
#include <string.h>
46
#include <stddef.h>
47
#define CAST(a, b) (a)(b)
48
#endif
49
50
51
#ifdef DEBUG
52
#include <stdio.h>
53
#define DPRINTF(fmt, ...) printf(fmt, __VA_ARGS__)
54
#else
55
#define DPRINTF(fmt, ...)
56
#endif
57
58
/*
59
 * if SIMH_TAPEMARKS == 0:
60
 *  check all the records and tapemarks
61
 * otherwise:
62
 *  check only up-to the number of tapemarks specified
63
 */
64
#ifndef SIMH_TAPEMARKS
65
2.82k
#define SIMH_TAPEMARKS 10
66
#endif
67
68
typedef union {
69
  char s[4];
70
  uint32_t u;
71
} myword; 
72
73
static myword simh_bo;
74
75
42.6k
#define NEED_SWAP (simh_bo.u == CAST(uint32_t, 0x01020304))
76
77
/*
78
 * swap an int
79
 */
80
static uint32_t
81
swap4(uint32_t sv)
82
0
{
83
0
  myword d, s;
84
0
  s.u = sv;
85
0
  d.s[0] = s.s[3];
86
0
  d.s[1] = s.s[2];
87
0
  d.s[2] = s.s[1];
88
0
  d.s[3] = s.s[0];
89
0
  return d.u;
90
0
}
91
92
93
static uint32_t
94
getlen(const unsigned char **uc, int *err)
95
42.6k
{
96
42.6k
  uint32_t n;
97
42.6k
  memcpy(&n, *uc, sizeof(n));
98
42.6k
  *err = 0;
99
42.6k
  *uc += sizeof(n);
100
42.6k
  if (NEED_SWAP)
101
0
    n = swap4(n);
102
42.6k
  if (n == 0xffffffff)  /* check for End of Medium */
103
97
    return n;
104
  /* Check bits 25 to 28 are not used */
105
42.5k
  *err = ((n & 0x00ffffff) != (n & 0x0fffffff));
106
42.5k
  n &= 0x00ffffff;  /* keep only the record len */
107
42.5k
  if (n & 1)
108
17.8k
    n++;
109
42.5k
  return n;
110
42.6k
}
111
112
static int
113
simh_parse(const unsigned char *uc, const unsigned char *ue)
114
25.3k
{
115
25.3k
  uint32_t nbytes, cbytes;
116
25.3k
  const unsigned char *orig_uc = uc;
117
25.3k
  size_t nt = 0, nr = 0;
118
25.3k
  int err = 0;
119
120
25.3k
  (void)memcpy(simh_bo.s, "\01\02\03\04", 4);
121
122
35.7k
  while (ue - uc >= CAST(ptrdiff_t, sizeof(nbytes))) {
123
34.1k
    nbytes = getlen(&uc, &err);
124
34.1k
    if (err)
125
16.2k
      return 0;
126
17.8k
    if ((nt > 0 || nr > 0) && nbytes == 0xFFFFFFFF)
127
      /* EOM after at least one record or tapemark */
128
6
      break;
129
17.8k
    if (nbytes == 0) {
130
2.82k
      nt++; /* count tapemarks */
131
2.82k
#if SIMH_TAPEMARKS
132
2.82k
      if (nt == SIMH_TAPEMARKS)
133
254
        break;
134
2.57k
#endif
135
2.57k
      continue;
136
2.82k
    }
137
    /* handle a data record */
138
15.0k
    uc += nbytes;
139
15.0k
    if (ue - uc < CAST(ptrdiff_t, sizeof(nbytes)))
140
6.52k
      break;
141
8.51k
    cbytes = getlen(&uc, &err);
142
8.51k
    if (err)
143
207
      return 0;
144
8.31k
    if (nbytes != cbytes)
145
523
      return 0;
146
7.78k
    nr++;
147
7.78k
  }
148
8.39k
  if (nt * sizeof(uint32_t) == CAST(size_t, uc - orig_uc))
149
1.85k
    return 0;  /* All examined data was tapemarks (0) */
150
6.54k
  if (nr == 0)    /* No records */
151
6.49k
    return 0;
152
52
  return 1;
153
6.54k
}
154
155
#ifndef TEST
156
int
157
file_is_simh(struct magic_set *ms, const struct buffer *b)
158
25.3k
{
159
25.3k
  const unsigned char *uc = CAST(const unsigned char *, b->fbuf);
160
25.3k
  const unsigned char *ue = uc + b->flen;
161
25.3k
  int mime = ms->flags & MAGIC_MIME;
162
163
25.3k
  if ((ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION)) != 0)
164
0
    return 0;
165
166
25.3k
  if (!simh_parse(uc, ue))
167
25.3k
    return 0;
168
169
52
  if (mime == MAGIC_MIME_ENCODING)
170
0
    return 1;
171
172
52
  if (mime) {
173
0
    if (file_printf(ms, "application/SIMH-tape-data") == -1)
174
0
      return -1;
175
0
    return 1;
176
0
  }
177
178
52
  if (file_printf(ms, "SIMH tape data") == -1)
179
0
    return -1;
180
181
52
  return 1;
182
52
}
183
184
#else
185
186
#include <sys/types.h>
187
#include <sys/stat.h>
188
#include <stdio.h>
189
#include <fcntl.h>
190
#include <unistd.h>
191
#include <stdlib.h>
192
#include <stdint.h>
193
#include <err.h>
194
195
int
196
main(int argc, char *argv[])
197
{
198
  int fd;
199
  struct stat st;
200
  unsigned char *p;
201
202
  if ((fd = open(argv[1], O_RDONLY)) == -1)
203
    err(EXIT_FAILURE, "Can't open `%s'", argv[1]);
204
205
  if (fstat(fd, &st) == -1)
206
    err(EXIT_FAILURE, "Can't stat `%s'", argv[1]);
207
208
  if ((p = CAST(char *, malloc(st.st_size))) == NULL)
209
    err(EXIT_FAILURE, "Can't allocate %jd bytes",
210
        (intmax_t)st.st_size);
211
  if (read(fd, p, st.st_size) != st.st_size)
212
    err(EXIT_FAILURE, "Can't read %jd bytes",
213
        (intmax_t)st.st_size);
214
  printf("is simh %d\n", simh_parse(p, p + st.st_size));
215
  return 0;
216
}
217
#endif