OpenCBM
t64.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version
5  * 2 of the License, or (at your option) any later version.
6  *
7  * Copyright 2001-2003 Michael Klein <michael(dot)klein(at)puffin(dot)lb(dot)shuttle(dot)de>
8 */
9 
10 #include <stdlib.h>
11 #include <string.h>
12 
13 #include "opencbm.h"
14 #include "inputfiles.h"
15 
16 static int probe(FILE *file, const char *fname, cbmcopy_message_cb msg_cb)
17 {
18  /* signature list stolen from cbmconvert */
19  const char signatures[][32] =
20  {
21  "C64 tape image file\0\0\0\0\0\0\0\0\0\0\0\0\0",
22  "C64S tape file\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
23  "C64S tape image file\0\0\0\0\0\0\0\0\0\0\0\0"
24  };
25  struct
26  {
27  char sig[32];
28  unsigned char major;
29  unsigned char minor;
30  unsigned char max_entries_l;
31  unsigned char max_entries_h;
32  unsigned char used_entries_l;
33  unsigned char used_entries_h;
34  char pad[2];
35  char name[24]; /* careful: not '\0'-terminated! */
36  } t64header;
37 
38  size_t i;
39  int used_entries;
40 
41  msg_cb( sev_debug, "checking for t64" );
42 
43  if(fread( &t64header, sizeof(t64header), 1, file) == 1)
44  {
45  for(i = 0; i < sizeof(signatures) / 32; i++)
46  {
47  if(memcmp(signatures[i], t64header.sig, 32) == 0)
48  {
49  used_entries =
50  t64header.used_entries_l +
51  t64header.used_entries_h * 256;
52  msg_cb( sev_debug, "found t64 signature '%s'", signatures[i] );
53  msg_cb( sev_debug, "tape version %u.%u",
54  t64header.major, t64header.minor );
55  msg_cb( sev_debug, "tape contains %d file%c",
56  used_entries, used_entries > 1 ? 's' : '\0' );
57  return used_entries;
58  }
59  }
60  }
61  rewind( file );
62  return 0;
63 }
64 
65 
66 static int read(FILE *file, const char *fname, int entry,
67  char *cbmname, char *type,
68  unsigned char **data, size_t *size,
69  cbmcopy_message_cb msg_cb)
70 {
71  struct
72  {
73  unsigned char c64s_type;
74  unsigned char c1541_type;
75  unsigned char start_l;
76  unsigned char start_h;
77  unsigned char end_l;
78  unsigned char end_h;
79  unsigned char unused1[2];
80  unsigned char offset[4]; /* l to h */
81  unsigned char unused2[4];
82  unsigned char name[16];
83  } t64entry;
84  long offset;
85  int i;
86  int start;
87  int end;
88 
89  if(fseek( file, 0x40 + 32 * entry, SEEK_SET ) == 0 &&
90  fread( &t64entry, sizeof(t64entry), 1, file ) == 1)
91  {
92  memcpy( cbmname, t64entry.name, 16 );
93  for( i = 15; i >= 0 && cbmname[i] == 0x20; i-- )
94  {
95  cbmname[i] = (char) 0xa0;
96  }
97  switch(t64entry.c1541_type)
98  {
99  case 0x01:
100  case 0x80:
101  case 'D' :
102  *type = 'D';
103  break;
104  case 0x81:
105  case 'S' :
106  *type = 'S';
107  break;
108  case 0x82:
109  case 'P' :
110  *type = 'P';
111  break;
112  case 0x83:
113  case 'U' :
114  *type = 'U';
115  break;
116  default:
117  msg_cb( sev_info, "unknown 1541 file type, using default" );
118  *type = 'P';
119  break;
120  }
121  for(offset = 0, i = 3; i >= 0; i--)
122  {
123  offset = offset * 0x100 + t64entry.offset[i];
124  }
125  msg_cb( sev_debug, "data offset = %08lx", offset );
126  start = t64entry.start_l + 0x100 * t64entry.start_h;
127  end = t64entry.end_l + 0x100 * t64entry.end_h;
128 
129  if(fseek(file, offset, SEEK_SET) == 0)
130  {
131  *size = 2 + (end - start);
132  *data = malloc(*size);
133  if(*data)
134  {
135  (*data)[0] = t64entry.start_l;
136  (*data)[1] = t64entry.start_h;
137  if(fread(&(*data)[2], (*size)-2, 1, file) == 1)
138  {
139  return 0;
140  }
141  else
142  {
143  msg_cb( sev_warning, "could not read file data" );
144  }
145  free(*data);
146  }
147  else
148  {
149  msg_cb( sev_warning, "no memory" );
150  }
151  }
152  else
153  {
154  msg_cb( sev_warning, "could not seek to file data" );
155  }
156  }
157  else
158  {
159  msg_cb( sev_warning, "could not seek to directory entry" );
160  }
161  return 1;
162 }
163 
164 DECLARE_INPUT_READER(t64);
DLL interface for accessing the driver.