Merge pull request #7 from ccawley2011/msvc
[debian-nspark.git] / arcfs.c
blobe7d6e2082a04b52aee81efea300c8cff80b3e005
2 /*
3 * Handle ArcFS format archives
5 * Author: Andrew Brooks, arb@comp.lancs.ac.uk
7 * $Header: arcfs.c 1.5 95/08/01 $
8 * $Log: arcfs.c,v $
9 * Revision 1.5 95/08/01 xx:xx:xx BB
10 * Fixes for Borland C/C++
11 * Removed use of floating point routines.
13 * Revision 1.4 95/01/06 11:58:45 arb
14 * Fixes for Alpha.
16 * Revision 1.3 94/12/12 17:25:25 arb
17 * Fixes for writesize.
19 * Revision 1.2 94/10/26 15:06:35 arb
20 * Fixed date and time conversion.
22 * Revision 1.1 94/02/28 21:41:23 arb
23 * Fixed header, fixed include ordering, fixed directory check,
24 * added seek to start of compressed data, fixed maxbits, ...
25 * ie. got the thing working at last!
27 * Revision 1.0 93/08/20 12:40:15 arb
28 * Initial revision
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <time.h>
34 #include <string.h>
35 #include "spark.h"
36 #ifdef POSIX
37 #include <sys/types.h>
38 #endif /* POSIX */
40 #if defined(RISCOS) || defined(__MSDOS__)
41 #include <stdlib.h>
42 #include <string.h>
43 #endif /* RISCOS || __MSDOS__ */
44 #include "arcfs.h"
46 #include "nsparkio.h"
48 #include "misc.h"
49 #include "error.h"
51 #ifndef SEEK_SET
52 #define SEEK_SET 0
53 #endif
56 * Public flag to indicate whether the current archive is ArcFS format
58 int arcfs = 0;
62 * Public number of compression bits, used in compress.c
64 int arcfs_maxbits = 0;
68 * Public size of file being extracted, used in io.c, crc.c
70 long writesize;
71 long crcsize;
75 * ArcFS header list element
77 struct arcfs_header_s
79 struct arcfs_header_s *next;
80 Byte maxbits;
81 Byte is_dir;
82 Byte info_byte;
83 Word info_word;
84 Word seek;
85 Header *header;
87 typedef struct arcfs_header_s *arcfs_header;
91 * Info byte
93 #define AFS_ENDDIR 0
94 #define AFS_DELETED 1
95 #define AFS_STORE 0x82
96 #define AFS_PACK 0x83
97 #define AFS_CRUNCH 0x88
98 #define AFS_COMPRESS 0xFF
102 * Static data
104 static int arcfs_initialised = 0;
105 static arcfs_header header_list = NULL;
106 static arcfs_header header_ptr = NULL;
110 * Convert RISC OS time to UNIX time.
111 * RISC OS time is five bytes of centiseconds since 1900.
112 * UNIX time is seconds since 1970.
113 * MSB of RISC OS time is LSB of `load' plus `exec'.
116 /* BB added extra prototype for Borland C/C++ */
118 struct tm *
119 rotm(Word load, Word exec)
121 Word low, high;
122 time_t t;
124 high = (load & 0xff) - 0x33l;
125 low = exec - 0x6e996a00l;
126 if (low > exec)
128 high--;
130 /* BB changed constant in next line to long */
131 /* cast to Word, then time_t as date stamps will all be 32 bits and time_t
132 * might be 64 bits */
133 t = (time_t)(Word)(high * 42949673L + low / 100L);
134 t -= (high / 25);
136 return (localtime(&t));
141 * Convert RISC OS time to SPARK time
144 /* BB added extra prototype for Borland C/C++ */
146 void
147 arcfs_fixtime(Header *hdr)
149 /* BB next line commented out, variable ti never used */
150 /* time_t ti; */
151 struct tm *tim;
153 /* Convert to UNIX time first (as it is easy) */
154 tim = rotm(hdr->load, hdr->exec);
156 /* Convert UNIX time to SPARK time */
157 hdr->date = (tim->tm_year - 80) << 9;
158 hdr->date |= (tim->tm_mon + 1) << 5;
159 hdr->date |= (tim->tm_mday);
160 hdr->time = (tim->tm_hour) << 11;
161 hdr->time |= (tim->tm_min) << 5;
162 hdr->time |= tim->tm_sec / 2;
167 * Read ArcFS header
169 Header *
170 arcfs_read_header(FILE *ifp)
172 static Header null_header;
173 static Word data_start;
174 Word header_length = 0;
175 Header *header;
176 Word version;
177 Word i;
178 Byte info_byte, name[12];
179 Word length, load, exec, attr, complen, info_word;
180 arcfs_header header_prev = NULL;
181 int j;
183 /* Return next header from list */
184 if (arcfs_initialised)
186 /* If end of list return an empty header structure to indicate EOF */
187 if (header_ptr == NULL)
188 return (&null_header);
190 /* Return next header in list */
191 header = header_ptr->header;
192 /* Seek to start of compressed data */
193 if ((!header_ptr->is_dir)
194 && (fseek(ifp, (long) header_ptr->seek, SEEK_SET)))
196 error("Cannot seek compressed data in this file");
197 return (&null_header);
199 /* Set up number of compression bits */
200 arcfs_maxbits = header_ptr->maxbits;
201 /*if (header_ptr->is_dir) header = &null_header; */
202 header_ptr = header_ptr->next;
203 return (header);
206 /* Header list not constructed yet, so read all headers from file */
207 arcfs_initialised = 1;
208 memset((char *) &null_header, '\0', sizeof(null_header));
209 null_header.comptype = 0;
210 header_length = read_word(ifp);
211 data_start = read_word(ifp);
212 if ((version = read_word(ifp)) > 40)
214 /* BB removed floating point routines from next line
215 This saves linking the floating point routines under DOS
216 which yields quite a reduction in executable size.
217 And it removes the need to have the FPE present under RISC OS. */
218 /* error("Archive created by a newer version of ArcFS (%.2f)",((float)version)/100); */
219 error("Archive created by a newer version of ArcFS (%d.%02d)",
220 version / 100, version % 100);
221 return (&null_header);
223 read_word(ifp); /* read/write version */
224 if ((version = read_word(ifp)) > 0)
226 error("Archive format %d not understood", version);
227 return (&null_header);
229 for (i = 0; i < 17; i++)
230 read_word(ifp); /* reserved */
232 /* Read list of headers */
233 for (i = 0; i < header_length / 36; i++)
235 /* Create list item */
236 header = (Header *) malloc(sizeof(Header));
237 header_ptr = (arcfs_header) malloc(sizeof(struct arcfs_header_s));
238 if ((header == NULL) || (header_ptr == NULL))
240 error("Out of memory");
241 return (&null_header);
244 /* Read ArcFS file header */
245 info_byte = read_byte(ifp);
246 for (j = 0; j < 11; j++)
248 name[j] = read_byte(ifp);
249 if (name[j] == PATHSEP)
250 name[j] = '_';
251 if (name[j] < ' ' || name[j] > '~')
252 name[j] = '\0';
254 name[j] = '\0';
255 length = read_word(ifp);
256 load = read_word(ifp);
257 exec = read_word(ifp);
258 attr = read_word(ifp);
259 complen = read_word(ifp);
260 info_word = read_word(ifp);
262 /* Examine, and create nspark header */
263 if (info_byte == AFS_DELETED)
265 free(header);
266 free(header_ptr);
267 continue;
269 /* BB changed next line for Borland C/C++ 4 */
270 /* header_ptr->is_dir = (info_word >> 31); */
271 #ifdef __MSDOS__
272 header_ptr->is_dir = (Halfword) (info_word >> 31);
273 #else
274 header_ptr->is_dir = (info_word >> 31);
275 #endif
276 header_ptr->info_byte = info_byte;
277 header_ptr->info_word = info_word;
278 /* BB changed next line for Borland C/C++ 4 */
279 /* header_ptr->maxbits = (attr & 0xff00) >> 8; */
280 #ifdef __MSDOS__
281 header_ptr->maxbits = (Halfword) (attr & 0xff00) >> 8;
282 #else
283 header_ptr->maxbits = (attr & 0xff00) >> 8;
284 #endif
285 /* BB changed constant in next line to long. */
286 header_ptr->seek = (info_word & 0x7fffffffL) + data_start;
287 header->comptype = info_byte;
288 strcpy(header->name, (char *) name);
289 header->complen = complen;
290 header->date = 0;
291 header->time = 0;
292 header->crc = (Halfword) (attr >> 16);
293 header->origlen = length;
294 header->load = load;
295 header->exec = exec;
296 header->attr = attr & 0xff;
298 arcfs_fixtime(header);
300 if (info_byte == AFS_ENDDIR)
302 /* Just return comptype == 0 */
303 *header = null_header;
304 header_ptr->is_dir = 0;
305 header_ptr->seek = 0;
308 /* If it is an ArcFS directory then convert to a Spark directory */
309 if (header_ptr->is_dir)
311 /* Make sure filetype is DDC */
312 header->comptype = CT_NOTCOMP2;
313 /* BB changed constant in next line to long. */
314 header->load = 0xfffddcffL;
317 /* Add list item to list */
318 /* Doing it here ensures that deleted items are not added */
319 header_ptr->header = header;
320 if (header_list == NULL)
321 header_list = header_ptr;
322 else
323 header_prev->next = header_ptr;
324 header_prev = header_ptr;
325 #ifdef DEBUGGING
326 print_header(header);
327 #endif
330 /* Return first element */
331 header_ptr = header_list;
332 header = header_ptr->header;
333 /* Seek to start of data for first element */
334 if ((!header_ptr->is_dir)
335 && (fseek(ifp, (long) header_ptr->seek, SEEK_SET)))
337 error("Cannot seek compressed data in this file");
338 return (&null_header);
340 /* Set up number of compression bits */
341 arcfs_maxbits = header_ptr->maxbits;
342 /*if (header_ptr->is_dir) header = &null_header; */
343 header_ptr = header_ptr->next;
344 return (header);