#include "unalf.h" #include "addrs.h" static int headers_read = 0; static int convert_eols = 0; static void die_arc(void) { fprintf(stderr, "%s: this is an ARC file, not ALF\n", self); exit(1); } static void die_not_alf(void) { fprintf(stderr, "%s: not an ALF file\n", self); exit(1); } static void eof_junk(void) { fprintf(stderr, "%s: junk at EOF (ignoring)\n", self); } static void check_hdr_size(const char *name, unsigned long size) { const char *desc; /* fits on a double-density disk? */ if(size < 184320) return; /* >= 16MB files are impossible because the decrunch algorithm ignores the high byte of the 4-byte length. */ if(size >= 16777216L) desc = "impossibly large (>=16MB)"; /* >1MB files are possible (e.g. with a hard drive on SpartaDOS X) but exceedingly rare in the Atari world. */ else if(size > 1048576L) desc = "suspiciously large (>1MB)"; else desc = "too large for a floppy disk (>180KB)"; fprintf(stderr, "%s: header #%d %s size is %s.\n", self, headers_read, name, desc); } static void sanity_check_header(void) { check_hdr_size("original", getquad(alf_hdr_origsize0)); check_hdr_size("compressed", getquad(alf_hdr_compsize0)); } /* return 1 if a header is read, 0 if not */ int read_alf_header(void) { u8 h1, h2; int bytes; bytes = fread(mem + alf_header, 1, 29, in_file); if(!bytes) { if(headers_read) return 0; else die_not_alf(); } else if(bytes < 29) { if(headers_read) { eof_junk(); return 0; } else { die_not_alf(); } } h1 = mem[alf_header]; h2 = mem[alf_hdr_sig]; if(h1 == 0x1a) { if(h2 < 0x0f) die_arc(); if(h2 == 0x0f) { headers_read++; sanity_check_header(); return 1; /* signature matches */ } } if(headers_read) eof_junk(); else die_not_alf(); return 0; } /* read buf_len_l/h bytes into buf_adr_l/h, then store the number of bytes actually read in buf_len_l/h. TODO: what about EOF? */ void readblock(void) { int bytes, len, bufadr; u8 *buf; bufadr = dpeek(buf_adr_l); buf = mem + bufadr; len = dpeek(buf_len_l); // fprintf(stderr, "readblock, bufadr = $%04x, len = $%04x\n", bufadr, len); bytes = fread(buf, 1, len, in_file); dpoke(buf_len_l, bytes); } static int is_printable(u8 c) { return (c == 0x9b || (c >= ' ' && c <= 124)); } static int is_text_file(u8 *buf) { return is_printable(buf[0]) && is_printable(buf[1]); } /* mirror of readblock(), plus EOL conversion if needed. With -a, a file is considered text if its first 2 bytes are printable ATASCII, including EOLs. With -aa, all files are converted. */ void writeblock(void) { int i, bytes, len, bufadr; u8 *buf; bufadr = dpeek(buf_adr_l); buf = mem + bufadr; len = dpeek(buf_len_l); if(new_file) { if(opts.txtconv > 1) { convert_eols = 1; } else if(opts.txtconv == 1 && len > 1) { convert_eols = is_text_file(buf); } else { convert_eols = 0; } } new_file = 0; if(convert_eols) { for(i = 0; i < len; i++) { if(buf[i] == 0x9b) buf[i] = '\n'; if(buf[i] == 0x7f) buf[i] = '\t'; } } // fprintf(stderr, "writeblock, bufadr = $%04x, len = $%04x\n", bufadr, len); bytes = fwrite(buf, 1, len, out_file); dpoke(buf_len_l, bytes); }