[Fuse-for-macosx-commits] SF.net SVN: fuse-for-macosx: [412] vendor/libdsk/current
Brought to you by:
fredm
|
From: <fr...@us...> - 2007-07-01 02:41:09
|
Revision: 412
http://svn.sourceforge.net/fuse-for-macosx/?rev=412&view=rev
Author: fredm
Date: 2007-06-30 19:41:10 -0700 (Sat, 30 Jun 2007)
Log Message:
-----------
Load . into vendor/libdsk/current.
Modified Paths:
--------------
vendor/libdsk/current/ChangeLog
vendor/libdsk/current/configure
vendor/libdsk/current/configure.in
vendor/libdsk/current/doc/libdsk.lyx
vendor/libdsk/current/doc/libdsk.pdf
vendor/libdsk/current/doc/libdsk.txt
vendor/libdsk/current/include/libdsk.h
vendor/libdsk/current/lib/compsq.c
vendor/libdsk/current/lib/drvcpcem.c
vendor/libdsk/current/lib/drvcpcem.h
vendor/libdsk/current/lib/drvntwdm.c
vendor/libdsk/current/man/apriboot.1
vendor/libdsk/current/man/dskdump.1
vendor/libdsk/current/man/dskform.1
vendor/libdsk/current/man/dskid.1
vendor/libdsk/current/man/dskscan.1
vendor/libdsk/current/man/dsktrans.1
vendor/libdsk/current/man/dskutil.1
vendor/libdsk/current/man/md3serial.1
Modified: vendor/libdsk/current/ChangeLog
===================================================================
--- vendor/libdsk/current/ChangeLog 2007-07-01 02:20:49 UTC (rev 411)
+++ vendor/libdsk/current/ChangeLog 2007-07-01 02:41:10 UTC (rev 412)
@@ -1,3 +1,25 @@
+2006-11-18 John Elliott
+
+ * libdsk-1.1.11 released.
+
+2006-08-02 John Elliott
+
+ * cpcemu driver: Bug fix when a sector is not found and it has
+ to start searching again at the beginning of the track.
+
+2006-07-23 John Elliott
+
+ * libdsk-1.1.11 released.
+
+2006-07-02 Ramlaid <www.ramlaid.com>
+
+ * cpcemu driver: Modified so that the dsk_trkids() function more
+ accurately reflects the result from a real disk. Also exposed the
+ ST0-ST3 registers.
+ * SQ compression: Doesn't leak file handles if file not compressed.
+ * NTWDM driver: Uses the passed sector size in dsk_xread / dsk_xwrite
+ rather than the sector size in the geometry structure.
+
2006-04-18 John Elliott
* libdsk-1.1.10 released.
Modified: vendor/libdsk/current/configure
===================================================================
--- vendor/libdsk/current/configure 2007-07-01 02:20:49 UTC (rev 411)
+++ vendor/libdsk/current/configure 2007-07-01 02:41:10 UTC (rev 412)
@@ -814,8 +814,8 @@
NONENONEs,x,x, &&
program_prefix=${target_alias}-
-VERSION=1.1.10
-UPDATED='April 18, 2006'
+VERSION=1.1.12
+UPDATED='November 18, 2006'
am__api_version="1.4"
# Find a good install program. We prefer a C program (faster),
# so one script is as good as another. But avoid the broken or
Modified: vendor/libdsk/current/configure.in
===================================================================
--- vendor/libdsk/current/configure.in 2007-07-01 02:20:49 UTC (rev 411)
+++ vendor/libdsk/current/configure.in 2007-07-01 02:41:10 UTC (rev 412)
@@ -2,8 +2,8 @@
AC_INIT(lib/dskopen.c)
AC_CONFIG_AUX_DIR(config)
AC_CANONICAL_SYSTEM
-VERSION=1.1.10
-UPDATED='April 18, 2006'
+VERSION=1.1.12
+UPDATED='November 18, 2006'
AM_INIT_AUTOMAKE(libdsk, $VERSION)
AM_CONFIG_HEADER(config.h)
Modified: vendor/libdsk/current/doc/libdsk.lyx
===================================================================
--- vendor/libdsk/current/doc/libdsk.lyx 2007-07-01 02:20:49 UTC (rev 411)
+++ vendor/libdsk/current/doc/libdsk.lyx 2007-07-01 02:41:10 UTC (rev 412)
@@ -26,7 +26,7 @@
\layout Title
-LibDsk v1.1.10
+LibDsk v1.1.12
\layout Author
John Elliott
@@ -136,6 +136,10 @@
For full details, see the file ChangeLog.
\layout Itemize
+Changes by Ramlaid <www.ramlaid.com> to the DSK and NTWDM drivers to improve
+ compatibility, and another fix to stop file handles leaking.
+\layout Itemize
+
Added a new driver:
\begin_inset Quotes eld
\end_inset
Modified: vendor/libdsk/current/doc/libdsk.pdf
===================================================================
(Binary files differ)
Modified: vendor/libdsk/current/doc/libdsk.txt
===================================================================
--- vendor/libdsk/current/doc/libdsk.txt 2007-07-01 02:20:49 UTC (rev 411)
+++ vendor/libdsk/current/doc/libdsk.txt 2007-07-01 02:41:10 UTC (rev 412)
@@ -1,4 +1,4 @@
-LibDsk v1.1.10
+LibDsk v1.1.12
John Elliott
@@ -198,6 +198,10 @@
For full details, see the file ChangeLog.
+ Changes by Ramlaid <www.ramlaid.com> to the DSK and
+ NTWDM drivers to improve compatibility, and another
+ fix to stop file handles leaking.
+
Added a new driver: "int25". This allows the DOS version
to run on Apricot PCs (which do not have an
IBM-compatible BIOS) and to access hard drive partitions.
Modified: vendor/libdsk/current/include/libdsk.h
===================================================================
--- vendor/libdsk/current/include/libdsk.h 2007-07-01 02:20:49 UTC (rev 411)
+++ vendor/libdsk/current/include/libdsk.h 2007-07-01 02:41:10 UTC (rev 412)
@@ -58,7 +58,7 @@
extern "C" {
#endif
-#define LIBDSK_VERSION "1.1.10"
+#define LIBDSK_VERSION "1.1.12"
/************************* TYPES ********************************/
Modified: vendor/libdsk/current/lib/compsq.c
===================================================================
--- vendor/libdsk/current/lib/compsq.c 2007-07-01 02:20:49 UTC (rev 411)
+++ vendor/libdsk/current/lib/compsq.c 2007-07-01 02:41:10 UTC (rev 412)
@@ -1,682 +1,686 @@
-/***************************************************************************
- * *
- * LIBDSK: General floppy and diskimage access library *
- * Copyright (C) 2002 John Elliott <jc...@se...> *
- * *
- * This library is free software; you can redistribute it and/or *
- * modify it under the terms of the GNU Library General Public *
- * License as published by the Free Software Foundation; either *
- * version 2 of the License, or (at your option) any later version. *
- * *
- * This library is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
- * Library General Public License for more details. *
- * *
- * You should have received a copy of the GNU Library General Public *
- * License along with this library; if not, write to the Free *
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, *
- * MA 02111-1307, USA *
- * *
- ***************************************************************************/
-
-/* Squeeze (Huffman) compression/decompression. This is entirely new code,
- * created by John Elliott to avoid possible licensing problems with the
- * Richard Greenlaw/Theo Pozzy code used in earlier releases.
- *
- * In brief: Richard Greenlaw's original code had no licence with it at all.
- * However, a file dated 1983 on the CP/M CDROM suggests that he
- * intended it as not-for-profit rather than true PD.
- *
- * Theo Pozzy's UNIX port of SQ (1985) implies that the code he used
- * is truly PD. But his belief that SQ was public domain may not
- * be correct in the light of the 1983 letter above.
- *
- * My thanks to Russell Marks for pointing this out.
- *
- * Note that my code is less sophisticated than Richard Greenlaw's original.
- * It doesn't, for example, try to deal with pathologically unbalanced
- * encoding trees (where a source byte encodes to more than 16 bits).
- *
- */
-
-#include "compi.h"
-#include "compsq.h"
-
-
-/******************************* compsq.c **********************************/
-typedef dsk_err_t (*RLEFUNC)(SQ_COMPRESS_DATA *self, int ch);
-
-
-
-/************************ RLE COMPRESSION FUNCTIONS ************************/
-static void rle_reset(SQ_COMPRESS_DATA *self)
-{
- self->rle_char = -1;
- self->rle_run = 0;
-}
-
-
-
-
-static dsk_err_t rle_flush(SQ_COMPRESS_DATA *self, RLEFUNC writer)
-{
- dsk_err_t err = DSK_ERR_OK;
-/* We encode sequences of >3 bytes using RLE. However, the RLE trigger byte
- * itself (0x90) is encoded as 2 bytes, and we can't encode sequences of it; it
- * would encode to (eg) 20 90 90 xx, and then decompress as (20 90 90) xx
- * when it was compressed as 20 (90 90 xx).
- */
- if ( self->rle_run > 3 && self->rle_char != RLECODE)
- {
- err = (*writer)(self, self->rle_char);
- if (!err) err = (*writer)(self, RLECODE);
- if (!err) err = (*writer)(self, self->rle_run);
- }
- else while (self->rle_run)
- {
- if (!err) err = (*writer)(self, self->rle_char);
- if (self->rle_char == RLECODE && !err) err = (*writer)(self, 0x00);
- --self->rle_run;
- }
- self->rle_run = 0;
- return err;
-}
-
-
-
-/* Generate an RLE stream from a file */
-static dsk_err_t rle_stream(SQ_COMPRESS_DATA *self, RLEFUNC writer)
-{
- int c;
- dsk_err_t err;
-
- while ( (c = fgetc(self->fp_in)) != EOF )
- {
- self->ck_sum += (unsigned char)c;
-/* If this character is the same as the last, increase the count. */
- if (c == self->rle_char)
- {
- ++self->rle_run;
- if (self->rle_run == 0xFF) /* Max length of run */
- { /* flush & start again */
- err = rle_flush(self, writer);
- if (err) return err;
- self->rle_char = -1;
- self->rle_run = 0;
- }
- }
- else
- {
-/* If not, write out what we've got and start again. */
- err = rle_flush(self, writer);
- if (err) return err;
- self->rle_char = c;
- self->rle_run = 1;
- }
- }
- if (ferror(self->fp_in)) return DSK_ERR_SYSERR;
-/* Write out what we've got; then EOF. */
- err = rle_flush(self, writer);
- if (err) return err;
- self->rle_char = SQ_EOF;
- self->rle_run = 1;
- err = rle_flush(self, writer);
- if (err) return err;
- rewind(self->fp_in);
- return DSK_ERR_OK;
-}
-
-
-/*
-static dsk_err_t rle_print(SQ_COMPRESS_DATA *self, int ch)
-{
- if (ch == '\r' || ch == '\n' || (ch > 0x1F && ch < 0x7F))
- fputc(ch, self->fp_out);
- else fprintf(self->fp_out, "<%02x>", ch);
- return DSK_ERR_OK;
-} */
-/******************* RLE COMPRESSION FUNCTIONS: END ************************/
-
-static dsk_err_t huf_counter(SQ_COMPRESS_DATA *self, int ch)
-{
- if (ch >= 0 && ch <= SQ_EOF) ++self->huf_count[ch + MAXNODE];
- else return DSK_ERR_COMPRESS;
-
- return DSK_ERR_OK;
-}
-
-/* Find the index of the smallest nonzero character count in huf_count.
- */
-static int huf_smallest(SQ_COMPRESS_DATA *self, int skip)
-{
- unsigned long mv = ~0UL;
- int n, mi = -1;
-
- for (n = 0; n < MAXLEAF + MAXNODE; n++)
- {
- if (n == skip) continue;
- if (self->huf_count[n] < mv && self->huf_count[n] > 0)
- {
- mv = self->huf_count[n];
- mi = n;
- }
- }
- return mi;
-}
-
-
-/* Add a node. */
-static void huf_addnode(SQ_COMPRESS_DATA *self, int n1, int n2)
-{
- short e_n1, e_n2;
-
- //printf("%04X:%04X\r\n", n1, n2);
-
- if (n1 < MAXNODE) e_n1 = n1; else e_n1 = MAXNODE - 1 - n1;
- if (n2 < MAXNODE) e_n2 = n2; else e_n2 = MAXNODE - 1 - n2;
-
- /* If parent not set, parent is MAXNODE */
- self->huf_node[self->huf_curnode].parent = MAXNODE;
- self->huf_node[self->huf_curnode].left = e_n1;
- self->huf_node[self->huf_curnode].right = e_n2;
-
-/* If nodes hold leaves, record them. If they hold other nodes, set parents. */
- if (n1 >= MAXNODE) self->huf_leaves[n1 - MAXNODE] = self->huf_curnode;
- else self->huf_node[n1].parent = self->huf_curnode;
- if (n2 >= MAXNODE) self->huf_leaves[n2 - MAXNODE] = self->huf_curnode;
- else self->huf_node[n2].parent = self->huf_curnode;
-
-}
-
-
-
-/* Generate the Huffman dictionary for a file */
-static dsk_err_t analyze(SQ_COMPRESS_DATA *self)
-{
- int n, n1, n2;
- dsk_err_t err;
-
- /* Initialise counters */
- self->ck_sum = 0;
- for (n = 0; n < MAXNODE + MAXLEAF; n++) self->huf_count[n] = 0;
- rle_reset(self);
- err = rle_stream(self, huf_counter);
- if (err) return err;
-
- /* Start allocating nodes from the end. That way, the root node,
- * the last to be populated, will have the lowest number. */
- self->huf_curnode = MAXNODE - 1;
- self->huf_nodecount = 0;
- for (n = 0; n < MAXNODE + MAXLEAF; n++) if (self->huf_count[n])
- ++self->huf_nodecount;
-
- /* Special case if there's only one node (empty file) */
- if (self->huf_nodecount == 1)
- {
- n1 = huf_smallest(self, -1);
- huf_addnode(self, n1, n1);
- self->huf_nodecount = 0;
- --self->huf_curnode;
- }
-
- /* huf_nodecount = number of leaves */
- while (self->huf_nodecount > 1)
- {
- n1 = huf_smallest(self, -1);
- n2 = huf_smallest(self, n1);
- /* We have n1 and n2: Two nodes to be combined */
- huf_addnode(self, n1, n2);
-
- self->huf_count[self->huf_curnode] =
- self->huf_count[n1] + self->huf_count[n2];
- self->huf_count[n1] = 0;
- self->huf_count[n2] = 0;
- --self->huf_curnode;
- --self->huf_nodecount;
- }
- /* self->huf_curnode is now the node before the root node */
- return DSK_ERR_OK;
-}
-
-static dsk_err_t writec(SQ_COMPRESS_DATA *self, unsigned char c)
-{
- if (fputc(c, self->fp_out) == EOF) return DSK_ERR_SYSERR;
-
- return DSK_ERR_OK;
-}
-
-
-static dsk_err_t writes(SQ_COMPRESS_DATA *self, unsigned short s)
-{
- dsk_err_t e;
-
- e = writec(self, (unsigned char)(s & 0xFF)); if (e) return e;
- e = writec(self, (unsigned char)((s >> 8) & 0xFF)); if (e) return e;
- return DSK_ERR_OK;
-}
-
-static unsigned char st_masks[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
-
-static dsk_err_t flipbits(SQ_COMPRESS_DATA *self)
-{
- int n, bit;
-
- for (n = self->huf_nbits - 1; n >= 0; n--)
- {
- bit = (self->huf_bits[n / 8] & st_masks[n % 8]);
-
- if (bit) self->huf_out |= st_masks[self->huf_nout];
- ++self->huf_nout;
- if (self->huf_nout == 8)
- {
- if (fputc(self->huf_out, self->fp_out) == EOF)
- return DSK_ERR_SYSERR;
- self->huf_nout = 0;
- self->huf_out = 0;
- }
- }
- return DSK_ERR_OK;
-}
-
-
-/* Add a bit to the output bitstream */
-static void pushbit(SQ_COMPRESS_DATA *self, int bit)
-{
- int offs = self->huf_nbits / 8;
- unsigned char mask = st_masks[self->huf_nbits % 8];
-
- if (offs >= sizeof(self->huf_bits)) return;
-
- if (bit) self->huf_bits[offs] |= mask;
- else self->huf_bits[offs] &= ~mask;
- ++self->huf_nbits;
-}
-
-
-static dsk_err_t huf_encode(SQ_COMPRESS_DATA *self, int ch)
-{
- unsigned short nodepos;
- signed short child;
-
- if (ch < 0 || ch > SQ_EOF) return DSK_ERR_COMPRESS;
- /* Now find where this character ended up in the tree */
- nodepos = self->huf_leaves[ch];
- self->huf_nbits = 0;
-
- child = (-1 - ch);
-
- do
- {
- if (self->huf_node[nodepos].left == child) pushbit(self, 0);
- else if (self->huf_node[nodepos].right == child) pushbit(self, 1);
- else return DSK_ERR_COMPRESS;
-
- child = nodepos;
- nodepos = self->huf_node[nodepos].parent;
- }
- while (nodepos < MAXNODE);
- /* self->huf_bits holds the output bitstream (in reverse order).
- * Now write it out to disc */
- return flipbits(self);
-}
-
-
-
-static dsk_err_t compress(SQ_COMPRESS_DATA *self)
-{
- char *s = self->sq_truename;
- dsk_err_t e;
- unsigned short dictbase;
- unsigned short dictlen;
- unsigned short dn;
-
- e = writes(self, MAGIC); if (e) return e; /* Magic */
- e = writes(self, self->ck_sum);
- if (e) return e; /* Source file checksum */
- do /* Filename */
- {
- e = writec(self, *s); if (e) return e;
- } while ( *(s++) );
-
- dictbase = self->huf_curnode + 1;
- /* Dictionary length = MAXNODE - dictbase */
- dictlen = MAXNODE - dictbase;
- e = writes(self, dictlen); if (e) return e;
- for (dn = dictbase; dn < MAXNODE; dn++)
- {
- short l = self->huf_node[dn].left;
- short r = self->huf_node[dn].right;
-
- if (l >= 0) l -= dictbase;
- if (r >= 0) r -= dictbase;
-
- e = writes(self, l);
- e = writes(self, r);
- }
- /* Dictionary written. Start spitting bytes. */
- self->huf_nout = 0;
- self->huf_out = 0;
- rle_reset(self);
- e = rle_stream(self, huf_encode); if (e) return e;
-
- /* Write any pending bits */
- if (self->huf_nout)
- {
- if (fputc(self->huf_out, self->fp_out) == EOF)
- return DSK_ERR_SYSERR;
- }
- fseek(self->fp_out, 2, SEEK_SET);
-
- return DSK_ERR_OK;
-}
-
-/* DEBUG CODE ONLY
-static dsk_err_t putter(SQ_COMPRESS_DATA *self, int ch)
-{
- if (fputc(ch, self->fp_out) == EOF) return DSK_ERR_SYSERR;
- return DSK_ERR_OK;
-} */
-
-static dsk_err_t squeeze(SQ_COMPRESS_DATA *self)
-{
- dsk_err_t err;
-
- err = analyze(self);
- if (err) return err;
- err = compress(self);
-
- return DSK_ERR_OK;
-}
-
-
-static dsk_err_t readc(SQ_COMPRESS_DATA *self, unsigned char *c)
-{
- int i;
-
- i = fgetc(self->fp_in);
- if (i == EOF) return DSK_ERR_SYSERR;
- *c = i;
- return DSK_ERR_OK;
-}
-
-
-static dsk_err_t readu(SQ_COMPRESS_DATA *self, unsigned short *u)
-{
- unsigned char c1, c2;
- dsk_err_t err;
-
- err = readc(self, &c1); if (err) return err;
- err = readc(self, &c2); if (err) return err;
-
- *u = ((c2 << 8) | c1);
- return DSK_ERR_OK;
-}
-
-
-
-static dsk_err_t reads(SQ_COMPRESS_DATA *self, signed short *s)
-{
- unsigned char c1, c2;
- dsk_err_t err;
-
- err = readc(self, &c1); if (err) return err;
- err = readc(self, &c2); if (err) return err;
-
- *s = ((c2 << 8) | c1);
- return DSK_ERR_OK;
-}
-
-static dsk_err_t ckputc(SQ_COMPRESS_DATA *self, unsigned char b)
-{
- if (fputc(b, self->fp_out) == EOF) return DSK_ERR_SYSERR;
- self->ck_sum += b;
- return DSK_ERR_OK;
-}
-
-static dsk_err_t wrbyte(SQ_COMPRESS_DATA *self, unsigned char b)
-{
- int n;
- dsk_err_t e;
-
- if (self->rle_run == 1)
- {
- /* Last byte was 0x90. The one before that is self->rle_char */
- if (b == 0)
- {
- /* xx 90 00 becomes xx 90 */
- if (self->rle_char != -1)
- {
- e = ckputc(self, (unsigned char)(self->rle_char)); if (e) return e;
- }
- e = ckputc(self, RLECODE); if (e) return e;
- }
- else
- {
- if (self->rle_char == -1) return DSK_ERR_SYSERR;
- for (n = 0; n < b; n++)
- {
- e = ckputc(self, (unsigned char)(self->rle_char)); if (e) return e;
- }
- }
- self->rle_run = 0;
- self->rle_char = -1;
- return DSK_ERR_OK;
- }
-
- if (b == RLECODE)
- {
- /* Retain rle_char */
- self->rle_run = 1;
- return DSK_ERR_OK;
- }
- /* No special characters */
- if (self->rle_char != -1)
- {
- e = ckputc(self, (unsigned char)(self->rle_char)); if (e) return e;
- }
- self->rle_char = b;
-
- return DSK_ERR_OK;
-}
-
-
-
-static dsk_err_t unsqueeze(SQ_COMPRESS_DATA *self)
-{
- dsk_err_t err;
- unsigned short magic, checksum;
- unsigned char c;
- unsigned short dictlen;
- unsigned short nd;
- unsigned short node;
- signed short code;
-
- self->ck_sum = 0;
- err = readu(self, &magic);
- if (err) return err;
- if (magic != MAGIC) return DSK_ERR_COMPRESS;
- err = readu(self, &checksum);
- /* Filename (skip) */
- do
- {
- err = readc(self, &c);
- if (err) return err;
- } while (c);
- /* Dictionary length */
- err = readu(self, &dictlen);
- if (err) return err;
- if (dictlen > MAXNODE) return DSK_ERR_COMPRESS;
- /* Dictionary */
- for (nd = 0; nd < dictlen; nd++)
- {
- err = reads(self, &self->huf_node[nd].left);
- if (err) return err;
- err = reads(self, &self->huf_node[nd].right);
- if (err) return err;
- }
- /* Now start decoding data */
- self->huf_out = 0;
- self->huf_nout = 8;
- node = 0;
- rle_reset(self);
-/* if dictlen == 0, the file is empty */
- if (dictlen) while (1)
- {
- if (self->huf_nout == 8)
- {
- self->huf_nout = 0;
- err = readc(self, &self->huf_out);
- if (err) return err;
- }
- code = self->huf_out & st_masks[self->huf_nout];
- ++self->huf_nout;
- if (code) code = self->huf_node[node].right;
- else code = self->huf_node[node].left;
-
- if (code < 0)
- {
- if (-1 - code == SQ_EOF) break; /* Reached EOF */
- err = wrbyte(self, (unsigned char)(-1 - code));
- if (err) return err;
- node = 0;
- }
- else node = code;
- }
- if (self->rle_char != -1)
- {
- err = ckputc(self, (unsigned char)(self->rle_char)); if (err) return err;
-
- }
- if (checksum != self->ck_sum) return DSK_ERR_COMPRESS;
- return DSK_ERR_OK;
-}
-
-
-/* This struct contains function pointers to the driver's functions, and the
- * size of its DSK_DRIVER subclass */
-
-COMPRESS_CLASS cc_sq =
-{
- sizeof(SQ_COMPRESS_DATA),
- "sq",
- "Squeeze (Huffman coding)",
- sq_open, /* open */
- sq_creat, /* create new */
- sq_commit, /* commit */
- sq_abort /* abort */
-};
-
-
-
-dsk_err_t sq_open(COMPRESS_DATA *self)
-{
- SQ_COMPRESS_DATA *sq_self;
- dsk_err_t err;
- unsigned short magic;
-
-
- /* Sanity check: Is this meant for our driver? */
- if (self->cd_class != &cc_sq) return DSK_ERR_BADPTR;
- sq_self = (SQ_COMPRESS_DATA *)self;
- sq_self->sq_truename = NULL;
- sq_self->fp_in = NULL;
- sq_self->fp_out = NULL;
-
- /* Open the file to decompress */
- err = comp_fopen(self, &sq_self->fp_in);
- if (err) return DSK_ERR_NOTME;
-
- /* Check for SQ signature */
- err = readu(sq_self, &magic);
- if (err) return err;
-
- if (magic != MAGIC)
- {
- fclose(sq_self->fp_in);
- return DSK_ERR_NOTME;
- }
- /* OK. This is a Squeezed file. Decompress it. */
- rewind(sq_self->fp_in);
- err = comp_mktemp(self, &sq_self->fp_out);
-
- if (!err) err = unsqueeze(sq_self);
- fclose(sq_self->fp_in);
- if (sq_self->fp_out) fclose(sq_self->fp_out);
- if (err && sq_self->sq_truename) free(sq_self->sq_truename);
- return err;
-}
-
-
-dsk_err_t sq_commit(COMPRESS_DATA *self)
-{
- SQ_COMPRESS_DATA *sq_self;
- dsk_err_t err = DSK_ERR_OK;
-
- if (self->cd_class != &cc_sq) return DSK_ERR_BADPTR;
- sq_self = (SQ_COMPRESS_DATA *)self;
-
- sq_self->fp_in = NULL;
- sq_self->fp_out = NULL;
- if (self->cd_cfilename && self->cd_ufilename)
- {
- sq_self->fp_in = fopen(self->cd_ufilename, "rb");
- sq_self->fp_out = fopen(self->cd_cfilename, "wb");
- if (!sq_self->fp_in || !sq_self->fp_out) err = DSK_ERR_SYSERR;
- else err = squeeze(sq_self);
- }
- if (sq_self->fp_in) fclose(sq_self->fp_in);
- if (sq_self->fp_out) fclose(sq_self->fp_out);
- if (sq_self->sq_truename) free(sq_self->sq_truename);
- sq_self->sq_truename = NULL;
-
- return err;
-}
-
-
-/* abort: Free truename */
-dsk_err_t sq_abort(COMPRESS_DATA *self)
-{
- SQ_COMPRESS_DATA *sq_self;
- if (self->cd_class != &cc_sq) return DSK_ERR_BADPTR;
- sq_self = (SQ_COMPRESS_DATA *)self;
-
- if (sq_self->sq_truename) free(sq_self->sq_truename);
- sq_self->sq_truename = NULL;
- return DSK_ERR_OK;
-}
-
-/* Create: Set up truename */
-dsk_err_t sq_creat(COMPRESS_DATA *self)
-{
- char *ss;
- SQ_COMPRESS_DATA *sq_self;
- if (self->cd_class != &cc_sq) return DSK_ERR_BADPTR;
- sq_self = (SQ_COMPRESS_DATA *)self;
-
- if (sq_self->sq_truename) free(sq_self->sq_truename);
- sq_self->sq_truename = NULL;
-
-/* Try to guess the true name of the file from the compressed name. This
- * can only be done for certain well-known name manglings. */
- sq_self->sq_truename = malloc(1 + strlen(self->cd_cfilename));
- if (!sq_self->sq_truename) return DSK_ERR_NOMEM;
-
- /* UNIX SQ squeezes files by appending ".SQ" */
- strcpy(sq_self->sq_truename, self->cd_cfilename);
- ss = strstr(sq_self->sq_truename, ".SQ");
- if (ss) *ss = 0;
-
- /* Convert .DQK back to .DSK */
- ss = strstr(sq_self->sq_truename, ".DQK");
- if (ss) memcpy(ss, ".DSK", 4);
-
- /* Convert .DQK back to .DSK */
- ss = strstr(sq_self->sq_truename, ".dqk");
- if (ss) memcpy(ss, ".dsk", 4);
-
- return DSK_ERR_OK;
-}
-
-
-
+/***************************************************************************
+ * *
+ * LIBDSK: General floppy and diskimage access library *
+ * Copyright (C) 2002 John Elliott <jc...@se...> *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ * This library is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public *
+ * License along with this library; if not, write to the Free *
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, *
+ * MA 02111-1307, USA *
+ * *
+ ***************************************************************************/
+
+/* Squeeze (Huffman) compression/decompression. This is entirely new code,
+ * created by John Elliott to avoid possible licensing problems with the
+ * Richard Greenlaw/Theo Pozzy code used in earlier releases.
+ *
+ * In brief: Richard Greenlaw's original code had no licence with it at all.
+ * However, a file dated 1983 on the CP/M CDROM suggests that he
+ * intended it as not-for-profit rather than true PD.
+ *
+ * Theo Pozzy's UNIX port of SQ (1985) implies that the code he used
+ * is truly PD. But his belief that SQ was public domain may not
+ * be correct in the light of the 1983 letter above.
+ *
+ * My thanks to Russell Marks for pointing this out.
+ *
+ * Note that my code is less sophisticated than Richard Greenlaw's original.
+ * It doesn't, for example, try to deal with pathologically unbalanced
+ * encoding trees (where a source byte encodes to more than 16 bits).
+ *
+ */
+
+#include "compi.h"
+#include "compsq.h"
+
+
+/******************************* compsq.c **********************************/
+typedef dsk_err_t (*RLEFUNC)(SQ_COMPRESS_DATA *self, int ch);
+
+
+
+/************************ RLE COMPRESSION FUNCTIONS ************************/
+static void rle_reset(SQ_COMPRESS_DATA *self)
+{
+ self->rle_char = -1;
+ self->rle_run = 0;
+}
+
+
+
+
+static dsk_err_t rle_flush(SQ_COMPRESS_DATA *self, RLEFUNC writer)
+{
+ dsk_err_t err = DSK_ERR_OK;
+/* We encode sequences of >3 bytes using RLE. However, the RLE trigger byte
+ * itself (0x90) is encoded as 2 bytes, and we can't encode sequences of it; it
+ * would encode to (eg) 20 90 90 xx, and then decompress as (20 90 90) xx
+ * when it was compressed as 20 (90 90 xx).
+ */
+ if ( self->rle_run > 3 && self->rle_char != RLECODE)
+ {
+ err = (*writer)(self, self->rle_char);
+ if (!err) err = (*writer)(self, RLECODE);
+ if (!err) err = (*writer)(self, self->rle_run);
+ }
+ else while (self->rle_run)
+ {
+ if (!err) err = (*writer)(self, self->rle_char);
+ if (self->rle_char == RLECODE && !err) err = (*writer)(self, 0x00);
+ --self->rle_run;
+ }
+ self->rle_run = 0;
+ return err;
+}
+
+
+
+/* Generate an RLE stream from a file */
+static dsk_err_t rle_stream(SQ_COMPRESS_DATA *self, RLEFUNC writer)
+{
+ int c;
+ dsk_err_t err;
+
+ while ( (c = fgetc(self->fp_in)) != EOF )
+ {
+ self->ck_sum += (unsigned char)c;
+/* If this character is the same as the last, increase the count. */
+ if (c == self->rle_char)
+ {
+ ++self->rle_run;
+ if (self->rle_run == 0xFF) /* Max length of run */
+ { /* flush & start again */
+ err = rle_flush(self, writer);
+ if (err) return err;
+ self->rle_char = -1;
+ self->rle_run = 0;
+ }
+ }
+ else
+ {
+/* If not, write out what we've got and start again. */
+ err = rle_flush(self, writer);
+ if (err) return err;
+ self->rle_char = c;
+ self->rle_run = 1;
+ }
+ }
+ if (ferror(self->fp_in)) return DSK_ERR_SYSERR;
+/* Write out what we've got; then EOF. */
+ err = rle_flush(self, writer);
+ if (err) return err;
+ self->rle_char = SQ_EOF;
+ self->rle_run = 1;
+ err = rle_flush(self, writer);
+ if (err) return err;
+ rewind(self->fp_in);
+ return DSK_ERR_OK;
+}
+
+
+/*
+static dsk_err_t rle_print(SQ_COMPRESS_DATA *self, int ch)
+{
+ if (ch == '\r' || ch == '\n' || (ch > 0x1F && ch < 0x7F))
+ fputc(ch, self->fp_out);
+ else fprintf(self->fp_out, "<%02x>", ch);
+ return DSK_ERR_OK;
+} */
+/******************* RLE COMPRESSION FUNCTIONS: END ************************/
+
+static dsk_err_t huf_counter(SQ_COMPRESS_DATA *self, int ch)
+{
+ if (ch >= 0 && ch <= SQ_EOF) ++self->huf_count[ch + MAXNODE];
+ else return DSK_ERR_COMPRESS;
+
+ return DSK_ERR_OK;
+}
+
+/* Find the index of the smallest nonzero character count in huf_count.
+ */
+static int huf_smallest(SQ_COMPRESS_DATA *self, int skip)
+{
+ unsigned long mv = ~0UL;
+ int n, mi = -1;
+
+ for (n = 0; n < MAXLEAF + MAXNODE; n++)
+ {
+ if (n == skip) continue;
+ if (self->huf_count[n] < mv && self->huf_count[n] > 0)
+ {
+ mv = self->huf_count[n];
+ mi = n;
+ }
+ }
+ return mi;
+}
+
+
+/* Add a node. */
+static void huf_addnode(SQ_COMPRESS_DATA *self, int n1, int n2)
+{
+ short e_n1, e_n2;
+
+ //printf("%04X:%04X\r\n", n1, n2);
+
+ if (n1 < MAXNODE) e_n1 = n1; else e_n1 = MAXNODE - 1 - n1;
+ if (n2 < MAXNODE) e_n2 = n2; else e_n2 = MAXNODE - 1 - n2;
+
+ /* If parent not set, parent is MAXNODE */
+ self->huf_node[self->huf_curnode].parent = MAXNODE;
+ self->huf_node[self->huf_curnode].left = e_n1;
+ self->huf_node[self->huf_curnode].right = e_n2;
+
+/* If nodes hold leaves, record them. If they hold other nodes, set parents. */
+ if (n1 >= MAXNODE) self->huf_leaves[n1 - MAXNODE] = self->huf_curnode;
+ else self->huf_node[n1].parent = self->huf_curnode;
+ if (n2 >= MAXNODE) self->huf_leaves[n2 - MAXNODE] = self->huf_curnode;
+ else self->huf_node[n2].parent = self->huf_curnode;
+
+}
+
+
+
+/* Generate the Huffman dictionary for a file */
+static dsk_err_t analyze(SQ_COMPRESS_DATA *self)
+{
+ int n, n1, n2;
+ dsk_err_t err;
+
+ /* Initialise counters */
+ self->ck_sum = 0;
+ for (n = 0; n < MAXNODE + MAXLEAF; n++) self->huf_count[n] = 0;
+ rle_reset(self);
+ err = rle_stream(self, huf_counter);
+ if (err) return err;
+
+ /* Start allocating nodes from the end. That way, the root node,
+ * the last to be populated, will have the lowest number. */
+ self->huf_curnode = MAXNODE - 1;
+ self->huf_nodecount = 0;
+ for (n = 0; n < MAXNODE + MAXLEAF; n++) if (self->huf_count[n])
+ ++self->huf_nodecount;
+
+ /* Special case if there's only one node (empty file) */
+ if (self->huf_nodecount == 1)
+ {
+ n1 = huf_smallest(self, -1);
+ huf_addnode(self, n1, n1);
+ self->huf_nodecount = 0;
+ --self->huf_curnode;
+ }
+
+ /* huf_nodecount = number of leaves */
+ while (self->huf_nodecount > 1)
+ {
+ n1 = huf_smallest(self, -1);
+ n2 = huf_smallest(self, n1);
+ /* We have n1 and n2: Two nodes to be combined */
+ huf_addnode(self, n1, n2);
+
+ self->huf_count[self->huf_curnode] =
+ self->huf_count[n1] + self->huf_count[n2];
+ self->huf_count[n1] = 0;
+ self->huf_count[n2] = 0;
+ --self->huf_curnode;
+ --self->huf_nodecount;
+ }
+ /* self->huf_curnode is now the node before the root node */
+ return DSK_ERR_OK;
+}
+
+static dsk_err_t writec(SQ_COMPRESS_DATA *self, unsigned char c)
+{
+ if (fputc(c, self->fp_out) == EOF) return DSK_ERR_SYSERR;
+
+ return DSK_ERR_OK;
+}
+
+
+static dsk_err_t writes(SQ_COMPRESS_DATA *self, unsigned short s)
+{
+ dsk_err_t e;
+
+ e = writec(self, (unsigned char)(s & 0xFF)); if (e) return e;
+ e = writec(self, (unsigned char)((s >> 8) & 0xFF)); if (e) return e;
+ return DSK_ERR_OK;
+}
+
+static unsigned char st_masks[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
+
+static dsk_err_t flipbits(SQ_COMPRESS_DATA *self)
+{
+ int n, bit;
+
+ for (n = self->huf_nbits - 1; n >= 0; n--)
+ {
+ bit = (self->huf_bits[n / 8] & st_masks[n % 8]);
+
+ if (bit) self->huf_out |= st_masks[self->huf_nout];
+ ++self->huf_nout;
+ if (self->huf_nout == 8)
+ {
+ if (fputc(self->huf_out, self->fp_out) == EOF)
+ return DSK_ERR_SYSERR;
+ self->huf_nout = 0;
+ self->huf_out = 0;
+ }
+ }
+ return DSK_ERR_OK;
+}
+
+
+/* Add a bit to the output bitstream */
+static void pushbit(SQ_COMPRESS_DATA *self, int bit)
+{
+ int offs = self->huf_nbits / 8;
+ unsigned char mask = st_masks[self->huf_nbits % 8];
+
+ if (offs >= sizeof(self->huf_bits)) return;
+
+ if (bit) self->huf_bits[offs] |= mask;
+ else self->huf_bits[offs] &= ~mask;
+ ++self->huf_nbits;
+}
+
+
+static dsk_err_t huf_encode(SQ_COMPRESS_DATA *self, int ch)
+{
+ unsigned short nodepos;
+ signed short child;
+
+ if (ch < 0 || ch > SQ_EOF) return DSK_ERR_COMPRESS;
+ /* Now find where this character ended up in the tree */
+ nodepos = self->huf_leaves[ch];
+ self->huf_nbits = 0;
+
+ child = (-1 - ch);
+
+ do
+ {
+ if (self->huf_node[nodepos].left == child) pushbit(self, 0);
+ else if (self->huf_node[nodepos].right == child) pushbit(self, 1);
+ else return DSK_ERR_COMPRESS;
+
+ child = nodepos;
+ nodepos = self->huf_node[nodepos].parent;
+ }
+ while (nodepos < MAXNODE);
+ /* self->huf_bits holds the output bitstream (in reverse order).
+ * Now write it out to disc */
+ return flipbits(self);
+}
+
+
+
+static dsk_err_t compress(SQ_COMPRESS_DATA *self)
+{
+ char *s = self->sq_truename;
+ dsk_err_t e;
+ unsigned short dictbase;
+ unsigned short dictlen;
+ unsigned short dn;
+
+ e = writes(self, MAGIC); if (e) return e; /* Magic */
+ e = writes(self, self->ck_sum);
+ if (e) return e; /* Source file checksum */
+ do /* Filename */
+ {
+ e = writec(self, *s); if (e) return e;
+ } while ( *(s++) );
+
+ dictbase = self->huf_curnode + 1;
+ /* Dictionary length = MAXNODE - dictbase */
+ dictlen = MAXNODE - dictbase;
+ e = writes(self, dictlen); if (e) return e;
+ for (dn = dictbase; dn < MAXNODE; dn++)
+ {
+ short l = self->huf_node[dn].left;
+ short r = self->huf_node[dn].right;
+
+ if (l >= 0) l -= dictbase;
+ if (r >= 0) r -= dictbase;
+
+ e = writes(self, l);
+ e = writes(self, r);
+ }
+ /* Dictionary written. Start spitting bytes. */
+ self->huf_nout = 0;
+ self->huf_out = 0;
+ rle_reset(self);
+ e = rle_stream(self, huf_encode); if (e) return e;
+
+ /* Write any pending bits */
+ if (self->huf_nout)
+ {
+ if (fputc(self->huf_out, self->fp_out) == EOF)
+ return DSK_ERR_SYSERR;
+ }
+ fseek(self->fp_out, 2, SEEK_SET);
+
+ return DSK_ERR_OK;
+}
+
+/* DEBUG CODE ONLY
+static dsk_err_t putter(SQ_COMPRESS_DATA *self, int ch)
+{
+ if (fputc(ch, self->fp_out) == EOF) return DSK_ERR_SYSERR;
+ return DSK_ERR_OK;
+} */
+
+static dsk_err_t squeeze(SQ_COMPRESS_DATA *self)
+{
+ dsk_err_t err;
+
+ err = analyze(self);
+ if (err) return err;
+ err = compress(self);
+
+ return DSK_ERR_OK;
+}
+
+
+static dsk_err_t readc(SQ_COMPRESS_DATA *self, unsigned char *c)
+{
+ int i;
+
+ i = fgetc(self->fp_in);
+ if (i == EOF) return DSK_ERR_SYSERR;
+ *c = i;
+ return DSK_ERR_OK;
+}
+
+
+static dsk_err_t readu(SQ_COMPRESS_DATA *self, unsigned short *u)
+{
+ unsigned char c1, c2;
+ dsk_err_t err;
+
+ err = readc(self, &c1); if (err) return err;
+ err = readc(self, &c2); if (err) return err;
+
+ *u = ((c2 << 8) | c1);
+ return DSK_ERR_OK;
+}
+
+
+
+static dsk_err_t reads(SQ_COMPRESS_DATA *self, signed short *s)
+{
+ unsigned char c1, c2;
+ dsk_err_t err;
+
+ err = readc(self, &c1); if (err) return err;
+ err = readc(self, &c2); if (err) return err;
+
+ *s = ((c2 << 8) | c1);
+ return DSK_ERR_OK;
+}
+
+static dsk_err_t ckputc(SQ_COMPRESS_DATA *self, unsigned char b)
+{
+ if (fputc(b, self->fp_out) == EOF) return DSK_ERR_SYSERR;
+ self->ck_sum += b;
+ return DSK_ERR_OK;
+}
+
+static dsk_err_t wrbyte(SQ_COMPRESS_DATA *self, unsigned char b)
+{
+ int n;
+ dsk_err_t e;
+
+ if (self->rle_run == 1)
+ {
+ /* Last byte was 0x90. The one before that is self->rle_char */
+ if (b == 0)
+ {
+ /* xx 90 00 becomes xx 90 */
+ if (self->rle_char != -1)
+ {
+ e = ckputc(self, (unsigned char)(self->rle_char)); if (e) return e;
+ }
+ e = ckputc(self, RLECODE); if (e) return e;
+ }
+ else
+ {
+ if (self->rle_char == -1) return DSK_ERR_SYSERR;
+ for (n = 0; n < b; n++)
+ {
+ e = ckputc(self, (unsigned char)(self->rle_char)); if (e) return e;
+ }
+ }
+ self->rle_run = 0;
+ self->rle_char = -1;
+ return DSK_ERR_OK;
+ }
+
+ if (b == RLECODE)
+ {
+ /* Retain rle_char */
+ self->rle_run = 1;
+ return DSK_ERR_OK;
+ }
+ /* No special characters */
+ if (self->rle_char != -1)
+ {
+ e = ckputc(self, (unsigned char)(self->rle_char)); if (e) return e;
+ }
+ self->rle_char = b;
+
+ return DSK_ERR_OK;
+}
+
+
+
+static dsk_err_t unsqueeze(SQ_COMPRESS_DATA *self)
+{
+ dsk_err_t err;
+ unsigned short magic, checksum;
+ unsigned char c;
+ unsigned short dictlen;
+ unsigned short nd;
+ unsigned short node;
+ signed short code;
+
+ self->ck_sum = 0;
+ err = readu(self, &magic);
+ if (err) return err;
+ if (magic != MAGIC) return DSK_ERR_COMPRESS;
+ err = readu(self, &checksum);
+ /* Filename (skip) */
+ do
+ {
+ err = readc(self, &c);
+ if (err) return err;
+ } while (c);
+ /* Dictionary length */
+ err = readu(self, &dictlen);
+ if (err) return err;
+ if (dictlen > MAXNODE) return DSK_ERR_COMPRESS;
+ /* Dictionary */
+ for (nd = 0; nd < dictlen; nd++)
+ {
+ err = reads(self, &self->huf_node[nd].left);
+ if (err) return err;
+ err = reads(self, &self->huf_node[nd].right);
+ if (err) return err;
+ }
+ /* Now start decoding data */
+ self->huf_out = 0;
+ self->huf_nout = 8;
+ node = 0;
+ rle_reset(self);
+/* if dictlen == 0, the file is empty */
+ if (dictlen) while (1)
+ {
+ if (self->huf_nout == 8)
+ {
+ self->huf_nout = 0;
+ err = readc(self, &self->huf_out);
+ if (err) return err;
+ }
+ code = self->huf_out & st_masks[self->huf_nout];
+ ++self->huf_nout;
+ if (code) code = self->huf_node[node].right;
+ else code = self->huf_node[node].left;
+
+ if (code < 0)
+ {
+ if (-1 - code == SQ_EOF) break; /* Reached EOF */
+ err = wrbyte(self, (unsigned char)(-1 - code));
+ if (err) return err;
+ node = 0;
+ }
+ else node = code;
+ }
+ if (self->rle_char != -1)
+ {
+ err = ckputc(self, (unsigned char)(self->rle_char)); if (err) return err;
+
+ }
+ if (checksum != self->ck_sum) return DSK_ERR_COMPRESS;
+ return DSK_ERR_OK;
+}
+
+
+/* This struct contains function pointers to the driver's functions, and the
+ * size of its DSK_DRIVER subclass */
+
+COMPRESS_CLASS cc_sq =
+{
+ sizeof(SQ_COMPRESS_DATA),
+ "sq",
+ "Squeeze (Huffman coding)",
+ sq_open, /* open */
+ sq_creat, /* create new */
+ sq_commit, /* commit */
+ sq_abort /* abort */
+};
+
+
+
+dsk_err_t sq_open(COMPRESS_DATA *self)
+{
+ SQ_COMPRESS_DATA *sq_self;
+ dsk_err_t err;
+ unsigned short magic;
+
+
+ /* Sanity check: Is this meant for our driver? */
+ if (self->cd_class != &cc_sq) return DSK_ERR_BADPTR;
+ sq_self = (SQ_COMPRESS_DATA *)self;
+ sq_self->sq_truename = NULL;
+ sq_self->fp_in = NULL;
+ sq_self->fp_out = NULL;
+
+ /* Open the file to decompress */
+ err = comp_fopen(self, &sq_self->fp_in);
+ if (err) return DSK_ERR_NOTME;
+
+ /* Check for SQ signature */
+ err = readu(sq_self, &magic);
+ if (err) /* v1.1.11 Don't leak file handles */
+ {
+ fclose(sq_self->fp_in);
+ return err;
+ }
+
+ if (magic != MAGIC)
+ {
+ fclose(sq_self->fp_in);
+ return DSK_ERR_NOTME;
+ }
+ /* OK. This is a Squeezed file. Decompress it. */
+ rewind(sq_self->fp_in);
+ err = comp_mktemp(self, &sq_self->fp_out);
+
+ if (!err) err = unsqueeze(sq_self);
+ fclose(sq_self->fp_in);
+ if (sq_self->fp_out) fclose(sq_self->fp_out);
+ if (err && sq_self->sq_truename) free(sq_self->sq_truename);
+ return err;
+}
+
+
+dsk_err_t sq_commit(COMPRESS_DATA *self)
+{
+ SQ_COMPRESS_DATA *sq_self;
+ dsk_err_t err = DSK_ERR_OK;
+
+ if (self->cd_class != &cc_sq) return DSK_ERR_BADPTR;
+ sq_self = (SQ_COMPRESS_DATA *)self;
+
+ sq_self->fp_in = NULL;
+ sq_self->fp_out = NULL;
+ if (self->cd_cfilename && self->cd_ufilename)
+ {
+ sq_self->fp_in = fopen(self->cd_ufilename, "rb");
+ sq_self->fp_out = fopen(self->cd_cfilename, "wb");
+ if (!sq_self->fp_in || !sq_self->fp_out) err = DSK_ERR_SYSERR;
+ else err = squeeze(sq_self);
+ }
+ if (sq_self->fp_in) fclose(sq_self->fp_in);
+ if (sq_self->fp_out) fclose(sq_self->fp_out);
+ if (sq_self->sq_truename) free(sq_self->sq_truename);
+ sq_self->sq_truename = NULL;
+
+ return err;
+}
+
+
+/* abort: Free truename */
+dsk_err_t sq_abort(COMPRESS_DATA *self)
+{
+ SQ_COMPRESS_DATA *sq_self;
+ if (self->cd_class != &cc_sq) return DSK_ERR_BADPTR;
+ sq_self = (SQ_COMPRESS_DATA *)self;
+
+ if (sq_self->sq_truename) free(sq_self->sq_truename);
+ sq_self->sq_truename = NULL;
+ return DSK_ERR_OK;
+}
+
+/* Create: Set up truename */
+dsk_err_t sq_creat(COMPRESS_DATA *self)
+{
+ char *ss;
+ SQ_COMPRESS_DATA *sq_self;
+ if (self->cd_class != &cc_sq) return DSK_ERR_BADPTR;
+ sq_self = (SQ_COMPRESS_DATA *)self;
+
+ if (sq_self->sq_truename) free(sq_self->sq_truename);
+ sq_self->sq_truename = NULL;
+
+/* Try to guess the true name of the file from the compressed name. This
+ * can only be done for certain well-known name manglings. */
+ sq_self->sq_truename = malloc(1 + strlen(self->cd_cfilename));
+ if (!sq_self->sq_truename) return DSK_ERR_NOMEM;
+
+ /* UNIX SQ squeezes files by appending ".SQ" */
+ strcpy(sq_self->sq_truename, self->cd_cfilename);
+ ss = strstr(sq_self->sq_truename, ".SQ");
+ if (ss) *ss = 0;
+
+ /* Convert .DQK back to .DSK */
+ ss = strstr(sq_self->sq_truename, ".DQK");
+ if (ss) memcpy(ss, ".DSK", 4);
+
+ /* Convert .DQK back to .DSK */
+ ss = strstr(sq_self->sq_truename, ".dqk");
+ if (ss) memcpy(ss, ".dsk", 4);
+
+ return DSK_ERR_OK;
+}
+
+
+
Modified: vendor/libdsk/current/lib/drvcpcem.c
===================================================================
--- vendor/libdsk/current/lib/drvcpcem.c 2007-07-01 02:20:49 UTC (rev 411)
+++ vendor/libdsk/current/lib/drvcpcem.c 2007-07-01 02:41:10 UTC (rev 412)
@@ -1,935 +1,1126 @@
-/***************************************************************************
- * *
- * LIBDSK: General floppy and diskimage access library *
- * Copyright (C) 2001,2005 John Elliott <jc...@se...> *
- * *
- * This library is free software; you can redistribute it and/or *
- * modify it under the terms of the GNU Library General Public *
- * License as published by the Free Software Foundation; either *
- * version 2 of the License, or (at your option) any later version. *
- * *
- * This library is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
- * Library General Public License for more details. *
- * *
- * You should have received a copy of the GNU Library General Public *
- * License along with this library; if not, write to the Free *
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, *
- * MA 02111-1307, USA *
- * *
- ***************************************************************************/
-
-/* Access functions for CPCEMU discs */
-
-#include "drvi.h"
-#include "drvcpcem.h"
-
-
-/* This struct contains function pointers to the driver's functions, and the
- * size of its DSK_DRIVER subclass */
-
-/* The CPCEMU drivers for normal and extended modes are in fact the same,
- * except for the "open" and "create" functions; these have been separated
- * simply so EDSKs can be created. */
-
-DRV_CLASS dc_cpcemu =
-{
- sizeof(CPCEMU_DSK_DRIVER),
- "dsk",
- "CPCEMU .DSK driver",
- cpcemu_open, /* open */
- cpcemu_creat, /* create new */
- cpcemu_close, /* close */
- cpcemu_read, /* read sector, working from physical address */
- cpcemu_write, /* write sector, working from physical address */
- cpcemu_format, /* format track, physical */
- NULL, /* get geometry */
- cpcemu_secid, /* logical sector ID */
- cpcemu_xseek, /* seek to track */
- cpcemu_status, /* get drive status */
- cpcemu_xread, /* read sector */
- cpcemu_xwrite, /* write sector */
-};
-
-DRV_CLASS dc_cpcext =
-{
- sizeof(CPCEMU_DSK_DRIVER),
- "edsk",
- "Extended .DSK driver",
- cpcext_open, /* open */
- cpcext_creat, /* create new */
- cpcemu_close, /* close */
- cpcemu_read, /* read sector, working from physical address */
- cpcemu_write, /* write sector, working from physical address */
- cpcemu_format, /* format track, physical */
- NULL, /* get geometry */
- cpcemu_secid, /* logical sector ID */
- cpcemu_xseek, /* seek to track */
- cpcemu_status, /* get drive status */
- cpcemu_xread, /* read sector */
- cpcemu_xwrite, /* write sector */
-};
-
-
-
-static dsk_err_t cpc_open(DSK_DRIVER *self, const char *filename, int ext);
-static dsk_err_t cpc_creat(DSK_DRIVER *self, const char *filename, int ext);
-
-
-dsk_err_t cpcemu_open(DSK_DRIVER *self, const char *filename)
-{
- return cpc_open(self, filename, 0);
-}
-
-dsk_err_t cpcext_open(DSK_DRIVER *self, const char *filename)
-{
- return cpc_open(self, filename, 1);
-}
-
-dsk_err_t cpcemu_creat(DSK_DRIVER *self, const char *filename)
-{
- return cpc_creat(self, filename, 0);
-}
-
-dsk_err_t cpcext_creat(DSK_DRIVER *self, const char *filename)
-{
- return cpc_creat(self, filename, 1);
-}
-
-
-#define DC_CHECK(self) if (self->dr_class != &dc_cpcemu && self->dr_class != &dc_cpcext) return DSK_ERR_BADPTR;
-
-
-/* Open DSK image, checking for the magic number */
-static dsk_err_t cpc_open(DSK_DRIVER *self, const char *filename, int extended)
-{
- CPCEMU_DSK_DRIVER *cpc_self;
- int n;
-
- /* Sanity check: Is this meant for our driver? */
- DC_CHECK(self)
- cpc_self = (CPCEMU_DSK_DRIVER *)self;
-
- cpc_self->cpc_fp = fopen(filename, "r+b");
- if (!cpc_self->cpc_fp)
- {
- cpc_self->cpc_readonly = 1;
- cpc_self->cpc_fp = fopen(filename, "rb");
- }
- if (!cpc_self->cpc_fp) return DSK_ERR_NOTME;
- /* Check for CPCEMU signature */
- if (fread(cpc_self->cpc_dskhead, 1, 256, cpc_self->cpc_fp) < 256)
- {
-/* 1.1.6 Don't leak file handles */
- fclose(cpc_self->cpc_fp);
- return DSK_ERR_NOTME;
- }
-
- if (extended)
- {
- if (memcmp("EXTENDED", cpc_self->cpc_dskhead, 8))
- {
-/* 1.1.6 Don't leak file handles */
- fclose(cpc_self->cpc_fp);
- return DSK_ERR_NOTME;
- }
- }
- else
- {
- if (memcmp("MV - CPC", cpc_self->cpc_dskhead, 8))
- {
-/* 1.1.6 Don't leak file handles */
- fclose(cpc_self->cpc_fp);
- return DSK_ERR_NOTME;
- }
- }
- /* OK, got signature. */
- cpc_self->cpc_trkhead[0] = 0;
- for (n = 0; n < 4; n++)
- {
- cpc_self->cpc_statusw[n] = -1;
- cpc_self->cpc_status[n] = 0;
- }
- return DSK_ERR_OK;
-}
-
-/* Create DSK image */
-static dsk_err_t cpc_creat(DSK_DRIVER *self, const char *filename, int extended)
-{
- CPCEMU_DSK_DRIVER *cpc_self;
- int n;
-
- /* Sanity check: Is this meant for our driver? */
- DC_CHECK(self)
- cpc_self = (CPCEMU_DSK_DRIVER *)self;
-
- cpc_self->cpc_fp = fopen(filename, "w+b");
- cpc_self->cpc_readonly = 0;
- if (!cpc_self->cpc_fp) return DSK_ERR_SYSERR;
- memset(cpc_self->cpc_dskhead, 0, 256);
-
- if (extended) strcpy((char *)cpc_self->cpc_dskhead,
- "EXTENDED CPC DSK File\r\nDisk-Info\r\n(LIBDSK)");
- else strcpy((char *)cpc_self->cpc_dskhead,
- "MV - CPCEMU Disk-File\r\nDisk-Info\r\n(LIBDSK)");
- if (fwrite(cpc_self->cpc_dskhead, 1 , 256, cpc_self->cpc_fp) < 256)
- return DSK_ERR_SYSERR;
- cpc_self->cpc_trkhead[0] = 0;
- for (n = 0; n < 4; n++)
- {
- cpc_self->cpc_statusw[n] = -1;
- cpc_self->cpc_status[n] = 0;
- }
- return DSK_ERR_OK;
-}
-
-
-dsk_err_t cpcemu_close(DSK_DRIVER *self)
-{
- CPCEMU_DSK_DRIVER *cpc_self;
-
- DC_CHECK(self)
- cpc_self = (CPCEMU_DSK_DRIVER *)self;
-
- if (cpc_self->cpc_fp)
- {
- if (fclose(cpc_self->cpc_fp) == EOF) return DSK_ERR_SYSERR;
- cpc_self->cpc_fp = NULL;
- }
- return DSK_ERR_OK;
-}
-
-
-
-
-
-
-/* Find the offset in a DSK for a particular cylinder/head.
- *
- * CPCEMU DSK files work in "tracks". For a single-sided disk, track number
- * is the same as cylinder number. For a double-sided disk, track number is
- * (2 * cylinder + head). This is independent of disc format.
- */
-static long lookup_track(CPCEMU_DSK_DRIVER *self, const DSK_GEOMETRY *geom,
- dsk_pcyl_t cylinder, dsk_phead_t head)
-{
- unsigned char *b;
- dsk_ltrack_t track;
- long trk_offset;
- unsigned int nt;
-
- if (!self->cpc_fp) return -1;
-
- /* [LIBDSK v0.6.0] Compare with our header, not the passed
- * geometry */
- /* Seek off the edge of the drive? Note that we allow one
- * extra cylinder & one extra head, so that we can move to
- * a blank track to format it. */
- if (cylinder > self->cpc_dskhead[0x30]) return -1;
- if (head > self->cpc_dskhead[0x31]) return -1;
-
- /* Convert cylinder & head to CPCEMU "track" */
-
- track = cylinder;
- if (self->cpc_dskhead[0x31] > 1) track *= 2;
- track += head;
-
- /* Look up the cylinder and head using the header. This behaves
- * differently in normal and extended DSK files */
-
- if (!memcmp(self->cpc_dskhead, "EXTENDED", 8))
- {
- trk_offset = 256; /* DSK header = 256 bytes */
- b = self->cpc_dskhead + 0x34;
- for (nt = 0; nt < track; nt++)
- {
- trk_offset += 256 * b[nt]; /* [v0.9.0] */
- }
- }
- else /* Normal; all tracks have the same length */
- {
- trk_offset = (self->cpc_dskhead[0x33] * 256);
- trk_offset += self->cpc_dskhead[0x32];
-
- trk_offset *= track; /* No. of tracks */
- trk_offset += 256; /* DSK header */
- }
- return trk_offset;
-}
-
-
-
-
-
-/* Seek to a cylinder. Checks if that particular cylinder exists.
- * We test for the existence of a cylinder by looking for Track <n>, Head 0.
- * Fortunately the DSK format does not allow for discs with different numbers
- * of tracks on each side (though this is obviously possible with a real disc)
- * so if head 0 exists then the whole cylinder does.
-
-
-static dsk_err_t seek_cylinder(CPCEMU_DSK_DRIVER *self, DSK_GEOMETRY *geom, int cylinder)
-{
- long nr;
- if (!self->cpc_fp) return DSK_ERR_NOTRDY;
-
- // Check if the DSK image goes out to the correct cylinder
- nr = lookup_track(self, geom, cylinder, 0);
-
- if (nr < 0) return DSK_ERR_SEEKFAIL;
- return DSK_ERR_OK;
-}
-*/
-
-/* Load the "Track-Info" header for the given cylinder and head */
-static dsk_err_t load_track_header(CPCEMU_DSK_DRIVER *self,
- const DSK_GEOMETRY *geom, int cylinder, int head)
-{
- long track;
- int sector_size;
- unsigned char rate, recording;
-
- track = lookup_track(self, geom, cylinder, head);
- if (track < 0) return DSK_ERR_SEEKFAIL; /* Bad track */
- fseek(self->cpc_fp, track, SEEK_SET);
- if (fread(self->cpc_trkhead, 1, 256, self->cpc_fp) < 256)
- return DSK_ERR_NOADDR; /* Missing address mark */
- if (memcmp(self->cpc_trkhead, "Track-Info", 10))
- {
- return DSK_ERR_NOADDR;
- }
- /* Check if the track density and recording mode match the density
- * and recording mode in the geometry. */
- sector_size = 128 << self->cpc_trkhead[0x14];
-
- rate = self->cpc_trkhead[0x12];
- recording = self->cpc_trkhead[0x13];
-
- /* Guess the data rate used. We assume Double Density, and then
- * look at the number of sectors in the track to see if the
- * format looks like a High Density one. */
- if (rate == 0)
- {
- if (sector_size == 1024 && self->cpc_trkhead[0x15] >= 7)
- {
- rate = 2; /* ADFS F */
- }
- else if (sector_size == 512 && self->cpc_trkhead[0x15] >= 15)
- {
- rate = 2; /* IBM PC 1.2M or 1.4M */
- }
- else rate = 1;
- }
- /* Similarly for recording mode. Note that I check for exactly
- * 10 sectors, because the MD3 copy protection scheme uses 9
- * 256-byte sectors and they're recorded using MFM. */
- if (recording == 0)
- {
- if (sector_size == 256 && self->cpc_trkhead[0x15] == 10)
- {
- recording = 1; /* BBC Micro DFS */
- }
- else recording = 2;
- }
- switch(rate)
- {
- /* 1: Single / Double Density */
- case 1: if (geom->dg_datarate != RATE_SD &&
- geom->dg_datarate != RATE_DD) return DSK_ERR_NOADDR;
- break;
- /* 2: High density */
- case 2: if (geom->dg_datarate != RATE_HD) return DSK_ERR_NOADDR;
- break;
- /* 3: Extra High Density */
- case 3: if (geom->dg_datarate != RATE_ED) return DSK_ERR_NOADDR;
- break;
- /* Unknown density */
- default:
- return DSK_ERR_NOADDR;
- }
- /* Check data rate */
- switch(recording)
- {
- case 1: if (!geom->dg_fm) return DSK_ERR_NOADDR;
- break;
- case 2: if (geom->dg_fm) return DSK_ERR_NOADDR;
- break;
- default: /* GCR??? */
- return DSK_ERR_NOADDR;
- }
- return DSK_ERR_OK;
-}
-
-
-/* Read a sector ID from a given track */
-dsk_err_t cpcemu_secid(DSK_DRIVER *self, const DSK_GEOMETRY *geom,
- dsk_pcyl_t cyl, dsk_phead_t head, DSK_FORMAT *result)
-{
- CPCEMU_DSK_DRIVER *cpc_self;
- dsk_err_t e;
- int offs;
-
- if (!self || !geom || !result)
- return DSK_ERR_BADPTR;
- DC_CHECK(self)
- cpc_self = (CPCEMU_DSK_DRIVER *)self;
-
- if (!cpc_self->cpc_fp) return DSK_ERR_NOTRDY;
-
- /* lookup_track() allows us to seek to a nonexistent track. */
- /* But we don't want this when reading; so ensure the track */
- /* does actually exist. */
- if (cyl >= cpc_self->cpc_dskhead[0x30]) return DSK_ERR_NOADDR;
- if (head >= cpc_self->cpc_dskhead[0x31]) return DSK_ERR_NOADDR;
-
-
- e = load_track_header(cpc_self, geom, cyl, head);
- if (e) return e;
-
- /* Offset of the chosen sector header */
- ++cpc_self->cpc_sector;
- offs = 0x18 + 8 * (cpc_self->cpc_sector % cpc_self->cpc_trkhead[0x15]);
-
- result->fmt_cylinder = cpc_self->cpc_trkhead[offs];
- result->fmt_head = cpc_self->cpc_trkhead[offs+1];
- result->fmt_sector = cpc_self->cpc_trkhead[offs+2];
- result->fmt_secsize = 128 << cpc_self->cpc_trkhead[offs+3];
- memset(cpc_self->cpc_status, 0, sizeof(cpc_self->cpc_status));
- return DSK_ERR_OK;
-}
-
-
-/* Find the offset of a sector in the current track
- * Enter with cpc_trkhead loaded and the file pointer
- * just after it (ie, you have just called load_track_header() )
- *
- * Returns secid = address of 8-byte sector info area in track header
- * seclen = actual length of sector data; may be a multiple of
- * the sector size for weak sectors
- */
-
-static long sector_offset(CPCEMU_DSK_DRIVER *self, dsk_psect_t sector,
- size_t *seclen, unsigned char **secid)
-{
- int maxsec = self->cpc_trkhead[0x15];
- long offset = 0;
- int n;
-
- /* Pointer to sector details */
- *secid = self->cpc_trkhead + 0x18;
-
- /* Length of sector */
- *seclen = (0x80 << self->cpc_trkhead[0x14]);
-
- /* Extended DSKs have individual sector sizes */
- if (!memcmp(self->cpc_dskhead, "EXTENDED", 8))
- {
- for (n = 0; n < maxsec; n++)
- {
- *seclen = (*secid)[6] + 256 * (*secid)[7]; /* [v0.9.0] */
- if ((*secid)[2] == sector) return offset;
- offset += (*seclen);
- (*secid) += 8;
- }
- }
- else /* Non-extended, all sector sizes are the same */
- {
- for (n = 0; n < maxsec; n++)
- {
- if ((*secid)[2] == sector) return offset;
- offset += (*seclen);
- (*secid) += 8;
- }
- }
- return -1; /* Sector not found */
-}
-
-
-static unsigned char *sector_head(CPCEMU_DSK_DRIVER *self, int sector)
-{
- int ms = self->cpc_trkhead[0x15];
- int sec;
-
- for (sec = 0; sec < ms; sec++)
- {
- if (self->cpc_trkhead[0x1A + 8 * sec] == sector)
- return self->cpc_trkhead + 0x18 + 8 * sec;
- }
- return NULL;
-}
-
-
-/* Seek within the DSK file to a given head & sector in the current cylinder.
- *
- * On entry, *request_len is the expected sector size.
- * If the sector is shorter than this, *request_len will be reduced.
- *
- * weak_copies will be set to 1 in normal use; 2 or more if multiple copies
- * of the sector have been saved.
- *
- * sseclen will be set to the actual size of a sector in the file, so that
- * a random copy can be extracted.
- */
-static dsk_err_t seekto_sector(CPCEMU_DSK_DRIVER *self,
- const DSK_GEOMETRY *geom, int cylinder, int head, int cyl_expected,
- int head_expected, int sector, size_t *request_len, int *weak_copies,
- size_t *sseclen)
-{
- int offs;
- size_t seclen; /* Length of sector data in file */
- dsk_err_t err;
- unsigned char *secid;
- long trkbase;
-
- *weak_copies = 1;
- err = load_track_header(self, geom, cylinder, head);
- if (err) return err;
- trkbase = ftell(self->cpc_fp);
- offs = (int)sector_offset(self, sector, &seclen, &secid);
-
- if (offs < 0) return DSK_ERR_NOADDR; /* Sector not found */
-
- if (cyl_expected != secid[0] || head_expected != secid[1])
- {
- /* We are not in the right place */
- return DSK_ERR_NOADDR;
- }
- *sseclen = 128 << (secid[3] & 7);
-/* Sector shorter than expected. Report a data error, and set
- * request_len to the actual size. */
- if ((*sseclen) < (*request_len))
- {
- err = DSK_ERR_DATAERR;
- *request_len = *sseclen;
- }
-/* Sector longer than expected. Report a data error but don't change
- * request_len */
- else if ((*sseclen) > (*request_len))
- {
- err = DSK_ERR_DATAERR;
- }
-/* If there is room for two or more copies, we have a weak-recording
- * situation. */
- if ((*sseclen) * 2 <= seclen)
- {
- *weak_copies = seclen / (*sseclen);
- }
-
- fseek(self->cpc_fp, trkbase + offs, SEEK_SET);
-
- return err;
-}
-
-
-/* Read a sector */
-dsk_err_t cpcemu_read(DSK_DRIVER *self, const DSK_GEOMETRY *geom,
- void *buf, dsk_pcyl_t cylinder,
- dsk_phead_t head, dsk_psect_t sector)
-{
- return cpcemu_xread(self, geom, buf, cylinder, head, cylinder,
- head, sector, geom->dg_secsize, 0);
-}
-
-dsk_err_t cpcemu_xread(DSK_DRIVER *self, const DSK_GEOMETRY *geom, void *buf,
- dsk_pcyl_t cylinder, dsk_phead_t head,
- dsk_pcyl_t cyl_expect, dsk_phead_t head_expect,
- dsk_psect_t sector, size_t sector_size, int *deleted)
-{
- CPCEMU_DSK_DRIVER *cpc_self;
- dsk_err_t err;
- int weak_copies;
- size_t sseclen;
- size_t len = sector_size; /* 1.1.2: Was geom->dg_secsize; but
- * that fails when individual sectors
- * are bigger than the size in geom. */
- int rdeleted = 0;
- int try_again = 0;
- unsigned char *sh;
-
- if (!buf || !geom || !self) return DSK_ERR_BADPTR;
- DC_CHECK(self)
- cpc_self = (CPCEMU_DSK_DRIVER *)self;
-
- if (deleted && *deleted) rdeleted = 0x40;
-
- do
- {
- err = seekto_sector(cpc_self, geom, cylinder,head,
- cyl_expect, head_expect, sector, &len,
- &weak_copies, &sseclen);
-/* Are we retrying because we are looking for deleted data and found
- * nondeleted or vice versa?
- *
- * If so, and we have run out of sectors in this track, AND we are on head 0,
- * AND the disc has 2 heads, AND we are in multitrack mode, then look on head 1
- * as well. Amazing.
- * */
- if (try_again == 1 && err == DSK_ERR_NOADDR)
- {
- err = DSK_ERR_NODATA;
- if ((!geom->dg_nomulti) && head == 0 &&
- cpc_self->cpc_dskhead[0x31] > 0)
- {
- head++;
- sector = geom->dg_secbase;
- continue;
- }
- }
- try_again = 0;
- if (err != DSK_ERR_DATAERR && err != DSK_ERR_OK)
- return err;
- /* We have the sector. But does it contain deleted data? */
- sh = sector_head(cpc_self, sector);
- if (!sh) return DSK_ERR_NODATA;
-
- if (deleted) *deleted = 0;
- if (rdeleted != (sh[5] & 0x40)) /* Mismatch! */
- {
- if (geom->dg_noskip)
- {
- if (deleted) *deleted = 1;
- }
- else
- {
-/* Try the next sector. */
- try_again = 1;
- ++sector;
- continue;
- }
- }
-/* This next line should never be true, because len starts as sector_size and
- * seekto_sector() only ever reduces it. */
- if (len > sector_size) len = sector_size;
-
-/* If there are multiple copies of the sector present, pick one at random */
- if (weak_copies > 1)
- {
- long offset = (rand() % weak_copies) * sseclen;
- fseek(cpc_self->cpc_fp, offset, SEEK_CUR);
- }
-
- if (fread(buf, 1, len, cpc_self->cpc_fp) < len)
- err = DSK_ERR_DATAERR;
-/* Sec...
[truncated message content] |