summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/tools/imgtool/modules/ti99.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mess/tools/imgtool/modules/ti99.c')
-rw-r--r--src/mess/tools/imgtool/modules/ti99.c5360
1 files changed, 0 insertions, 5360 deletions
diff --git a/src/mess/tools/imgtool/modules/ti99.c b/src/mess/tools/imgtool/modules/ti99.c
deleted file mode 100644
index 220cbebdb27..00000000000
--- a/src/mess/tools/imgtool/modules/ti99.c
+++ /dev/null
@@ -1,5360 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Raphael Nabet
-/*
- Handlers for ti99 disk images
-
- We support the following types of image:
- * floppy disks ("DSK format") in v9t9, pc99 and old mess image format
- * hard disks ("WIN format") in MAME harddisk format (256-byte sectors only,
- i.e. no SCSI)
- Files are extracted in TIFILES format. There is a compile-time option to
- extract text files in flat format instead, but I need to re-implement it
- properly (using filters comes to mind).
-
- Raphael Nabet, 2002-2004
-
- TODO:
- - finish and test hd support ***test sibling FDR support***
- - check allocation bitmap against corruption when an image is opened
-*/
-
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <time.h>
-#include "imgtool.h"
-#include "harddisk.h"
-#include "imghd.h"
-
-/*
- Concepts shared by both disk structures:
- ----------------------------------------
-
- In both formats, the entire disk surface is split into physical records,
- each 256-byte-long. For best efficiency, the sector size is usually 256
- bytes so that one sector is equivalent to a physical record (this is true
- with floppies and HFDC hard disks). If the sector size is not 256 bytes
- (e.g. 512 bytes with SCSI hard disks, possibly 128 bytes on a TI-99
- simulator running on TI-990), sectors are grouped or split to form 256-byte
- physical records. Physical records are numbered from 0, with the first
- starting on sector 0 track 0. To avoid confusion with physical records in
- files, such physical records will be called "absolute physical records",
- abbreviated as "absolute physrecs" or "aphysrecs".
-
- Disk space is allocated in units referred to as AUs. Each AU represents an
- integral number of 256-byte physical records. The number of physrecs per
- AU varies depending on the disk format and size. AUs are numbered from 0,
- with the first starting with absolute physrec 0.
-
- Absolute physrec 0 contains a 256-byte record with volume information,
- which is called "Volume Information Block", abbreviated as "vib".
-
- To keep track of which areas on the disk are allocated and which are free,
- disk managers maintain a bit map of allocated AUs (called "allocation
- bitmap", abbreviated as "abm"). Each bit in the allocation bitmap
- represents an AU: if a bit is 0, the AU is free; if a bit is 1, the AU is
- allocated (or possibly bad if the disk manager can track bad sectors).
- Where on the disk the abm is located depends on the disk structure (see
- structure-specific description for details).
-
- Files are implemented as a succession of 256-byte physical records. To
- avoid confusion with absolute physical records, these physical records will
- be called "file physical records", abbreviated as "file physrecs" or
- "fphysrecs".
-
- Programs do normally not access file physical records directly. They may
- call high-level file routines that enable to create either fixed-length
- logical records of any size from 1 through 255, or variable-length records
- of any size from 0 through 254: logical records are grouped by file
- managers into 256-byte physical records. Some disk managers (HFDC and
- SCSI) allow programs to create fixed-length records larger than 255 bytes,
- too, but few programs use this possibility. Additionally, program files
- can be created: program files do not implement any logical record, and can
- be seen as a flat byte stream, not unlike files under MSDOS, UNIX and the C
- standard library. (Unfortunately, the API for program files lacks
- flexibility, and most programs that need to process a flat byte stream
- will use fixed-size records of 128 bytes.)
-
- Fixed-length records (reclen < 256) are grouped like this:
- fphysrec 0 fphysrec 1
- _______________ _______________
- |R0 |R1 |R2 |X| |R3 |R4 |R5 |X|
- --------------- ---------------
- \_/ \_/
- unused unused
- (size < reclen) (size < reclen)
-
- Fixed-length records (reclen > 256) are grouped like this:
- fphysrec 0 fphysrec 1 fphysrec 2 fphysrec 3 ...
- _________________ _________________ _________________ _________________
- | R0 (#0-255) | | R0 (#256-511) | |R0 (#512-end)|X| | R1 (#0-255) | ...
- ----------------- ----------------- ----------------- -----------------
- \_/
- unused
-
- Variable length records are grouped like this:
- fphysrec 0:
- byte:
- ------------------------------
- 0 |l0 = length of record 0 data|
- |----------------------------|
- 1 | |
- | |
- : | record 0 data |
- | |
- l0 | |
- |----------------------------|
- l0+1 |l1 = length of record 1 data|
- |----------------------------|
- l0+2 | |
- | |
- : | record 1 data |
- | |
- l0+l1+1 | |
- |----------------------------|
- : : :
- : : :
- |----------------------------|
- n |lm = length of record m data|
- |----------------------------|
- n+1 | |
- | |
- : | record m data |
- | |
- n+lm | |
- |----------------------------|
- n+lm+1 |>ff: EOR mark |
- |----------------------------|
- n+lm+2 | |
- | |
- : | unused |
- : |(we should have size < lm+1)|
- | |
- 255 | |
- ------------------------------
-
- fphysrec 1:
- byte:
- ------------------------------
- 0 |lm+1=length of record 0 data|
- |----------------------------|
- 1 | |
- | |
- : | record m+1 data |
- | |
- lm+1 | |
- |----------------------------|
- : : :
- : : :
-
- I think the EOR mark is not required if all 256 bytes of a physical
- record are used by logical records.
-
-
- All files are associated with a "file descriptor record" ("fdr") that holds
- file information (name, format, length) and points to the data AUs. The WIN
- disk structure also supports sibling FDRs, in case a file is so fragmented
- that all the data pointers cannot fit in one FDR; the DSK disk structure
- does not implement any such feature, and you may be unable to append data
- to an existing file if it is too fragmented, even though the disk is not
- full.
-
-
- DSK disk structure:
- -------------------
-
- The DSK disk structure is used for floppy disks, and a few RAMDISKs as
- well. It supports 1600 AUs and 16 MBytes at most (the 16 MByte value is a
- theorical maximum, as I doubt anyone has ever created so big a DSK volume).
-
- The disk sector size is always 256 bytes (the only potential exceptions are
- the SCSI floppy disk units and the TI-99 simulator on TI-990, but I don't
- know anything about either).
-
- For some reason, the number of physrecs per AU is always a power of 2.
- Originally, AUs always were one physical record each. However, since the
- allocation bitmap cannot support more than 1600 AUs, disks larger than
- 400kbytes need to have several physical records per AU. Note that
- relatively few disk controllers implement AUs that span multiple physical
- records (IIRC, these are Myarc's HFDC, SCSI DSR with floppy disk interface,
- and some upgraded Myarc and Corcomp DD floppy controllers).
-
- The allocation bitmap is located in the VIB. It is 200 bytes long, and
- supports 1600 AUs at most.
-
- Directories are implemented with a "File Descriptor Index Record" (FDIR)
- for each directory. The FDIR is array of 0 through 128 words, containing
- the aphysrec address of each fdr in the directory, sorted by ascending file
- name, terminated with a 0. Note that, while we should be prepared to read
- images images with 128 entries, I think (not 100% sure) that we should
- write no more than 127 for compatibility with some existing disk managers.
-
- Originally, the DSK structure only supported one directory level (i.e. the
- root directory level). The FDIR record for the root directory is always
- located in aphysrec 1. Moreover, Myarc extended the DSK structure to
- support up to 3 subdirectories in the root directory (note that there is no
- support for more subdirs, or for subdirs located in subdirs). To do so,
- they used an unused field of the VIB to hold the 10-char name of each
- directory and the aphysrec address of the associated FDIR record.
-
- aphysrec 0: Volume Information Block (VIB): see below
- aphysrec 1: FDIR for root directory
- Remaining AUs are used for fdr and data (and subdirectory FDIR if
- applicable). There is one FDIR record per directory; the FDIR points to
- the FDR for each file in the directory. The FDR (File Descriptor Record)
- contains the file information (name, format, length, pointers to data
- physrecs/AUs, etc).
-
-
- WIN disk structure:
- -------------------
-
- The WIN disk structure is used for hard disks. It supports 65535 AUs and
- 256 MBytes at most.
-
- The disk sector size is 256 bytes on HFDC, 512 bytes on SCSI. 512-byte
- sectors are split into 256-byte physical records.
-
- We may have from 1 through 16 physrecs per AUs. Since we cannot have more
- than 65535 AUs, we need to have several physical records per AU in disks
- larger than 16 Mbytes.
-
- Contrary to the DSK disk structure, the WIN disk structure supports
- hierarchic subdirectories, with a limit of 114 subdirectories and 127 files
- per directory. Each directory is associated with both a "Directory
- Descriptor Record" (DDR) and a "File Descriptor Index Record" (FDIR). The
- only exception is the root directory, which uses the VIB instead of a DDR
- (the VIB includes all the important fields of the DDR). The DDR contains
- some directory info (name, number of files and subdirectories directly
- enclosed in the directory, AU address of the FDIR of the parent directory,
- etc), the AU address of the associated FDIR, and the AU address of the DDR
- of up to 114 subdirectories, sorted by ascending directory name. The WIN
- FDIR is similar to, yet different from, the DSK FDIR: it contains up to 127
- (vs. 128) AU address (vs. aphysrec address) of each fdr in the directory,
- sorted by ascending file name. Additionally, it includes the AU address of
- the associated DDR.
-
- When a file has more than 54 data fragments, the disk manager creates
- sibling FDRs that hold additional fragments. (Sibling FDRs are called
- offspring FDRs in most existing documentation, but I prefer "sibling FDRs"
- as "offspring FDRs" wrongly suggests a directory-like hierarchy.
- Incidentally, I cannot really figure out why they chose to duplicate the
- FDR rather than create a file extension record, but there must be a
- reason.) Note that sibling FDRs usually fill unused physrecs in the AU
- allocated for the eldest FDR, and a new AU is allocated for new sibling
- FDRs only when the first AU is full.
-
- aphysrec 0: Volume Information Block (VIB): see below
- aphysrec 1-n (where n = 1+SUP(number_of_AUs/2048)): Volume bitmap
- Remaining AUs are used for ddr, fdir, fdr and data.
-*/
-
-/* Since string length is encoded with a byte, the maximum length of a string
-is 255. Since we need to add a device name (1 char minimum, typically 4 chars)
-and a '.' separator, we chose a practical value of 250 (though few applications
-will accept paths of such length). */
-#define MAX_PATH_LEN 253
-#define MAX_SAFE_PATH_LEN 250
-
-#define MAX_DIR_LEVEL 125 /* We need to put a recursion limit to avoid endless recursion hazard */
-
-
-#if 0
-#pragma mark MISCELLANEOUS UTILITIES
-#endif
-
-/*
- Miscellaneous utilities that are used to handle TI data types
-*/
-
-struct UINT16BE
-{
- UINT8 bytes[2];
-};
-
-struct UINT16LE
-{
- UINT8 bytes[2];
-};
-
-INLINE UINT16 get_UINT16BE(UINT16BE word)
-{
- return (word.bytes[0] << 8) | word.bytes[1];
-}
-
-INLINE void set_UINT16BE(UINT16BE *word, UINT16 data)
-{
- word->bytes[0] = (data >> 8) & 0xff;
- word->bytes[1] = data & 0xff;
-}
-
-INLINE UINT16 get_UINT16LE(UINT16LE word)
-{
- return word.bytes[0] | (word.bytes[1] << 8);
-}
-
-INLINE void set_UINT16LE(UINT16LE *word, UINT16 data)
-{
- word->bytes[0] = data & 0xff;
- word->bytes[1] = (data >> 8) & 0xff;
-}
-
-/*
- Convert a C string to a 10-character file name (padded with spaces if necessary)
-
- dst (O): destination 10-character array
- src (I): source C string
-*/
-static void str_to_fname(char dst[10], const char *src)
-{
- int i;
-
-
- i = 0;
-
- /* copy 10 characters at most */
- if (src)
- while ((i<10) && (src[i]!='\0'))
- {
- dst[i] = src[i];
- i++;
- }
-
- /* pad with spaces */
- while (i<10)
- {
- dst[i] = ' ';
- i++;
- }
-}
-
-/*
- Convert a 10-character file name to a C string (removing trailing spaces if necessary)
-
- dst (O): destination C string
- src (I): source 10-character array
- n (I): length of dst buffer (string may be truncated if less than 11)
-*/
-static void fname_to_str(char *dst, const char src[10], int n)
-{
- int i;
- int last_nonspace;
-
-
- /* copy 10 characters at most */
- if (--n > 10)
- n = 10;
-
- /* copy filename */
- i = 0;
- last_nonspace = -1;
-
- while (i<n)
- {
- dst[i] = src[i];
- if (src[i] != ' ')
- last_nonspace = i;
- i++;
- }
-
- /* terminate with '\0' */
- dst[last_nonspace+1] = '\0';
-}
-
-/*
- Check a 10-character file name.
-
- filename (I): 10-character array with file name
-
- Return non-zero if the file name is invalid.
-*/
-static int check_fname(const char filename[10])
-{
- int i;
- int space_found_flag;
-
-
- /* check and copy file name */
- space_found_flag = FALSE;
- for (i=0; i<10; i++)
- {
- switch (filename[i])
- {
- case '.':
- case '\0':
- /* illegal characters */
- return 1;
- case ' ':
- /* illegal in a file name, but file names shorter than 10
- characters are padded with spaces */
- space_found_flag = TRUE;
- break;
- default:
- /* all other characters are legal (though non-ASCII characters,
- control characters and even lower-case characters are not
- recommended) */
- if (space_found_flag)
- return 1;
- break;
- }
- }
-
- return 0;
-}
-
-/*
- Check a file path.
-
- fpath (I): C string with file path
-
- Return non-zero if the file path is invalid.
-*/
-static int check_fpath(const char *fpath)
-{
- const char *element_start, *element_end;
- int element_len;
-
-
- /* first check that the path is not too long and that there is no space
- character */
- if ((strlen(fpath) > MAX_PATH_LEN) || strchr(fpath, ' '))
- return 1;
-
- /* check that each path element has an acceptable length */
- element_start = fpath;
- do
- {
- /* find next path element */
- element_end = strchr(element_start, '.');
- element_len = element_end ? (element_end - element_start) : strlen(element_start);
- if ((element_len > 10) || (element_len == 0))
- return 1;
-
- /* iterate */
- if (element_end)
- element_start = element_end+1;
- else
- element_start = NULL;
- }
- while (element_start);
-
- return 0;
-}
-
-#if 0
-#pragma mark -
-#pragma mark LEVEL 1 DISK ROUTINES
-#endif
-
-/*
- Level 1 deals with accessing the disk hardware (in our case, the raw disk
- image).
-
- Higher level routines will only know the disk as a succession of
- 256-byte-long physical records addressed by a linear address.
-*/
-
-/*
- Disk geometry
-*/
-struct ti99_geometry
-{
- int secspertrack;
- int cylinders;
- int heads;
-};
-
-/*
- Physical sector address
-*/
-struct ti99_sector_address
-{
- int sector;
- int cylinder;
- int side;
-};
-
-/*
- Time stamp (used in fdr, and WIN VIB/DDR)
-*/
-struct ti99_date_time
-{
- UINT8 time_MSB, time_LSB;/* 0-4: hour, 5-10: minutes, 11-15: seconds/2 */
- UINT8 date_MSB, date_LSB;/* 0-6: year, 7-10: month, 11-15: day */
-};
-
-/*
- Subdirectory descriptor (HFDC only)
-
- The HFDC supports up to 3 subdirectories.
-*/
-struct dsk_subdir
-{
- char name[10]; /* subdirectory name (10 characters, pad with spaces) */
- UINT16BE fdir_aphysrec; /* aphysrec address of fdir record for this subdirectory */
-};
-
-/*
- DSK VIB record
-
- Most fields in this record are only relevant to level 2 routines, but level
- 1 routines need the disk geometry information extracted from the VIB.
-*/
-struct dsk_vib
-{
- char name[10]; /* disk volume name (10 characters, pad with spaces) */
- UINT16BE totphysrecs; /* total number of physrecs on disk (usually 360, */
- /* 720, 640, 1280 or 1440). (TI originally */
- /* said it should be the total number of AUs, */
- /* but, in practice, DSRs that supports disks */
- /* over 400kbytes (e.g. HFDC) write the total */
- /* number of physrecs.) */
- UINT8 secspertrack; /* sectors per track (usually 9 (FM SD), */
- /* 16 or 18 (MFM DD), or 36 (MFM HD) */
- UINT8 id[3]; /* 'DSK' */
- UINT8 protection; /* 'P' if disk is protected, ' ' otherwise. */
- UINT8 cylinders; /* tracks per side (usually 40) */
- UINT8 heads; /* sides (1 or 2) */
- UINT8 density; /* density: 1 (FM SD), 2 (MFM DD), or 3 (MFM HD) */
- dsk_subdir subdir[3]; /* descriptor for up to 3 subdirectories (HFDC only) */
- /* reserved by TI */
- UINT8 abm[200]; /* allocation bitmap: there is one bit per AU. */
- /* A binary 1 in a bit position indicates that */
- /* the allocation unit associated with that */
- /* bit has been allocated. */
- /* Bits corresponding to system reserved AUs, */
- /* non-existant AUs, and bad AUs, are set to one, too. */
- /* (AU 0 is associated to LSBit of byte 0, */
- /* AU 7 to MSBit of byte 0, AU 8 to LSBit */
- /* of byte 1, etc.) */
-};
-
-enum ti99_img_format
-{
- if_mess,
- if_v9t9,
- if_pc99_fm,
- if_pc99_mfm,
- if_harddisk
-};
-
-/*
- level-1 disk image descriptor
-*/
-struct ti99_lvl1_imgref
-{
- ti99_img_format img_format; /* tells the image format */
- imgtool_stream *file_handle; /* imgtool file handle */
- struct mess_hard_disk_file harddisk_handle; /* MAME harddisk handle (harddisk format) */
- ti99_geometry geometry; /* geometry */
- unsigned pc99_track_len; /* unformatted track length (pc99 format) */
- UINT32 *pc99_data_offset_array; /* offset for each sector (pc99 format) */
-};
-
-/*
- calculate CRC for data address marks or sector data
-
- crc (I/O): current CRC value to be updated (initialize to 0xffff before
- calling this function for the first time)
- value: new byte of data to update the CRC with
-*/
-static void calc_crc(UINT16 *crc, UINT8 value)
-{
- UINT8 l, h;
-
- l = value ^ (*crc >> 8);
- *crc = (*crc & 0xff) | (l << 8);
- l >>= 4;
- l ^= (*crc >> 8);
- *crc <<= 8;
- *crc = (*crc & 0xff00) | l;
- l = (l << 4) | (l >> 4);
- h = l;
- l = (l << 2) | (l >> 6);
- l &= 0x1f;
- *crc = *crc ^ (l << 8);
- l = h & 0xf0;
- *crc = *crc ^ (l << 8);
- l = (h << 1) | (h >> 7);
- l &= 0xe0;
- *crc = *crc ^ l;
-}
-
-/*
- Parse a PC99 disk image
-
- file_handle (I/O): imgtool file handle
- fm_format (I): if true, the image is in FM format, otherwise it is in MFM
- format
- pass (I): 0 for first pass, 1 for second pass
- vib (O): buffer where the vib should be stored (first pass)
- geometry (O): disk image geometry (second pass)
- data_offset_array (O): array of data offset to generate (second pass)
- out_track_len (O): track length is returned there
-
- Return imgtool error code
-*/
-#define MAX_TRACK_LEN 6872
-#define DATA_OFFSET_NONE 0xffffffff
-static int parse_pc99_image(imgtool_stream *file_handle, int fm_format, int pass, dsk_vib *vib, const ti99_geometry *geometry, UINT32 *data_offset_array, unsigned *out_track_len)
-{
- int track_len, num_tracks; /* length of a track in bytes, and number of tracks */
- int phys_track;
- int expected_cylinder, expected_head;
- int track_start_pos, track_pos;
- UINT8 c;
- UINT8 cylinder, head, sector;
- int seclen;
- UINT8 crc1, crc2;
- UINT16 crc;
- long data_offset;
- UINT8 track_buf[MAX_TRACK_LEN];
- int i;
-
- if (fm_format)
- track_len = 3253;
- else
- track_len = 6872;
-
- if (out_track_len)
- *out_track_len = track_len;
-
- if (stream_size(file_handle) % track_len)
- return IMGTOOLERR_CORRUPTIMAGE;
-
- num_tracks = stream_size(file_handle) / track_len;
- if (num_tracks <= 0)
- return IMGTOOLERR_CORRUPTIMAGE;
-
- /* we only support 40-track-per-side images */
- if ((num_tracks != 40) && (num_tracks != 80))
- return IMGTOOLERR_UNIMPLEMENTED;
-
- if (pass == 1)
- {
- /* initialize offset map */
- for (head = 0; head < geometry->heads; head++)
- for (cylinder = 0; cylinder < geometry->cylinders; cylinder++)
- for (sector = 0; sector < geometry->secspertrack; sector++)
- data_offset_array[(head*geometry->cylinders + cylinder)*geometry->secspertrack + sector] = DATA_OFFSET_NONE;
- }
- /* rewind to start of file */
- stream_seek(file_handle, 0, SEEK_SET);
-
- /* pass 0 only looks for vib in track 0; pass 1 scans every track */
- for (phys_track=0; phys_track < ((pass == 1) ? num_tracks : 1); phys_track++)
- {
- if (stream_read(file_handle, track_buf, track_len) != track_len)
- return IMGTOOLERR_READERROR;
-
- /* we only support 40-track-per-side images */
- expected_cylinder = phys_track % 40;
- expected_head = phys_track / 40;
-
- track_start_pos = 0;
-
- while (track_start_pos < track_len)
- {
- if (fm_format)
- {
- do
- {
- c = track_buf[track_start_pos];
- track_start_pos++;
- } while ((c != 0xfe) && (track_start_pos < track_len));
-
- if (c != 0xfe)
- break;
-
- track_pos = track_start_pos;
-
- crc = 0xffff;
- calc_crc(& crc, c);
- }
- else
- {
- do
- {
- c = track_buf[track_start_pos];
- track_start_pos++;
- } while ((c != 0xa1) && (track_start_pos < track_len));
-
- if (c != 0xa1)
- break;
-
- track_pos = track_start_pos;
-
- c = track_buf[track_pos];
- track_pos++;
- if (track_pos == track_len)
- track_pos = 0;
-
- if (c != 0xa1)
- continue;
-
- c = track_buf[track_pos];
- track_pos++;
- if (track_pos == track_len)
- track_pos = 0;
-
- if (c != 0xa1)
- continue;
-
- crc = 0xffff;
- calc_crc(& crc, c);
-
- c = track_buf[track_pos];
- track_pos++;
- if (track_pos == track_len)
- track_pos = 0;
-
- if (c != 0xfe)
- continue;
- }
-
- c = track_buf[track_pos];
- track_pos++;
- if (track_pos == track_len)
- track_pos = 0;
-
- cylinder = c;
- calc_crc(& crc, c);
-
- c = track_buf[track_pos];
- track_pos++;
- if (track_pos == track_len)
- track_pos = 0;
-
- head = c;
- calc_crc(& crc, c);
-
- c = track_buf[track_pos];
- track_pos++;
- if (track_pos == track_len)
- track_pos = 0;
-
- sector = c;
- calc_crc(& crc, c);
-
- c = track_buf[track_pos];
- track_pos++;
- if (track_pos == track_len)
- track_pos = 0;
-
- seclen = 128 << c;
- calc_crc(& crc, c);
-
- c = track_buf[track_pos];
- track_pos++;
- if (track_pos == track_len)
- track_pos = 0;
-
- crc1 = c;
- calc_crc(& crc, c);
-
- c = track_buf[track_pos];
- track_pos++;
- if (track_pos == track_len)
- track_pos = 0;
-
- crc2 = c;
- calc_crc(& crc, c);
-
-#if 0
- /* CRC seems to be completely hosed */
- if (crc)
- printf("aargh!");
-#endif
- if ((seclen != 256) || (crc1 != 0xf7) || (crc2 != 0xf7)
- || (cylinder != expected_cylinder) || (head != expected_head)
- || ((pass == 1) && ((cylinder >= geometry->cylinders)
- || (head >= geometry->heads)
- || (sector >= geometry->secspertrack))))
- continue;
-
- c = track_buf[track_pos];
- track_pos++;
- if (track_pos == track_len)
- track_pos = 0;
-
- while (c == (fm_format ? 0xff : 0x4e))
- {
- c = track_buf[track_pos];
- track_pos++;
- if (track_pos == track_len)
- track_pos = 0;
- }
-
- while (c == 0x00)
- {
- c = track_buf[track_pos];
- track_pos++;
- if (track_pos == track_len)
- track_pos = 0;
- }
-
- if (fm_format)
- {
- if (c != 0xfb)
- continue;
-
- crc = 0xffff;
- calc_crc(& crc, c);
- }
- else
- {
- if (c != 0xa1)
- continue;
-
- c = track_buf[track_pos];
- track_pos++;
- if (track_pos == track_len)
- track_pos = 0;
-
- if (c != 0xa1)
- continue;
-
- c = track_buf[track_pos];
- track_pos++;
- if (track_pos == track_len)
- track_pos = 0;
-
- if (c != 0xa1)
- continue;
-
- crc = 0xffff;
- calc_crc(& crc, c);
-
- c = track_buf[track_pos];
- track_pos++;
- if (track_pos == track_len)
- track_pos = 0;
-
- if (c != 0xfb)
- continue;
- }
- data_offset = track_pos;
- for (i=0; i<seclen; i++)
- {
- c = track_buf[track_pos];
- track_pos++;
- if (track_pos == track_len)
- track_pos = 0;
-
- calc_crc(& crc, c);
- }
-
- c = track_buf[track_pos];
- track_pos++;
- if (track_pos == track_len)
- track_pos = 0;
-
- crc1 = c;
- calc_crc(& crc, c);
-
- c = track_buf[track_pos];
- track_pos++;
- if (track_pos == track_len)
- track_pos = 0;
-
- crc2 = c;
- calc_crc(& crc, c);
-
-#if 0
- /* CRC seems to be completely hosed */
- if (crc)
- printf("aargh!");
-#endif
- if ((crc1 != 0xf7) || (crc2 != 0xf7))
- continue;
-
- switch (pass)
- {
- case 0:
- if ((cylinder == 0) && (head == 0) && (sector == 0))
- {
- /* return vib */
- if ((data_offset + 256) <= track_len)
- memcpy(vib, track_buf + data_offset, 256);
- else
- {
- memcpy((UINT8 *)vib, track_buf + data_offset, track_len-data_offset);
- memcpy((UINT8 *)vib + (track_len-data_offset), track_buf, 256-(track_len-data_offset));
- }
- return 0;
- }
- break;
-
- case 1:
- /* set up offset map */
- if (data_offset_array[(head*geometry->cylinders + cylinder)*geometry->secspertrack + sector] != DATA_OFFSET_NONE)
- /* error: duplicate sector */
- return IMGTOOLERR_CORRUPTIMAGE;
- data_offset_array[(head*geometry->cylinders + cylinder)*geometry->secspertrack + sector] = data_offset;
- break;
- }
- }
- }
-
- if (pass == 0)
- return IMGTOOLERR_CORRUPTIMAGE;
-
- if (pass == 1)
- {
- /* check offset map */
- for (head = 0; head < geometry->heads; head++)
- for (cylinder = 0; cylinder < geometry->cylinders; cylinder++)
- for (sector = 0; sector < geometry->secspertrack; sector++)
- if (data_offset_array[(head*geometry->cylinders + cylinder)*geometry->secspertrack + sector] == DATA_OFFSET_NONE)
- /* error: missing sector */
- return IMGTOOLERR_CORRUPTIMAGE;
- }
-
- return 0;
-}
-
-
-/*
- Read the volume information block (aphysrec 0) assuming no geometry
- information. (Called when an image is opened to figure out the
- geometry information.)
-
- file_handle (I/O): imgtool file handle
- img_format (I): image format (MESS, V9T9 or PC99)
- dest (O): pointer to 256-byte destination buffer
-
- Return imgtool error code
-*/
-static int read_image_vib_no_geometry(imgtool_stream *file_handle, ti99_img_format img_format, dsk_vib *dest)
-{
- int reply;
-
- switch (img_format)
- {
- case if_mess:
- case if_v9t9:
- /* seek to sector */
- reply = stream_seek(file_handle, 0, SEEK_SET);
- if (reply)
- return IMGTOOLERR_READERROR;
- /* read it */
- reply = stream_read(file_handle, dest, 256);
- if (reply != 256)
- return IMGTOOLERR_READERROR;
- return 0;
-
- case if_pc99_fm:
- case if_pc99_mfm:
- return parse_pc99_image(file_handle, img_format == if_pc99_fm, 0, dest, NULL, NULL, NULL);
-
- case if_harddisk:
- /* not implemented, because we don't need it */
- break;
- }
-
- return IMGTOOLERR_UNIMPLEMENTED;
-}
-
-/*
- Open a disk image at level 1
-
- file_handle (I/O): imgtool file handle
- img_format (I): image format (MESS, V9T9, PC99, or MAME harddisk)
- l1_img (O): level-1 image handle
- vib (O): buffer where the vib should be stored (floppy images only)
-
- Return imgtool error code
-*/
-static imgtoolerr_t open_image_lvl1(imgtool_stream *file_handle, ti99_img_format img_format, ti99_lvl1_imgref *l1_img, dsk_vib *vib)
-{
- imgtoolerr_t err;
- int reply;
- UINT16 totphysrecs;
-
-
- l1_img->img_format = img_format;
- l1_img->file_handle = file_handle;
-
- if (img_format == if_harddisk)
- {
- const hard_disk_info *info;
-
- err = imghd_open(file_handle, &l1_img->harddisk_handle);
- if (err)
- return err;
-
- info = imghd_get_header(&l1_img->harddisk_handle);
- l1_img->geometry.cylinders = info->cylinders;
- l1_img->geometry.heads = info->heads;
- l1_img->geometry.secspertrack = info->sectors;
- if (info->sectorbytes != 256)
- {
- imghd_close(&l1_img->harddisk_handle);
- return IMGTOOLERR_CORRUPTIMAGE; /* TODO: support 512-byte sectors */
- }
-
-#if 0
- /* read vib */
- reply = read_absolute_physrec(l1_img, 0, vib);
- if (reply)
- return reply;
-#endif
- }
- else
- {
- /* read vib */
- reply = read_image_vib_no_geometry(file_handle, img_format, vib);
- if (reply)
- return (imgtoolerr_t)reply;
-
- /* extract geometry information */
- totphysrecs = get_UINT16BE(vib->totphysrecs);
-
- l1_img->geometry.secspertrack = vib->secspertrack;
- if (l1_img->geometry.secspertrack == 0)
- /* Some images might be like this, because the original SSSD TI
- controller always assumes 9. */
- l1_img->geometry.secspertrack = 9;
- l1_img->geometry.cylinders = vib->cylinders;
- if (l1_img->geometry.cylinders == 0)
- /* Some images are like this, because the original SSSD TI
- controller always assumes 40. */
- l1_img->geometry.cylinders = 40;
- l1_img->geometry.heads = vib->heads;
- if (l1_img->geometry.heads == 0)
- /* Some images are like this, because the original SSSD TI
- controller always assumes that tracks beyond 40 are on side 2. */
- l1_img->geometry.heads = totphysrecs / (l1_img->geometry.secspertrack * l1_img->geometry.cylinders);
-
- /* check information */
- if ((totphysrecs != (l1_img->geometry.secspertrack * l1_img->geometry.cylinders * l1_img->geometry.heads))
- || (totphysrecs < 2)
- || memcmp(vib->id, "DSK", 3) || (! strchr(" P", vib->protection))
- || (((img_format == if_mess) || (img_format == if_v9t9))
- && (stream_size(file_handle) != totphysrecs*256U)))
- return (imgtoolerr_t)IMGTOOLERR_CORRUPTIMAGE;
-
- if ((img_format == if_pc99_fm) || (img_format == if_pc99_mfm))
- {
- l1_img->pc99_data_offset_array = (UINT32*)malloc(sizeof(*l1_img->pc99_data_offset_array)*totphysrecs);
- if (! l1_img->pc99_data_offset_array)
- return IMGTOOLERR_OUTOFMEMORY;
- reply = parse_pc99_image(file_handle, img_format == if_pc99_fm, 1, NULL, & l1_img->geometry, l1_img->pc99_data_offset_array, &l1_img->pc99_track_len);
- if (reply)
- {
- free(l1_img->pc99_data_offset_array);
- return (imgtoolerr_t)reply;
- }
- }
- }
-
- return (imgtoolerr_t)0;
-}
-
-/*
- Close a disk image at level 1
-
- l1_img (I/O): level-1 image handle
-
- Return imgtool error code
-*/
-static void close_image_lvl1(ti99_lvl1_imgref *l1_img)
-{
- if (l1_img->img_format == if_harddisk)
- {
- imghd_close(&l1_img->harddisk_handle);
- }
-
- stream_close(l1_img->file_handle);
-
- if ((l1_img->img_format == if_pc99_fm) || (l1_img->img_format == if_pc99_mfm))
- free(l1_img->pc99_data_offset_array);
-}
-
-/*
- Convert physical sector address to offset in disk image (old MESS and V9T9
- formats only)
-
- l1_img (I/O): level-1 image handle
- address (I): physical sector address
-
- Return offset in image
-*/
-INLINE int sector_address_to_image_offset(const ti99_lvl1_imgref *l1_img, const ti99_sector_address *address)
-{
- int offset = 0;
-
- switch (l1_img->img_format)
- {
- case if_mess:
- /* old MESS format */
- offset = (((address->cylinder*l1_img->geometry.heads) + address->side)*l1_img->geometry.secspertrack + address->sector)*256;
- break;
-
- case if_v9t9:
- /* V9T9 format */
- if (address->side & 1)
- /* on side 1, tracks are stored in the reverse order */
- offset = (((address->side*l1_img->geometry.cylinders) + (l1_img->geometry.cylinders-1 - address->cylinder))*l1_img->geometry.secspertrack + address->sector)*256;
- else
- offset = (((address->side*l1_img->geometry.cylinders) + address->cylinder)*l1_img->geometry.secspertrack + address->sector)*256;
- break;
-
- case if_pc99_fm:
- case if_pc99_mfm:
- /* pc99 format */
- case if_harddisk:
- /* harddisk format */
- assert(1); /* not implemented */
- break;
- }
-
- return offset;
-}
-
-/*
- Read one 256-byte sector from a disk image
-
- l1_img (I/O): level-1 image handle
- address (I): physical sector address
- dest (O): pointer to 256-byte destination buffer
-
- Return non-zero on error
-*/
-static int read_sector(ti99_lvl1_imgref *l1_img, const ti99_sector_address *address, void *dest)
-{
- int reply;
- UINT32 track_len, track_offset, sector_offset;
-
- switch (l1_img->img_format)
- {
- case if_mess:
- /* old MESS format */
- case if_v9t9:
- /* V9T9 format */
- /* seek to sector */
- reply = stream_seek(l1_img->file_handle, sector_address_to_image_offset(l1_img, address), SEEK_SET);
- if (reply)
- return 1;
- /* read it */
- reply = stream_read(l1_img->file_handle, dest, 256);
- if (reply != 256)
- return 1;
- break;
-
- case if_pc99_fm:
- case if_pc99_mfm:
- /* pc99 format */
- track_len = l1_img->pc99_track_len;
- track_offset = (address->side*l1_img->geometry.cylinders + address->cylinder)*track_len;
- sector_offset = l1_img->pc99_data_offset_array[(address->side*l1_img->geometry.cylinders + address->cylinder)*l1_img->geometry.secspertrack + address->sector];
-
- if ((sector_offset + 256) <= track_len)
- {
- /* seek to sector */
- reply = stream_seek(l1_img->file_handle, track_offset+sector_offset, SEEK_SET);
- if (reply)
- return 1;
- /* read it */
- reply = stream_read(l1_img->file_handle, dest, 256);
- if (reply != 256)
- return 1;
- }
- else
- {
- /* seek to sector */
- reply = stream_seek(l1_img->file_handle, track_offset+sector_offset, SEEK_SET);
- if (reply)
- return 1;
- /* read first chunk (until end of track) */
- reply = stream_read(l1_img->file_handle, (UINT8 *)dest, track_len-sector_offset);
- if (reply != track_len-sector_offset)
- return 1;
-
- /* wrap to start of track */
- reply = stream_seek(l1_img->file_handle, track_offset, SEEK_SET);
- if (reply)
- return 1;
- /* read remnant of sector */
- reply = stream_read(l1_img->file_handle, (UINT8 *)dest + (track_len-sector_offset), 256-(track_len-sector_offset));
- if (reply != 256-(track_len-sector_offset))
- return 1;
- }
- break;
-
- case if_harddisk:
- /* not implemented */
- assert(1);
- /*return imghd_read(l1_img->harddisk_handle, ((address->cylinder*l1_img->geometry.heads) + address->side)*l1_img->geometry.secspertrack + address->sector, 1, dest) != 1;*/
- break;
- }
-
- return 0;
-}
-
-/*
- Write one 256-byte sector to a disk image
-
- l1_img (I/O): level-1 image handle
- address (I): physical sector address
- src (I): pointer to 256-byte source buffer
-
- Return non-zero on error
-*/
-static int write_sector(ti99_lvl1_imgref *l1_img, const ti99_sector_address *address, const void *src)
-{
- int reply;
- UINT32 track_len, track_offset, sector_offset;
-
- switch (l1_img->img_format)
- {
- case if_mess:
- /* old MESS format */
- case if_v9t9:
- /* V9T9 format */
- /* seek to sector */
- reply = stream_seek(l1_img->file_handle, sector_address_to_image_offset(l1_img, address), SEEK_SET);
- if (reply)
- return 1;
- /* write it */
- reply = stream_write(l1_img->file_handle, src, 256);
- if (reply != 256)
- return 1;
- break;
-
- case if_pc99_fm:
- case if_pc99_mfm:
- /* pc99 format */
- track_len = l1_img->pc99_track_len;
- track_offset = (address->side*l1_img->geometry.cylinders + address->cylinder)*track_len;
- sector_offset = l1_img->pc99_data_offset_array[(address->side*l1_img->geometry.cylinders + address->cylinder)*l1_img->geometry.secspertrack + address->sector];
-
- if ((sector_offset + 256) <= track_len)
- {
- /* seek to sector */
- reply = stream_seek(l1_img->file_handle, track_offset+sector_offset, SEEK_SET);
- if (reply)
- return 1;
- /* write it */
- reply = stream_write(l1_img->file_handle, src, 256);
- if (reply != 256)
- return 1;
- }
- else
- {
- /* seek to sector */
- reply = stream_seek(l1_img->file_handle, track_offset+sector_offset, SEEK_SET);
- if (reply)
- return 1;
- /* write first chunk (until end of track) */
- reply = stream_write(l1_img->file_handle, (UINT8 *)src, track_len-sector_offset);
- if (reply != track_len-sector_offset)
- return 1;
-
- /* wrap to start of track */
- reply = stream_seek(l1_img->file_handle, track_offset, SEEK_SET);
- if (reply)
- return 1;
- /* write remnant of sector */
- reply = stream_write(l1_img->file_handle, (UINT8 *)src + (track_len-sector_offset), 256-(track_len-sector_offset));
- if (reply != 256-(track_len-sector_offset))
- return 1;
- }
- break;
-
- case if_harddisk:
- /* not implemented */
- assert(1);
- /*return imghd_write(l1_img->harddisk_handle, ((address->cylinder*l1_img->geometry.heads) + address->side)*l1_img->geometry.secspertrack + address->sector, 1, src) != 1;*/
- break;
- }
-
- return 0;
-}
-
-/*
- Convert physical record address to sector address (DSK format)
-
- aphysrec (I): absolute physrec address
- geometry (I): disk image geometry
- address (O): physical sector address
-*/
-static void dsk_aphysrec_to_sector_address(int aphysrec, const ti99_geometry *geometry, ti99_sector_address *address)
-{
- address->sector = aphysrec % geometry->secspertrack;
- aphysrec /= geometry->secspertrack;
- address->cylinder = aphysrec % geometry->cylinders;
- address->side = aphysrec / geometry->cylinders;
- if (address->side & 1)
- /* on side 1, tracks are stored in the reverse order */
- address->cylinder = geometry->cylinders-1 - address->cylinder;
-}
-
-/*
- Convert physical record address to sector address (WIN format for HFDC)
-
- Note that physical address translation makes sense for HFDC, but not SCSI.
-
- aphysrec (I): absolute physrec address
- geometry (I): disk image geometry
- address (O): physical sector address
-*/
-#ifdef UNUSED_FUNCTION
-static void win_aphysrec_to_sector_address(int aphysrec, const ti99_geometry *geometry, ti99_sector_address *address)
-{
- address.sector = aphysrec % l1_img->geometry.secspertrack;
- aphysrec /= l1_img->geometry.secspertrack;
- address.side = aphysrec % l1_img->geometry.heads;
- address.cylinder = aphysrec / l1_img->geometry.heads;
-}
-#endif
-
-/*
- Read one 256-byte physical record from a disk image
-
- l1_img (I/O): level-1 image handle
- aphysrec (I): absolute physrec address
- dest (O): pointer to 256-byte destination buffer
-
- Return non-zero on error
-*/
-static int read_absolute_physrec(ti99_lvl1_imgref *l1_img, unsigned aphysrec, void *dest)
-{
- ti99_sector_address address;
-
-
- if (l1_img->img_format == if_harddisk)
- {
-#if 0
- win_aphysrec_to_sector_address(aphysrec, & l1_img->geometry, & address);
- return read_sector(l1_img, & address, dest);
-#endif
-
- return imghd_read(&l1_img->harddisk_handle, aphysrec, dest) != IMGTOOLERR_SUCCESS;
- }
- else
- {
- dsk_aphysrec_to_sector_address(aphysrec, & l1_img->geometry, & address);
-
- return read_sector(l1_img, & address, dest);
- }
-}
-
-/*
- Write one 256-byte physical record to a disk image
-
- l1_img (I/O): level-1 image handle
- aphysrec (I): absolute physrec address
- src (I): pointer to 256-byte source buffer
-
- Return non-zero on error
-*/
-static int write_absolute_physrec(ti99_lvl1_imgref *l1_img, unsigned aphysrec, const void *src)
-{
- ti99_sector_address address;
-
-
- if (l1_img->img_format == if_harddisk)
- {
-#if 0
- win_aphysrec_to_sector_address(aphysrec, & l1_img->geometry, & address);
- return write_sector(l1_img, & address, dest);
-#endif
-
- return imghd_write(&l1_img->harddisk_handle, aphysrec, src) != IMGTOOLERR_SUCCESS;
- }
- else
- {
- dsk_aphysrec_to_sector_address(aphysrec, & l1_img->geometry, & address);
-
- return write_sector(l1_img, & address, src);
- }
-}
-
-#if 0
-#pragma mark -
-#pragma mark LEVEL 2 DISK ROUTINES
-#endif
-
-/*
- Level 2 implements files as a succession of 256-byte-long physical records.
-
- Level 2 implements allocation bitmap (and AU), disk catalog, etc.
-*/
-
-/*
- WIN VIB/DDR record
-*/
-struct win_vib_ddr
-{
- char name[10]; /* disk volume name (10 characters, pad with spaces) */
- UINT16BE totAUs; /* total number of AUs */
- UINT8 secspertrack; /* HFDC: sectors per track (typically 32) */
- /* SCSI: reserved */
- union
- {
- struct
- {
- UINT8 id[3]; /* V1 VIB: 'WIN' */
- } vib_v1;
-
- struct /* V2 VIB: extra params */
- {
- UINT8 res_AUs; /* # AUs reserved for vib, bitmap, ddr, fdir and fdr, divided by 64 */
- UINT8 step_spd; /* HFDC: step speed (0-7) */
- /* SCSI: reserved */
- UINT8 red_w_cur;/* HFDC: reduced write current cylinder, divided by 8 */
- /* SCSI: reserved */
- } vib_v2;
-
- struct
- {
- UINT8 id[3]; /* DDR: 'DIR' */
- } ddr;
- } u;
- UINT16BE params; /* bits 0-3: sectors/AU - 1 */
- /* HFDC: */
- /* bits 4-7: # heads - 1 */
- /* bit 8: V1: buffered head stepping flag */
- /* V2: reserved */
- /* bit 9-15: write precompensation track, divided by 16 */
- /* SCSI: */
- /* bits 4-15: reserved */
- ti99_date_time creation;/* date and time of creation */
- UINT8 num_files; /* number of files in directory */
- UINT8 num_subdirs; /* number of subdirectories in directory */
- UINT16BE fdir_AU; /* points to root directory fdir */
- union
- {
- struct
- {
- UINT16BE dsk1_AU; /* HFDC: points to current dsk1 emulation image (0 if none) */
- /* SCSI: reserved */
- } vib;
-
- struct
- {
- UINT16BE parent_ddr_AU; /* points to parent directory DDR */
- } ddr;
- } u2;
- UINT16BE subdir_AU[114];/* points to all subdirectory DDRs */
-};
-
-/*
- AU format
-*/
-struct ti99_AUformat
-{
- int totAUs; /* total number of AUs */
- int physrecsperAU; /* number of 256-byte physical records per AU */
-};
-
-/*
- DSK directory reference: 0 for root, 1 for 1st subdir, 2 for 2nd subdir, 3
- for 3rd subdir
-*/
-/*typedef int dir_ref;*/
-
-/*
- catalog entry (used for in-memory catalog)
-*/
-struct dir_entry
-{
- UINT16 dir_ptr; /* DSK: unused */
- /* WIN: AU address of the DDR for this directory */
- char name[10]; /* name of this directory (copied from the VIB for DSK, DDR for WIN) */
-};
-
-struct file_entry
-{
- UINT16 fdr_ptr; /* DSK: aphysrec address of the FDR for this file */
- /* WIN: AU address of the FDR for this file */
- char name[10]; /* name of this file (copied from FDR) */
-};
-
-struct ti99_catalog
-{
- int num_subdirs; /* number of subdirectories */
- int num_files; /* number of files */
- dir_entry subdirs[114]; /* description of each subdir */
- file_entry files[128]; /* description of each file */
-};
-
-/*
- level-2 disk image descriptor
-*/
-struct ti99_lvl2_imgref_dsk
-{
- UINT16 totphysrecs; /* total number of aphysrecs (extracted from vib record in aphysrec 0) */
- ti99_catalog catalogs[4]; /* catalog of root directory and up to 3 subdirectories */
- UINT16 fdir_aphysrec[4]; /* fdir aphysrec address for root directory
- and up to 3 subdirectories */
-};
-
-enum win_vib_t
-{
- win_vib_v1,
- win_vib_v2
-};
-struct ti99_lvl2_imgref_win
-{
- win_vib_t vib_version; /* version of the vib record in aphysrec 0 (see win_vib_ddr) */
-};
-
-enum l2i_t
-{
- L2I_DSK,
- L2I_WIN
-};
-
-struct ti99_lvl2_imgref
-{
- ti99_lvl1_imgref l1_img;/* image format, imgtool image handle, image geometry */
- ti99_AUformat AUformat; /* AU format */
- int data_offset; /* In order to reduce seek times when searching the
- disk for a given file name, fdr (and ddr, and
- fdir) records are preferentially allocated in
- AUs n to data_offset, whereas data records are
- preferentially allocated in AUs starting at
- data_offset. */
- /* With the DSK disk structure, n is always 2 (if 1
- physrec per AU) or 1 (if 2 physrecs per AU or
- more), and data_offset is arbitrarily chosen as
- 34. */
- /* With the WIN disk structure, n depends on the
- size of the volume bitmap, which itself depends
- on the number of AUs on disk (we always have n
- <= 33), and data_offset is read from the vib
- record (except with the obsolete v1 VIB, where
- we use a default value of 64). */
- char vol_name[10]; /* cached volume name (extracted from vib record in aphysrec 0) */
-
- UINT8 abm[8192]; /* allocation bitmap */
-
- l2i_t type; /* structure format */
-
- union
- {
- ti99_lvl2_imgref_dsk dsk;
- ti99_lvl2_imgref_win win;
- }; /* structure-specific info */
-};
-
-/*
- file flags found in fdr (and tifiles)
-*/
-enum
-{
- fdr99_f_program = 0x01, /* set for program files */
- fdr99_f_int = 0x02, /* set for binary files */
- fdr99_f_wp = 0x08, /* set if file is write-protected */
- /*fdr99_f_backup = 0x10,*/ /* set if file has been modified since last backup */
- /*fdr99_f_dskimg = 0x20,*/ /* set if file is a DSK image (HFDC HD only) */
- fdr99_f_var = 0x80 /* set if file uses variable-length records*/
-};
-
-/*
- DSK FDR record
-*/
-struct dsk_fdr
-{
- char name[10]; /* file name (10 characters, pad with spaces) */
- UINT16BE xreclen; /* extended record len: if record len is >= 256, */
- /* reclen is set to 0 and the actual reclen is */
- /* stored here (Myarc HFDC only). TI reserved */
- /* this field for data chain pointer extension, */
- /* but this was never implemented. */
- UINT8 flags; /* file status flags (see enum above) */
- UINT8 recsperphysrec; /* logical records per physrec */
- /* ignored for variable length record files and */
- /* program files */
- UINT16BE fphysrecs; /* file length in physrecs */
- /* Note that the HFDC defines this field as the */
- /* number of allocated physrecs in the cluster */
- /* chain (i.e. rounded on the next AU */
- /* boundary), so level-3 routines should use */
- /* the fixrecs field instead to determine the */
- /* logical length of field. IIRC, the HFDC */
- /* implementation is regarded as a bug because */
- /* program files do not define the fixrecs field */
- /* field, so program field saved by the HFDC */
- /* DSR may be larger whan they should. */
- UINT8 eof; /* EOF offset in last physrec for variable length */
- /* record files and program files (0->256)*/
- UINT8 reclen; /* logical record size in bytes ([1,255] 0->256) */
- /* Maximum allowable record size for variable */
- /* length record files. Reserved for program */
- /* files (set to 0). Set to 0 if reclen >=256 */
- /* (HFDC only). */
- UINT16LE fixrecs; /* file length in logical records */
- /* For variable length record files, number of */
- /* 256-byte records actually used. */
- ti99_date_time creation;/* date and time of creation (HFDC and BwG only; */
- /* reserved in TI) */
- ti99_date_time update; /* date and time of last write to file (HFDC and */
- /* BwG only; reserved in TI) */
- UINT8 clusters[76][3]; /* data cluster table: 0 through 76 entries (3 */
- /* bytes each), one entry for each file cluster. */
- /* 12 bits: address of first AU of cluster */
- /* 12 bits: offset of last 256-byte record in cluster */
-};
-
-/*
- WIN FDR record
-*/
-struct win_fdr
-{
- char name[10]; /* file name (10 characters, pad with spaces) */
- UINT16BE xreclen; /* extended record len: if record len is >= 256, */
- /* reclen is set to 0 and the actual reclen is */
- /* stored here (Myarc HFDC only). TI reserved */
- /* this field for data chain pointer extension, */
- /* but this was never implemented. */
- UINT8 flags; /* file status flags (see enum above) */
- UINT8 recsperphysrec; /* logical records per physrec */
- /* ignored for variable length record files and */
- /* program files */
- UINT16BE fphysrecs_LSW; /* eldest FDR: file length in physrecs */
- /* Note that the HFDC defines this field as the */
- /* number of allocated physrecs in the cluster */
- /* chain (i.e. rounded on the next AU */
- /* boundary), so level-3 routines should use */
- /* the fixrecs field instead to determine the */
- /* logical length of field. IIRC, the HFDC */
- /* implementation is regarded as a bug because */
- /* program files do not define the fixrecs field */
- /* field, so program field saved by the HFDC */
- /* DSR may be larger whan they should. */
- /* other sibling FDRs: index of the first file */
- /* physrec in this particular sibling FDR */
- UINT8 eof; /* EOF offset in last physrec for variable length */
- /* record files and program files (0->256)*/
- UINT8 reclen; /* logical record size in bytes ([1,255]) */
- /* Maximum allowable record size for variable */
- /* length record files. Reserved for program */
- /* files (set to 0). Set to 0 if reclen >=256 */
- /* (HFDC only). */
- UINT16LE fixrecs_LSW; /* file length in logical records */
- /* For variable length record files, number of */
- /* 256-byte records actually used. */
- ti99_date_time creation;/* date and time of creation */
- ti99_date_time update; /* date and time of last write to file */
-
- char id[2]; /* 'FI' */
- UINT16BE prevsibFDR_AU; /* address of the AU where previous sibling FDR is */
- /* (see also xinfo_LSB) */
- UINT16BE nextsibFDR_AU; /* address of the AU where next sibling FDR is */
- /* (see also xinfo_LSB) */
- UINT16BE sibFDR_AUlen; /* total number of data AUs allocated in this particular sibling FDR */
- UINT16BE parent_FDIR_AU;/* FDIR the file is listed in */
- UINT8 xinfo_MSB; /* extended information (MSByte) */
- /* bits 0-3: MSN of fphysrecs */
- /* bits 4-7: MSN of fixrecs */
- UINT8 xinfo_LSB; /* extended information (LSByte) */
- /* bits 8-11: physrec offset within AU for */
- /* previous sibling FDR (see prevsibFDR_AU) */
- /* bits 12-15: physrec offset within AU for */
- /* next sibling FDR (see nextsibFDR_AU) */
- UINT16BE clusters[54][2];/* data cluster table: 0 through 54 entries (4 */
- /* bytes each), one entry for each file cluster. */
- /* 16 bits: address of first AU of cluster */
- /* 16 bits: address of last AU of cluster */
-};
-
-/*
- tifile header: stand-alone file
-*/
-struct tifile_header
-{
- char tifiles[8]; /* always '\7TIFILES' */
- UINT16BE fphysrecs; /* file length in physrecs */
- UINT8 flags; /* see enum above */
- UINT8 recsperphysrec; /* records per physrec */
- UINT8 eof; /* current position of eof in last physrec (0->255)*/
- UINT8 reclen; /* bytes per record ([1,255] 0->256) */
- UINT16BE fixrecs; /* file length in records */
- UINT8 res[128-16]; /* reserved */
- /* * variant a: */
- /* 112 chars: 0xCA53 repeated 56 times */
- /* * variant b: */
- /* 4 chars: unknown */
- /* 108 chars: 0xCA53 repeated 54 times */
- /* * variant c: */
- /* 10 chars: original TI file name filed with spaces */
- /* 102 chars: spaces */
- /* * variant d: */
- /* 10 chars: original TI file name filed with spaces */
- /* 2 chars: CR+LF */
- /* 98 chars: spaces */
- /* 2 chars: CR+LF */
- /* * variant e: */
- /* 10 chars: original TI file name */
- /* 4 bytes: unknown */
- /* 4 bytes: time & date of creation */
- /* 4 bytes: time & date of last update */
- /* 90 chars: spaces */
- /* * variant f: */
- /* 6 bytes: 'MYTERM' */
- /* 4 bytes: time & date of creation */
- /* 4 bytes: time & date of last update */
- /* 2 bytes: unknown (always >0000) */
- /* 96 chars: 0xCA53 repeated 56 times */
-};
-
-/*
- level-2 file descriptor
-*/
-struct ti99_lvl2_fileref_dsk
-{
- struct ti99_lvl2_imgref *l2_img;
- int fdr_aphysrec;
- dsk_fdr fdr;
-};
-
-struct ti99_lvl2_fileref_win
-{
- struct ti99_lvl2_imgref *l2_img;
- unsigned fphysrecs; /* copy of field in the eldest FDR */
- unsigned eldestfdr_aphysrec; /* aphysrec address of the eldest FDR */
- unsigned curfdr_aphysrec; /* aphysrec address of the currently open sibling FDR */
- win_fdr curfdr; /* buffer with currently open sibling FDR */
-};
-
-struct ti99_lvl2_fileref_tifiles
-{
- imgtool_stream *file_handle;
- tifile_header hdr;
-};
-
-enum l2f_type_t
-{
- L2F_DSK,
- L2F_WIN,
- L2F_TIFILES
-};
-
-struct ti99_lvl2_fileref
-{
- l2f_type_t type;
- union
- {
- ti99_lvl2_fileref_dsk dsk;
- ti99_lvl2_fileref_win win;
- ti99_lvl2_fileref_tifiles tifiles;
- };
-};
-
-/*
- Compare two (possibly empty) catalog entry for qsort
-*/
-static int cat_file_compare_qsort(const void *p1, const void *p2)
-{
- const file_entry *entry1 = (const file_entry *)p1;
- const file_entry *entry2 = (const file_entry *)p2;
-
- if ((entry1->fdr_ptr == 0) && (entry2->fdr_ptr == 0))
- return 0;
- else if (entry1->fdr_ptr == 0)
- return +1;
- else if (entry2->fdr_ptr == 0)
- return -1;
- else
- return memcmp(entry1->name, entry2->name, 10);
-}
-
-static int cat_dir_compare_qsort(const void *p1, const void *p2)
-{
- const dir_entry *entry1 = (const dir_entry *)p1;
- const dir_entry *entry2 = (const dir_entry *)p2;
-
- if ((entry1->dir_ptr == 0) && (entry2->dir_ptr == 0))
- return 0;
- else if (entry1->dir_ptr == 0)
- return +1;
- else if (entry2->dir_ptr == 0)
- return -1;
- else
- return memcmp(entry1->name, entry2->name, 10);
-}
-
-/*
- Read a directory catalog from disk image
-
- l2_img: image reference
- aphysrec: physical record address of the FDIR
- dest: pointer to the destination buffer where the catalog should be written
-
- Return an error code if there was an error, 0 otherwise.
-*/
-static int dsk_read_catalog(struct ti99_lvl2_imgref *l2_img, int aphysrec, ti99_catalog *dest)
-{
- int totphysrecs = l2_img->dsk.totphysrecs;
- UINT16BE fdir_buf[128];
- dsk_fdr fdr;
- int i;
- int reply;
-
-
- /* Read FDIR record */
- reply = read_absolute_physrec(& l2_img->l1_img, aphysrec, fdir_buf);
- if (reply)
- return IMGTOOLERR_READERROR;
-
- /* Copy FDIR info to catalog structure */
- for (i=0; i<128; i++)
- dest->files[i].fdr_ptr = get_UINT16BE(fdir_buf[i]);
-
- /* Check FDIR pointers and check and extract file names from DDRs */
- for (i=0; i<128; i++)
- {
- if (dest->files[i].fdr_ptr >= totphysrecs)
- {
- return IMGTOOLERR_CORRUPTIMAGE;
- }
- else if (dest->files[i].fdr_ptr)
- {
- reply = read_absolute_physrec(& l2_img->l1_img, dest->files[i].fdr_ptr, &fdr);
- if (reply)
- return IMGTOOLERR_READERROR;
-
- /* check and copy file name */
- if (check_fname(fdr.name))
- return IMGTOOLERR_CORRUPTIMAGE;
- memcpy(dest->files[i].name, fdr.name, 10);
- }
- }
-
- /* Check catalog */
- for (i=0; i<127; i++)
- {
- if (((! dest->files[i].fdr_ptr) && dest->files[i+1].fdr_ptr)
- || ((dest->files[i].fdr_ptr && dest->files[i+1].fdr_ptr) && (memcmp(dest->files[i].name, dest->files[i+1].name, 10) >= 0)))
- {
- /* if the catalog is not sorted, we repair it */
- qsort(dest->files, ARRAY_LENGTH(dest->files), sizeof(dest->files[0]),
- cat_file_compare_qsort);
- break;
- }
- }
-
- /* Set file count */
- for (i=0; (i<128) && (dest->files[i].fdr_ptr != 0); i++)
- ;
- dest->num_files = i;
-
- /* Set subdir count to 0 (subdirs are loaded elsewhere) */
- dest->num_subdirs = 0;
-
- return 0;
-}
-
-/*
- Read a directory catalog from disk image
-
- l2_img: image reference
- DDR_AU: AU address of the VIB/DDR
- dest: pointer to the destination buffer where the catalog should be written
-
- Return an error code if there was an error, 0 otherwise.
-*/
-static int win_read_catalog(struct ti99_lvl2_imgref *l2_img, int DDR_AU, ti99_catalog *dest)
-{
- win_vib_ddr ddr_buf;
- UINT16BE fdir_buf[128];
- win_fdr fdr_buf;
- int i;
- int reply;
-
-
- /* Read DDR record */
- reply = read_absolute_physrec(& l2_img->l1_img, DDR_AU*l2_img->AUformat.physrecsperAU, &ddr_buf);
- if (reply)
- return IMGTOOLERR_READERROR;
-
- /* sanity checks */
- if ((ddr_buf.num_files > 127) || (ddr_buf.num_subdirs > 114) || (get_UINT16BE(ddr_buf.fdir_AU) > l2_img->AUformat.totAUs))
- return IMGTOOLERR_CORRUPTIMAGE;
-
- /* set file count and subdir count */
- dest->num_files = ddr_buf.num_files;
- dest->num_subdirs = ddr_buf.num_subdirs;
-
- /* Copy DDR info to catalog structure */
- for (i=0; i<ddr_buf.num_subdirs; i++)
- dest->subdirs[i].dir_ptr = get_UINT16BE(ddr_buf.subdir_AU[i]);
-
- /* Read FDIR record */
- reply = read_absolute_physrec(& l2_img->l1_img, get_UINT16BE(ddr_buf.fdir_AU)*l2_img->AUformat.physrecsperAU, fdir_buf);
- if (reply)
- return IMGTOOLERR_READERROR;
-
- /* Copy FDIR info to catalog structure */
- for (i=0; i<dest->num_files; i++)
- dest->files[i].fdr_ptr = get_UINT16BE(fdir_buf[i]);
-
- /* Check DDR pointers and check and extract file names from FDRs */
- for (i=0; i<dest->num_subdirs; i++)
- {
- if (dest->subdirs[i].dir_ptr >= l2_img->AUformat.totAUs)
- {
- return IMGTOOLERR_CORRUPTIMAGE;
- }
- else if (dest->subdirs[i].dir_ptr)
- {
- reply = read_absolute_physrec(& l2_img->l1_img, dest->subdirs[i].dir_ptr*l2_img->AUformat.physrecsperAU, &ddr_buf);
- if (reply)
- return IMGTOOLERR_READERROR;
-
- /* check and copy file name */
- if (check_fname(ddr_buf.name))
- return IMGTOOLERR_CORRUPTIMAGE;
- memcpy(dest->subdirs[i].name, ddr_buf.name, 10);
- }
- }
-
- /* Check FDIR pointers and check and extract file names from FDRs */
- for (i=0; i<dest->num_files; i++)
- {
- if (dest->files[i].fdr_ptr >= l2_img->AUformat.totAUs)
- {
- return IMGTOOLERR_CORRUPTIMAGE;
- }
- else if (dest->files[i].fdr_ptr)
- {
- reply = read_absolute_physrec(& l2_img->l1_img, dest->files[i].fdr_ptr*l2_img->AUformat.physrecsperAU, &fdr_buf);
- if (reply)
- return IMGTOOLERR_READERROR;
-
- /* check and copy file name */
- if (check_fname(fdr_buf.name))
- return IMGTOOLERR_CORRUPTIMAGE;
- memcpy(dest->files[i].name, fdr_buf.name, 10);
- }
- }
-
- /* Check catalog */
-
- /* Check subdir order */
- for (i=0; i<dest->num_subdirs-1; i++)
- {
- if (((! dest->subdirs[i].dir_ptr) && dest->subdirs[i+1].dir_ptr)
- || ((dest->subdirs[i].dir_ptr && dest->subdirs[i+1].dir_ptr) && (memcmp(dest->subdirs[i].name, dest->subdirs[i+1].name, 10) >= 0)))
- {
- /* if the subdir catalog is not sorted, we repair it */
- qsort(dest->subdirs, dest->num_subdirs, sizeof(dest->subdirs[0]), cat_dir_compare_qsort);
- break;
- }
- }
-
- /* Fix subdir count */
- while (dest->num_subdirs && (dest->subdirs[dest->num_subdirs-1].dir_ptr == 0))
- dest->num_subdirs--;
-
- /* Check file order */
- for (i=0; i<dest->num_files-1; i++)
- {
- if (((! dest->files[i].fdr_ptr) && dest->files[i+1].fdr_ptr)
- || ((dest->files[i].fdr_ptr && dest->files[i+1].fdr_ptr) && (memcmp(dest->files[i].name, dest->files[i+1].name, 10) >= 0)))
- {
- /* if the file catalog is not sorted, we repair it */
- qsort(dest->files, dest->num_files, sizeof(dest->files[0]), cat_file_compare_qsort);
- break;
- }
- }
-
- /* Fix file count */
- while (dest->num_files && (dest->files[dest->num_files-1].fdr_ptr == 0))
- dest->num_files--;
-
- return 0;
-}
-
-/*
- Search for a file path on a floppy image
-
- l2_img: image reference
- fpath: path of the file to search
- parent_ref_valid: set to TRUE if either the file was found or the file was
- not found but its parent dir was
- parent_ref: reference to parent dir (0 for root)
- out_is_dir: TRUE if element is a directory
- catalog_index: on output, index of file catalog entry (may be NULL)
-*/
-static int dsk_find_catalog_entry(struct ti99_lvl2_imgref *l2_img, const char *fpath, int *parent_ref_valid, int *parent_ref, int *out_is_dir, int *catalog_index)
-{
- int i;
- const ti99_catalog *cur_catalog;
- const char *element_start, *element_end;
- int element_len;
- char element[10];
- int is_dir = FALSE;
-
-
- cur_catalog = & l2_img->dsk.catalogs[0];
- if (parent_ref_valid)
- (* parent_ref_valid) = FALSE;
- if (parent_ref)
- *parent_ref = 0;
-
- element_start = fpath;
- do
- {
- /* find next path element */
- element_end = strchr(element_start, '.');
- element_len = element_end ? (element_end - element_start) : strlen(element_start);
- if ((element_len > 10) || (element_len == 0))
- return IMGTOOLERR_BADFILENAME;
- /* last path element */
- if ((!element_end) && parent_ref_valid)
- (* parent_ref_valid) = TRUE;
-
- /* generate file name */
- memcpy(element, element_start, element_len);
- memset(element+element_len, ' ', 10-element_len);
-
- /* search entry in subdirectories */
- for (i = 0; i<cur_catalog->num_subdirs; i++)
- {
- if (! memcmp(element, cur_catalog->subdirs[i].name, 10))
- {
- is_dir = TRUE;
- break;
- }
- }
-
- /* if it failed, search entry in files */
- if (i == cur_catalog->num_subdirs)
- {
- for (i = 0; i<cur_catalog->num_files; i++)
- {
- if (! memcmp(element, cur_catalog->files[i].name, 10))
- {
- is_dir = FALSE;
- break;
- }
- }
- /* exit if not found */
- if (i == cur_catalog->num_files)
- {
- return IMGTOOLERR_FILENOTFOUND;
- }
- }
-
- /* iterate */
- if (element_end)
- {
- element_start = element_end+1;
-
- if (! is_dir)
- /* this is not a directory */
- return IMGTOOLERR_BADFILENAME;
-
- /* initialize cur_catalog */
- cur_catalog = & l2_img->dsk.catalogs[i+1];
- if (parent_ref)
- *parent_ref = i+1;
- }
- else
- element_start = NULL;
- }
- while (element_start);
-
- if (out_is_dir)
- *out_is_dir = is_dir;
-
- if (catalog_index)
- *catalog_index = i;
-
- return 0;
-}
-
-/*
- Search for a file path on a harddisk image
-
- l2_img: image reference
- fpath: path of the file to search
- parent_ref_valid: set to TRUE if either the file was found or the file was
- not found but its parent dir was
- parent_ddr_AU: parent DDR AU address (0 for root)
- parent_catalog: catalog of parent dir (cannot be NULL)
- out_is_dir: TRUE if element is a directory
- catalog_index: on output, index of file catalog entry (may be NULL)
-*/
-static int win_find_catalog_entry(struct ti99_lvl2_imgref *l2_img, const char *fpath,
- int *parent_ref_valid, int *parent_ddr_AU, ti99_catalog *parent_catalog,
- int *out_is_dir, int *catalog_index)
-{
- int i;
- const char *element_start, *element_end;
- int element_len;
- char element[10];
- int is_dir = FALSE;
- int errorcode;
-
- if (parent_ref_valid)
- (* parent_ref_valid) = FALSE;
- if (parent_ddr_AU)
- *parent_ddr_AU = 0;
-
- errorcode = win_read_catalog(l2_img, 0, parent_catalog);
- if (errorcode)
- return errorcode;
-
- element_start = fpath;
- do
- {
- /* find next path element */
- element_end = strchr(element_start, '.');
- element_len = element_end ? (element_end - element_start) : strlen(element_start);
- if ((element_len > 10) || (element_len == 0))
- return IMGTOOLERR_BADFILENAME;
- /* last path element */
- if ((!element_end) && parent_ref_valid)
- (* parent_ref_valid) = TRUE;
-
- /* generate file name */
- memcpy(element, element_start, element_len);
- memset(element+element_len, ' ', 10-element_len);
-
- /* search entry in subdirectories */
- for (i = 0; i<parent_catalog->num_subdirs; i++)
- {
- if (! memcmp(element, parent_catalog->subdirs[i].name, 10))
- {
- is_dir = TRUE;
- break;
- }
- }
-
- /* if it failed, search entry in files */
- if (i == parent_catalog->num_subdirs)
- {
- for (i = 0; i<parent_catalog->num_files; i++)
- {
- if (! memcmp(element, parent_catalog->files[i].name, 10))
- {
- is_dir = FALSE;
- break;
- }
- }
- /* exit if not found */
- if (i == parent_catalog->num_files)
- {
- return IMGTOOLERR_FILENOTFOUND;
- }
- }
-
- /* iterate */
- if (element_end)
- {
- element_start = element_end+1;
-
- if (! is_dir)
- /* this is not a directory */
- return IMGTOOLERR_BADFILENAME;
-
- if (parent_ddr_AU)
- *parent_ddr_AU = parent_catalog->subdirs[i].dir_ptr;
-
- errorcode = win_read_catalog(l2_img, parent_catalog->subdirs[i].dir_ptr, parent_catalog);
- if (errorcode)
- return errorcode;
- }
- else
- element_start = NULL;
- }
- while (element_start);
-
- if (out_is_dir)
- *out_is_dir = is_dir;
-
- if (catalog_index)
- *catalog_index = i;
-
- return 0;
-}
-
-/*
- Allocate one AU on disk, for use as a fdr record
-
- l2_img: image reference
- fdr_AU: on output, address of allocated AU
-*/
-static int alloc_fdr_AU(struct ti99_lvl2_imgref *l2_img, unsigned *fdr_AU)
-{
- int totAUs = l2_img->AUformat.totAUs;
- int i;
-
- for (i=0; i<totAUs; i++)
- {
- if (! (l2_img->abm[i >> 3] & (1 << (i & 7))))
- {
- *fdr_AU = i;
- l2_img->abm[i >> 3] |= 1 << (i & 7);
-
- return 0;
- }
- }
-
- return IMGTOOLERR_NOSPACE;
-}
-
-INLINE int get_dsk_fdr_cluster_baseAU(struct ti99_lvl2_imgref *l2_img, dsk_fdr *fdr, int cluster_index)
-{
- int reply;
-
- /* read base AU/physrec for this cluster */
- reply = ((fdr->clusters[cluster_index][1] & 0xf) << 8) | fdr->clusters[cluster_index][0];
- /* convert to AU address */
- if (l2_img->AUformat.physrecsperAU <= 2)
- reply /= l2_img->AUformat.physrecsperAU;
-
- return reply;
-}
-
-INLINE int get_dsk_fdr_cluster_baseaphysrec(struct ti99_lvl2_imgref *l2_img, dsk_fdr *fdr, int cluster_index)
-{
- int reply;
-
- /* read base AU/physrec for this cluster */
- reply = ((fdr->clusters[cluster_index][1] & 0xf) << 8) | fdr->clusters[cluster_index][0];
- /* convert to physrec address */
- if (l2_img->AUformat.physrecsperAU > 2)
- reply *= l2_img->AUformat.physrecsperAU;
-
- return reply;
-}
-
-INLINE int get_dsk_fdr_cluster_lastfphysrec(dsk_fdr *fdr, int cluster_index)
-{
- return (fdr->clusters[cluster_index][2] << 4) | (fdr->clusters[cluster_index][1] >> 4);
-}
-
-INLINE void set_dsk_fdr_cluster_lastfphysrec(dsk_fdr *fdr, int cluster_index, int data)
-{
- fdr->clusters[cluster_index][1] = (fdr->clusters[cluster_index][1] & 0x0f) | (data << 4);
- fdr->clusters[cluster_index][2] = data >> 4;
-}
-
-INLINE void set_dsk_fdr_cluster(struct ti99_lvl2_imgref *l2_img, dsk_fdr *fdr, int cluster_index, int baseAU, int lastfphysrec)
-{
- /* convert AU address to FDR value */
- if (l2_img->AUformat.physrecsperAU <= 2)
- baseAU *= l2_img->AUformat.physrecsperAU;
-
- /* write cluster entry */
- fdr->clusters[cluster_index][0] = baseAU;
- fdr->clusters[cluster_index][1] = ((baseAU >> 8) & 0x0f) | (lastfphysrec << 4);
- fdr->clusters[cluster_index][2] = lastfphysrec >> 4;
-}
-
-INLINE unsigned get_win_fdr_fphysrecs(win_fdr *fdr)
-{
- return (((unsigned) fdr->xinfo_MSB << 12) & 0xf0000) | get_UINT16BE(fdr->fphysrecs_LSW);
-}
-
-INLINE void set_win_fdr_fphysrecs(win_fdr *fdr, unsigned data)
-{
- fdr->xinfo_MSB = (fdr->xinfo_MSB & 0x0f) | ((data >> 12) & 0xf0);
- set_UINT16BE(&fdr->fphysrecs_LSW, data & 0xffff);
-}
-
-INLINE unsigned get_win_fdr_fixrecs(win_fdr *fdr)
-{
- return (((unsigned) fdr->xinfo_MSB << 16) & 0xf0000) | get_UINT16LE(fdr->fixrecs_LSW);
-}
-
-INLINE void set_win_fdr_fixrecs(win_fdr *fdr, unsigned data)
-{
- fdr->xinfo_MSB = (fdr->xinfo_MSB & 0xf0) | ((data >> 16) & 0x0f);
- set_UINT16LE(&fdr->fixrecs_LSW, data & 0xffff);
-}
-
-INLINE unsigned get_win_fdr_prevsibFDR_aphysrec(struct ti99_lvl2_imgref *l2_img, win_fdr *fdr)
-{
- unsigned prevsibFDR_AU = get_UINT16BE(fdr->prevsibFDR_AU);
-
- return prevsibFDR_AU
- ? (prevsibFDR_AU * l2_img->AUformat.physrecsperAU + ((fdr->xinfo_LSB >> 4) & 0xf))
- : 0;
-}
-
-INLINE unsigned get_win_fdr_nextsibFDR_aphysrec(struct ti99_lvl2_imgref *l2_img, win_fdr *fdr)
-{
- unsigned nextsibFDR_AU = get_UINT16BE(fdr->nextsibFDR_AU);
-
- return nextsibFDR_AU
- ? (nextsibFDR_AU * l2_img->AUformat.physrecsperAU + (fdr->xinfo_LSB & 0xf))
- : 0;
-}
-
-INLINE unsigned get_win_fdr_cursibFDR_basefphysrec(win_fdr *fdr)
-{
- return get_UINT16BE(fdr->prevsibFDR_AU) ? get_win_fdr_fphysrecs(fdr) : 0;
-}
-
-/*
- Advance to next sibling FDR
-*/
-static int win_goto_next_sibFDR(ti99_lvl2_fileref_win *win_file)
-{
- if (get_UINT16BE(win_file->curfdr.nextsibFDR_AU) == 0)
- return IMGTOOLERR_UNEXPECTED;
-
- win_file->curfdr_aphysrec = get_win_fdr_nextsibFDR_aphysrec(win_file->l2_img, &win_file->curfdr);
- if (read_absolute_physrec(& win_file->l2_img->l1_img, win_file->curfdr_aphysrec, &win_file->curfdr))
- return IMGTOOLERR_READERROR;
-
- return 0;
-}
-
-/*
- Back to previous sibling FDR
-*/
-static int win_goto_prev_sibFDR(ti99_lvl2_fileref_win *win_file)
-{
- if (get_UINT16BE(win_file->curfdr.prevsibFDR_AU) == 0)
- return IMGTOOLERR_UNEXPECTED;
-
- win_file->curfdr_aphysrec = get_win_fdr_prevsibFDR_aphysrec(win_file->l2_img, &win_file->curfdr);
- if (read_absolute_physrec(& win_file->l2_img->l1_img, win_file->curfdr_aphysrec, &win_file->curfdr))
- return IMGTOOLERR_READERROR;
-
- return 0;
-}
-
-/*
- Append a new sibling FDR at the end of the sibling FDR list, and open it.
-
- You must have gone to the end of the list.
-*/
-static int win_alloc_sibFDR(ti99_lvl2_fileref_win *win_file)
-{
- unsigned oldfdr_AU, oldfdr_physrecinAU;
- unsigned newfdr_AU, newfdr_physrecinAU;
- int allocated = FALSE;
- int errorcode;
- unsigned cursibFDR_basefphysrec;
-
- if (get_UINT16BE(win_file->curfdr.nextsibFDR_AU))
- return IMGTOOLERR_UNEXPECTED;
-
- oldfdr_AU = win_file->curfdr_aphysrec / win_file->l2_img->AUformat.physrecsperAU;
- oldfdr_physrecinAU = win_file->curfdr_aphysrec % win_file->l2_img->AUformat.physrecsperAU;
-
- if (oldfdr_physrecinAU != (win_file->l2_img->AUformat.physrecsperAU - 1))
- { /* current AU is not full */
- newfdr_AU = oldfdr_AU;
- newfdr_physrecinAU = oldfdr_physrecinAU + 1;
- }
- else
- { /* current AU is full: allocate another */
- errorcode = alloc_fdr_AU(win_file->l2_img, &newfdr_AU);
- if (errorcode)
- return errorcode;
- newfdr_physrecinAU = 0;
- allocated = TRUE;
- }
-
- set_UINT16BE(&win_file->curfdr.nextsibFDR_AU, newfdr_AU);
- win_file->curfdr.xinfo_LSB = (win_file->curfdr.xinfo_LSB & 0xf0) | newfdr_physrecinAU;
-
- /* save current sibling FDR */
- if (write_absolute_physrec(& win_file->l2_img->l1_img, win_file->curfdr_aphysrec, &win_file->curfdr))
- {
- /* clear pointer */
- set_UINT16BE(&win_file->curfdr.nextsibFDR_AU, 0);
- win_file->curfdr.xinfo_LSB = win_file->curfdr.xinfo_LSB & 0xf0;
- if (allocated)
- /* free AU */
- win_file->l2_img->abm[newfdr_AU >> 3] |= 1 << (newfdr_AU & 7);
- return IMGTOOLERR_WRITEERROR;
- }
-
- /* now update in-memory structure to describe new sibling FDR */
- cursibFDR_basefphysrec = get_win_fdr_cursibFDR_basefphysrec(&win_file->curfdr)
- + get_UINT16BE(win_file->curfdr.sibFDR_AUlen) * win_file->l2_img->AUformat.physrecsperAU;
-
- set_UINT16BE(&win_file->curfdr.nextsibFDR_AU, 0);
- set_UINT16BE(&win_file->curfdr.prevsibFDR_AU, oldfdr_AU);
- win_file->curfdr.xinfo_LSB = oldfdr_physrecinAU << 4;
-
- win_file->curfdr_aphysrec = newfdr_AU * win_file->l2_img->AUformat.physrecsperAU + newfdr_physrecinAU;
-
- set_win_fdr_fphysrecs(&win_file->curfdr, cursibFDR_basefphysrec);
- set_UINT16BE(&win_file->curfdr.sibFDR_AUlen, 0);
- memset(win_file->curfdr.clusters, 0, sizeof(win_file->curfdr.clusters));
-
- return 0;
-}
-
-/*
- Extend a file with nb_alloc_physrecs extra physrecs
-
- dsk_file: file reference
- nb_alloc_physrecs: number of physical records to allocate
-*/
-static int dsk_alloc_file_physrecs(ti99_lvl2_fileref_dsk *dsk_file, int nb_alloc_physrecs)
-{
- int totAUs = dsk_file->l2_img->AUformat.totAUs;
- int free_physrecs;
- int fphysrecs;
- int i;
- int cluster_index;
- int last_sec, p_last_sec = 0;
- int cur_block_seclen;
- int cluster_baseAU, cluster_AUlen;
- int first_best_block_baseAU = 0, first_best_block_seclen;
- int second_best_block_baseAU = 0, second_best_block_seclen;
- int search_start;
-
- /* compute free space */
- free_physrecs = 0;
- for (i=0; i<totAUs; i++)
- {
- if (! (dsk_file->l2_img->abm[i >> 3] & (1 << (i & 7))))
- free_physrecs += dsk_file->l2_img->AUformat.physrecsperAU;
- }
-
- /* check we have enough free space */
- if (free_physrecs < nb_alloc_physrecs)
- return IMGTOOLERR_NOSPACE;
-
- /* current number of data physrecs in file */
- fphysrecs = get_UINT16BE(dsk_file->fdr.fphysrecs);
-
- if (fphysrecs == 0)
- { /* cluster array must be empty */
- cluster_index = 0;
- }
- else
- { /* try to extend last block */
- last_sec = -1;
- for (cluster_index=0; cluster_index<76; cluster_index++)
- {
- p_last_sec = last_sec;
- last_sec = get_dsk_fdr_cluster_lastfphysrec(&dsk_file->fdr, cluster_index);
- if (last_sec >= (fphysrecs-1))
- break;
- }
- if (cluster_index == 76)
- /* that sucks */
- return IMGTOOLERR_CORRUPTIMAGE;
-
- if (last_sec > (fphysrecs-1))
- { /* some extra space has already been allocated */
- cur_block_seclen = last_sec - (fphysrecs-1);
- if (cur_block_seclen > nb_alloc_physrecs)
- cur_block_seclen = nb_alloc_physrecs;
-
- fphysrecs += cur_block_seclen;
- set_UINT16BE(& dsk_file->fdr.fphysrecs, fphysrecs);
- nb_alloc_physrecs -= cur_block_seclen;
- if (! nb_alloc_physrecs)
- return 0; /* done */
- }
-
- /* round up to next AU boundary */
- last_sec = last_sec + dsk_file->l2_img->AUformat.physrecsperAU - (last_sec % dsk_file->l2_img->AUformat.physrecsperAU) - 1;
-
- if (last_sec > (fphysrecs-1))
- { /* some extra space has already been allocated */
- cur_block_seclen = last_sec - (fphysrecs-1);
- if (cur_block_seclen > nb_alloc_physrecs)
- cur_block_seclen = nb_alloc_physrecs;
-
- fphysrecs += cur_block_seclen;
- set_UINT16BE(& dsk_file->fdr.fphysrecs, fphysrecs);
- set_dsk_fdr_cluster_lastfphysrec(&dsk_file->fdr, cluster_index, fphysrecs-1);
- nb_alloc_physrecs -= cur_block_seclen;
- if (! nb_alloc_physrecs)
- return 0; /* done */
- }
-
- /* read base AU address for this cluster */
- cluster_baseAU = get_dsk_fdr_cluster_baseAU(dsk_file->l2_img, &dsk_file->fdr, cluster_index);
- /* point past cluster end */
- cluster_baseAU += (last_sec-p_last_sec/*+file->l2_img->AUformat.physrecsperAU-1*/) / dsk_file->l2_img->AUformat.physrecsperAU;
- /* count free physrecs after last block */
- cur_block_seclen = 0;
- for (i=cluster_baseAU; (! (dsk_file->l2_img->abm[i >> 3] & (1 << (i & 7)))) && (cur_block_seclen < nb_alloc_physrecs) && (i < totAUs); i++)
- cur_block_seclen += dsk_file->l2_img->AUformat.physrecsperAU;
- if (cur_block_seclen)
- { /* extend last block */
- if (cur_block_seclen > nb_alloc_physrecs)
- cur_block_seclen = nb_alloc_physrecs;
-
- fphysrecs += cur_block_seclen;
- set_UINT16BE(& dsk_file->fdr.fphysrecs, fphysrecs);
- last_sec += cur_block_seclen;
- nb_alloc_physrecs -= cur_block_seclen;
- set_dsk_fdr_cluster_lastfphysrec(&dsk_file->fdr, cluster_index, last_sec);
- cluster_AUlen = (cur_block_seclen + dsk_file->l2_img->AUformat.physrecsperAU - 1) / dsk_file->l2_img->AUformat.physrecsperAU;
- for (i=0; i<cluster_AUlen; i++)
- dsk_file->l2_img->abm[(i+cluster_baseAU) >> 3] |= 1 << ((i+cluster_baseAU) & 7);
- if (! nb_alloc_physrecs)
- return 0; /* done */
- }
- cluster_index++;
- if (cluster_index == 76)
- /* that sucks */
- return IMGTOOLERR_NOSPACE;
- }
-
- search_start = dsk_file->l2_img->data_offset; /* initially, search for free space only in data space */
- while (nb_alloc_physrecs)
- {
- /* find smallest data block at least nb_alloc_physrecs in length, and largest data block less than nb_alloc_physrecs in length */
- first_best_block_seclen = INT_MAX;
- second_best_block_seclen = 0;
- for (i=search_start; i<totAUs; i++)
- {
- if (! (dsk_file->l2_img->abm[i >> 3] & (1 << (i & 7))))
- { /* found one free block */
- /* compute its length */
- cluster_baseAU = i;
- cur_block_seclen = 0;
- while ((i<totAUs) && (! (dsk_file->l2_img->abm[i >> 3] & (1 << (i & 7)))))
- {
- cur_block_seclen += dsk_file->l2_img->AUformat.physrecsperAU;
- i++;
- }
- /* compare to previous best and second-best blocks */
- if ((cur_block_seclen < first_best_block_seclen) && (cur_block_seclen >= nb_alloc_physrecs))
- {
- first_best_block_baseAU = cluster_baseAU;
- first_best_block_seclen = cur_block_seclen;
- if (cur_block_seclen == nb_alloc_physrecs)
- /* no need to search further */
- break;
- }
- else if ((cur_block_seclen > second_best_block_seclen) && (cur_block_seclen < nb_alloc_physrecs))
- {
- second_best_block_baseAU = cluster_baseAU;
- second_best_block_seclen = cur_block_seclen;
- }
- }
- }
-
- if (first_best_block_seclen != INT_MAX)
- { /* found one contiguous block which can hold it all */
- fphysrecs += nb_alloc_physrecs;
- set_UINT16BE(& dsk_file->fdr.fphysrecs, fphysrecs);
-
- set_dsk_fdr_cluster(dsk_file->l2_img, &dsk_file->fdr, cluster_index, first_best_block_baseAU, fphysrecs-1);
- cluster_AUlen = (nb_alloc_physrecs + dsk_file->l2_img->AUformat.physrecsperAU - 1) / dsk_file->l2_img->AUformat.physrecsperAU;
- for (i=0; i<cluster_AUlen; i++)
- dsk_file->l2_img->abm[(i+first_best_block_baseAU) >> 3] |= 1 << ((i+first_best_block_baseAU) & 7);
-
- nb_alloc_physrecs = 0;
- }
- else if (second_best_block_seclen != 0)
- { /* jeez, we need to fragment it. We use the largest smaller block to limit fragmentation. */
- fphysrecs += second_best_block_seclen;
- set_UINT16BE(& dsk_file->fdr.fphysrecs, fphysrecs);
-
- set_dsk_fdr_cluster(dsk_file->l2_img, &dsk_file->fdr, cluster_index, second_best_block_baseAU, fphysrecs-1);
- cluster_AUlen = (second_best_block_seclen + dsk_file->l2_img->AUformat.physrecsperAU - 1) / dsk_file->l2_img->AUformat.physrecsperAU;
- for (i=0; i<cluster_AUlen; i++)
- dsk_file->l2_img->abm[(i+second_best_block_baseAU) >> 3] |= 1 << ((i+second_best_block_baseAU) & 7);
-
- nb_alloc_physrecs -= second_best_block_seclen;
-
- cluster_index++;
- if (cluster_index == 76)
- /* that sucks */
- return IMGTOOLERR_NOSPACE;
- }
- else if (search_start != 0)
- { /* we did not find any free physrec in the data section of the disk */
- search_start = 0; /* time to fall back to fdr space */
- }
- else
- return IMGTOOLERR_NOSPACE; /* This should never happen, as we pre-check that there is enough free space */
- }
-
- return 0;
-}
-
-/*
- Extend a file with nb_alloc_physrecs extra physrecs
-
- win_file: file reference
- nb_alloc_physrecs: number of physical records to allocate
-*/
-static int win_alloc_file_physrecs(ti99_lvl2_fileref_win *win_file, int nb_alloc_physrecs)
-{
- int totAUs = win_file->l2_img->AUformat.totAUs;
- int free_physrecs;
- int fphysrecs;
- int i;
- int cluster_index;
- int num_fphysrec;
- int cur_block_seclen;
- int cluster_baseAU, cluster_AUlen;
- int first_best_block_baseAU = 0, first_best_block_seclen;
- int second_best_block_baseAU = 0, second_best_block_seclen;
- int search_start;
- int errorcode;
-
- /* compute free space */
- free_physrecs = 0;
- for (i=0; i<totAUs; i++)
- {
- if (! (win_file->l2_img->abm[i >> 3] & (1 << (i & 7))))
- free_physrecs += win_file->l2_img->AUformat.physrecsperAU;
- }
-
- /* check we have enough free space */
- if (free_physrecs < nb_alloc_physrecs)
- return IMGTOOLERR_NOSPACE;
-
- /* move to last sibling non-empty FDR */
- while ((get_UINT16BE(win_file->curfdr.nextsibFDR_AU) != 0) &&
- (get_UINT16BE(win_file->curfdr.clusters[53][0]) != 0))
- {
- errorcode = win_goto_next_sibFDR(win_file);
- if (errorcode)
- return errorcode;
- }
- if ((get_UINT16BE(win_file->curfdr.clusters[0][0]) == 0) && (get_UINT16BE(win_file->curfdr.prevsibFDR_AU) != 0))
- { /* this is annoying: we have found a sibling FDR filled with 0s: rewind
- to last non-empty sibling if applicable */
- errorcode = win_goto_prev_sibFDR(win_file);
- if (errorcode)
- return errorcode;
- }
-
- /* current number of data physrecs in file */
- fphysrecs = win_file->fphysrecs;
-
- /* current number of allocated physrecs */
- num_fphysrec = get_win_fdr_cursibFDR_basefphysrec(&win_file->curfdr)
- + get_UINT16BE(win_file->curfdr.sibFDR_AUlen) * win_file->l2_img->AUformat.physrecsperAU;
-
- if (num_fphysrec > fphysrecs)
- { /* some extra space has already been allocated */
- cur_block_seclen = num_fphysrec - fphysrecs;
- if (cur_block_seclen > nb_alloc_physrecs)
- cur_block_seclen = nb_alloc_physrecs;
-
- fphysrecs += cur_block_seclen;
- win_file->fphysrecs = fphysrecs;
- /* TODO: update eldest FDR fphysrecs field */
- /*set_win_fdr_fphysrecs(& win_file->rootfdr.fphysrecs, fphysrecs);*/
- nb_alloc_physrecs -= cur_block_seclen;
- if (! nb_alloc_physrecs)
- return 0; /* done */
- }
-
- /* find last non-empty cluster */
- for (cluster_index=0; (cluster_index<54) && (get_UINT16BE(win_file->curfdr.clusters[cluster_index][0]) != 0); cluster_index++)
- ;
- /* if we are dealing with an empty file, we will have (cluster_index == 0)... */
- if (cluster_index != 0)
- {
- cluster_index--;
- /* try to extend last cluster */
- /* point past cluster end */
- cluster_baseAU = get_UINT16BE(win_file->curfdr.clusters[cluster_index][1]) + 1;
- /* count free physrecs after last block */
- cur_block_seclen = 0;
- for (i=cluster_baseAU; (! (win_file->l2_img->abm[i >> 3] & (1 << (i & 7)))) && (cur_block_seclen < nb_alloc_physrecs) && (i < totAUs); i++)
- cur_block_seclen += win_file->l2_img->AUformat.physrecsperAU;
- if (cur_block_seclen)
- { /* extend last block */
- if (cur_block_seclen > nb_alloc_physrecs)
- cur_block_seclen = nb_alloc_physrecs;
-
- fphysrecs += cur_block_seclen;
- cluster_AUlen = (cur_block_seclen + win_file->l2_img->AUformat.physrecsperAU - 1) / win_file->l2_img->AUformat.physrecsperAU;
- win_file->fphysrecs = fphysrecs;
- /* TODO: update eldest FDR fphysrecs field */
- /*set_win_fdr_fphysrecs(& win_file->rootfdr.fphysrecs, fphysrecs);*/
- set_UINT16BE(&win_file->curfdr.sibFDR_AUlen,
- get_UINT16BE(win_file->curfdr.sibFDR_AUlen)+cluster_AUlen);
- set_UINT16BE(&win_file->curfdr.clusters[cluster_index][1],
- get_UINT16BE(win_file->curfdr.clusters[cluster_index][1])+cluster_AUlen);
- for (i=0; i<cluster_AUlen; i++)
- win_file->l2_img->abm[(i+cluster_baseAU) >> 3] |= 1 << ((i+cluster_baseAU) & 7);
- nb_alloc_physrecs -= cur_block_seclen;
- if (! nb_alloc_physrecs)
- return 0; /* done */
- }
- /* now point to first free entry in cluster table */
- cluster_index++;
- }
-
- search_start = win_file->l2_img->data_offset; /* initially, search for free space only in data space */
- while (nb_alloc_physrecs)
- {
- /* find smallest data block at least nb_alloc_physrecs in length, and largest data block less than nb_alloc_physrecs in length */
- first_best_block_seclen = INT_MAX;
- second_best_block_seclen = 0;
- for (i=search_start; i<totAUs; i++)
- {
- if (! (win_file->l2_img->abm[i >> 3] & (1 << (i & 7))))
- { /* found one free block */
- /* compute its length */
- cluster_baseAU = i;
- cur_block_seclen = 0;
- while ((i<totAUs) && (! (win_file->l2_img->abm[i >> 3] & (1 << (i & 7)))))
- {
- cur_block_seclen += win_file->l2_img->AUformat.physrecsperAU;
- i++;
- }
- /* compare to previous best and second-best blocks */
- if ((cur_block_seclen < first_best_block_seclen) && (cur_block_seclen >= nb_alloc_physrecs))
- {
- first_best_block_baseAU = cluster_baseAU;
- first_best_block_seclen = cur_block_seclen;
- if (cur_block_seclen == nb_alloc_physrecs)
- /* no need to search further */
- break;
- }
- else if ((cur_block_seclen > second_best_block_seclen) && (cur_block_seclen < nb_alloc_physrecs))
- {
- second_best_block_baseAU = cluster_baseAU;
- second_best_block_seclen = cur_block_seclen;
- }
- }
- }
-
- if ((first_best_block_seclen != INT_MAX) || (second_best_block_seclen != 0))
- {
- if (cluster_index == 54)
- {
- /* end of cluster list: go to next sibling FDR */
- if (write_absolute_physrec(& win_file->l2_img->l1_img, win_file->curfdr_aphysrec, &win_file->curfdr))
- return IMGTOOLERR_WRITEERROR;
- if (get_UINT16BE(win_file->curfdr.nextsibFDR_AU) != 0)
- { /* read next sibling FDR */
- errorcode = win_goto_next_sibFDR(win_file);
- if (errorcode)
- return errorcode;
- }
- else
- { /* allocate new sibling FDR */
- errorcode = win_alloc_sibFDR(win_file);
- if (errorcode)
- return errorcode;
- }
- cluster_index = 0;
- }
- }
-
- if (first_best_block_seclen != INT_MAX)
- { /* found one contiguous block which can hold it all */
- fphysrecs += nb_alloc_physrecs;
- cluster_AUlen = (nb_alloc_physrecs + win_file->l2_img->AUformat.physrecsperAU - 1) / win_file->l2_img->AUformat.physrecsperAU;
- win_file->fphysrecs = fphysrecs;
- /* TODO: update eldest FDR fphysrecs field */
- /*set_win_fdr_fphysrecs(& win_file->rootfdr.fphysrecs, fphysrecs);*/
- set_UINT16BE(&win_file->curfdr.sibFDR_AUlen,
- get_UINT16BE(win_file->curfdr.sibFDR_AUlen)+cluster_AUlen);
- set_UINT16BE(&win_file->curfdr.clusters[cluster_index][0], first_best_block_baseAU);
- set_UINT16BE(&win_file->curfdr.clusters[cluster_index][1],
- first_best_block_baseAU+cluster_AUlen-1);
-
- for (i=0; i<cluster_AUlen; i++)
- win_file->l2_img->abm[(i+first_best_block_baseAU) >> 3] |= 1 << ((i+first_best_block_baseAU) & 7);
-
- nb_alloc_physrecs = 0;
- }
- else if (second_best_block_seclen != 0)
- { /* jeez, we need to fragment it. We use the largest smaller block to limit fragmentation. */
- fphysrecs += second_best_block_seclen;
- cluster_AUlen = (second_best_block_seclen + win_file->l2_img->AUformat.physrecsperAU - 1) / win_file->l2_img->AUformat.physrecsperAU;
- win_file->fphysrecs = fphysrecs;
- /* TODO: update eldest FDR fphysrecs field */
- /*set_win_fdr_fphysrecs(& win_file->rootfdr.fphysrecs, fphysrecs);*/
- set_UINT16BE(&win_file->curfdr.sibFDR_AUlen,
- get_UINT16BE(win_file->curfdr.sibFDR_AUlen)+cluster_AUlen);
- set_UINT16BE(&win_file->curfdr.clusters[cluster_index][0], second_best_block_baseAU);
- set_UINT16BE(&win_file->curfdr.clusters[cluster_index][1],
- second_best_block_baseAU+cluster_AUlen-1);
-
- for (i=0; i<cluster_AUlen; i++)
- win_file->l2_img->abm[(i+second_best_block_baseAU) >> 3] |= 1 << ((i+second_best_block_baseAU) & 7);
-
- nb_alloc_physrecs -= second_best_block_seclen;
-
- /* now point to first free entry in cluster table */
- cluster_index++;
- }
- else if (search_start != 0)
- { /* we did not find any free physrec in the data section of the disk */
- search_start = 0; /* time to fall back to fdr space */
- }
- else
- return IMGTOOLERR_NOSPACE; /* This should never happen, as we pre-check that there is enough free space */
- }
-
- return 0;
-}
-
-/*
- Allocate a new (empty) file
-*/
-static int new_file_lvl2_dsk(struct ti99_lvl2_imgref *l2_img, int parent_ref, char filename[10], struct ti99_lvl2_fileref *l2_file)
-{
- ti99_catalog *catalog = &l2_img->dsk.catalogs[parent_ref];
- unsigned fdr_AU, fdr_aphysrec;
- int catalog_index, i;
- int reply = 0;
- int errorcode;
-
-
- if (catalog->num_files >= 127)
- /* if num_files == 128, catalog is full */
- /* if num_files == 127, catalog is not full, but we don't want to write
- a 128th entry for compatibility with some existing DSRs that detect the
- end of the FDIR array with a 0 entry (and do not check that the index
- has not reached 128) */
- return IMGTOOLERR_NOSPACE;
-
- /* find insertion point in catalog */
- for (i=0; (i < catalog->num_files) && ((reply = memcmp(catalog->files[i].name, filename, 10)) < 0); i++)
- ;
-
- if ((i<catalog->num_files) && (reply == 0))
- /* file already exists */
- return IMGTOOLERR_BADFILENAME;
- else
- {
- /* otherwise insert new entry */
- catalog_index = i;
- errorcode = alloc_fdr_AU(l2_img, &fdr_AU);
- if (errorcode)
- return errorcode;
- fdr_aphysrec = fdr_AU * l2_img->AUformat.physrecsperAU;
-
- /* shift catalog entries until the insertion point */
- for (i=catalog->num_files; i>catalog_index; i--)
- catalog->files[i] = catalog->files[i-1];
-
- /* write new catalog entry */
- catalog->files[catalog_index].fdr_ptr = fdr_aphysrec;
- memcpy(catalog->files[catalog_index].name, filename, 10);
-
- /* update catalog len */
- catalog->num_files++;
- }
-
- /* set up file handle */
- l2_file->type = L2F_DSK;
- l2_file->dsk.l2_img = l2_img;
- l2_file->dsk.fdr_aphysrec = fdr_aphysrec;
- memset(&l2_file->dsk.fdr, 0, sizeof(l2_file->dsk.fdr));
- memcpy(l2_file->dsk.fdr.name, filename, 10);
-
- return 0;
-}
-
-/*
- Allocate a new (empty) file
-*/
-static int new_file_lvl2_win(struct ti99_lvl2_imgref *l2_img, ti99_catalog *parent_catalog, char filename[10], struct ti99_lvl2_fileref *l2_file)
-{
- unsigned fdr_AU;
- int catalog_index, i;
- int reply = 0;
- int errorcode;
-
-
- if (parent_catalog->num_files >= 127)
- /* if num_files == 127, catalog is full */
- return IMGTOOLERR_NOSPACE;
-
- /* find insertion point in catalog */
- for (i=0; (i < parent_catalog->num_files) && ((reply = memcmp(parent_catalog->files[i].name, filename, 10)) < 0); i++)
- ;
-
- if ((i<parent_catalog->num_files) && (reply == 0))
- /* file already exists */
- return IMGTOOLERR_BADFILENAME;
- else
- {
- /* otherwise insert new entry */
- catalog_index = i;
- errorcode = alloc_fdr_AU(l2_img, &fdr_AU);
- if (errorcode)
- return errorcode;
-
- /* shift catalog entries until the insertion point */
- for (i=parent_catalog->num_files; i>catalog_index; i--)
- parent_catalog->files[i] = parent_catalog->files[i-1];
-
- /* write new catalog entry */
- parent_catalog->files[catalog_index].fdr_ptr = fdr_AU;
- memcpy(parent_catalog->files[catalog_index].name, filename, 10);
-
- /* update catalog len */
- parent_catalog->num_files++;
- }
-
- /* set up file handle */
- l2_file->type = L2F_WIN;
- l2_file->win.l2_img = l2_img;
- l2_file->win.fphysrecs = 0;
- l2_file->win.eldestfdr_aphysrec = fdr_AU * l2_img->AUformat.physrecsperAU;
- l2_file->win.curfdr_aphysrec = l2_file->win.eldestfdr_aphysrec;
- memset(&l2_file->win.curfdr, 0, sizeof(l2_file->win.curfdr));
- memcpy(l2_file->win.curfdr.name, filename, 10);
-
- return 0;
-}
-
-/*
- Allocate a new (empty) file
-*/
-static int new_file_lvl2_tifiles(imgtool_stream *file_handle, struct ti99_lvl2_fileref *l2_file)
-{
- /* set up file handle */
- l2_file->type = L2F_TIFILES;
- l2_file->tifiles.file_handle = file_handle;
- memset(&l2_file->tifiles.hdr, 0, sizeof(l2_file->tifiles.hdr));
- l2_file->tifiles.hdr.tifiles[0] = '\7';
- l2_file->tifiles.hdr.tifiles[1] = 'T';
- l2_file->tifiles.hdr.tifiles[2] = 'I';
- l2_file->tifiles.hdr.tifiles[3] = 'F';
- l2_file->tifiles.hdr.tifiles[4] = 'I';
- l2_file->tifiles.hdr.tifiles[5] = 'L';
- l2_file->tifiles.hdr.tifiles[6] = 'E';
- l2_file->tifiles.hdr.tifiles[7] = 'S';
-
- return 0;
-}
-
-/*
- Open an existing file on a floppy image
-
- l2_img: level 2 image the file is located on
- fpath: access path to the file
- file: set up if open is successful
-*/
-static int open_file_lvl2_dsk(struct ti99_lvl2_imgref *l2_img, const char *fpath, struct ti99_lvl2_fileref *l2_file)
-{
- int parent_ref, is_dir, catalog_index;
- int reply;
-
-
- reply = dsk_find_catalog_entry(l2_img, fpath, NULL, &parent_ref, &is_dir, &catalog_index);
- if (reply)
- return reply;
-
- if (is_dir)
- /* this is not a file */
- return IMGTOOLERR_BADFILENAME;
-
- l2_file->type = L2F_DSK;
- l2_file->dsk.l2_img = l2_img;
- l2_file->dsk.fdr_aphysrec = l2_img->dsk.catalogs[parent_ref].files[catalog_index].fdr_ptr;
- if (read_absolute_physrec(& l2_img->l1_img, l2_file->dsk.fdr_aphysrec, &l2_file->dsk.fdr))
- return IMGTOOLERR_READERROR;
-
- return 0;
-}
-
-/*
- Open an existing file on a harddisk image
-
- l2_img: level 2 image the file is located on
- fpath: access path to the file
- file: set up if open is successful
-*/
-static int open_file_lvl2_win(struct ti99_lvl2_imgref *l2_img, const char *fpath, struct ti99_lvl2_fileref *l2_file)
-{
- int parent_ref, is_dir, catalog_index;
- ti99_catalog catalog;
- int reply;
-
- reply = win_find_catalog_entry(l2_img, fpath, NULL, &parent_ref, &catalog, &is_dir, &catalog_index);
- if (reply)
- return reply;
-
- if (is_dir)
- /* this is not a file */
- return IMGTOOLERR_BADFILENAME;
-
- l2_file->type = L2F_WIN;
- l2_file->win.l2_img = l2_img;
- l2_file->win.eldestfdr_aphysrec = catalog.files[catalog_index].fdr_ptr * l2_img->AUformat.physrecsperAU;
- l2_file->win.curfdr_aphysrec = l2_file->win.eldestfdr_aphysrec;
- if (read_absolute_physrec(& l2_img->l1_img, l2_file->win.curfdr_aphysrec, &l2_file->win.curfdr))
- return IMGTOOLERR_READERROR;
- l2_file->win.fphysrecs = get_win_fdr_fphysrecs(&l2_file->win.curfdr);
-
- /* check integrity of FDR sibling chain */
- /* note that as we check that the back chain is consistent with the forward
- chain, we will also detect any cycle in the sibling chain, so we do not
- need to check against them explicitely */
- if (get_UINT16BE(l2_file->win.curfdr.prevsibFDR_AU) != 0)
- return IMGTOOLERR_CORRUPTIMAGE;
-
- {
- int i, pastendoflist_flag;
- unsigned cur_fphysrec, sibFDR_AUlen;
- win_fdr *cur_fdr, fdr_buf;
- unsigned curfdr_aphysrec, prevfdr_aphysrec;
-
- cur_fphysrec = 0;
- pastendoflist_flag = 0;
- cur_fdr = &l2_file->win.curfdr;
- curfdr_aphysrec = l2_file->win.eldestfdr_aphysrec;
-
- while (1)
- {
- sibFDR_AUlen = 0;
- i=0;
- if (! pastendoflist_flag)
- {
- /* compute number of allocated AUs and check number of AUs */
- for (; i<54; i++)
- {
- if (get_UINT16BE(cur_fdr->clusters[i][0]) == 0)
- {
- pastendoflist_flag = TRUE;
- break;
- }
- sibFDR_AUlen += get_UINT16BE(cur_fdr->clusters[i][1])
- - get_UINT16BE(cur_fdr->clusters[i][0])
- + 1;
- }
- }
- /* clear remainder of cluster table */
- for (; i<54; i++)
- {
-#if 0
- set_UINT16BE(&cur_fdr->clusters[i][0], 0);
- set_UINT16BE(&cur_fdr->clusters[i][1], 0);
-#endif
- if ((get_UINT16BE(cur_fdr->clusters[i][0]) != 0) || (get_UINT16BE(cur_fdr->clusters[i][1]) != 0))
- return IMGTOOLERR_CORRUPTIMAGE;
- }
-
- /* check sibFDR_AUlen field */
- if (get_UINT16BE(cur_fdr->sibFDR_AUlen) != sibFDR_AUlen)
- return IMGTOOLERR_CORRUPTIMAGE;
-
- /* update current file physrec position to point to end of sibling FDR */
- cur_fphysrec += sibFDR_AUlen * l2_file->win.l2_img->AUformat.physrecsperAU;
-
- /* exit loop if end of sibling chain */
- if (! get_UINT16BE(cur_fdr->nextsibFDR_AU))
- break;
-
- /* otherwise read next FDR */
- if (get_UINT16BE(cur_fdr->nextsibFDR_AU) >= l2_file->win.l2_img->AUformat.totAUs)
- return IMGTOOLERR_CORRUPTIMAGE;
-
- prevfdr_aphysrec = curfdr_aphysrec;
- curfdr_aphysrec = get_win_fdr_nextsibFDR_aphysrec(l2_file->win.l2_img, cur_fdr);
- if (read_absolute_physrec(& l2_file->win.l2_img->l1_img, curfdr_aphysrec, &fdr_buf))
- return IMGTOOLERR_READERROR;
- cur_fdr = &fdr_buf;
-
- /* check that back chaining is consistent with forward chaining */
- if (get_win_fdr_prevsibFDR_aphysrec(l2_file->win.l2_img, &fdr_buf) != prevfdr_aphysrec)
- return IMGTOOLERR_CORRUPTIMAGE;
- /* check fphysrecs field */
- if (get_win_fdr_fphysrecs(&fdr_buf) != cur_fphysrec)
- return IMGTOOLERR_CORRUPTIMAGE;
-
- /* check consistency of informative fields (name, record format, flags, etc) */
- if (memcmp(fdr_buf.name, l2_file->win.curfdr.name, 10)
- || (get_UINT16BE(fdr_buf.xreclen) != get_UINT16BE(l2_file->win.curfdr.xreclen))
- || (fdr_buf.flags != l2_file->win.curfdr.flags)
- || (fdr_buf.recsperphysrec != l2_file->win.curfdr.recsperphysrec)
- || (fdr_buf.eof != l2_file->win.curfdr.eof)
- || (fdr_buf.reclen != l2_file->win.curfdr.reclen)
- || (get_UINT16LE(fdr_buf.fixrecs_LSW) != get_UINT16LE(l2_file->win.curfdr.fixrecs_LSW))
- || memcmp(&fdr_buf.creation, &l2_file->win.curfdr.creation, 4)
- || memcmp(&fdr_buf.update, &l2_file->win.curfdr.update, 4)
- /*|| memcmp(fdr_buf.id, l2_file->win.curfdr.id, 2)*/
- || (get_UINT16BE(fdr_buf.parent_FDIR_AU) != get_UINT16BE(l2_file->win.curfdr.parent_FDIR_AU))
- || ((fdr_buf.xinfo_MSB & 0xf) != (l2_file->win.curfdr.xinfo_MSB & 0xf)))
- return IMGTOOLERR_CORRUPTIMAGE;
- }
- if (cur_fphysrec < l2_file->win.fphysrecs)
- return IMGTOOLERR_CORRUPTIMAGE;
- }
-
- return 0;
-}
-
-/*
- Open an existing file in TIFILES format
-*/
-static int open_file_lvl2_tifiles(imgtool_stream *file_handle, struct ti99_lvl2_fileref *l2_file)
-{
- /* set up file handle */
- l2_file->type = L2F_TIFILES;
- l2_file->tifiles.file_handle = file_handle;
-
- /* seek to header */
- if (stream_seek(l2_file->tifiles.file_handle, 0, SEEK_SET))
- return IMGTOOLERR_READERROR;
- /* read it */
- if (stream_read(l2_file->tifiles.file_handle, &l2_file->tifiles.hdr, sizeof(l2_file->tifiles.hdr)) != sizeof(l2_file->tifiles.hdr))
- return IMGTOOLERR_READERROR;
-
- return 0;
-}
-
-/*
- compute the aphysrec address for a given file physical record (fphysrec)
-
- l2_img: image where the file is located
-*/
-static int dsk_fphysrec_to_aphysrec(ti99_lvl2_fileref_dsk *dsk_file, unsigned fphysrec, unsigned *aphysrec)
-{
- int cluster_index;
- int cluster_firstfphysrec, cluster_lastfphysrec;
- int cluster_baseaphysrec;
-
-
- /* check parameter */
- if (fphysrec >= get_UINT16BE(dsk_file->fdr.fphysrecs))
- return IMGTOOLERR_UNEXPECTED;
-
-
- /* search for the cluster in the data chain pointers array */
- cluster_firstfphysrec = 0;
- for (cluster_index=0; cluster_index<76; cluster_index++)
- {
- /* read curent file block table entry */
- cluster_lastfphysrec = get_dsk_fdr_cluster_lastfphysrec(&dsk_file->fdr, cluster_index);
- if (cluster_lastfphysrec >= fphysrec)
- break;
- cluster_firstfphysrec = cluster_lastfphysrec+1;
- }
- if (cluster_index == 76)
- /* if not found, the file is corrupt */
- return IMGTOOLERR_CORRUPTIMAGE;
-
- /* read base aphysrec address for this cluster */
- cluster_baseaphysrec = get_dsk_fdr_cluster_baseaphysrec(dsk_file->l2_img, &dsk_file->fdr, cluster_index);
- /* return absolute physrec address */
- *aphysrec = cluster_baseaphysrec + (fphysrec - cluster_firstfphysrec);
- return 0;
-}
-
-/*
- compute the aphysrec address for a given file physical record (fphysrec)
-
- l2_img: image where the file is located
-*/
-static int win_fphysrec_to_aphysrec(ti99_lvl2_fileref_win *win_file, unsigned fphysrec, unsigned *aphysrec)
-{
- int cluster_index;
- int cluster_firstfphysrec, cluster_lastfphysrec;
- int cluster_baseaphysrec;
- int errorcode;
-
-
- /* check parameter */
- if (fphysrec >= win_file->fphysrecs)
- return IMGTOOLERR_UNEXPECTED;
-
- /* look for correct sibling */
- if (fphysrec < get_win_fdr_cursibFDR_basefphysrec(& win_file->curfdr))
- {
- while (fphysrec < get_win_fdr_cursibFDR_basefphysrec(& win_file->curfdr))
- {
- if (get_UINT16BE(win_file->curfdr.prevsibFDR_AU) == 0)
- return IMGTOOLERR_CORRUPTIMAGE;
- errorcode = win_goto_prev_sibFDR(win_file);
- if (errorcode)
- return errorcode;
- }
- }
- else /*if (fphysrec >= get_win_fdr_cursibFDR_basefphysrec(& dsk_file->curfdr))*/
- {
- while (fphysrec >= (get_win_fdr_cursibFDR_basefphysrec(& win_file->curfdr)
- + get_UINT16BE(win_file->curfdr.sibFDR_AUlen) * win_file->l2_img->AUformat.physrecsperAU))
- {
- if (get_UINT16BE(win_file->curfdr.nextsibFDR_AU) == 0)
- return IMGTOOLERR_CORRUPTIMAGE;
- errorcode = win_goto_next_sibFDR(win_file);
- if (errorcode)
- return errorcode;
- }
- }
-
-
- /* search for the cluster in the data chain pointers array */
- cluster_firstfphysrec = get_win_fdr_cursibFDR_basefphysrec(& win_file->curfdr);
- for (cluster_index = 0; cluster_index<54; cluster_index++)
- {
- cluster_lastfphysrec = cluster_firstfphysrec
- + (get_UINT16BE(win_file->curfdr.clusters[cluster_index][1])
- - get_UINT16BE(win_file->curfdr.clusters[cluster_index][0])
- + 1)
- * win_file->l2_img->AUformat.physrecsperAU;
- if (fphysrec < cluster_lastfphysrec)
- break;
-
- cluster_firstfphysrec = cluster_lastfphysrec;
- }
-
- if (cluster_index == 54)
- return IMGTOOLERR_CORRUPTIMAGE;
-
-
- /* read base aphysrec address for this cluster */
- cluster_baseaphysrec = get_UINT16BE(win_file->curfdr.clusters[cluster_index][0]) * win_file->l2_img->AUformat.physrecsperAU;
- /* return absolute physrec address */
- *aphysrec = cluster_baseaphysrec + (fphysrec - cluster_firstfphysrec);
- return 0;
-}
-
-/*
- read a 256-byte physical record from a file
-*/
-static int read_file_physrec(struct ti99_lvl2_fileref *l2_file, unsigned fphysrec, void *dest)
-{
- int errorcode;
- unsigned aphysrec;
-
- switch (l2_file->type)
- {
- case L2F_DSK:
- /* compute absolute physrec address */
- errorcode = dsk_fphysrec_to_aphysrec(&l2_file->dsk, fphysrec, &aphysrec);
- if (errorcode)
- return errorcode;
- /* read physrec */
- if (read_absolute_physrec(& l2_file->dsk.l2_img->l1_img, aphysrec, dest))
- return IMGTOOLERR_READERROR;
- break;
-
- case L2F_WIN:
- /* compute absolute physrec address */
- errorcode = win_fphysrec_to_aphysrec(&l2_file->win, fphysrec, &aphysrec);
- if (errorcode)
- return errorcode;
- /* read physrec */
- if (read_absolute_physrec(& l2_file->win.l2_img->l1_img, aphysrec, dest))
- return IMGTOOLERR_READERROR;
- break;
-
- case L2F_TIFILES:
- /* seek to physrec */
- if (stream_seek(l2_file->tifiles.file_handle, 128+256*fphysrec, SEEK_SET))
- return IMGTOOLERR_READERROR;
- /* read it */
- if (stream_read(l2_file->tifiles.file_handle, dest, 256) != 256)
- return IMGTOOLERR_READERROR;
- break;
- }
-
- return 0;
-}
-
-/*
- read a 256-byte physical record from a file
-*/
-static int write_file_physrec(struct ti99_lvl2_fileref *l2_file, unsigned fphysrec, const void *src)
-{
- int errorcode;
- unsigned aphysrec;
-
- switch (l2_file->type)
- {
- case L2F_DSK:
- /* compute absolute physrec address */
- errorcode = dsk_fphysrec_to_aphysrec(&l2_file->dsk, fphysrec, &aphysrec);
- if (errorcode)
- return errorcode;
- /* write physrec */
- if (write_absolute_physrec(& l2_file->dsk.l2_img->l1_img, aphysrec, src))
- return IMGTOOLERR_WRITEERROR;
- break;
-
- case L2F_WIN:
- /* compute absolute physrec address */
- errorcode = win_fphysrec_to_aphysrec(&l2_file->win, fphysrec, &aphysrec);
- if (errorcode)
- return errorcode;
- /* write physrec */
- if (write_absolute_physrec(& l2_file->win.l2_img->l1_img, aphysrec, src))
- return IMGTOOLERR_WRITEERROR;
- break;
-
- case L2F_TIFILES:
- /* seek to physrec */
- if (stream_seek(l2_file->tifiles.file_handle, 128+256*fphysrec, SEEK_SET))
- return IMGTOOLERR_WRITEERROR;
- /* write it */
- if (stream_write(l2_file->tifiles.file_handle, src, 256) != 256)
- return IMGTOOLERR_WRITEERROR;
- break;
- }
-
- return 0;
-}
-
-/*
- Write a field in every fdr record associated to a file
-*/
-#ifdef UNUSED_FUNCTION
-static int set_win_fdr_field(struct ti99_lvl2_fileref *l2_file, size_t offset, size_t size, void *data)
-{
- win_fdr fdr_buf;
- unsigned fdr_aphysrec;
- int errorcode = 0;
-
- for (fdr_aphysrec = l2_file->win.eldestfdr_aphysrec;
- fdr_aphysrec && ((errorcode = (read_absolute_physrec(&l2_file->win.l2_img->l1_img, fdr_aphysrec, &fdr_buf) ? IMGTOOLERR_READERROR : 0)) == 0);
- fdr_aphysrec = get_win_fdr_nextsibFDR_physrec(l2_file->win.l2_img, &fdr_buf))
- {
- memcpy(((UINT8 *) &fdr_buf) + offset, data, size);
- if (write_absolute_physrec(&l2_file->win.l2_img->l1_img, fdr_aphysrec, &fdr_buf))
- {
- errorcode = IMGTOOLERR_WRITEERROR;
- break;
- }
- }
-
- return errorcode;
-}
-#endif
-
-static UINT8 get_file_flags(struct ti99_lvl2_fileref *l2_file)
-{
- int reply = 0;
-
- switch (l2_file->type)
- {
- case L2F_DSK:
- reply = l2_file->dsk.fdr.flags;
- break;
-
- case L2F_WIN:
- reply = l2_file->win.curfdr.flags;
- break;
-
- case L2F_TIFILES:
- reply = l2_file->tifiles.hdr.flags;
- break;
- }
-
- return reply;
-}
-
-static void set_file_flags(struct ti99_lvl2_fileref *l2_file, UINT8 data)
-{
- switch (l2_file->type)
- {
- case L2F_DSK:
- l2_file->dsk.fdr.flags = data;
- break;
-
- case L2F_WIN:
- l2_file->win.curfdr.flags = data;
- break;
-
- case L2F_TIFILES:
- l2_file->tifiles.hdr.flags = data;
- break;
- }
-}
-
-static UINT8 get_file_recsperphysrec(struct ti99_lvl2_fileref *l2_file)
-{
- int reply = 0;
-
- switch (l2_file->type)
- {
- case L2F_DSK:
- reply = l2_file->dsk.fdr.recsperphysrec;
- break;
-
- case L2F_WIN:
- reply = l2_file->win.curfdr.recsperphysrec;
- break;
-
- case L2F_TIFILES:
- reply = l2_file->tifiles.hdr.recsperphysrec;
- break;
- }
-
- return reply;
-}
-
-static void set_file_recsperphysrec(struct ti99_lvl2_fileref *l2_file, UINT8 data)
-{
- switch (l2_file->type)
- {
- case L2F_DSK:
- l2_file->dsk.fdr.recsperphysrec = data;
- break;
-
- case L2F_WIN:
- l2_file->win.curfdr.recsperphysrec = data;
- break;
-
- case L2F_TIFILES:
- l2_file->tifiles.hdr.recsperphysrec = data;
- break;
- }
-}
-
-static unsigned get_file_fphysrecs(struct ti99_lvl2_fileref *l2_file)
-{
- int reply = 0;
-
- switch (l2_file->type)
- {
- case L2F_DSK:
- reply = get_UINT16BE(l2_file->dsk.fdr.fphysrecs);
- break;
-
- case L2F_WIN:
- reply = l2_file->win.fphysrecs;
- break;
-
- case L2F_TIFILES:
- reply = get_UINT16BE(l2_file->tifiles.hdr.fphysrecs);
- break;
- }
-
- return reply;
-}
-
-static int set_file_fphysrecs(struct ti99_lvl2_fileref *l2_file, unsigned data)
-{
- switch (l2_file->type)
- {
- case L2F_DSK:
- if (data >= 65536)
- return IMGTOOLERR_UNIMPLEMENTED;
- set_UINT16BE(&l2_file->dsk.fdr.fphysrecs, data);
- break;
-
- case L2F_WIN:
- l2_file->win.fphysrecs = data;
- break;
-
- case L2F_TIFILES:
- if (data >= 65536)
- return IMGTOOLERR_UNIMPLEMENTED;
- set_UINT16BE(&l2_file->tifiles.hdr.fphysrecs, data);
- break;
- }
-
- return 0;
-}
-
-static UINT8 get_file_eof(struct ti99_lvl2_fileref *l2_file)
-{
- int reply = 0;
-
- switch (l2_file->type)
- {
- case L2F_DSK:
- reply = l2_file->dsk.fdr.eof;
- break;
-
- case L2F_WIN:
- reply = l2_file->win.curfdr.eof;
- break;
-
- case L2F_TIFILES:
- reply = l2_file->tifiles.hdr.eof;
- break;
- }
-
- return reply;
-}
-
-static void set_file_eof(struct ti99_lvl2_fileref *l2_file, UINT8 data)
-{
- switch (l2_file->type)
- {
- case L2F_DSK:
- l2_file->dsk.fdr.eof = data;
- break;
-
- case L2F_WIN:
- l2_file->win.curfdr.eof = data;
- break;
-
- case L2F_TIFILES:
- l2_file->tifiles.hdr.eof = data;
- break;
- }
-}
-
-static UINT16 get_file_reclen(struct ti99_lvl2_fileref *l2_file)
-{
- int reply = 0;
-
- switch (l2_file->type)
- {
- case L2F_DSK:
- reply = l2_file->dsk.fdr.reclen;
- if ((reply == 0) && (! (l2_file->dsk.fdr.flags & (fdr99_f_program /*| fdr99_f_var*/))))
- reply = get_UINT16BE(l2_file->dsk.fdr.xreclen);
- break;
-
- case L2F_WIN:
- reply = l2_file->win.curfdr.reclen;
- if ((reply == 0) && (! (l2_file->win.curfdr.flags & (fdr99_f_program /*| fdr99_f_var*/))))
- reply = get_UINT16BE(l2_file->win.curfdr.xreclen);
- break;
-
- case L2F_TIFILES:
- reply = l2_file->tifiles.hdr.reclen;
- break;
- }
-
- return reply;
-}
-
-static int set_file_reclen(struct ti99_lvl2_fileref *l2_file, UINT16 data)
-{
- switch (l2_file->type)
- {
- case L2F_DSK:
- if (data < 256)
- {
- l2_file->dsk.fdr.reclen = data;
- set_UINT16BE(&l2_file->dsk.fdr.xreclen, 0);
- }
- else
- {
- l2_file->dsk.fdr.reclen = 0;
- set_UINT16BE(&l2_file->dsk.fdr.xreclen, data);
- }
- break;
-
- case L2F_WIN:
- if (data < 256)
- {
- l2_file->win.curfdr.reclen = data;
- set_UINT16BE(&l2_file->win.curfdr.xreclen, 0);
- }
- else
- {
- l2_file->win.curfdr.reclen = 0;
- set_UINT16BE(&l2_file->win.curfdr.xreclen, data);
- }
- break;
-
- case L2F_TIFILES:
- if (data >= 256)
- return IMGTOOLERR_UNIMPLEMENTED;
- l2_file->tifiles.hdr.reclen = data;
- break;
- }
-
- return 0;
-}
-
-static unsigned get_file_fixrecs(struct ti99_lvl2_fileref *l2_file)
-{
- int reply = 0;
-
- switch (l2_file->type)
- {
- case L2F_DSK:
- reply = get_UINT16LE(l2_file->dsk.fdr.fixrecs);
- break;
-
- case L2F_WIN:
- reply = get_win_fdr_fixrecs(&l2_file->win.curfdr);
- break;
-
- case L2F_TIFILES:
- reply = get_UINT16BE(l2_file->tifiles.hdr.fixrecs);
- break;
- }
-
- return reply;
-}
-
-static int set_file_fixrecs(struct ti99_lvl2_fileref *l2_file, unsigned data)
-{
- switch (l2_file->type)
- {
- case L2F_DSK:
- if (data >= 65536)
- return IMGTOOLERR_UNIMPLEMENTED;
- set_UINT16LE(&l2_file->dsk.fdr.fixrecs, data);
- break;
-
- case L2F_WIN:
- set_win_fdr_fixrecs(&l2_file->win.curfdr, data);
- break;
-
- case L2F_TIFILES:
- if (data >= 65536)
- return IMGTOOLERR_UNIMPLEMENTED;
- set_UINT16BE(&l2_file->tifiles.hdr.fixrecs, data);
- break;
- }
-
- return 0;
-}
-
-static void get_file_creation_date(struct ti99_lvl2_fileref *l2_file, ti99_date_time *reply)
-{
- switch (l2_file->type)
- {
- case L2F_DSK:
- *reply = l2_file->dsk.fdr.creation;
- break;
-
- case L2F_WIN:
- *reply = l2_file->win.curfdr.creation;
- break;
-
- case L2F_TIFILES:
- memset(reply, 0, sizeof(*reply));
- break;
- }
-}
-
-static void set_file_creation_date(struct ti99_lvl2_fileref *l2_file, ti99_date_time data)
-{
- switch (l2_file->type)
- {
- case L2F_DSK:
- l2_file->dsk.fdr.creation = data;
- break;
-
- case L2F_WIN:
- l2_file->win.curfdr.creation = data;
- break;
-
- case L2F_TIFILES:
- break;
- }
-}
-
-static void get_file_update_date(struct ti99_lvl2_fileref *l2_file, ti99_date_time *reply)
-{
- switch (l2_file->type)
- {
- case L2F_DSK:
- *reply = l2_file->dsk.fdr.update;
- break;
-
- case L2F_WIN:
- *reply = l2_file->win.curfdr.update;
- break;
-
- case L2F_TIFILES:
- memset(reply, 0, sizeof(*reply));
- break;
- }
-}
-
-static void set_file_update_date(struct ti99_lvl2_fileref *l2_file, ti99_date_time data)
-{
- switch (l2_file->type)
- {
- case L2F_DSK:
- l2_file->dsk.fdr.update = data;
- break;
-
- case L2F_WIN:
- l2_file->win.curfdr.update = data;
- break;
-
- case L2F_TIFILES:
- break;
- }
-}
-
-#ifdef UNUSED_FUNCTION
-static void current_date_time(ti99_date_time *reply)
-{
- /* All these functions should be ANSI */
- time_t cur_time = time(NULL);
- struct tm expanded_time = *localtime(& cur_time);
-
- reply->time_MSB = (expanded_time.tm_hour << 3) | (expanded_time.tm_min >> 3);
- reply->time_LSB = (expanded_time.tm_min << 5) | (expanded_time.tm_sec >> 1);
- reply->date_MSB = ((expanded_time.tm_year % 100) << 1) | ((expanded_time.tm_mon+1) >> 3);
- reply->date_LSB = ((expanded_time.tm_mon+1) << 5) | expanded_time.tm_mday;
-}
-#endif
-
-#if 0
-#pragma mark -
-#pragma mark LEVEL 3 DISK ROUTINES
-#endif
-
-/*
- Level 3 implements files as a succession of logical records.
-
- There are three types of files:
- * program files that are not implemented at level 3 (no logical record)
- * files with fixed-size records (random-access files)
- * files with variable-size records (sequential-access)
-*/
-
-struct ti99_lvl3_fileref
-{
- ti99_lvl2_fileref l2_file;
-
- int cur_log_rec;
- int cur_phys_rec;
- int cur_pos_in_phys_rec;
-};
-
-#ifdef UNUSED_FUNCTION
-/*
- Open a file on level 3.
-
- To open a file on level 3, you must open (or create) the file on level 2,
- then pass the file reference to open_file_lvl3.
-*/
-static int open_file_lvl3(ti99_lvl3_fileref *l3_file)
-{
- l3_file->cur_log_rec = 0;
- l3_file->cur_phys_rec = 0;
- l3_file->cur_pos_in_phys_rec = 0;
-
- /*if ()*/
-
- return 0;
-}
-
-/*
- Test a file for EOF
-*/
-static int is_eof(ti99_lvl3_fileref *l3_file)
-{
- int flags = get_file_flags(&l3_file->l2_file);
- int fphysrecs = get_file_fphysrecs(&l3_file->l2_file);
- int fdr_eof = get_file_eof(&l3_file->l2_file);
-
- if (flags & fdr99_f_var)
- {
- return (l3_file->cur_phys_rec >= fphysrecs);
- }
- else
- {
- return ((l3_file->cur_phys_rec >= fphysrecs)
- || ((l3_file->cur_phys_rec == (fphysrecs-1))
- && (l3_file->cur_pos_in_phys_rec >= (fdr_eof ? fdr_eof : 256))));
- }
-}
-
-/*
- Read next record from a file
-*/
-static int read_next_record(ti99_lvl3_fileref *l3_file, void *dest, int *out_reclen)
-{
- int errorcode;
- UINT8 physrec_buf[256];
- int reclen;
- int flags = get_file_flags(&l3_file->l2_file);
- int fphysrecs = get_file_fphysrecs(&l3_file->l2_file);
- int fdr_eof = get_file_eof(&l3_file->l2_file);
-
- if (flags & fdr99_f_program)
- {
- /* program files have no level-3 record */
- return IMGTOOLERR_UNEXPECTED;
- }
- else if (flags & fdr99_f_var)
- {
- /* variable-length records */
- if (is_eof(l3_file))
- return IMGTOOLERR_UNEXPECTED;
- errorcode = read_file_physrec(&l3_file->l2_file, l3_file->cur_phys_rec, physrec_buf);
- if (errorcode)
- return errorcode;
- /* read reclen */
- reclen = physrec_buf[l3_file->cur_pos_in_phys_rec];
- /* check integrity */
- if ((reclen == 0xff) || (reclen > get_file_reclen(&l3_file->l2_file))
- || ((l3_file->cur_pos_in_phys_rec + 1 + reclen) > 256))
- return IMGTOOLERR_CORRUPTIMAGE;
- /* copy to buffer */
- memcpy(dest, physrec_buf + l3_file->cur_pos_in_phys_rec + 1, reclen);
- l3_file->cur_pos_in_phys_rec += reclen + 1;
- /* skip to next physrec if needed */
- if ((l3_file->cur_pos_in_phys_rec == 256)
- || (physrec_buf[l3_file->cur_pos_in_phys_rec] == 0xff))
- {
- l3_file->cur_pos_in_phys_rec = 0;
- l3_file->cur_phys_rec++;
- }
- (* out_reclen) = reclen;
- }
- else
- {
- /* fixed len records */
- reclen = get_file_reclen(&l3_file->l2_file);
- if (is_eof(l3_file))
- return IMGTOOLERR_UNEXPECTED;
- if ((l3_file->cur_pos_in_phys_rec + reclen) > 256)
- {
- l3_file->cur_pos_in_phys_rec = 0;
- l3_file->cur_phys_rec++;
- }
- if ((l3_file->cur_phys_rec >= fphysrecs)
- || ((l3_file->cur_phys_rec == (fphysrecs-1))
- && ((l3_file->cur_pos_in_phys_rec + reclen) >= (fdr_eof ? fdr_eof : 256))))
- return IMGTOOLERR_CORRUPTIMAGE;
- errorcode = read_file_physrec(&l3_file->l2_file, l3_file->cur_phys_rec, physrec_buf);
- if (errorcode)
- return errorcode;
- memcpy(dest, physrec_buf + l3_file->cur_pos_in_phys_rec, reclen);
- l3_file->cur_pos_in_phys_rec += reclen;
- if (l3_file->cur_pos_in_phys_rec == 256)
- {
- l3_file->cur_pos_in_phys_rec = 0;
- l3_file->cur_phys_rec++;
- }
- (* out_reclen) = reclen;
- }
-
- return 0;
-}
-#endif
-
-#if 0
-#pragma mark -
-#pragma mark IMGTOOL MODULE IMPLEMENTATION
-#endif
-
-/*
- ti99 catalog iterator, used when imgtool reads the catalog
-*/
-struct dsk_iterator
-{
- struct ti99_lvl2_imgref *image;
- int level;
- int listing_subdirs; /* true if we are listing subdirectories at current level */
- int index[2]; /* current index in the disk catalog */
- ti99_catalog *cur_catalog; /* current catalog */
-};
-
-struct win_iterator
-{
- struct ti99_lvl2_imgref *image;
- int level;
- int listing_subdirs; /* true if we are listing subdirectories at current level */
- int index[MAX_DIR_LEVEL]; /* current index in the disk catalog */
- ti99_catalog catalog[MAX_DIR_LEVEL]; /* current catalog */
-};
-
-
-static imgtoolerr_t dsk_image_init_mess(imgtool_image *image, imgtool_stream *f);
-static imgtoolerr_t dsk_image_init_v9t9(imgtool_image *image, imgtool_stream *f);
-static imgtoolerr_t dsk_image_init_pc99_fm(imgtool_image *image, imgtool_stream *f);
-static imgtoolerr_t dsk_image_init_pc99_mfm(imgtool_image *image, imgtool_stream *f);
-static imgtoolerr_t win_image_init(imgtool_image *image, imgtool_stream *f);
-static void ti99_image_exit(imgtool_image *img);
-static void ti99_image_info(imgtool_image *img, char *string, size_t len);
-static imgtoolerr_t dsk_image_beginenum(imgtool_directory *enumeration, const char *path);
-static imgtoolerr_t dsk_image_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent);
-static imgtoolerr_t win_image_beginenum(imgtool_directory *enumeration, const char *path);
-static imgtoolerr_t win_image_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent);
-static imgtoolerr_t ti99_image_freespace(imgtool_partition *partition, UINT64 *size);
-static imgtoolerr_t ti99_image_readfile(imgtool_partition *partition, const char *fpath, const char *fork, imgtool_stream *destf);
-static imgtoolerr_t ti99_image_writefile(imgtool_partition *partition, const char *fpath, const char *fork, imgtool_stream *sourcef, option_resolution *writeoptions);
-static imgtoolerr_t dsk_image_deletefile(imgtool_partition *partition, const char *fpath);
-static imgtoolerr_t win_image_deletefile(imgtool_partition *partition, const char *fpath);
-static imgtoolerr_t dsk_image_create_mess(imgtool_image *image, imgtool_stream *f, option_resolution *createoptions);
-static imgtoolerr_t dsk_image_create_v9t9(imgtool_image *image, imgtool_stream *f, option_resolution *createoptions);
-
-enum
-{
- dsk_createopts_volname = 'A',
- dsk_createopts_sides = 'B',
- dsk_createopts_tracks = 'C',
- dsk_createopts_sectors = 'D',
- dsk_createopts_protection = 'E',
- dsk_createopts_density = 'F'
-};
-
-static OPTION_GUIDE_START( dsk_create_optionguide )
- OPTION_STRING(dsk_createopts_volname, "label", "Volume name" )
- OPTION_INT(dsk_createopts_sides, "sides", "Sides" )
- OPTION_INT(dsk_createopts_tracks, "tracks", "Tracks" )
- OPTION_INT(dsk_createopts_sectors, "sectors", "Sectors (1->9 for SD, 1->18 for DD, 1->36 for HD)" )
- OPTION_INT(dsk_createopts_protection, "protection", "Protection (0 for normal, 1 for protected)" )
- OPTION_ENUM_START(dsk_createopts_density, "density", "Density" )
- OPTION_ENUM( 0, "Auto", "Auto" )
- OPTION_ENUM( 1, "SD", "Single Density" )
- OPTION_ENUM( 2, "DD", "Double Density" )
- OPTION_ENUM( 3, "HD", "High Density" )
- OPTION_ENUM_END
-OPTION_GUIDE_END
-
-#define dsk_create_optionspecs "B1-[2];C1-[40]-80;D1-[18]-36;E[0]-1;F[0]-3"
-
-static void ti99_getinfo(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info)
-{
- switch(state)
- {
- case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: info->i = sizeof(ti99_lvl2_imgref); break;
- case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(dsk_iterator); break;
-
- case IMGTOOLINFO_STR_EOLN: strcpy(info->s = imgtool_temp_str(), "\r"); break;
- case IMGTOOLINFO_PTR_CLOSE: info->close = ti99_image_exit; break;
- case IMGTOOLINFO_PTR_INFO: info->info = ti99_image_info; break;
- case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = ti99_image_freespace; break;
- case IMGTOOLINFO_PTR_READ_FILE: info->read_file = ti99_image_readfile; break;
- case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = ti99_image_writefile; break;
- }
-}
-
-static void ti99_dsk_getinfo(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info)
-{
- switch(state)
- {
- case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "dsk"); break;
- case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = dsk_image_beginenum; break;
- case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = dsk_image_nextenum; break;
- case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = dsk_image_deletefile; break;
- default: ti99_getinfo(imgclass, state, info);
- }
-}
-
-void ti99_old_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info)
-{
- switch(state)
- {
- case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "ti99_old"); break;
- case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "TI99 Diskette (old MESS format)"); break;
- case IMGTOOLINFO_PTR_OPEN: info->open = dsk_image_init_mess; break;
- case IMGTOOLINFO_PTR_CREATE: info->create = dsk_image_create_mess; break;
- case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = dsk_create_optionguide; break;
- case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), dsk_create_optionspecs); break;
- default: ti99_dsk_getinfo(imgclass, state, info); break;
- }
-}
-
-void ti99_v9t9_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info)
-{
- switch(state)
- {
- case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "v9t9"); break;
- case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "TI99 Diskette (V9T9 format)"); break;
- case IMGTOOLINFO_PTR_OPEN: info->open = dsk_image_init_v9t9; break;
- case IMGTOOLINFO_PTR_CREATE: info->create = dsk_image_create_v9t9; break;
- case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = dsk_create_optionguide; break;
- case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), dsk_create_optionspecs); break;
- default: ti99_dsk_getinfo(imgclass, state, info); break;
- }
-}
-
-void ti99_pc99fm_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info)
-{
- switch(state)
- {
- case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "pc99fm"); break;
- case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "TI99 Diskette (PC99 FM format)"); break;
- case IMGTOOLINFO_PTR_OPEN: info->open = dsk_image_init_pc99_fm; break;
- case IMGTOOLINFO_PTR_CREATE: /* info->create = dsk_image_create_pc99fm; */ break;
- default: ti99_dsk_getinfo(imgclass, state, info); break;
- }
-}
-
-void ti99_pc99mfm_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info)
-{
- switch(state)
- {
- case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "pc99mfm"); break;
- case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "TI99 Diskette (PC99 MFM format)"); break;
- case IMGTOOLINFO_PTR_OPEN: info->open = dsk_image_init_pc99_mfm; break;
- case IMGTOOLINFO_PTR_CREATE: /* info->create = dsk_image_create_pc99mfm; */ break;
- default: ti99_dsk_getinfo(imgclass, state, info); break;
- }
-}
-
-void ti99_ti99hd_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info)
-{
- switch(state)
- {
- case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "ti99hd"); break;
- case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "TI99 Harddisk"); break;
- case IMGTOOLINFO_PTR_OPEN: info->open = win_image_init; break;
- case IMGTOOLINFO_PTR_CREATE: /* info->create = hd_image_create; */ break;
-
- case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "hd"); break;
- case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = win_image_beginenum; break;
- case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = win_image_nextenum; break;
- case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = win_image_deletefile; break;
- default: ti99_getinfo(imgclass, state, info);
- }
-}
-
-
-
-/*
- Open a file as a ti99_image (common code).
-*/
-static int dsk_image_init(imgtool_image *img, imgtool_stream *f, ti99_img_format img_format)
-{
- struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(img);
- dsk_vib vib;
- int reply;
- int totphysrecs;
- unsigned fdir_aphysrec;
- int i;
-
- /* open disk image at level 1 */
- reply = open_image_lvl1(f, img_format, &image->l1_img, &vib);
- if (reply)
- return reply;
-
- /* open disk image at level 2 */
- image->type = L2I_DSK;
-
- /* @BN@ */
- /* Copy in the allocation bit map! */
- memcpy(image->abm, vib.abm, 200);
- /* first compute AU size and number of AUs */
- totphysrecs = get_UINT16BE(vib.totphysrecs);
-
- image->AUformat.physrecsperAU = (totphysrecs + 1599) / 1600;
- /* round to next larger power of 2 */
- for (i = 1; i < image->AUformat.physrecsperAU; i <<= 1)
- ;
- image->AUformat.physrecsperAU = i;
- image->AUformat.totAUs = totphysrecs / image->AUformat.physrecsperAU;
-
- /* extract number of physrecs */
- image->dsk.totphysrecs = get_UINT16BE(vib.totphysrecs);
-
- /* read and check main volume catalog */
- reply = dsk_read_catalog(image, 1, &image->dsk.catalogs[0]);
- if (reply)
- return reply;
-
- image->dsk.fdir_aphysrec[0] = 1;
-
- /* read and check subdirectory catalogs */
- /* Note that the reserved areas used for HFDC subdirs may be used for other
- purposes by other FDRs, so, if we get any error, we will assume there is no
- subdir after all... */
- image->dsk.catalogs[0].num_subdirs = 0;
- for (i=0; i<3; i++)
- {
- fdir_aphysrec = get_UINT16BE(vib.subdir[i].fdir_aphysrec);
- if ((! memcmp(vib.subdir[i].name, "\0\0\0\0\0\0\0\0\0\0", 10))
- || (! memcmp(vib.subdir[i].name, " ", 10)))
- {
- /* name is empty: fine with us unless there is a fdir pointer */
- if (fdir_aphysrec != 0)
- {
- image->dsk.catalogs[0].num_subdirs = 0;
- break;
- }
- }
- else if (check_fname(vib.subdir[i].name))
- {
- /* name is invalid: this is not an HFDC format floppy */
- image->dsk.catalogs[0].num_subdirs = 0;
- break;
- }
- else
- {
- /* there is a non-empty name */
- if ((fdir_aphysrec == 0) || (fdir_aphysrec >= totphysrecs))
- {
- /* error: fdir pointer is invalid or NULL */
- image->dsk.catalogs[0].num_subdirs = 0;
- break;
- }
- /* fill in descriptor fields */
- image->dsk.fdir_aphysrec[image->dsk.catalogs[0].num_subdirs+1] = fdir_aphysrec;
- /*image->dsk.catalogs[0].subdirs[image->dsk.catalogs[0].num_subdirs].dir_ptr = fdir_aphysrec;*/
- memcpy(image->dsk.catalogs[0].subdirs[image->dsk.catalogs[0].num_subdirs].name, vib.subdir[i].name, 10);
- reply = dsk_read_catalog(image, fdir_aphysrec, &image->dsk.catalogs[image->dsk.catalogs[0].num_subdirs+1]);
- if (reply)
- {
- /* error: invalid fdir */
- image->dsk.catalogs[0].num_subdirs = 0;
- break;
- }
- /* found valid subdirectory: increment subdir count */
- image->dsk.catalogs[0].num_subdirs++;
- }
- }
-
- /* extract volume name */
- memcpy(image->vol_name, vib.name, 10);
-
- /* initialize default data_offset */
- image->data_offset = 32+2;
-
- return 0;
-}
-
-/*
- Open a file as a ti99_image (MESS format).
-*/
-static imgtoolerr_t dsk_image_init_mess(imgtool_image *image, imgtool_stream *f)
-{
- return (imgtoolerr_t)dsk_image_init(image, f, if_mess);
-}
-
-/*
- Open a file as a ti99_image (V9T9 format).
-*/
-static imgtoolerr_t dsk_image_init_v9t9(imgtool_image *image, imgtool_stream *f)
-{
- return (imgtoolerr_t)dsk_image_init(image, f, if_v9t9);
-}
-
-/*
- Open a file as a ti99_image (PC99 FM format).
-*/
-static imgtoolerr_t dsk_image_init_pc99_fm(imgtool_image *image, imgtool_stream *f)
-{
- return (imgtoolerr_t)dsk_image_init(image, f, if_pc99_fm);
-}
-
-/*
- Open a file as a ti99_image (PC99 MFM format).
-*/
-static imgtoolerr_t dsk_image_init_pc99_mfm(imgtool_image *image, imgtool_stream *f)
-{
- return (imgtoolerr_t)dsk_image_init(image, f, if_pc99_mfm);
-}
-
-/*
- Open a file as a ti99_image (harddisk format).
-*/
-static imgtoolerr_t win_image_init(imgtool_image *img, imgtool_stream *f)
-{
- struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(img);
- win_vib_ddr vib;
- int reply;
- int i;
-
- /* open disk image at level 1 */
- reply = open_image_lvl1(f, if_harddisk, & image->l1_img, NULL);
- if (reply)
- return (imgtoolerr_t)reply;
-
- /* open disk image at level 2 */
- image->type = L2I_WIN;
-
- /* read VIB */
- reply = read_absolute_physrec(&image->l1_img, 0, &vib);
- if (reply)
- return (imgtoolerr_t)reply;
-
- /* guess VIB version */
- image->win.vib_version = memcmp(vib.u.vib_v1.id, "WIN", 3) ? win_vib_v2 : win_vib_v1;
-
- /* extract AU size and number of AUs */
- image->AUformat.physrecsperAU = ((get_UINT16BE(vib.params) >> 12) & 0xf) + 1;
- image->AUformat.totAUs = get_UINT16BE(vib.totAUs);
-
- /* extract volume name */
- memcpy(image->vol_name, vib.name, 10);
-
- /* extract data_offset */
- switch (image->win.vib_version)
- {
- case win_vib_v1:
- image->data_offset = 64;
- break;
-
- case win_vib_v2:
- image->data_offset = vib.u.vib_v2.res_AUs * 64;
- break;
- }
-
- /* read allocation bitmap (aphysrecs 1 through n, n<=33) */
- for (i=0; i < (image->AUformat.totAUs+2047)/2048; i++)
- {
- reply = read_absolute_physrec(&image->l1_img, i+1, image->abm+i*256);
- if (reply)
- return (imgtoolerr_t)reply;
- }
-
- return (imgtoolerr_t)0;
-}
-
-/*
- close a ti99_image
-*/
-static void ti99_image_exit(imgtool_image *img)
-{
- struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(img);
-
- close_image_lvl1(&image->l1_img);
-}
-
-/*
- get basic information on a ti99_image
-
- Currently returns the volume name
-*/
-static void ti99_image_info(imgtool_image *img, char *string, size_t len)
-{
- struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(img);
- char vol_name[11];
-
- fname_to_str(vol_name, image->vol_name, 11);
-
- snprintf(string, len, "%s", vol_name);
-}
-
-/*
- Open the disk catalog for enumeration
-*/
-static imgtoolerr_t dsk_image_beginenum(imgtool_directory *enumeration, const char *path)
-{
- struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(imgtool_directory_image(enumeration));
- dsk_iterator *iter = (dsk_iterator *) imgtool_directory_extrabytes(enumeration);
-
- iter->image = image;
- iter->level = 0;
- iter->listing_subdirs = 1;
- iter->index[0] = 0;
- iter->cur_catalog = &iter->image->dsk.catalogs[0];
-
- return (imgtoolerr_t)0;
-}
-
-/*
- Enumerate disk catalog next entry
-*/
-static imgtoolerr_t dsk_image_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent)
-{
- dsk_iterator *iter = (dsk_iterator*) imgtool_directory_extrabytes(enumeration);
- dsk_fdr fdr;
- int reply;
- unsigned fdr_aphysrec;
-
-
- ent->corrupt = 0;
- ent->eof = 0;
-
- /* iterate through catalogs to next file or dir entry */
- while ((iter->level >= 0)
- && (iter->index[iter->level] >= (iter->listing_subdirs
- ? iter->cur_catalog->num_subdirs
- : iter->cur_catalog->num_files)))
- {
- if (iter->listing_subdirs)
- {
- iter->listing_subdirs = 0;
- iter->index[iter->level] = 0;
- }
- else
- {
- iter->listing_subdirs = 1;
- if (! iter->level)
- iter->level = -1;
- else
- {
- iter->level = 0;
- iter->index[0]++;
- iter->cur_catalog = &iter->image->dsk.catalogs[0];
- }
- }
- }
-
- if (iter->level < 0)
- {
- ent->eof = 1;
- }
- else
- {
- if (iter->listing_subdirs)
- {
- fname_to_str(ent->filename, iter->image->dsk.catalogs[0].subdirs[iter->index[iter->level]].name, ARRAY_LENGTH(ent->filename));
-
- /* set type of DIR */
- snprintf(ent->attr, ARRAY_LENGTH(ent->attr), "DIR");
-
- /* len in physrecs */
- /* @BN@ return length in bytes */
- /* ent->filesize = 1; */
- ent->filesize = 256;
-
- /* recurse subdirectory */
- iter->listing_subdirs = 0; /* no need to list subdirs as only the
- root dir has subdirs in DSK format */
- iter->level = 1;
- iter->cur_catalog = &iter->image->dsk.catalogs[iter->index[0]+1];
- iter->index[iter->level] = 0;
- }
- else
- {
- fdr_aphysrec = iter->cur_catalog->files[iter->index[iter->level]].fdr_ptr;
- reply = read_absolute_physrec(& iter->image->l1_img, fdr_aphysrec, & fdr);
- if (reply)
- return IMGTOOLERR_READERROR;
-#if 0
- fname_to_str(ent->filename, fdr.name, ARRAY_LENGTH(ent->filename));
-#else
- {
- char buf[11];
-
- ent->filename[0] = '\0';
- if (iter->level)
- {
- fname_to_str(ent->filename, iter->image->dsk.catalogs[0].subdirs[iter->index[0]].name, ARRAY_LENGTH(ent->filename));
- strncat(ent->filename, ".", ARRAY_LENGTH(ent->filename) - 1);
- }
- fname_to_str(buf, fdr.name, 11);
- strncat(ent->filename, buf, ARRAY_LENGTH(ent->filename) - 1);
- }
-#endif
- /* parse flags */
- if (fdr.flags & fdr99_f_program)
- snprintf(ent->attr, ARRAY_LENGTH(ent->attr), "PGM%s",
- (fdr.flags & fdr99_f_wp) ? " R/O" : "");
- else
- snprintf(ent->attr, ARRAY_LENGTH(ent->attr), "%c/%c %d%s",
- (fdr.flags & fdr99_f_int) ? 'I' : 'D',
- (fdr.flags & fdr99_f_var) ? 'V' : 'F',
- fdr.reclen,
- (fdr.flags & fdr99_f_wp) ? " R/O" : "");
- /* len in physrecs */
- /* @BN@ return length in bytes */
- /* ent->filesize = get_UINT16BE(fdr.fphysrecs); */
- ent->filesize = (get_UINT16BE(fdr.fphysrecs)+1)*256;
-
- iter->index[iter->level]++;
- }
- }
-
- return (imgtoolerr_t)0;
-}
-
-/*
- Open the disk catalog for enumeration
-*/
-static imgtoolerr_t win_image_beginenum(imgtool_directory *enumeration, const char *path)
-{
- struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(imgtool_directory_image(enumeration));
- win_iterator *iter = (win_iterator *) imgtool_directory_extrabytes(enumeration);
- imgtoolerr_t errorcode;
-
- iter->image = image;
- iter->level = 0;
- iter->listing_subdirs = 1;
- iter->index[0] = 0;
- errorcode = (imgtoolerr_t)win_read_catalog(image, 0, &iter->catalog[0]);
- if (errorcode)
- return errorcode;
-
- return (imgtoolerr_t)0;
-}
-
-/*
- Enumerate disk catalog next entry
-*/
-static imgtoolerr_t win_image_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent)
-{
- win_iterator *iter = (win_iterator *) imgtool_directory_extrabytes(enumeration);
- unsigned fdr_aphysrec;
- win_fdr fdr;
- int reply;
- int i;
-
-
- ent->corrupt = 0;
- ent->eof = 0;
-
- /* iterate through catalogs to next file or dir entry */
- while ((iter->level >= 0)
- && (iter->index[iter->level] >= (iter->listing_subdirs
- ? iter->catalog[iter->level].num_subdirs
- : iter->catalog[iter->level].num_files)))
- {
- if (iter->listing_subdirs)
- {
- iter->listing_subdirs = 0;
- iter->index[iter->level] = 0;
- }
- else
- {
- iter->listing_subdirs = 1;
- iter->level--;
- iter->index[iter->level]++;
- }
- }
-
- if (iter->level < 0)
- {
- ent->eof = 1;
- }
- else
- {
- if (iter->listing_subdirs)
- {
-#if 0
- fname_to_str(ent->filename, iter->catalog[iter->level].subdirs[iter->index[iter->level]].name, ARRAY_LENGTH(ent->filename));
-#else
- {
- char buf[11];
-
- ent->filename[0] = '\0';
- for (i=0; i<iter->level; i++)
- {
- fname_to_str(buf, iter->catalog[i].subdirs[iter->index[i]].name, 11);
- strncat(ent->filename, buf, ARRAY_LENGTH(ent->filename) - 1);
- strncat(ent->filename, ".", ARRAY_LENGTH(ent->filename) - 1);
- }
- fname_to_str(buf, iter->catalog[iter->level].subdirs[iter->index[iter->level]].name, 11);
- strncat(ent->filename, buf, ARRAY_LENGTH(ent->filename) - 1);
- }
-#endif
-
- /* set type of DIR */
- snprintf(ent->attr, ARRAY_LENGTH(ent->attr), "DIR");
-
- /* len in physrecs */
- /* @BN@ return length in bytes */
- /* ent->filesize = 2; */
- ent->filesize = 512;
-
- /* recurse subdirectory */
- /*iter->listing_subdirs = 1;*/
- iter->level++;
- iter->index[iter->level] = 0;
- reply = win_read_catalog(iter->image, iter->catalog[iter->level-1].subdirs[iter->index[iter->level-1]].dir_ptr, &iter->catalog[iter->level]);
- if (reply)
- {
- ent->corrupt = 1;
- return (imgtoolerr_t)reply;
- }
- }
- else
- {
- fdr_aphysrec = iter->catalog[iter->level].files[iter->index[iter->level]].fdr_ptr*iter->image->AUformat.physrecsperAU;
- reply = read_absolute_physrec(& iter->image->l1_img, fdr_aphysrec, & fdr);
- if (reply)
- return IMGTOOLERR_READERROR;
-#if 0
- fname_to_str(ent->filename, iter->catalog[iter->level].files[iter->index[iter->level]].name, ARRAY_LENGTH(ent->filename));
-#else
- {
- char buf[11];
-
- ent->filename[0] = '\0';
- for (i=0; i<iter->level; i++)
- {
- fname_to_str(buf, iter->catalog[i].subdirs[iter->index[i]].name, 11);
- strncat(ent->filename, buf, ARRAY_LENGTH(ent->filename) - 1);
- strncat(ent->filename, ".", ARRAY_LENGTH(ent->filename) - 1);
- }
- fname_to_str(buf, iter->catalog[iter->level].files[iter->index[iter->level]].name, 11);
- strncat(ent->filename, buf, ARRAY_LENGTH(ent->filename) - 1);
- }
-#endif
- /* parse flags */
- if (fdr.flags & fdr99_f_program)
- snprintf(ent->attr, ARRAY_LENGTH(ent->attr), "PGM%s",
- (fdr.flags & fdr99_f_wp) ? " R/O" : "");
- else
- snprintf(ent->attr, ARRAY_LENGTH(ent->attr), "%c/%c %d%s",
- (fdr.flags & fdr99_f_int) ? 'I' : 'D',
- (fdr.flags & fdr99_f_var) ? 'V' : 'F',
- fdr.reclen,
- (fdr.flags & fdr99_f_wp) ? " R/O" : "");
- /* len in physrecs */
- /* @BN@ return length in bytes */
- /* ent->filesize = get_win_fdr_fphysrecs(&fdr); */
- ent->filesize = (get_win_fdr_fphysrecs(&fdr)+1)*256;
-
- iter->index[iter->level]++;
- }
- }
-
- return (imgtoolerr_t)0;
-}
-
-/*
- Compute free space on disk image (in AUs)
-*/
-static imgtoolerr_t ti99_image_freespace(imgtool_partition *partition, UINT64 *size)
-{
- imgtool_image *img = imgtool_partition_image(partition);
- struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(img);
- size_t freeAUs;
- int i;
-
- freeAUs = 0;
- for (i=0; i<image->AUformat.totAUs; i++)
- {
- if (! (image->abm[i >> 3] & (1 << (i & 7))))
- freeAUs++;
- }
-
- /* @BN@ return free space in bytes */
- /* *size = freeAUs; */
- *size = freeAUs*256;
-
- return IMGTOOLERR_SUCCESS;
-}
-
-/*
- Extract a file from a ti99_image. The file is saved in tifile format.
-*/
-static imgtoolerr_t ti99_image_readfile(imgtool_partition *partition, const char *fpath, const char *fork, imgtool_stream *destf)
-{
- imgtool_image *img = imgtool_partition_image(partition);
-#if 1
-
- /* extract data as TIFILES */
- struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(img);
- ti99_lvl2_fileref src_file;
- ti99_lvl2_fileref dst_file;
- ti99_date_time date_time;
- int fphysrecs;
- int i;
- UINT8 buf[256];
- imgtoolerr_t errorcode;
-
-
- if (check_fpath(fpath))
- return IMGTOOLERR_BADFILENAME;
-
- /* open file on TI image */
- switch (image->type)
- {
- case L2I_DSK:
- errorcode = (imgtoolerr_t)open_file_lvl2_dsk(image, fpath, &src_file);
- break;
-
- case L2I_WIN:
- errorcode = (imgtoolerr_t)open_file_lvl2_win(image, fpath, &src_file);
- break;
-
- default:
- errorcode = (imgtoolerr_t)-1;
- break;
- }
- if (errorcode)
- return errorcode;
-
- errorcode = (imgtoolerr_t)new_file_lvl2_tifiles(destf, &dst_file);
- if (errorcode)
- return errorcode;
-
- /* write TIFILE header */
- /* set up parameters */
- set_file_flags(&dst_file, get_file_flags(&src_file));
- set_file_recsperphysrec(&dst_file, get_file_recsperphysrec(&src_file));
- errorcode = (imgtoolerr_t)set_file_fphysrecs(&dst_file, get_file_fphysrecs(&src_file));
- if (errorcode)
- return errorcode;
- set_file_eof(&dst_file, get_file_eof(&src_file));
- errorcode = (imgtoolerr_t)set_file_reclen(&dst_file, get_file_reclen(&src_file));
- if (errorcode)
- return errorcode;
- errorcode = (imgtoolerr_t)set_file_fixrecs(&dst_file, get_file_fixrecs(&src_file));
- if (errorcode)
- return errorcode;
-
- get_file_creation_date(&src_file, &date_time);
-#if 0
- if ((date_time.time_MSB == 0) || (date_time.time_LSB == 0)
- || (date_time.date_MSB == 0) || (date_time.date_LSB == 0))
- current_date_time(&date_time);
-#endif
- set_file_creation_date(&dst_file, date_time);
-
- get_file_update_date(&src_file, &date_time);
-#if 0
- if ((date_time.time_MSB == 0) || (date_time.time_LSB == 0)
- || (date_time.date_MSB == 0) || (date_time.date_LSB == 0))
- current_date_time(&date_time);
-#endif
- set_file_update_date(&dst_file, date_time);
-
- if (stream_write(destf, & dst_file.tifiles.hdr, 128) != 128)
- return (imgtoolerr_t)IMGTOOLERR_WRITEERROR;
-
- /* copy data to TIFILE */
- fphysrecs = get_file_fphysrecs(&src_file);
-
- for (i=0; i<fphysrecs; i++)
- {
- errorcode = (imgtoolerr_t)read_file_physrec(& src_file, i, buf);
- if (errorcode)
- return errorcode;
-
- errorcode = (imgtoolerr_t)write_file_physrec(& dst_file, i, buf);
- if (errorcode)
- return errorcode;
- }
-
- return (imgtoolerr_t)0;
-
-#else
-
- struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(img);
- ti99_lvl3_fileref src_file;
- UINT8 buf[256];
- int reclen;
- char lineend = '\r';
- int errorcode;
-
-
- if (check_fpath(fpath))
- return IMGTOOLERR_BADFILENAME;
-
- /* open file on TI image */
- switch (image->type)
- {
- case L2I_DSK:
- errorcode = open_file_lvl2_dsk(image, fpath, &src_file.l2_file);
- break;
-
- case L2I_WIN:
- errorcode = open_file_lvl2_win(image, fpath, &src_file.l2_file);
- break;
- }
- if (errorcode)
- return errorcode;
-
- errorcode = open_file_lvl3(& src_file);
- if (errorcode)
- return errorcode;
-
- /* write text data */
- while (! is_eof(& src_file))
- {
- errorcode = read_next_record(& src_file, buf, & reclen);
- if (errorcode)
- return errorcode;
- if (stream_write(destf, buf, reclen) != reclen)
- return IMGTOOLERR_WRITEERROR;
- if (stream_write(destf, &lineend, 1) != 1)
- return IMGTOOLERR_WRITEERROR;
- }
-
- return 0;
-
-#endif
-}
-
-/*
- Add a file to a ti99_image. The file must be in tifile format.
-*/
-static imgtoolerr_t ti99_image_writefile(imgtool_partition *partition, const char *fpath, const char *fork, imgtool_stream *sourcef, option_resolution *writeoptions)
-{
- imgtool_image *img = imgtool_partition_image(partition);
- struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(img);
- const char *filename;
- char ti_fname[10];
- ti99_lvl2_fileref src_file;
- ti99_lvl2_fileref dst_file;
- ti99_date_time date_time;
- int i;
- int fphysrecs;
- UINT8 buf[256];
- imgtoolerr_t errorcode;
- int parent_ref_valid, parent_ref = 0;
- ti99_catalog *catalog, catalog_buf = {0, };
-
-
- (void) writeoptions;
-
- if (check_fpath(fpath))
- return IMGTOOLERR_BADFILENAME;
-
- switch (image->type)
- {
- case L2I_DSK:
- errorcode = (imgtoolerr_t)dsk_find_catalog_entry(image, fpath, &parent_ref_valid, &parent_ref, NULL, NULL);
- if (errorcode == 0)
- /* file already exists: causes an error for now */
- return (imgtoolerr_t)IMGTOOLERR_UNEXPECTED;
- else if ((! parent_ref_valid) || (errorcode != IMGTOOLERR_FILENOTFOUND))
- return (imgtoolerr_t)errorcode;
- break;
-
- case L2I_WIN:
- errorcode = (imgtoolerr_t)win_find_catalog_entry(image, fpath, &parent_ref_valid, &parent_ref, &catalog_buf, NULL, NULL);
- if (errorcode == 0)
- /* file already exists: causes an error for now */
- return (imgtoolerr_t)IMGTOOLERR_UNEXPECTED;
- else if ((! parent_ref_valid) || (errorcode != IMGTOOLERR_FILENOTFOUND))
- return (imgtoolerr_t)errorcode;
- break;
- }
-
- errorcode =(imgtoolerr_t) open_file_lvl2_tifiles(sourcef, & src_file);
- if (errorcode)
- return (imgtoolerr_t)errorcode;
-
- /* create new file */
- filename = strrchr(fpath, '.');
- if (filename)
- filename++;
- else
- filename = fpath;
- str_to_fname(ti_fname, filename);
- switch (image->type)
- {
- case L2I_DSK:
- errorcode = (imgtoolerr_t)new_file_lvl2_dsk(image, parent_ref, ti_fname, &dst_file);
- if (errorcode)
- return (imgtoolerr_t)errorcode;
- break;
-
- case L2I_WIN:
- errorcode = (imgtoolerr_t)new_file_lvl2_win(image, &catalog_buf, ti_fname, &dst_file);
- if (errorcode)
- return (imgtoolerr_t)errorcode;
- break;
- }
-
- /* set up parameters */
- set_file_flags(&dst_file, get_file_flags(&src_file));
- set_file_recsperphysrec(&dst_file, get_file_recsperphysrec(&src_file));
- errorcode = (imgtoolerr_t)set_file_fphysrecs(&dst_file, /*get_file_fphysrecs(&src_file)*/0);
- if (errorcode)
- return (imgtoolerr_t)errorcode;
- set_file_eof(&dst_file, get_file_eof(&src_file));
- errorcode = (imgtoolerr_t)set_file_reclen(&dst_file, get_file_reclen(&src_file));
- if (errorcode)
- return (imgtoolerr_t)errorcode;
- errorcode = (imgtoolerr_t)set_file_fixrecs(&dst_file, get_file_fixrecs(&src_file));
- if (errorcode)
- return (imgtoolerr_t)errorcode;
-
- get_file_creation_date(&src_file, &date_time);
-#if 0
- if ((date_time.time_MSB == 0) || (date_time.time_LSB == 0)
- || (date_time.date_MSB == 0) || (date_time.date_LSB == 0))
- current_date_time(&date_time);
-#endif
- set_file_creation_date(&dst_file, date_time);
-
- get_file_update_date(&src_file, &date_time);
-#if 0
- if ((date_time.time_MSB == 0) || (date_time.time_LSB == 0)
- || (date_time.date_MSB == 0) || (date_time.date_LSB == 0))
- current_date_time(&date_time);
-#endif
- set_file_update_date(&dst_file, date_time);
-
- /* alloc data physrecs */
- fphysrecs = get_file_fphysrecs(&src_file);
- switch (dst_file.type)
- {
- case L2F_DSK:
- errorcode = (imgtoolerr_t)dsk_alloc_file_physrecs(&dst_file.dsk, fphysrecs);
- if (errorcode)
- return (imgtoolerr_t)errorcode;
- break;
-
- case L2F_WIN:
- errorcode = (imgtoolerr_t)win_alloc_file_physrecs(&dst_file.win, fphysrecs);
- if (errorcode)
- return (imgtoolerr_t)errorcode;
- break;
-
- case L2F_TIFILES:
- break;
- }
-
- /* copy data */
- for (i=0; i<fphysrecs; i++)
- {
- if (stream_read(sourcef, buf, 256) != 256)
- return (imgtoolerr_t)IMGTOOLERR_READERROR;
-
- errorcode = (imgtoolerr_t)write_file_physrec(& dst_file, i, buf);
- if (errorcode)
- return (imgtoolerr_t)errorcode;
- }
-
- /* write fdr */
- switch (image->type)
- {
- case L2I_DSK:
- if (write_absolute_physrec(& image->l1_img, dst_file.dsk.fdr_aphysrec, &dst_file.dsk.fdr))
- return (imgtoolerr_t)IMGTOOLERR_WRITEERROR;
- break;
-
- case L2I_WIN:
- /* save fphysrecs field as well */
- if (dst_file.win.curfdr_aphysrec == dst_file.win.eldestfdr_aphysrec)
- set_win_fdr_fphysrecs(&dst_file.win.curfdr, dst_file.win.fphysrecs);
- if (write_absolute_physrec(& image->l1_img, dst_file.win.curfdr_aphysrec, &dst_file.win.curfdr))
- return (imgtoolerr_t)IMGTOOLERR_WRITEERROR;
- if (dst_file.win.curfdr_aphysrec != dst_file.win.eldestfdr_aphysrec)
- {
- dst_file.win.curfdr_aphysrec = dst_file.win.eldestfdr_aphysrec;
- if (read_absolute_physrec(& image->l1_img, dst_file.win.curfdr_aphysrec, &dst_file.win.curfdr))
- return (imgtoolerr_t)IMGTOOLERR_WRITEERROR;
- set_win_fdr_fphysrecs(&dst_file.win.curfdr, dst_file.win.fphysrecs);
- if (write_absolute_physrec(& image->l1_img, dst_file.win.curfdr_aphysrec, &dst_file.win.curfdr))
- return (imgtoolerr_t)IMGTOOLERR_WRITEERROR;
- }
- break;
- }
-
- /* update catalog */
- switch (image->type)
- {
- case L2I_DSK:
- catalog = &image->dsk.catalogs[parent_ref];
- for (i=0; i<128; i++)
- {
- buf[2*i] = catalog->files[i].fdr_ptr >> 8;
- buf[2*i+1] = catalog->files[i].fdr_ptr & 0xff;
- }
- if (write_absolute_physrec(& image->l1_img, image->dsk.fdir_aphysrec[parent_ref], buf))
- return (imgtoolerr_t)IMGTOOLERR_WRITEERROR;
- break;
-
- case L2I_WIN:
- {
- win_vib_ddr parent_ddr;
- int fdir_AU;
-
- /* update VIB/DDR and get FDIR AU address */
- if (read_absolute_physrec(& image->l1_img, parent_ref * image->AUformat.physrecsperAU, &parent_ddr))
- return (imgtoolerr_t)IMGTOOLERR_READERROR;
- parent_ddr.num_files = catalog_buf.num_files;
- if (write_absolute_physrec(& image->l1_img, parent_ref * image->AUformat.physrecsperAU, &parent_ddr))
- return (imgtoolerr_t)IMGTOOLERR_WRITEERROR;
- fdir_AU = get_UINT16BE(parent_ddr.fdir_AU);
-
- /* generate FDIR and save it */
- for (i=0; i<127; i++)
- {
- buf[2*i] = catalog_buf.files[i].fdr_ptr >> 8;
- buf[2*i+1] = catalog_buf.files[i].fdr_ptr & 0xff;
- }
- buf[254] = parent_ref >> 8;
- buf[255] = parent_ref & 0xff;
- if (write_absolute_physrec(& image->l1_img, fdir_AU * image->AUformat.physrecsperAU, buf))
- return (imgtoolerr_t)IMGTOOLERR_WRITEERROR;
- }
- break;
- }
-
- /* update bitmap */
- switch (image->type)
- {
- case L2I_DSK:
- {
- dsk_vib vib;
-
- if (read_absolute_physrec(& image->l1_img, 0, &vib))
- return (imgtoolerr_t)IMGTOOLERR_READERROR;
- memcpy(vib.abm, image->abm, 200);
- if (write_absolute_physrec(& image->l1_img, 0, &vib))
- return (imgtoolerr_t)IMGTOOLERR_WRITEERROR;
- }
- break;
-
- case L2I_WIN:
- /* save allocation bitmap (aphysrecs 1 through n, n<=33) */
- for (i=0; i < (image->AUformat.totAUs+2047)/2048; i++)
- if (write_absolute_physrec(&image->l1_img, i+1, image->abm+i*256))
- return (imgtoolerr_t)IMGTOOLERR_WRITEERROR;
- break;
- }
-
- return (imgtoolerr_t)0;
-}
-
-/*
- Delete a file from a ti99_image.
-*/
-static imgtoolerr_t dsk_image_deletefile(imgtool_partition *partition, const char *fpath)
-{
- imgtool_image *img = imgtool_partition_image(partition);
- struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(img);
- dsk_fdr fdr;
- int i, cluster_index;
- unsigned cur_AU, cluster_lastfphysrec;
-// int fphysrecs;
- int parent_ref, is_dir, catalog_index;
- imgtoolerr_t errorcode;
- UINT8 buf[256];
- ti99_catalog *catalog;
-
-
- if (check_fpath(fpath))
- return IMGTOOLERR_BADFILENAME;
-
- errorcode = (imgtoolerr_t)dsk_find_catalog_entry(image, fpath, NULL, &parent_ref, &is_dir, &catalog_index);
- if (errorcode)
- return errorcode;
-
- if (is_dir)
- {
- catalog = &image->dsk.catalogs[catalog_index+1];
-
- if ((catalog->num_files != 0) || (catalog->num_subdirs != 0))
- return IMGTOOLERR_UNIMPLEMENTED;
-
- catalog = &image->dsk.catalogs[0];
-
- /* free fdir AU */
- cur_AU = image->dsk.fdir_aphysrec[catalog_index+1] / image->AUformat.physrecsperAU;
- image->abm[cur_AU >> 3] &= ~ (1 << (cur_AU & 7));
-
- /* delete catalog entry */
- for (i=catalog_index; i<2; i++)
- {
- catalog->subdirs[i] = catalog->subdirs[i+1];
- image->dsk.fdir_aphysrec[i+1] = image->dsk.fdir_aphysrec[i+2];
- }
- memset(catalog->subdirs[2].name, 0, 10);
- catalog->subdirs[2].dir_ptr = 0;
- image->dsk.fdir_aphysrec[3] = 0;
- catalog->num_subdirs--;
-
- /* update directory and bitmap in vib */
- {
- dsk_vib vib;
-
- if (read_absolute_physrec(& image->l1_img, 0, &vib))
- return IMGTOOLERR_READERROR;
-
- for (i=0; i<3; i++)
- {
- memcpy(vib.subdir[i].name, catalog->subdirs[i].name, 10);
- set_UINT16BE(&vib.subdir[i].fdir_aphysrec, image->dsk.fdir_aphysrec[i+1]);
- }
-
- memcpy(vib.abm, image->abm, 200);
-
- if (write_absolute_physrec(& image->l1_img, 0, &vib))
- return IMGTOOLERR_WRITEERROR;
- }
- }
- else
- {
- catalog = &image->dsk.catalogs[parent_ref];
-
- if (read_absolute_physrec(& image->l1_img, catalog->files[catalog_index].fdr_ptr, &fdr))
- return IMGTOOLERR_READERROR;
-
- /* free data AUs */
-// fphysrecs =
- get_UINT16BE(fdr.fphysrecs);
-
- i = 0;
- cluster_index = 0;
- while (cluster_index < 76)
- {
- cur_AU = get_dsk_fdr_cluster_baseAU(image, & fdr, cluster_index);
- if (cur_AU == 0)
- /* end of cluster list */
- break;
- cluster_lastfphysrec = get_dsk_fdr_cluster_lastfphysrec(& fdr, cluster_index);
-
- while (i<=cluster_lastfphysrec)
- {
- /* the condition below is an error, but it should not prevent
- us from deleting the file */
- if (cur_AU >= image->AUformat.totAUs)
- /*return IMGTOOLERR_CORRUPTIMAGE;*/
- break;
-
- image->abm[cur_AU >> 3] &= ~ (1 << (cur_AU & 7));
-
- i += image->AUformat.physrecsperAU;
- cur_AU++;
- }
-
- cluster_index++;
- }
- /* the condition below is an error, but it should not prevent us from
- deleting the file */
-#if 0
- if (i<fphysrecs)
- return IMGTOOLERR_CORRUPTIMAGE;
-#endif
-
- /* free fdr AU */
- cur_AU = catalog->files[catalog_index].fdr_ptr / image->AUformat.physrecsperAU;
- image->abm[cur_AU >> 3] &= ~ (1 << (cur_AU & 7));
-
- /* delete catalog entry */
- for (i=catalog_index; i<127; i++)
- catalog->files[i] = catalog->files[i+1];
- catalog->files[127].fdr_ptr = 0;
- catalog->num_files--;
-
- /* update parent fdir */
- for (i=0; i<128; i++)
- {
- buf[2*i] = catalog->files[i].fdr_ptr >> 8;
- buf[2*i+1] = catalog->files[i].fdr_ptr & 0xff;
- }
- if (write_absolute_physrec(& image->l1_img, image->dsk.fdir_aphysrec[parent_ref], buf))
- return IMGTOOLERR_WRITEERROR;
-
- /* update bitmap */
- {
- dsk_vib vib;
-
- if (read_absolute_physrec(& image->l1_img, 0, &vib))
- return IMGTOOLERR_READERROR;
- memcpy(vib.abm, image->abm, 200);
- if (write_absolute_physrec(& image->l1_img, 0, &vib))
- return IMGTOOLERR_WRITEERROR;
- }
- }
-
- return (imgtoolerr_t)0;
-}
-
-static imgtoolerr_t win_image_deletefile(imgtool_partition *partition, const char *fpath)
-{
- imgtool_image *img = imgtool_partition_image(partition);
- struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(img);
- int parent_ddr_AU, is_dir, catalog_index;
- win_fdr fdr;
- int i;
- unsigned cur_AU, end_AU;
- unsigned curfdr_aphysrec;
- unsigned cursibFDR_index, endsibFDR_index = 0;
- int errorcode;
- UINT8 buf[256];
- ti99_catalog catalog;
-
-
- if (check_fpath(fpath))
- return (imgtoolerr_t)IMGTOOLERR_BADFILENAME;
-
- errorcode = win_find_catalog_entry(image, fpath, NULL, &parent_ddr_AU, &catalog, &is_dir, &catalog_index);
- if (errorcode)
- return (imgtoolerr_t)errorcode;
-
- if (is_dir)
- {
- unsigned DDR_AU;
- win_vib_ddr ddr_buf;
-
- /* Read DDR record */
- DDR_AU = catalog.subdirs[catalog_index].dir_ptr;
- if (read_absolute_physrec(& image->l1_img, DDR_AU*image->AUformat.physrecsperAU, &ddr_buf))
- return (imgtoolerr_t)IMGTOOLERR_READERROR;
-
- /* read FDIR AU pointer */
- cur_AU = get_UINT16BE(ddr_buf.fdir_AU);
-
- /* sanity checks */
- if ((ddr_buf.num_files > 127) || (ddr_buf.num_subdirs > 114) || (cur_AU > image->AUformat.totAUs))
- return (imgtoolerr_t)IMGTOOLERR_CORRUPTIMAGE;
-
- if ((ddr_buf.num_files != 0) || (ddr_buf.num_subdirs != 0))
- return (imgtoolerr_t)IMGTOOLERR_UNIMPLEMENTED;
-
- /* free fdir AU */
- image->abm[cur_AU >> 3] &= ~ (1 << (cur_AU & 7));
-
- /* free ddr AU */
- image->abm[DDR_AU >> 3] &= ~ (1 << (DDR_AU & 7));
-
- /* delete parent catalog entry */
- for (i=catalog_index; i<113; i++)
- catalog.subdirs[i] = catalog.subdirs[i+1];
- catalog.subdirs[113].dir_ptr = 0;
- catalog.num_subdirs--;
-
- /* update parent VIB/DDR */
- if (read_absolute_physrec(& image->l1_img, parent_ddr_AU * image->AUformat.physrecsperAU, &ddr_buf))
- return (imgtoolerr_t)IMGTOOLERR_READERROR;
- ddr_buf.num_subdirs = catalog.num_subdirs;
- for (i=0; i<114; i++)
- set_UINT16BE(&ddr_buf.subdir_AU[i], catalog.subdirs[i].dir_ptr);
- if (write_absolute_physrec(& image->l1_img, parent_ddr_AU * image->AUformat.physrecsperAU, &ddr_buf))
- return (imgtoolerr_t)IMGTOOLERR_WRITEERROR;
-
- /* save allocation bitmap (aphysrecs 1 through n, n<=33) */
- for (i=0; i < (image->AUformat.totAUs+2047)/2048; i++)
- if (write_absolute_physrec(&image->l1_img, i+1, image->abm+i*256))
- return (imgtoolerr_t)IMGTOOLERR_WRITEERROR;
- }
- else
- {
- /* check integrity of FDR sibling chain, and go to last sibling */
- /* note that as we check that the back chain is consistent with the forward
- chain, we will also detect any cycle in the sibling chain, so we do not
- need to check against them explicitely */
- {
- int pastendoflist_flag;
- unsigned prevfdr_aphysrec;
-
-
- pastendoflist_flag = 0;
- cursibFDR_index = 0;
- curfdr_aphysrec = catalog.files[catalog_index].fdr_ptr * image->AUformat.physrecsperAU;
- if (read_absolute_physrec(& image->l1_img, curfdr_aphysrec, &fdr))
- return (imgtoolerr_t)IMGTOOLERR_READERROR;
-
- if (get_UINT16BE(fdr.prevsibFDR_AU) != 0)
- return (imgtoolerr_t)IMGTOOLERR_CORRUPTIMAGE;
-
- while (1)
- {
- if (! pastendoflist_flag)
- {
- /* look for end of list */
- for (i=0; i<54; i++)
- {
- if (get_UINT16BE(fdr.clusters[i][0]) == 0)
- {
- endsibFDR_index = cursibFDR_index;
- pastendoflist_flag = TRUE;
- break;
- }
- }
- }
-
- /* exit loop if end of sibling chain */
- if (! get_UINT16BE(fdr.nextsibFDR_AU))
- break;
-
- /* otherwise read next FDR */
- if (get_UINT16BE(fdr.nextsibFDR_AU) >= image->AUformat.totAUs)
- return (imgtoolerr_t)IMGTOOLERR_CORRUPTIMAGE;
-
- prevfdr_aphysrec = curfdr_aphysrec;
- curfdr_aphysrec = get_win_fdr_nextsibFDR_aphysrec(image, &fdr);
- if (read_absolute_physrec(& image->l1_img, curfdr_aphysrec, &fdr))
- return (imgtoolerr_t)IMGTOOLERR_READERROR;
- cursibFDR_index++;
-
- /* check that back chaining is consistent with forward chaining */
- if (get_win_fdr_prevsibFDR_aphysrec(image, &fdr) != prevfdr_aphysrec)
- return (imgtoolerr_t)IMGTOOLERR_CORRUPTIMAGE;
- }
- if (! pastendoflist_flag)
- endsibFDR_index = cursibFDR_index;
- }
-
-
- while (1)
- {
- if (cursibFDR_index <= endsibFDR_index)
- {
- for (i = 0; i < 54; i++)
- {
- cur_AU = get_UINT16BE(fdr.clusters[i][0]);
- if (cur_AU == 0)
- /* end of cluster list */
- break;
- end_AU = get_UINT16BE(fdr.clusters[i][1]);
-
- while (cur_AU<=end_AU)
- {
- /* the condition below is an error, but it should not prevent
- us from deleting the file */
- if (cur_AU >= image->AUformat.totAUs)
- /*return IMGTOOLERR_CORRUPTIMAGE;*/
- break;
-
- image->abm[cur_AU >> 3] &= ~ (1 << (cur_AU & 7));
-
- cur_AU++;
- }
- }
- }
-
- /* free fdr AU if applicable */
- if ((curfdr_aphysrec % image->AUformat.physrecsperAU) == 0)
- {
- cur_AU = curfdr_aphysrec / image->AUformat.physrecsperAU;
- image->abm[cur_AU >> 3] &= ~ (1 << (cur_AU & 7));
- }
-
- if (cursibFDR_index == 0)
- break;
- curfdr_aphysrec = get_win_fdr_prevsibFDR_aphysrec(image, &fdr);
- if (read_absolute_physrec(& image->l1_img, curfdr_aphysrec, &fdr))
- return (imgtoolerr_t)IMGTOOLERR_READERROR;
- cursibFDR_index--;
- }
-
-
- /* delete catalog entry */
- for (i=catalog_index; i<127; i++)
- catalog.files[i] = catalog.files[i+1];
- catalog.files[127].fdr_ptr = 0;
- catalog.num_files--;
-
-
- /* update VIB/DDR and get FDIR AU address */
- {
- win_vib_ddr parent_ddr;
-
- if (read_absolute_physrec(& image->l1_img, parent_ddr_AU * image->AUformat.physrecsperAU, &parent_ddr))
- return (imgtoolerr_t)IMGTOOLERR_READERROR;
- parent_ddr.num_files = catalog.num_files;
- if (write_absolute_physrec(& image->l1_img, parent_ddr_AU * image->AUformat.physrecsperAU, &parent_ddr))
- return (imgtoolerr_t)IMGTOOLERR_WRITEERROR;
- cur_AU = get_UINT16BE(parent_ddr.fdir_AU);
- }
-
- /* generate FDIR and save it */
- for (i=0; i<127; i++)
- {
- buf[2*i] = catalog.files[i].fdr_ptr >> 8;
- buf[2*i+1] = catalog.files[i].fdr_ptr & 0xff;
- }
- buf[254] = parent_ddr_AU >> 8;
- buf[255] = parent_ddr_AU & 0xff;
- if (write_absolute_physrec(& image->l1_img, cur_AU * image->AUformat.physrecsperAU, buf))
- return (imgtoolerr_t)IMGTOOLERR_WRITEERROR;
-
- /* save allocation bitmap (aphysrecs 1 through n, n<=33) */
- for (i=0; i < (image->AUformat.totAUs+2047)/2048; i++)
- if (write_absolute_physrec(&image->l1_img, i+1, image->abm+i*256))
- return (imgtoolerr_t)IMGTOOLERR_WRITEERROR;
- }
-
- return (imgtoolerr_t)0;
-}
-
-/*
- Create a blank ti99_image (common code).
-
- Supports MESS and V9T9 formats only
-*/
-static imgtoolerr_t dsk_image_create(imgtool_image *image, imgtool_stream *f, option_resolution *createoptions, ti99_img_format img_format)
-{
- const char *volname;
- int density;
- ti99_lvl1_imgref l1_img;
- int protected_var;
-
- int totphysrecs, physrecsperAU, totAUs;
-
- dsk_vib vib;
- UINT8 empty_sec[256];
-
- int i;
-
- l1_img.img_format = img_format;
- l1_img.file_handle = f;
-
- /* read options */
- volname = option_resolution_lookup_string(createoptions, dsk_createopts_volname);
- l1_img.geometry.heads = option_resolution_lookup_int(createoptions, dsk_createopts_sides);
- l1_img.geometry.cylinders = option_resolution_lookup_int(createoptions, dsk_createopts_tracks);
- l1_img.geometry.secspertrack = option_resolution_lookup_int(createoptions, dsk_createopts_sectors);
- protected_var = option_resolution_lookup_int(createoptions, dsk_createopts_protection);
- density = option_resolution_lookup_int(createoptions, dsk_createopts_density);
-
- /* NPW 03-DEC-2003 - Fixes a crash if volname is NULL */
- if (!volname)
- volname = "";
-
- totphysrecs = l1_img.geometry.secspertrack * l1_img.geometry.cylinders * l1_img.geometry.heads;
- physrecsperAU = (totphysrecs + 1599) / 1600;
- /* round to next larger power of 2 */
- for (i = 1; i < physrecsperAU; i <<= 1)
- ;
- physrecsperAU = i;
- totAUs = totphysrecs / physrecsperAU;
-
- /* auto-density */
- if (density == 0)
- {
- if (l1_img.geometry.secspertrack <= 9)
- density = 1;
- else if (l1_img.geometry.secspertrack <= 18)
- density = 2;
- else
- density = 3;
- }
-
- /* check volume name */
- if (strchr(volname, '.') || strchr(volname, ' ') || (strlen(volname) > 10))
- return /*IMGTOOLERR_BADFILENAME*/IMGTOOLERR_PARAMCORRUPT;
-
- /* FM disks can hold fewer sector per track than MFM disks */
- if ((density == 1) && (l1_img.geometry.secspertrack > 9))
- return IMGTOOLERR_PARAMTOOLARGE;
-
- /* DD disks can hold fewer sector per track than HD disks */
- if ((density == 2) && (l1_img.geometry.secspertrack > 18))
- return IMGTOOLERR_PARAMTOOLARGE;
-
- /* check total disk size */
- if (totphysrecs < 2)
- return IMGTOOLERR_PARAMTOOSMALL;
-
- /* initialize vib in aphysrec 0 */
-
- /* set volume name */
- str_to_fname(vib.name, volname);
-
- /* set every header field */
- set_UINT16BE(& vib.totphysrecs, totphysrecs);
- vib.secspertrack = l1_img.geometry.secspertrack;
- vib.id[0] = 'D';
- vib.id[1] = 'S';
- vib.id[2] = 'K';
- vib.protection = protected_var ? 'P' : ' ';
- vib.cylinders = l1_img.geometry.cylinders;
- vib.heads = l1_img.geometry.heads;
- vib.density = density;
- for (i=0; i<3; i++)
- {
- memset(vib.subdir[i].name, '\0', 10);
- set_UINT16BE(& vib.subdir[i].fdir_aphysrec, 0);
- }
-
- /* clear bitmap */
- for (i=0; i < (totAUs>>3); i++)
- vib.abm[i] = 0;
-
- if (totAUs & 7)
- {
- vib.abm[i] = 0xff << (totAUs & 7);
- i++;
- }
-
- for (; i < 200; i++)
- vib.abm[i] = 0xff;
-
- /* mark first 2 aphysrecs (vib and fdir) as used */
- vib.abm[0] |= (physrecsperAU == 1) ? 3 : 1;
-
- /* write aphysrec 0 */
- if (write_absolute_physrec(& l1_img, 0, &vib))
- return IMGTOOLERR_WRITEERROR;
-
-
- /* now clear every other physrecs, including the FDIR record */
- memset(empty_sec, 0, sizeof(empty_sec));
-
- for (i=1; i<totphysrecs; i++)
- if (write_absolute_physrec(& l1_img, i, empty_sec))
- return IMGTOOLERR_WRITEERROR;
-
-
- return (imgtoolerr_t)dsk_image_init(image, f, img_format);
-}
-
-/*
- Create a blank ti99_image (MESS format).
-*/
-static imgtoolerr_t dsk_image_create_mess(imgtool_image *image, imgtool_stream *f, option_resolution *createoptions)
-{
- return dsk_image_create(image, f, createoptions, if_mess);
-}
-
-/*
- Create a blank ti99_image (V9T9 format).
-*/
-static imgtoolerr_t dsk_image_create_v9t9(imgtool_image *image, imgtool_stream *f, option_resolution *createoptions)
-{
- return dsk_image_create(image, f, createoptions, if_v9t9);
-}