From 80f77697cb067969d8a1b4dbc412cef30aa01ac4 Mon Sep 17 00:00:00 2001 From: ketmar Date: Mon, 6 Jun 2022 04:18:53 +0000 Subject: [PATCH] libfusefdc: reformatted UDI i/o code FossilOrigin-Name: 4d4792961f0a8d4317cae7d4efb87bcb80ba22aca88c36c616611a69d86db2fe --- src/libfdc/dskldr_udi.c | 2 +- src/libfusefdc/crc.c | 19 +- src/libfusefdc/crc.h | 2 +- src/libfusefdc/disk_udi.c | 849 ++++++++++++++++++++++++---------------------- 4 files changed, 446 insertions(+), 426 deletions(-) rewrite src/libfusefdc/disk_udi.c (62%) diff --git a/src/libfdc/dskldr_udi.c b/src/libfdc/dskldr_udi.c index 5367516..7ffd60e 100644 --- a/src/libfdc/dskldr_udi.c +++ b/src/libfdc/dskldr_udi.c @@ -26,7 +26,7 @@ static void udiCRC32 (uint32_t *crcp, const uint8_t *buf, int len) { while (len--) { crc ^= -1^*buf++; for (int k = 8; --k; ) { int temp = -(crc&1); crc >>= 1, crc ^= 0xEDB88320&temp; } - crc ^= FLPERR_SHIT; + crc ^= -1; } *crcp = crc; } diff --git a/src/libfusefdc/crc.c b/src/libfusefdc/crc.c index 87300ef..161797f 100644 --- a/src/libfusefdc/crc.c +++ b/src/libfusefdc/crc.c @@ -23,7 +23,7 @@ #include "crc.h" -static const uint16_t crc_fdc_table[] = { +static const uint16_t crc_fdc_table[256] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, @@ -55,22 +55,23 @@ static const uint16_t crc_fdc_table[] = { 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, - 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0, }; + /* CRC-16-CCITT: G(x) = x^16 + x^12 + x^5 + 1 */ uint16_t crc_fdc (uint16_t crc, uint8_t data) { return ((crc<<8)^crc_fdc_table[((crc>>8)^data)&0xff])&0xffff; } -int32_t crc_udi (int32_t crc, uint8_t data) { - crc ^= (int32_t)(-1)^data; - for (int i = 8; i > 0; --i) { - int32_t temp = -(crc&1); - crc >>= 1; - crc ^= (uint32_t)0xedb88320&temp; +uint32_t crc_udi (uint32_t crc, uint8_t data) { + crc ^= (~(uint32_t)0)^data; + for (unsigned i = 8; i > 0; --i) { + uint32_t temp = (crc&1 ? ~(uint32_t)0 : 0); + crc = (crc>>1)|(crc&0x80000000U); + crc ^= 0xedb88320U&temp; } - crc ^= (int32_t)(-1); + crc ^= ~(uint32_t)0; return crc; } diff --git a/src/libfusefdc/crc.h b/src/libfusefdc/crc.h index 6aebd44..7169730 100644 --- a/src/libfusefdc/crc.h +++ b/src/libfusefdc/crc.h @@ -27,7 +27,7 @@ uint16_t crc_fdc (uint16_t crc, uint8_t data); -int32_t crc_udi (int32_t crc, uint8_t data); +uint32_t crc_udi (uint32_t crc, uint8_t data); #endif diff --git a/src/libfusefdc/disk_udi.c b/src/libfusefdc/disk_udi.c dissimilarity index 62% index e5d6a49..a15ed58 100644 --- a/src/libfusefdc/disk_udi.c +++ b/src/libfusefdc/disk_udi.c @@ -1,415 +1,434 @@ -/* disk.c: Routines for handling disk images - Copyright (c) 2007-2017 Gergely Szasz - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - - Author contact information: - - Philip: philip-fuse@shadowmagic.org.uk - -*/ -#ifdef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION -//========================================================================== -// -// udi_read_compressed -// -//========================================================================== -static int udi_read_compressed (const uint8_t *buffer, - size_t compr_size, size_t uncompr_size, - uint8_t **data, size_t *data_size) -{ - libspectrum_error error; - uint8_t *tmp; - size_t olength = uncompr_size; - - tmp = NULL; - - error = libspectrum_zlib_inflate(buffer, compr_size, &tmp, &olength); - if (error) return error; - - if (*data_size < uncompr_size) { - *data = realloc(*data, uncompr_size); - *data_size = uncompr_size; - } - memcpy(*data, tmp, uncompr_size); - libspectrum_free(tmp); - - return 0; -} - - -//========================================================================== -// -// udi_write_compressed -// -//========================================================================== -static int udi_write_compressed (const uint8_t *buffer, - size_t uncompr_size, size_t *compr_size, - uint8_t **data, size_t *data_size) -{ - libspectrum_error error; - uint8_t *tmp; - - tmp = NULL; - error = libspectrum_zlib_compress(buffer, uncompr_size, &tmp, compr_size); - if (error) return error; - - if (*data_size < *compr_size) { - *data = realloc(*data, *compr_size ); - *data_size = *compr_size; - } - memcpy(*data, tmp, *compr_size); - libspectrum_free(tmp); - - return LIBSPECTRUM_ERROR_NONE; -} -#endif /* #ifdef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION */ - - -//========================================================================== -// -// udi_pack_tracks -// -//========================================================================== -static void udi_pack_tracks (disk_t *d) { - int i, tlen, clen, ttyp; - uint8_t *tmp; - - for (i = 0; i < d->sides*d->cylinders; ++i) { - DISK_SET_TRACK_IDX( d, i ); - tmp = d->track; - ttyp = tmp[-1]; - tlen = tmp[-3] + 256 * tmp[-2]; - clen = DISK_CLEN( tlen ); - tmp += tlen; - /* copy clock if needed */ - if( tmp != d->clocks ) - memcpy( tmp, d->clocks, clen ); - if( ttyp == 0x00 || ttyp == 0x01 ) continue; - tmp += clen; - if( ttyp & 0x02 ) { /* copy FM marks */ - if( tmp != d->fm ) - memcpy( tmp, d->fm, clen ); - tmp += clen; - } - if( ! ( ttyp & 0x80 ) ) continue; - if( tmp != d->weak ) /* copy WEAK marks*/ - memcpy( tmp, d->weak, clen ); - } -} - -static void -udi_unpack_tracks( disk_t *d ) -{ - int i, tlen, clen, ttyp; - uint8_t *tmp; - uint8_t mask[] = { 0xff, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe }; - - for( i = 0; i < d->sides * d->cylinders; i++ ) { - DISK_SET_TRACK_IDX( d, i ); - tmp = d->track; - ttyp = tmp[-1]; - tlen = tmp[-3] + 256 * tmp[-2]; - clen = DISK_CLEN( tlen ); - tmp += tlen; - if( ttyp & 0x80 ) tmp += clen; - if( ttyp & 0x02 ) tmp += clen; - if( ( ttyp & 0x80 ) ) { /* copy WEAK marks*/ - if( tmp != d->weak ) - memcpy( d->weak, tmp, clen ); - tmp -= clen; - } else { /* clear WEAK marks*/ - memset( d->weak, 0, clen ); - } - if( ttyp & 0x02 ) { /* copy FM marks */ - if( tmp != d->fm ) - memcpy( d->fm, tmp, clen ); - tmp -= clen; - } else { /* set/clear FM marks*/ - memset( d->fm, ttyp & 0x01 ? 0xff : 0, clen ); - if( tlen % 8 ) { /* adjust last byte */ - d->fm[clen - 1] &= mask[ tlen % 8 ]; - } - } - /* copy clock if needed */ - if( tmp != d->clocks ) - memcpy( d->clocks, tmp, clen ); - } -} - -/* calculate track len from type, if type eq. 0x00/0x01/0x02/0x80/0x81/0x82 - !!! not for 0x83 nor 0xf0 !!! -*/ -#define UDI_TLEN( type, bpt ) ( ( bpt ) + DISK_CLEN( bpt ) * ( 1 + \ - ( type & 0x02 ? 1 : 0 ) + \ - ( type & 0x80 ? 1 : 0 ) ) ) - -static int -udi_uncompress_tracks( disk_t *d ) -{ - int i; - uint8_t *data = NULL; -#ifdef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION - size_t data_size = 0; - int bpt, tlen, clen, ttyp; -#endif /* #ifdef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION */ - - for( i = 0; i < d->sides * d->cylinders; i++ ) { - DISK_SET_TRACK_IDX( d, i ); - if( d->track[-1] != 0xf0 ) continue; /* if not compressed */ - -#ifndef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION - /* if libspectrum cannot support */ - return d->status = DISK_UNSUP; -#else /* #ifndef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION */ - clen = d->track[-3] + 256 * d->track[-2] + 1; - ttyp = d->track[0]; /* compressed track type */ - bpt = d->track[1] + 256 * d->track[2]; /* compressed track len... */ - tlen = UDI_TLEN( ttyp, bpt ); - d->track[-1] = ttyp; - d->track[-3] = d->track[1]; - d->track[-2] = d->track[2]; - if( udi_read_compressed( d->track + 3, clen, tlen, &data, &data_size ) ) { - if( data ) free( data ); - return d->status = DISK_UNSUP; - } - memcpy( d->track, data, tlen ); /* read track */ -#endif /* #ifndef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION */ - } - if( data ) free( data ); - return DISK_OK; -} - -#ifdef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION -static int -udi_compress_tracks( disk_t *d ) -{ - int i, tlen; - uint8_t *data = NULL; - size_t clen, data_size = 0; - - for( i = 0; i < d->sides * d->cylinders; i++ ) { - DISK_SET_TRACK_IDX( d, i ); - if( d->track[-1] == 0xf0 ) continue; /* already compressed??? */ - - tlen = UDI_TLEN( d->track[-1], d->track[-3] + 256 * d->track[-2] ); - /* if fail to compress, skip ... */ - if( udi_write_compressed( d->track, tlen, &clen, &data, &data_size ) || - clen < 1 ) continue; - /* if compression too large, skip... */ - if( clen > 65535 || clen >= tlen ) continue; - d->track[0] = d->track[-1]; /* track type... */ - d->track[1] = d->track[-3]; /* compressed track len... */ - d->track[2] = d->track[-2]; /* compressed track len... */ - memcpy( d->track + 3, data, clen ); /* read track */ - clen--; - d->track[-1] = 0xf0; - d->track[-3] = clen & 0xff; - d->track[-2] = ( clen >> 8 ) & 0xff; - } - if( data ) free( data ); - return DISK_OK; -} -#endif /* #ifdef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION */ - -static int -open_udi( buffer_t *buffer, disk_t *d, int preindex_unused ) -{ - int i, bpt, ttyp, tlen, error; - size_t eof; - uint32_t crc; - - crc = ~(uint32_t) 0; - - /* check file length */ - eof = buff[4] + 256 * buff[5] + 65536 * buff[6] + 16777216 * buff[7]; - if( eof != buffer->file.length - 4 ) - return d->status = DISK_OPEN; - /* check CRC32 */ - for( i = 0; i < eof; i++ ) - crc = crc_udi( crc, buff[i] ); - if( crc != buff[eof] + 256 * buff[eof + 1] + 65536 * buff[eof + 2] + - 16777216 * buff[eof + 3] ) - return d->status = DISK_OPEN; - - d->sides = buff[10] + 1; - d->cylinders = buff[9] + 1; - GEOM_CHECK; - d->density = DISK_DENS_AUTO; - buffer->index = 16; - d->bpt = 0; - - /* scan file for the longest track */ - for( i = 0; buffer->index < eof; i++ ) { - if( buffavail( buffer ) < 3 ) - return d->status = DISK_OPEN; - ttyp = buff[0]; - if( ttyp != 0x00 && ttyp != 0x01 && ttyp != 0x02 && ttyp != 0x80 && - ttyp != 0x81 && ttyp != 0x82 && ttyp != 0x83 && ttyp != 0xf0 ) - return d->status = DISK_UNSUP; - - /* if libspectrum cannot suppot*/ -#ifndef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION - if( ttyp == 0xf0 ) d->status = DISK_UNSUP; -#endif /* #ifndef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION */ - if( ttyp == 0x83 ) { /* multiple read */ - if( i == 0 ) return d->status = DISK_GEOM; /* cannot be first track */ - i--; bpt = 0; /* not a real track */ - tlen = buff[1] + 256 * buff[2]; /* current track len... */ - tlen = ( tlen & 0xfff8 ) * ( tlen & 0x07 ); - } else if( ttyp == 0xf0 ) { /* compressed track */ - if( buffavail( buffer ) < 7 ) - return d->status = DISK_OPEN; - bpt = buff[4] + 256 * buff[5]; - tlen = 7 + buff[1] + 256 * buff[2]; - } else { - bpt = buff[1] + 256 * buff[2]; /* current track len... */ - tlen = 3 + UDI_TLEN( ttyp, bpt ); - } - if( bpt > d->bpt ) - d->bpt = bpt; - if( buffseek( buffer, tlen, SEEK_CUR ) == -1 ) - return d->status = DISK_OPEN; - } - - if( d->bpt == 0 ) - return d->status = DISK_GEOM; - - bpt = d->bpt; /* save the maximal value */ - d->tlen = 3 + bpt + 3 * DISK_CLEN( bpt ); - d->bpt = 0; /* we know exactly the track len... */ - if( disk_alloc( d ) != DISK_OK ) - return d->status; - d->bpt = bpt; /* restore the maximal byte per track */ - buffer->index = 16; - - for( i = 0; buffer->index < eof; i++ ) { - DISK_SET_TRACK_IDX( d, i ); - ttyp = buff[0]; - bpt = buff[1] + 256 * buff[2]; /* current track len... */ - - memset( d->track, 0x4e, d->bpt ); /* fillup */ - /* read track + clocks */ - if( ttyp == 0x83 ) { /* multiple read */ - i--; /* not a real track */ - DISK_SET_TRACK_IDX( d, i ); /* back to previouse track */ - d->weak += buff[3] + 256 * buff[4]; /* add offset to weak */ - tlen = ( buff[1] + 256 * buff[2] ) >> 3; /* weak len in bytes */ - for( tlen--; tlen >= 0; tlen-- ) - d->weak[tlen] = 0xff; - tlen = buff[1] + 256 * buff[2]; /* current track len... */ - tlen = ( tlen & 0xfff8 ) * ( tlen & 0x07 ); - buffseek( buffer, tlen, SEEK_CUR ); - } else { - if( ttyp == 0xf0 ) /* compressed */ - tlen = bpt + 4; - else - tlen = UDI_TLEN( ttyp, bpt ); - d->track[-1] = ttyp; - d->track[-3] = buff[1]; - d->track[-2] = buff[2]; - buffer->index += 3; - buffread( d->track, tlen, buffer ); /* first read data */ - } - } - error = udi_uncompress_tracks( d ); - if( error ) return error; - udi_unpack_tracks( d ); - - return d->status = DISK_OK; -} - - -//========================================================================== -// -// write_udi -// -//========================================================================== -static int write_udi (FILE *file, disk_t *d) { - int i, j, error=error; - size_t len; - uint32_t crc; - uint8_t head[256]; - - udi_pack_tracks( d ); -#ifdef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION - udi_compress_tracks( d ); -#endif /* #ifdef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION */ - - crc = ~( uint32_t ) 0; - len = 16; - - for( i = 0; i < d->sides * d->cylinders; i++ ) { /* check tracks */ - DISK_SET_TRACK_IDX( d, i ); - if( d->track[-1] == 0xf0 ) - len += 7 + d->track[-3] + 256 * d->track[-2]; - else - len += 3 + UDI_TLEN( d->track[-1], d->track[-3] + 256 * d->track[-2] ); - } - head[0] = 'U'; - head[1] = 'D'; - head[2] = 'I'; - head[3] = '!'; - head[4] = len & 0xff; - head[5] = ( len >> 8 ) & 0xff; - head[6] = ( len >> 16 ) & 0xff; - head[7] = ( len >> 24 ) & 0xff; - head[8] = 0x00; - head[9] = d->cylinders - 1; - head[10] = d->sides - 1; - head[11] = head[12] = head[13] = head[14] = head[15] = 0; - if( fwrite( head, 16, 1, file ) != 1 ) - return d->status = DISK_WRPART; - for( j = 0; j < 16; j++ ) - crc = crc_udi( crc, head[j] ); - for( i = 0; i < d->sides * d->cylinders; i++ ) { /* write tracks */ - DISK_SET_TRACK_IDX( d, i ); - head[0] = d->track[-1]; /* track type */ - head[1] = d->track[-3]; /* track len */ - head[2] = d->track[-2]; /* track len2 */ - if( fwrite( head, 3, 1, file ) != 1 ) - return d->status = DISK_WRPART; - - for( j = 0; j < 3; j++ ) - crc = crc_udi( crc, head[j] ); - - if( d->track[-1] == 0xf0 ) - len = 4 + d->track[-3] + 256 * d->track[-2]; - else - len = UDI_TLEN( d->track[-1], d->track[-3] + 256 * d->track[-2] ); - if( fwrite( d->track, len, 1, file ) != 1 ) - return d->status = DISK_WRPART; - - for( j = len; j > 0; j-- ) { - crc = crc_udi( crc, *d->track ); - d->track++; - } - } - head[0] = crc & 0xff; - head[1] = ( crc >> 8 ) & 0xff; - head[2] = ( crc >> 16 ) & 0xff; - head[3] = ( crc >> 24 ) & 0xff; - if( fwrite( head, 4, 1, file ) != 1 ) /* CRC */ - fclose( file ); - -#ifdef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION - /* Keep tracks uncompressed in memory */ - error = udi_uncompress_tracks( d ); - if( error ) return error; -#endif /* #ifdef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION */ - - udi_unpack_tracks( d ); - return d->status = DISK_OK; -} +/* disk.c: Routines for handling disk images + Copyright (c) 2007-2017 Gergely Szasz + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + Author contact information: + + Philip: philip-fuse@shadowmagic.org.uk + +*/ +#ifdef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION +//========================================================================== +// +// udi_read_compressed +// +//========================================================================== +static int udi_read_compressed (const uint8_t *buffer, + size_t compr_size, size_t uncompr_size, + uint8_t **data, size_t *data_size) +{ + libspectrum_error error; + uint8_t *tmp; + size_t olength = uncompr_size; + + tmp = NULL; + + error = libspectrum_zlib_inflate(buffer, compr_size, &tmp, &olength); + if (error) return error; + + if (*data_size < uncompr_size) { + *data = realloc(*data, uncompr_size); + *data_size = uncompr_size; + } + memcpy(*data, tmp, uncompr_size); + libspectrum_free(tmp); + + return 0; +} + + +//========================================================================== +// +// udi_write_compressed +// +//========================================================================== +static int udi_write_compressed (const uint8_t *buffer, + size_t uncompr_size, size_t *compr_size, + uint8_t **data, size_t *data_size) +{ + libspectrum_error error; + uint8_t *tmp; + + tmp = NULL; + error = libspectrum_zlib_compress(buffer, uncompr_size, &tmp, compr_size); + if (error) return error; + + if (*data_size < *compr_size) { + *data = realloc(*data, *compr_size ); + *data_size = *compr_size; + } + memcpy(*data, tmp, *compr_size); + libspectrum_free(tmp); + + return LIBSPECTRUM_ERROR_NONE; +} +#endif /* LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION */ + + +//========================================================================== +// +// udi_pack_tracks +// +//========================================================================== +static void udi_pack_tracks (disk_t *d) { + int i, tlen, clen, ttyp; + uint8_t *tmp; + + for (i = 0; i < d->sides*d->cylinders; ++i) { + DISK_SET_TRACK_IDX(d, i); + tmp = d->track; + ttyp = tmp[-1]; + tlen = tmp[-3]+256*tmp[-2]; + clen = DISK_CLEN(tlen); + tmp += tlen; + /* copy clock if needed */ + if (tmp != d->clocks) memcpy(tmp, d->clocks, clen); + if (ttyp == 0x00 || ttyp == 0x01) continue; + tmp += clen; + if (ttyp&0x02) { + /* copy FM marks */ + if (tmp != d->fm) memcpy(tmp, d->fm, clen); + tmp += clen; + } + if ((ttyp&0x80) == 0) continue; + /* copy WEAK marks*/ + if (tmp != d->weak) memcpy(tmp, d->weak, clen); + } +} + + +//========================================================================== +// +// udi_unpack_tracks +// +//========================================================================== +static void udi_unpack_tracks (disk_t *d) { + int i, tlen, clen, ttyp; + uint8_t *tmp; + const uint8_t mask[] = { 0xff, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe }; + for (i = 0; i < d->sides*d->cylinders; ++i) { + DISK_SET_TRACK_IDX(d, i); + tmp = d->track; + ttyp = tmp[-1]; + tlen = tmp[-3]+256*tmp[-2]; + clen = DISK_CLEN(tlen); + tmp += tlen; + if (ttyp&0x80) tmp += clen; + if (ttyp&0x02) tmp += clen; + if ((ttyp&0x80)) { + /* copy WEAK marks */ + if (tmp != d->weak) memcpy(d->weak, tmp, clen); + tmp -= clen; + } else { + /* clear WEAK marks */ + memset(d->weak, 0, clen); + } + if (ttyp&0x02) { + /* copy FM marks */ + if (tmp != d->fm) memcpy(d->fm, tmp, clen); + tmp -= clen; + } else { + /* set/clear FM marks */ + memset(d->fm, (ttyp&0x01 ? 0xff : 0), clen); + if (tlen%8) { + /* adjust last byte */ + d->fm[clen-1] &= mask[tlen%8]; + } + } + /* copy clock if needed */ + if (tmp != d->clocks) memcpy(d->clocks, tmp, clen); + } +} + +/* calculate track len from type, if type eq. 0x00/0x01/0x02/0x80/0x81/0x82 + !!! not for 0x83 nor 0xf0 !!! +*/ +#define UDI_TLEN( type, bpt ) ((bpt)+DISK_CLEN(bpt)*(1+(type&0x02 ? 1 : 0)+(type&0x80 ? 1 : 0))) + + +//========================================================================== +// +// udi_uncompress_tracks +// +//========================================================================== +static int udi_uncompress_tracks (disk_t *d) { + int i; + uint8_t *data = NULL; + #ifdef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION + size_t data_size = 0; + int bpt, tlen, clen, ttyp; + #endif + + for (i = 0; i < d->sides*d->cylinders; ++i) { + DISK_SET_TRACK_IDX(d, i); + if (d->track[-1] != 0xf0) continue; /* if not compressed */ + + #ifndef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION + /* if libspectrum cannot support */ + return d->status = DISK_UNSUP; + #else + clen = d->track[-3]+256*d->track[-2]+1; + ttyp = d->track[0]; /* compressed track type */ + bpt = d->track[1]+256*d->track[2]; /* compressed track len... */ + tlen = UDI_TLEN(ttyp, bpt); + d->track[-1] = ttyp; + d->track[-3] = d->track[1]; + d->track[-2] = d->track[2]; + if (udi_read_compressed(d->track+3, clen, tlen, &data, &data_size)) { + if (data) free(data); + return (d->status = DISK_UNSUP); + } + memcpy(d->track, data, tlen); /* read track */ + #endif + } + if (data) free(data); + return DISK_OK; +} + + +#ifdef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION +//========================================================================== +// +// udi_compress_tracks +// +//========================================================================== +static int udi_compress_tracks (disk_t *d) { + int i, tlen; + uint8_t *data = NULL; + size_t clen, data_size = 0; + + for (i = 0; i < d->sides*d->cylinders; ++i) { + DISK_SET_TRACK_IDX(d, i); + if (d->track[-1] == 0xf0) continue; /* already compressed??? */ + + tlen = UDI_TLEN(d->track[-1], d->track[-3]+256*d->track[-2]); + /* if fail to compress, skip ... */ + if (udi_write_compressed(d->track, tlen, &clen, &data, &data_size ) || clen < 1) continue; + /* if compression too large, skip... */ + if (clen > 65535 || clen >= tlen) continue; + d->track[0] = d->track[-1]; /* track type... */ + d->track[1] = d->track[-3]; /* compressed track len... */ + d->track[2] = d->track[-2]; /* compressed track len... */ + memcpy(d->track+3, data, clen); /* read track */ + --clen; + d->track[-1] = 0xf0; + d->track[-3] = clen&0xff; + d->track[-2] = (clen>>8)&0xff; + } + if (data) free(data); + return DISK_OK; +} +#endif + + +//========================================================================== +// +// open_udi +// +//========================================================================== +static int open_udi (buffer_t *buffer, disk_t *d, int preindex_unused) { + int i, bpt, ttyp, tlen, error; + size_t eof; + uint32_t crc; + + crc = ~(uint32_t)0; + + /* check file length */ + eof = buff[4]+256U*buff[5]+65536U*buff[6]+16777216U*buff[7]; + if (eof != buffer->file.length-4) return (d->status = DISK_OPEN); + + /* check CRC32 */ + for (i = 0; i < eof; ++i) crc = crc_udi(crc, buff[i]); + if (crc != buff[eof]+256U*buff[eof+1]+65536U*buff[eof+2]+16777216U*buff[eof+3]) { + return (d->status = DISK_OPEN); + } + + d->sides = buff[10]+1; + d->cylinders = buff[9]+1; + GEOM_CHECK; + d->density = DISK_DENS_AUTO; + buffer->index = 16; + d->bpt = 0; + + /* scan file for the longest track */ + for (i = 0; buffer->index < eof; ++i) { + if (buffavail(buffer) < 3) return (d->status = DISK_OPEN); + + ttyp = buff[0]; + if (ttyp != 0x00 && ttyp != 0x01 && ttyp != 0x02 && ttyp != 0x80 && + ttyp != 0x81 && ttyp != 0x82 && ttyp != 0x83 && ttyp != 0xf0) + { + return d->status = DISK_UNSUP; + } + + /* if libspectrum cannot suppot*/ + #ifndef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION + if (ttyp == 0xf0) d->status = DISK_UNSUP; + #endif + if (ttyp == 0x83) { + /* multiple read */ + if (i == 0) return (d->status = DISK_GEOM); /* cannot be first track */ + /* not a real track */ + --i; + bpt = 0; + tlen = buff[1]+256*buff[2]; /* current track len... */ + tlen = ( tlen&0xfff8 )*(tlen&0x07); + } else if (ttyp == 0xf0) { + /* compressed track */ + if (buffavail(buffer) < 7) return (d->status = DISK_OPEN); + bpt = buff[4]+256*buff[5]; + tlen = 7+buff[1]+256*buff[2]; + } else { + bpt = buff[1]+256*buff[2]; /* current track len... */ + tlen = 3+UDI_TLEN(ttyp, bpt); + } + if (bpt > d->bpt) d->bpt = bpt; + if (buffseek(buffer, tlen, SEEK_CUR) == -1) return (d->status = DISK_OPEN); + } + + if (d->bpt == 0) return (d->status = DISK_GEOM); + + bpt = d->bpt; /* save the maximal value */ + d->tlen = 3+bpt+3*DISK_CLEN(bpt); + d->bpt = 0; /* we know exactly the track len... */ + + if (disk_alloc(d) != DISK_OK) return d->status; + + d->bpt = bpt; /* restore the maximal byte per track */ + buffer->index = 16; + + for (i = 0; buffer->index < eof; ++i) { + DISK_SET_TRACK_IDX(d, i); + ttyp = buff[0]; + bpt = buff[1]+256*buff[2]; /* current track len... */ + memset(d->track, 0x4e, d->bpt); /* fillup */ + /* read track + clocks */ + if (ttyp == 0x83) { + /* multiple read */ + --i; /* not a real track */ + DISK_SET_TRACK_IDX(d, i); /* back to previouse track */ + d->weak += buff[3]+256*buff[4]; /* add offset to weak */ + tlen = (buff[1]+256*buff[2])>>3; /* weak len in bytes */ + for (--tlen; tlen >= 0; --tlen) d->weak[tlen] = 0xff; + tlen = buff[1]+256*buff[2]; /* current track len... */ + tlen = (tlen&0xfff8)*(tlen&0x07); + buffseek(buffer, tlen, SEEK_CUR); + } else { + if (ttyp == 0xf0) { + /* compressed */ + tlen = bpt+4; + } else { + tlen = UDI_TLEN(ttyp, bpt); + } + d->track[-1] = ttyp; + d->track[-3] = buff[1]; + d->track[-2] = buff[2]; + buffer->index += 3; + buffread(d->track, tlen, buffer); /* first read data */ + } + } + + error = udi_uncompress_tracks( d ); + if (error) return error; + udi_unpack_tracks(d); + + return (d->status = DISK_OK); +} + + +//========================================================================== +// +// write_udi +// +//========================================================================== +static int write_udi (FILE *file, disk_t *d) { + int i, j, error=error; + size_t len; + uint32_t crc; + uint8_t head[256]; + + udi_pack_tracks(d); + #ifdef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION + udi_compress_tracks(d); + #endif + + crc = ~(uint32_t)0; + len = 16; + + /* check tracks */ + for (i = 0; i < d->sides*d->cylinders; ++i) { + DISK_SET_TRACK_IDX(d, i); + if (d->track[-1] == 0xf0) { + len += 7+d->track[-3]+256*d->track[-2]; + } else { + len += 3+UDI_TLEN(d->track[-1], d->track[-3]+256*d->track[-2]); + } + } + + head[0] = 'U'; + head[1] = 'D'; + head[2] = 'I'; + head[3] = '!'; + head[4] = len&0xff; + head[5] = (len>>8)&0xff; + head[6] = (len>>16)&0xff; + head[7] = (len>>24)&0xff; + head[8] = 0x00; + head[9] = d->cylinders-1; + head[10] = d->sides-1; + head[11] = head[12] = head[13] = head[14] = head[15] = 0; + if (fwrite(head, 16, 1, file) != 1) return (d->status = DISK_WRPART); + + for (j = 0; j < 16; ++j) crc = crc_udi(crc, head[j]); + + /* write tracks */ + for (i = 0; i < d->sides*d->cylinders; ++i) { + DISK_SET_TRACK_IDX(d, i); + head[0] = d->track[-1]; /* track type */ + head[1] = d->track[-3]; /* track len */ + head[2] = d->track[-2]; /* track len2 */ + if (fwrite(head, 3, 1, file) != 1) return (d->status = DISK_WRPART); + + for (j = 0; j < 3; ++j) crc = crc_udi(crc, head[j]); + + if (d->track[-1] == 0xf0) { + len = 4+d->track[-3]+256*d->track[-2]; + } else { + len = UDI_TLEN(d->track[-1], d->track[-3]+256*d->track[-2]); + } + if (fwrite(d->track, len, 1, file) != 1) return (d->status = DISK_WRPART); + + for (j = len; j > 0; --j) { + crc = crc_udi(crc, *d->track); + ++d->track; + } + } + + head[0] = crc&0xff; + head[1] = (crc>>8)&0xff; + head[2] = (crc>>16)&0xff; + head[3] = (crc>>24)&0xff; + if (fwrite(head, 4, 1, file) != 1) fclose(file); /* CRC */ + + #ifdef LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION + /* Keep tracks uncompressed in memory */ + error = udi_uncompress_tracks(d); + if (error) return error; + #endif + + udi_unpack_tracks(d); + return (d->status = DISK_OK); +} -- 2.11.4.GIT