summaryrefslogtreecommitdiffstatshomepage
path: root/src/tools/imgtool/modules/prodos.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/imgtool/modules/prodos.cpp')
-rw-r--r--src/tools/imgtool/modules/prodos.cpp2290
1 files changed, 0 insertions, 2290 deletions
diff --git a/src/tools/imgtool/modules/prodos.cpp b/src/tools/imgtool/modules/prodos.cpp
deleted file mode 100644
index 32170b3ecae..00000000000
--- a/src/tools/imgtool/modules/prodos.cpp
+++ /dev/null
@@ -1,2290 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Raphael Nabet
-/****************************************************************************
-
- prodos.cpp
-
- Apple II ProDOS disk images
-
-*****************************************************************************
-
- Notes:
- - ProDOS disks are split into 512 byte blocks.
-
- ProDOS directory structure:
-
- Offset Length Description
- ------ ------ -----------
- 0 2 ???
- 2 2 Next block (0 if end)
- 4 39 Directory Entry
- 43 39 Directory Entry
- ...
- 472 39 Directory Entry
- 511 1 ???
-
-
- ProDOS directory entry structure:
-
- Offset Length Description
- ------ ------ -----------
- 0 1 Storage type (bits 7-4)
- 10 - Seedling File (1 block)
- 20 - Sapling File (2-256 blocks)
- 30 - Tree File (257-32768 blocks)
- 40 - Pascal Areas on ProFile HDs (???)
- 50 - GS/OS Extended File (data and rsrc fork)
- E0 - Subdirectory Header
- F0 - Volume Header
- 1 15 File name (NUL padded)
- 16 1 File type
- 17 2 Key pointer
- 19 2 Blocks used
- 21 3 File size
- 24 4 Creation date
- 28 1 ProDOS version that created the file
- 29 1 Minimum ProDOS version needed to read the file
- 30 1 Access byte
- 31 2 Auxilary file type
- 33 4 Last modified date
- 37 2 Header pointer
-
-
- In "seedling files", the key pointer points to a single block that is the
- whole file. In "sapling files", the key pointer points to an index block
- that contains 256 2-byte index pointers that point to the actual blocks of
- the files. These 2-byte values are not contiguous; the low order byte is
- in the first half of the block, and the high order byte is in the second
- half of the block. In "tree files", the key pointer points to an index
- block of index blocks.
-
- ProDOS dates are 32-bit little endian values
-
- bits 0- 4 Day
- bits 5- 8 Month (0-11)
- bits 9-15 Year (0-49 is 2000-2049, 50-99 is 1950-1999)
- bits 16-21 Minute
- bits 24-28 Hour
-
-
- ProDOS directory and volume headers have this information:
-
- Offset Length Description
- ------ ------ -----------
- 31 1 Length of the entry; generally is 39
- 32 1 Number of entries per block; generally is 13
- 33 2 Active entry count in directory
- 35 2 Volume bitmap block number
- 37 2 Total blocks on volume
-
- GS/OS Extended Files (storage type $5) point to an extended key block that
- contains information about the two forks. The first half of the extended
- key block contains info about the data form, and the second half the
- resource fork. Both sides have the following format:
-
- Offset Length Description
- ------ ------ -----------
- 0 1 Storage type (bits 3-0, unlike the directory entry)
- 1 2 Key pointer
- 3 2 Blocks used
- 5 3 File size
- 8 1 Size of secondary info #1 (must be 18 to be valid)
- 9 1 Secondary info #1 type (1=FInfo 2=xFInfo)
- 10 16 FInfo or xFInfo
- 26 1 Size of secondary info #2 (must be 18 to be valid)
- 27 1 Secondary info #2 type (1=FInfo 2=xFInfo)
- 28 16 FInfo or xFInfo
-
- FInfo format:
-
- Offset Length Description
- ------ ------ -----------
- 0 4 File type
- 4 4 File creator
- 8 2 Finder flags
- 10 2 X Coordinate
- 12 2 Y Coordinate
- 14 2 Finder folder
-
- xFInfo format:
-
- Offset Length Description
- ------ ------ -----------
- 0 2 Icon ID
- 2 6 Reserved
- 8 1 Script Code
- 9 1 Extended flags
- 10 2 Comment ID
- 12 4 Put Away Directory
-
-
- For more info, consult ProDOS technical note #25
- (http://web.pdx.edu/~heiss/technotes/pdos/tn.pdos.25.html)
-
-*****************************************************************************/
-
-#include "imgtool.h"
-#include "formats/imageutl.h"
-#include "formats/ap2_dsk.h"
-#include "formats/ap_dsk35.h"
-#include "iflopimg.h"
-
-#include "macutil.h"
-
-#include "opresolv.h"
-
-#define ROOTDIR_BLOCK 2
-#define BLOCK_SIZE 512
-
-static const uint8_t apple35_tracklen_800kb[80] =
-{
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
-};
-
-static int apple35_sectors_per_track(floppy_image_legacy *image, int track)
-{
- int sectors;
-
- assert(track >= 0);
- assert(track < std::size(apple35_tracklen_800kb));
-
- sectors = apple35_tracklen_800kb[track];
- return sectors;
-}
-
-struct prodos_diskinfo
-{
- imgtoolerr_t (*load_block)(imgtool::image &image, int block, void *buffer);
- imgtoolerr_t (*save_block)(imgtool::image &image, int block, const void *buffer);
- uint8_t dirent_size;
- uint8_t dirents_per_block;
- uint16_t volume_bitmap_block;
- uint16_t total_blocks;
-};
-
-struct prodos_direnum
-{
- uint32_t block;
- uint32_t index;
- uint8_t block_data[BLOCK_SIZE];
-};
-
-struct prodos_dirent
-{
- char filename[16];
- uint8_t storage_type;
- uint16_t extkey_pointer;
- uint16_t key_pointer[2];
- uint32_t filesize[2];
- int depth[2];
- uint32_t lastmodified_time;
- uint32_t creation_time;
-
- /* FInfo */
- uint32_t file_type;
- uint32_t file_creator;
- uint16_t finder_flags;
- uint16_t coord_x;
- uint16_t coord_y;
- uint16_t finder_folder;
-
- /* xFInfo */
- uint16_t icon_id;
- uint8_t script_code;
- uint8_t extended_flags;
- uint16_t comment_id;
- uint32_t putaway_directory;
-};
-
-enum creation_policy_t
-{
- CREATE_NONE,
- CREATE_FILE,
- CREATE_DIR
-};
-
-
-
-static imgtool::datetime prodos_crack_time(uint32_t prodos_time)
-{
- util::arbitrary_datetime dt;
- dt.second = 0;
- dt.minute = ((prodos_time >> 16) & 0x3F);
- dt.hour = ((prodos_time >> 24) & 0x1F);
- dt.day_of_month = ((prodos_time >> 0) & 0x1F);
- dt.month = ((prodos_time >> 5) & 0x0F) + 1;
- dt.year = ((prodos_time >> 9) & 0x7F) + 1900;
- if (dt.year <= 1949)
- dt.year += 100;
-
- return imgtool::datetime(imgtool::datetime::datetime_type::LOCAL, dt);
-}
-
-
-
-static uint32_t prodos_setup_time(time_t ansi_time)
-{
- struct tm t;
- uint32_t result = 0;
-
- t = *localtime(&ansi_time);
- if ((t.tm_year >= 100) && (t.tm_year <= 149))
- t.tm_year -= 100;
-
- result |= (((uint32_t) t.tm_min) & 0x003F) << 16;
- result |= (((uint32_t) t.tm_hour) & 0x001F) << 24;
- result |= (((uint32_t) t.tm_mday) & 0x001F) << 0;
- result |= (((uint32_t) t.tm_mon) & 0x000F) << 5;
- result |= (((uint32_t) t.tm_year) & 0x007F) << 9;
- return result;
-}
-
-
-
-static uint32_t prodos_time_now(void)
-{
- time_t now;
- time(&now);
- return prodos_setup_time(now);
-}
-
-
-
-static int is_file_storagetype(uint8_t storage_type)
-{
- return ((storage_type >= 0x10) && (storage_type <= 0x3F))
- || ((storage_type >= 0x50) && (storage_type <= 0x5F));
-}
-
-
-
-static int is_normalfile_storagetype(uint8_t storage_type)
-{
- return ((storage_type >= 0x10) && (storage_type <= 0x3F));
-}
-
-
-
-static int is_extendedfile_storagetype(uint8_t storage_type)
-{
- return ((storage_type >= 0x50) && (storage_type <= 0x5F));
-}
-
-
-
-static int is_dir_storagetype(uint8_t storage_type)
-{
- return (storage_type >= 0xE0) && (storage_type <= 0xEF);
-}
-
-
-
-static prodos_diskinfo *get_prodos_info(imgtool::image &image)
-{
- prodos_diskinfo *info;
- info = (prodos_diskinfo *) imgtool_floppy_extrabytes(image);
- return info;
-}
-
-
-
-/* ----------------------------------------------------------------------- */
-
-static void prodos_find_block_525(imgtool::image &image, int block,
- uint32_t *track, uint32_t *head, uint32_t *sector1, uint32_t *sector2)
-{
- static const uint8_t skewing[] =
- {
- 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,
- 0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F
- };
-
- block *= 2;
-
- *track = block / APPLE2_SECTOR_COUNT;
- *head = 0;
- *sector1 = skewing[block % APPLE2_SECTOR_COUNT + 0];
- *sector2 = skewing[block % APPLE2_SECTOR_COUNT + 1];
-}
-
-
-
-static imgtoolerr_t prodos_load_block_525(imgtool::image &image,
- int block, void *buffer)
-{
- floperr_t ferr;
- uint32_t track, head, sector1, sector2;
-
- prodos_find_block_525(image, block, &track, &head, &sector1, &sector2);
-
- /* read first sector */
- ferr = floppy_read_sector(imgtool_floppy(image), head, track,
- sector1, 0, ((uint8_t *) buffer) + 0, 256);
- if (ferr)
- return imgtool_floppy_error(ferr);
-
- /* read second sector */
- ferr = floppy_read_sector(imgtool_floppy(image), head, track,
- sector2, 0, ((uint8_t *) buffer) + 256, 256);
- if (ferr)
- return imgtool_floppy_error(ferr);
-
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_save_block_525(imgtool::image &image,
- int block, const void *buffer)
-{
- floperr_t ferr;
- uint32_t track, head, sector1, sector2;
-
- prodos_find_block_525(image, block, &track, &head, &sector1, &sector2);
-
- /* read first sector */
- ferr = floppy_write_sector(imgtool_floppy(image), head, track,
- sector1, 0, ((const uint8_t *) buffer) + 0, 256, 0); /* TODO: pass ddam argument from imgtool */
- if (ferr)
- return imgtool_floppy_error(ferr);
-
- /* read second sector */
- ferr = floppy_write_sector(imgtool_floppy(image), head, track,
- sector2, 0, ((const uint8_t *) buffer) + 256, 256, 0); /* TODO: pass ddam argument from imgtool */
- if (ferr)
- return imgtool_floppy_error(ferr);
-
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static void prodos_setprocs_525(imgtool::image &image)
-{
- prodos_diskinfo *info;
- info = get_prodos_info(image);
- info->load_block = prodos_load_block_525;
- info->save_block = prodos_save_block_525;
-}
-
-
-
-/* ----------------------------------------------------------------------- */
-
-static imgtoolerr_t prodos_find_block_35(imgtool::image &image, int block,
- uint32_t *track, uint32_t *head, uint32_t *sector)
-{
- int sides = 2;
-
- *track = 0;
- while(block >= (apple35_sectors_per_track(imgtool_floppy(image), *track) * sides))
- {
- block -= (apple35_sectors_per_track(imgtool_floppy(image), (*track)++) * sides);
- if (*track >= 80)
- return IMGTOOLERR_SEEKERROR;
- }
-
- *head = block / apple35_sectors_per_track(imgtool_floppy(image), *track);
- *sector = block % apple35_sectors_per_track(imgtool_floppy(image), *track);
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_load_block_35(imgtool::image &image,
- int block, void *buffer)
-{
- imgtoolerr_t err;
- floperr_t ferr;
- uint32_t track, head, sector;
-
- err = prodos_find_block_35(image, block, &track, &head, &sector);
- if (err)
- return err;
-
- ferr = floppy_read_sector(imgtool_floppy(image), head, track, sector, 0, buffer, 512);
- if (ferr)
- return imgtool_floppy_error(ferr);
-
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_save_block_35(imgtool::image &image,
- int block, const void *buffer)
-{
- imgtoolerr_t err;
- floperr_t ferr;
- uint32_t track, head, sector;
-
- err = prodos_find_block_35(image, block, &track, &head, &sector);
- if (err)
- return err;
-
- ferr = floppy_write_sector(imgtool_floppy(image), head, track, sector, 0, buffer, 512, 0); /* TODO: pass ddam argument from imgtool */
- if (ferr)
- return imgtool_floppy_error(ferr);
-
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static void prodos_setprocs_35(imgtool::image &image)
-{
- prodos_diskinfo *info;
- info = get_prodos_info(image);
- info->load_block = prodos_load_block_35;
- info->save_block = prodos_save_block_35;
-}
-
-
-
-/* ----------------------------------------------------------------------- */
-
-static imgtoolerr_t prodos_load_block(imgtool::image &image,
- int block, void *buffer)
-{
- prodos_diskinfo *diskinfo;
- diskinfo = get_prodos_info(image);
- return diskinfo->load_block(image, block, buffer);
-}
-
-
-
-static imgtoolerr_t prodos_save_block(imgtool::image &image,
- int block, const void *buffer)
-{
- prodos_diskinfo *diskinfo;
- diskinfo = get_prodos_info(image);
- return diskinfo->save_block(image, block, buffer);
-}
-
-
-
-static imgtoolerr_t prodos_clear_block(imgtool::image &image, int block)
-{
- uint8_t buffer[BLOCK_SIZE];
- memset(buffer, 0, sizeof(buffer));
- return prodos_save_block(image, block, buffer);
-}
-
-
-
-/* ----------------------------------------------------------------------- */
-
-static imgtoolerr_t prodos_diskimage_open(imgtool::image &image)
-{
- imgtoolerr_t err;
- uint8_t buffer[BLOCK_SIZE];
- prodos_diskinfo *di;
- const uint8_t *ent;
-
- di = get_prodos_info(image);
-
- /* specify defaults */
- di->dirent_size = 39;
- di->dirents_per_block = 13;
-
- /* load the first block, hoping that the volume header is first */
- err = prodos_load_block(image, ROOTDIR_BLOCK, buffer);
- if (err)
- return err;
-
- ent = &buffer[4];
-
- /* did we find the volume header? */
- if ((ent[0] & 0xF0) == 0xF0)
- {
- di->dirent_size = pick_integer_le(ent, 31, 1);
- di->dirents_per_block = pick_integer_le(ent, 32, 1);
- di->volume_bitmap_block = pick_integer_le(ent, 35, 2);
- di->total_blocks = pick_integer_le(ent, 37, 2);
- }
-
- /* sanity check these values */
- if (di->dirent_size < 39)
- return IMGTOOLERR_CORRUPTIMAGE;
- if (di->dirents_per_block * di->dirent_size >= BLOCK_SIZE)
- return IMGTOOLERR_CORRUPTIMAGE;
- if (di->volume_bitmap_block >= di->total_blocks)
- return IMGTOOLERR_CORRUPTIMAGE;
-
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_diskimage_open_525(imgtool::image &image, imgtool::stream::ptr &&dummy)
-{
- prodos_setprocs_525(image);
- return prodos_diskimage_open(image);
-}
-
-
-
-static imgtoolerr_t prodos_diskimage_open_35(imgtool::image &image, imgtool::stream::ptr &&dummy)
-{
- prodos_setprocs_35(image);
- return prodos_diskimage_open(image);
-}
-
-
-
-/* ----------------------------------------------------------------------- */
-
-static imgtoolerr_t prodos_load_volume_bitmap(imgtool::image &image, uint8_t **bitmap)
-{
- imgtoolerr_t err;
- prodos_diskinfo *di;
- uint8_t *alloc_bitmap;
- uint32_t bitmap_blocks, i;
-
- di = get_prodos_info(image);
-
- bitmap_blocks = (di->total_blocks + (BLOCK_SIZE * 8) - 1) / (BLOCK_SIZE * 8);
- alloc_bitmap = (uint8_t*)malloc(bitmap_blocks * BLOCK_SIZE);
- if (!alloc_bitmap)
- {
- err = IMGTOOLERR_OUTOFMEMORY;
- goto done;
- }
-
- for (i = 0; i < bitmap_blocks; i++)
- {
- err = prodos_load_block(image, di->volume_bitmap_block + i,
- &alloc_bitmap[i * BLOCK_SIZE]);
- if (err)
- goto done;
- }
-
- err = IMGTOOLERR_SUCCESS;
-
-done:
- if (err && alloc_bitmap)
- {
- free(alloc_bitmap);
- alloc_bitmap = NULL;
- }
- *bitmap = alloc_bitmap;
- return err;
-}
-
-
-
-static imgtoolerr_t prodos_save_volume_bitmap(imgtool::image &image, const uint8_t *bitmap)
-{
- imgtoolerr_t err;
- prodos_diskinfo *di;
- uint32_t bitmap_blocks, i;
-
- di = get_prodos_info(image);
-
- bitmap_blocks = (di->total_blocks + (BLOCK_SIZE * 8) - 1) / (BLOCK_SIZE * 8);
-
- for (i = 0; i < bitmap_blocks; i++)
- {
- err = prodos_save_block(image, di->volume_bitmap_block + i,
- &bitmap[i * BLOCK_SIZE]);
- if (err)
- return err;
- }
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static void prodos_set_volume_bitmap_bit(uint8_t *buffer, uint16_t block, int value)
-{
- uint8_t mask;
- buffer += block / 8;
- mask = 1 << (7 - (block % 8));
- if (value)
- *buffer |= mask;
- else
- *buffer &= ~mask;
-}
-
-
-
-static int prodos_get_volume_bitmap_bit(const uint8_t *buffer, uint16_t block)
-{
- uint8_t mask;
- buffer += block / 8;
- mask = 1 << (7 - (block % 8));
- return (*buffer & mask) ? 1 : 0;
-}
-
-
-
-static imgtoolerr_t prodos_alloc_block(imgtool::image &image, uint8_t *bitmap,
- uint16_t *block)
-{
- imgtoolerr_t err = IMGTOOLERR_SUCCESS;
- prodos_diskinfo *di;
- uint16_t bitmap_blocks, i;
- uint8_t *alloc_bitmap = NULL;
-
- di = get_prodos_info(image);
- *block = 0;
- bitmap_blocks = (di->total_blocks + (BLOCK_SIZE * 8) - 1) / (BLOCK_SIZE * 8);
-
- if (!bitmap)
- {
- err = prodos_load_volume_bitmap(image, &alloc_bitmap);
- if (err)
- goto done;
- bitmap = alloc_bitmap;
- }
-
- for (i = (di->volume_bitmap_block + bitmap_blocks); i < di->total_blocks; i++)
- {
- if (!prodos_get_volume_bitmap_bit(bitmap, i))
- {
- prodos_set_volume_bitmap_bit(bitmap, i, 1);
- *block = i;
- break;
- }
- }
-
- if (*block > 0)
- {
- if (alloc_bitmap)
- {
- err = prodos_save_volume_bitmap(image, bitmap);
- if (err)
- goto done;
- }
- }
- else
- {
- err = IMGTOOLERR_NOSPACE;
- }
-
-done:
- if (err)
- *block = 0;
- if (alloc_bitmap)
- free(alloc_bitmap);
- return err;
-}
-
-
-
-/* ----------------------------------------------------------------------- */
-
-static imgtoolerr_t prodos_diskimage_create(imgtool::image &image, util::option_resolution *opts)
-{
- imgtoolerr_t err;
- uint32_t heads, tracks, sectors, sector_bytes;
- uint32_t dirent_size, volume_bitmap_block, i;
- uint32_t volume_bitmap_block_count, total_blocks;
- uint8_t buffer[BLOCK_SIZE];
-
- heads = opts->lookup_int('H');
- tracks = opts->lookup_int('T');
- sectors = opts->lookup_int('S');
- sector_bytes = opts->lookup_int('L');
-
- dirent_size = 39;
- volume_bitmap_block = 6;
- total_blocks = tracks * heads * sectors * sector_bytes / BLOCK_SIZE;
- volume_bitmap_block_count = (total_blocks + (BLOCK_SIZE * 8) - 1) / (BLOCK_SIZE * 8);
-
- /* prepare initial dir block */
- memset(buffer, 0, sizeof(buffer));
- place_integer_le(buffer, 4 + 0, 1, 0xF0);
- place_integer_le(buffer, 4 + 31, 1, dirent_size);
- place_integer_le(buffer, 4 + 32, 1, BLOCK_SIZE / dirent_size);
- place_integer_le(buffer, 4 + 35, 2, volume_bitmap_block);
- place_integer_le(buffer, 4 + 37, 2, total_blocks);
-
- err = prodos_save_block(image, ROOTDIR_BLOCK, buffer);
- if (err)
- return err;
-
- /* setup volume bitmap */
- memset(buffer, 0, sizeof(buffer));
- for (i = 0; i < (volume_bitmap_block + volume_bitmap_block_count); i++)
- prodos_set_volume_bitmap_bit(buffer, i, 1);
- prodos_save_block(image, volume_bitmap_block, buffer);
-
- /* and finally open the image */
- return prodos_diskimage_open(image);
-}
-
-
-
-static imgtoolerr_t prodos_diskimage_create_525(imgtool::image &image, imgtool::stream::ptr &&dummy, util::option_resolution *opts)
-{
- prodos_setprocs_525(image);
- return prodos_diskimage_create(image, opts);
-}
-
-
-
-static imgtoolerr_t prodos_diskimage_create_35(imgtool::image &image, imgtool::stream::ptr &&dummy, util::option_resolution *opts)
-{
- prodos_setprocs_35(image);
- return prodos_diskimage_create(image, opts);
-}
-
-
-
-/* ----------------------------------------------------------------------- */
-
-static imgtoolerr_t prodos_enum_seek(imgtool::image &image,
- prodos_direnum *appleenum, uint32_t block, uint32_t index)
-{
- imgtoolerr_t err;
- uint8_t buffer[BLOCK_SIZE];
-
- if (appleenum->block != block)
- {
- if (block != 0)
- {
- err = prodos_load_block(image, block, buffer);
- if (err)
- return err;
- memcpy(appleenum->block_data, buffer, sizeof(buffer));
- }
- appleenum->block = block;
- }
-
- appleenum->index = index;
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static uint8_t *next_info_block(uint8_t *buffer, size_t *position)
-{
- size_t side = *position & 0x100;
- size_t subpos = *position & 0x0FF;
- uint8_t *result;
-
- if (subpos < 8)
- {
- subpos = 8;
- *position = side + subpos;
- }
-
- while((buffer[side + subpos] == 0x00) || (subpos + buffer[side + subpos] > 0x100))
- {
- if (side)
- return NULL;
-
- side = 0x100;
- subpos = 8;
- }
-
- result = &buffer[side + subpos];
- subpos += *result;
- *position = side + subpos;
- return result;
-}
-
-
-
-static uint8_t *alloc_info_block(uint8_t *buffer, size_t block_size, uint8_t block_type)
-{
- size_t position = 0;
- size_t side;
- size_t subpos;
- uint8_t *result;
-
- while(next_info_block(buffer, &position))
- ;
-
- side = position & 0x100;
- subpos = position & 0x0FF;
-
- if ((subpos + block_size) > 0x100)
- return NULL;
-
- result = &buffer[side + subpos];
- *(result++) = (uint8_t) block_size;
- *(result++) = block_type;
- memset(result, 0, block_size - 2);
- return result;
-}
-
-
-
-static imgtoolerr_t prodos_get_next_dirent(imgtool::image &image,
- prodos_direnum *appleenum, prodos_dirent &ent)
-{
- imgtoolerr_t err;
- prodos_diskinfo *di;
- size_t finfo_offset;
- uint32_t next_block, next_index;
- uint32_t offset;
- uint8_t buffer[BLOCK_SIZE];
- const uint8_t *info_ptr;
- int fork_num;
-
- di = get_prodos_info(image);
- memset(&ent, 0, sizeof(ent));
-
- /* have we hit the end of the file? */
- if (appleenum->block == 0)
- return IMGTOOLERR_SUCCESS;
-
- /* populate the resulting dirent */
- offset = appleenum->index * di->dirent_size + 4;
- ent.storage_type = appleenum->block_data[offset + 0];
- memcpy(ent.filename, &appleenum->block_data[offset + 1], 15);
- ent.filename[15] = '\0';
- ent.creation_time = pick_integer_le(appleenum->block_data, offset + 24, 4);
- ent.lastmodified_time = pick_integer_le(appleenum->block_data, offset + 33, 4);
- ent.file_type = 0x3F3F3F3F;
- ent.file_creator = 0x3F3F3F3F;
- ent.finder_flags = 0;
- ent.coord_x = 0;
- ent.coord_y = 0;
- ent.finder_folder = 0;
- ent.icon_id = 0;
- ent.script_code = 0;
- ent.extended_flags = 0;
- ent.comment_id = 0;
- ent.putaway_directory = 0;
-
- if (is_extendedfile_storagetype(ent.storage_type))
- {
- /* this is a ProDOS extended file; we need to get the extended info
- * block */
- ent.extkey_pointer = pick_integer_le(appleenum->block_data, offset + 17, 2);
-
- err = prodos_load_block(image, ent.extkey_pointer, buffer);
- if (err)
- return err;
-
- for (fork_num = 0; fork_num <= 1; fork_num++)
- {
- ent.key_pointer[fork_num] = pick_integer_le(buffer, 1 + (fork_num * 256), 2);
- ent.filesize[fork_num] = pick_integer_le(buffer, 5 + (fork_num * 256), 3);
- ent.depth[fork_num] = buffer[fork_num * 256] & 0x0F;
- }
-
- finfo_offset = 0;
- while((info_ptr = next_info_block(buffer, &finfo_offset)) != NULL)
- {
- if (*(info_ptr++) == 18)
- {
- switch(*(info_ptr++))
- {
- case 1: /* FInfo */
- ent.file_type = pick_integer_be(info_ptr, 0, 4);
- ent.file_creator = pick_integer_be(info_ptr, 4, 4);
- ent.finder_flags = pick_integer_be(info_ptr, 8, 2);
- ent.coord_x = pick_integer_be(info_ptr, 10, 2);
- ent.coord_y = pick_integer_be(info_ptr, 12, 2);
- ent.finder_folder = pick_integer_be(info_ptr, 14, 4);
- break;
-
- case 2: /* xFInfo */
- ent.icon_id = pick_integer_be(info_ptr, 0, 2);
- ent.script_code = pick_integer_be(info_ptr, 8, 1);
- ent.extended_flags = pick_integer_be(info_ptr, 9, 1);
- ent.comment_id = pick_integer_be(info_ptr, 10, 2);
- ent.putaway_directory = pick_integer_be(info_ptr, 12, 4);
- break;
- }
- }
- }
- }
- else
- {
- /* normal ProDOS files have all of the info right here */
- ent.key_pointer[0] = pick_integer_le(appleenum->block_data, offset + 17, 2);
- ent.filesize[0] = pick_integer_le(appleenum->block_data, offset + 21, 3);
- ent.depth[0] = ent.storage_type >> 4;
- }
-
- /* identify next entry */
- next_block = appleenum->block;
- next_index = appleenum->index + 1;
- if (next_index >= di->dirents_per_block)
- {
- next_block = pick_integer_le(appleenum->block_data, 2, 2);
- next_index = 0;
- }
-
- /* seek next block */
- err = prodos_enum_seek(image, appleenum, next_block, next_index);
- if (err)
- return err;
-
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-/* changes a normal file to a ProDOS extended file */
-static imgtoolerr_t prodos_promote_file(imgtool::image &image, uint8_t *bitmap, prodos_dirent *ent)
-{
- imgtoolerr_t err;
- uint16_t new_block;
- uint8_t buffer[BLOCK_SIZE];
-
- assert(is_normalfile_storagetype(ent->storage_type));
-
- err = prodos_alloc_block(image, bitmap, &new_block);
- if (err)
- return err;
-
- /* create raw extended info block */
- memset(buffer, 0, sizeof(buffer));
- err = prodos_save_block(image, new_block, buffer);
- if (err)
- return err;
-
- ent->storage_type = (ent->storage_type & 0x0F) | 0x50;
- ent->extkey_pointer = new_block;
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_put_dirent(imgtool::image &image,
- prodos_direnum *appleenum, prodos_dirent *ent)
-{
- imgtoolerr_t err;
- prodos_diskinfo *di;
- uint32_t offset;
- size_t finfo_offset;
- uint8_t buffer[BLOCK_SIZE];
- int fork_num;
- int needs_finfo = false;
- int needs_xfinfo = false;
- uint8_t *info_ptr;
- uint8_t *finfo;
- uint8_t *xfinfo;
-
- di = get_prodos_info(image);
- offset = appleenum->index * di->dirent_size + 4;
-
- /* determine whether we need FInfo and/or xFInfo */
- if (is_normalfile_storagetype(ent->storage_type))
- {
- needs_finfo = (ent->file_type != 0x3F3F3F3F) ||
- (ent->file_creator != 0x3F3F3F3F) ||
- (ent->finder_flags != 0) ||
- (ent->coord_x != 0) ||
- (ent->coord_y != 0) ||
- (ent->finder_folder != 0);
-
- needs_xfinfo = (ent->icon_id != 0) ||
- (ent->script_code != 0) ||
- (ent->extended_flags != 0) ||
- (ent->comment_id != 0) ||
- (ent->putaway_directory != 0);
- }
-
- /* do we need to promote this file to an extended file? */
- if (!is_extendedfile_storagetype(ent->storage_type)
- && (needs_finfo || needs_xfinfo))
- {
- err = prodos_promote_file(image, NULL, ent);
- if (err)
- return err;
- }
-
- /* write out the storage type, filename, creation and lastmodified times */
- appleenum->block_data[offset + 0] = ent->storage_type;
- memcpy(&appleenum->block_data[offset + 1], ent->filename, 15);
- place_integer_le(appleenum->block_data, offset + 24, 4, ent->creation_time);
- place_integer_le(appleenum->block_data, offset + 33, 4, ent->lastmodified_time);
-
- if (is_extendedfile_storagetype(ent->storage_type))
- {
- /* ProDOS extended file */
- err = prodos_load_block(image, ent->extkey_pointer, buffer);
- if (err)
- return err;
-
- finfo = NULL;
- xfinfo = NULL;
-
- for (fork_num = 0; fork_num <= 1; fork_num++)
- {
- place_integer_le(buffer, 1 + (fork_num * 256), 2, ent->key_pointer[fork_num]);
- place_integer_le(buffer, 5 + (fork_num * 256), 3, ent->filesize[fork_num]);
- buffer[fork_num * 256] = ent->depth[fork_num];
- }
-
- finfo_offset = 0;
- while((info_ptr = next_info_block(buffer, &finfo_offset)) != NULL)
- {
- if (*(info_ptr++) == 18)
- {
- switch(*(info_ptr++))
- {
- case 1: /* FInfo */
- finfo = info_ptr;
- break;
-
- case 2: /* xFInfo */
- xfinfo = info_ptr;
- break;
- }
- }
- }
-
- /* allocate the finfo and/or xinfo blocks, if we need them */
- if (needs_finfo && !finfo)
- finfo = alloc_info_block(buffer, 18, 1);
- if (needs_xfinfo && !xfinfo)
- xfinfo = alloc_info_block(buffer, 18, 2);
-
- if (finfo)
- {
- place_integer_be(finfo, 0, 4, ent->file_type);
- place_integer_be(finfo, 4, 4, ent->file_creator);
- place_integer_be(finfo, 8, 2, ent->finder_flags);
- place_integer_be(finfo, 10, 2, ent->coord_x);
- place_integer_be(finfo, 12, 2, ent->coord_y);
- place_integer_be(finfo, 14, 4, ent->finder_folder);
- }
-
- if (xfinfo)
- {
- place_integer_be(xfinfo, 0, 2, ent->icon_id);
- place_integer_be(xfinfo, 8, 1, ent->script_code);
- place_integer_be(xfinfo, 9, 1, ent->extended_flags);
- place_integer_be(xfinfo, 10, 2, ent->comment_id);
- place_integer_be(xfinfo, 12, 4, ent->putaway_directory);
- }
-
- err = prodos_save_block(image, ent->extkey_pointer, buffer);
- if (err)
- return err;
-
- place_integer_le(appleenum->block_data, offset + 17, 2, ent->extkey_pointer);
- place_integer_le(appleenum->block_data, offset + 21, 3, BLOCK_SIZE);
- }
- else
- {
- /* normal file */
- place_integer_le(appleenum->block_data, offset + 17, 2, ent->key_pointer[0]);
- place_integer_le(appleenum->block_data, offset + 21, 3, ent->filesize[0]);
- }
-
- err = prodos_save_block(image, appleenum->block, appleenum->block_data);
- if (err)
- return err;
-
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_lookup_path(imgtool::image &image, const char *path,
- creation_policy_t create, prodos_direnum *direnum, prodos_dirent *ent)
-{
- imgtoolerr_t err;
- prodos_direnum my_direnum;
- uint32_t block = ROOTDIR_BLOCK;
- const char *old_path;
- uint16_t this_block;
- uint32_t this_index;
- uint16_t free_block = 0;
- uint32_t free_index = 0;
- uint16_t new_file_block;
- uint8_t buffer[BLOCK_SIZE];
-
- if (!direnum)
- direnum = &my_direnum;
-
- while(*path)
- {
- memset(direnum, 0, sizeof(*direnum));
- err = prodos_enum_seek(image, direnum, block, 0);
- if (err)
- goto done;
-
- do
- {
- this_block = direnum->block;
- this_index = direnum->index;
-
- err = prodos_get_next_dirent(image, direnum, *ent);
- if (err)
- goto done;
-
- /* if we need to create a file entry and this is free, track it */
- if (create && this_block && !free_block && !ent->storage_type)
- {
- free_block = this_block;
- free_index = this_index;
- }
- }
- while(direnum->block && (strcmp(path, ent->filename) || (
- !is_file_storagetype(ent->storage_type) &&
- !is_dir_storagetype(ent->storage_type))));
-
- old_path = path;
- path += strlen(path) + 1;
- if (*path)
- {
- /* we have found part of the path; we are not finished yet */
- if (!is_dir_storagetype(ent->storage_type))
- {
- err = IMGTOOLERR_FILENOTFOUND;
- goto done;
- }
- block = ent->key_pointer[0];
- }
- else if (!direnum->block)
- {
- /* did not find file; maybe we need to create it */
- if (create == CREATE_NONE)
- {
- err = IMGTOOLERR_FILENOTFOUND;
- goto done;
- }
-
- /* do we need to expand the directory? */
- if (!free_block)
- {
- if (this_block == 0)
- {
- err = IMGTOOLERR_CORRUPTFILE;
- goto done;
- }
-
- err = prodos_load_block(image, this_block, buffer);
- if (err)
- goto done;
-
- /* allocate a block */
- err = prodos_alloc_block(image, NULL, &free_block);
- if (err)
- goto done;
-
- /* clear out this new block */
- err = prodos_clear_block(image, free_block);
- if (err)
- goto done;
-
- /* save this link */
- place_integer_le(buffer, 2, 2, free_block);
- err = prodos_save_block(image, this_block, buffer);
- if (err)
- goto done;
-
- free_index = 0;
- }
-
- /* seek back to the free space */
- err = prodos_enum_seek(image, direnum, free_block, free_index);
- if (err)
- goto done;
-
- new_file_block = 0;
- if (create == CREATE_DIR)
- {
- /* if we are creating a directory, we need to create a new block */
- err = prodos_alloc_block(image, NULL, &new_file_block);
- if (err)
- goto done;
-
- err = prodos_clear_block(image, new_file_block);
- if (err)
- goto done;
- }
-
- /* prepare the dirent */
- memset(ent, 0, sizeof(*ent));
- ent->storage_type = (create == CREATE_DIR) ? 0xe0 : 0x10;
- ent->creation_time = ent->lastmodified_time = prodos_time_now();
- ent->key_pointer[0] = new_file_block;
- ent->file_type = 0x3F3F3F3F;
- ent->file_creator = 0x3F3F3F3F;
- strncpy(ent->filename, old_path, std::size(ent->filename));
-
- /* and place it */
- err = prodos_put_dirent(image, direnum, ent);
- if (err)
- goto done;
-
- this_block = free_block;
- this_index = free_index;
- }
- else
- {
- /* we've found the file; seek that dirent */
- err = prodos_enum_seek(image, direnum, this_block, this_index);
- if (err)
- goto done;
- }
- }
-
- err = IMGTOOLERR_SUCCESS;
-done:
- return err;
-}
-
-
-
-static imgtoolerr_t prodos_fill_file(imgtool::image &image, uint8_t *bitmap,
- uint16_t key_block, int key_block_allocated,
- int depth, uint32_t blockcount, uint32_t block_index)
-{
- imgtoolerr_t err;
- prodos_diskinfo *di;
- int dirty;
- int sub_block_allocated;
- uint16_t i, sub_block, new_sub_block;
- uint8_t buffer[BLOCK_SIZE];
-
- di = get_prodos_info(image);
-
- if (key_block_allocated)
- {
- /* we are on a recently allocated key block; start fresh */
- memset(buffer, 0, sizeof(buffer));
- dirty = true;
- }
- else
- {
- /* this is a preexisting key block */
- err = prodos_load_block(image, key_block, buffer);
- if (err)
- return err;
- dirty = false;
- }
-
- for (i = 0; i < 256; i++)
- {
- sub_block_allocated = false;
-
- sub_block = buffer[i + 256];
- sub_block <<= 8;
- sub_block += buffer[i + 0];
-
- new_sub_block = sub_block;
- if ((block_index < blockcount) && (sub_block == 0))
- {
- err = prodos_alloc_block(image, bitmap, &new_sub_block);
- if (err)
- return err;
- sub_block_allocated = true;
- }
- else if ((block_index >= blockcount) && (sub_block != 0))
- {
- new_sub_block = 0;
- if (sub_block < di->total_blocks)
- prodos_set_volume_bitmap_bit(bitmap, sub_block, 0);
- }
-
- /* did we change the block? */
- if (new_sub_block != sub_block)
- {
- dirty = true;
- buffer[i + 0] = new_sub_block >> 0;
- buffer[i + 256] = new_sub_block >> 8;
- if (sub_block == 0)
- sub_block = new_sub_block;
- }
-
- /* call recursive function */
- if (depth > 2)
- {
- err = prodos_fill_file(image, bitmap, sub_block, sub_block_allocated, depth - 1, blockcount, block_index);
- if (err)
- return err;
- }
-
- /* increment index */
- block_index += 1 << ((depth - 2) * 8);
- }
-
- /* if we changed anything, then save the block */
- if (dirty)
- {
- err = prodos_save_block(image, key_block, buffer);
- if (err)
- return err;
- }
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_set_file_block_count(imgtool::image &image, prodos_direnum *direnum,
- prodos_dirent *ent, uint8_t *bitmap, int fork_num, uint32_t new_blockcount)
-{
- imgtoolerr_t err;
- int depth, new_depth, i;
- uint16_t new_block, block;
- uint8_t buffer[BLOCK_SIZE];
- uint16_t key_pointer;
-
- if (fork_num && (new_blockcount > 0) && !is_extendedfile_storagetype(ent->storage_type))
- {
- /* need to change a normal file to an extended file */
- err = prodos_promote_file(image, bitmap, ent);
- if (err)
- return err;
- }
-
- key_pointer = ent->key_pointer[fork_num];
- depth = ent->depth[fork_num];
-
- /* determine the new tree depth */
- if (new_blockcount <= 1)
- new_depth = 1;
- else if (new_blockcount <= 256)
- new_depth = 2;
- else
- new_depth = 3;
-
- /* are we zero length, and do we have to create a block? */
- if ((new_blockcount >= 1) && (key_pointer == 0))
- {
- err = prodos_alloc_block(image, bitmap, &new_block);
- if (err)
- return err;
- key_pointer = new_block;
- }
-
- /* do we have to grow the tree? */
- while(new_depth > depth)
- {
- err = prodos_alloc_block(image, bitmap, &new_block);
- if (err)
- return err;
-
- /* create this new key block, with a link to the previous one */
- memset(buffer, 0, sizeof(buffer));
- buffer[0] = (uint8_t) (key_pointer >> 0);
- buffer[256] = (uint8_t) (key_pointer >> 8);
- err = prodos_save_block(image, new_block, buffer);
- if (err)
- return err;
-
- depth++;
- key_pointer = new_block;
- }
-
- /* do we have to shrink the tree? */
- while(new_depth < depth)
- {
- err = prodos_load_block(image, key_pointer, buffer);
- if (err)
- return err;
-
- for (i = 1; i < 256; i++)
- {
- block = buffer[i + 256];
- block <<= 8;
- block |= buffer[i + 0];
-
- if (block > 0)
- {
- if (depth > 2)
- {
- /* remove this block's children */
- err = prodos_fill_file(image, bitmap, block, false, depth - 1, 0, 0);
- if (err)
- return err;
- }
-
- /* and remove this block */
- prodos_set_volume_bitmap_bit(bitmap, block, 0);
- }
- }
-
- /* remove this key block */
- prodos_set_volume_bitmap_bit(bitmap, key_pointer, 0);
-
- /* set the new key pointer */
- block = buffer[256];
- block <<= 8;
- block |= buffer[0];
- key_pointer = block;
-
- depth--;
- }
-
- if (new_blockcount > 0)
- {
- /* fill out the file tree */
- err = prodos_fill_file(image, bitmap, key_pointer, false, depth, new_blockcount, 0);
- if (err)
- return err;
- }
- else if (key_pointer != 0)
- {
- /* we are now zero length, and don't need a key pointer */
- prodos_set_volume_bitmap_bit(bitmap, key_pointer, 0);
- key_pointer = 0;
- }
-
- /* change the depth if we are not an extended file */
- if (is_normalfile_storagetype(ent->storage_type))
- {
- ent->storage_type &= ~0xF0;
- ent->storage_type |= depth * 0x10;
- }
-
- ent->key_pointer[fork_num] = key_pointer;
- ent->depth[fork_num] = depth;
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_set_file_size(imgtool::image &image, prodos_direnum *direnum,
- prodos_dirent *ent, int fork_num, uint32_t new_size)
-{
- imgtoolerr_t err = IMGTOOLERR_SUCCESS;
- uint32_t blockcount, new_blockcount;
- uint8_t *bitmap = NULL;
-
- if (ent->filesize[fork_num] != new_size)
- {
- blockcount = (ent->filesize[fork_num] + BLOCK_SIZE - 1) / BLOCK_SIZE;
- new_blockcount = (new_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
-
- /* do we need to change the block chain? */
- if (new_blockcount != blockcount)
- {
- err = prodos_load_volume_bitmap(image, &bitmap);
- if (err)
- goto done;
-
- err = prodos_set_file_block_count(image, direnum, ent, bitmap, fork_num, new_blockcount);
- if (err)
- goto done;
-
- err = prodos_save_volume_bitmap(image, bitmap);
- if (err)
- goto done;
- }
-
- ent->filesize[fork_num] = new_size;
- err = prodos_put_dirent(image, direnum, ent);
- if (err)
- goto done;
- }
-
-done:
- if (bitmap)
- free(bitmap);
- return err;
-}
-
-
-
-static uint32_t prodos_get_storagetype_maxfilesize(uint8_t storage_type)
-{
- uint32_t max_filesize = 0;
- switch(storage_type & 0xF0)
- {
- case 0x10:
- max_filesize = BLOCK_SIZE * 1;
- break;
- case 0x20:
- max_filesize = BLOCK_SIZE * 256;
- break;
- case 0x30:
- case 0x50:
- max_filesize = BLOCK_SIZE * 32768;
- break;
- }
- return max_filesize;
-}
-
-
-
-static imgtoolerr_t prodos_diskimage_beginenum(imgtool::directory &enumeration, const char *path)
-{
- imgtoolerr_t err;
- imgtool::image &image(enumeration.image());
- prodos_direnum *appleenum;
- prodos_dirent ent;
- uint16_t block = ROOTDIR_BLOCK;
-
- appleenum = (prodos_direnum *) enumeration.extra_bytes();
-
- /* find subdirectory, if appropriate */
- if (*path)
- {
- err = prodos_lookup_path(image, path, CREATE_NONE, NULL, &ent);
- if (err)
- return err;
-
- /* only work on directories */
- if (!is_dir_storagetype(ent.storage_type))
- return IMGTOOLERR_FILENOTFOUND;
-
- block = ent.key_pointer[0];
- }
-
- /* seek initial block */
- err = prodos_enum_seek(image, appleenum, block, 0);
- if (err)
- return err;
-
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_diskimage_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent)
-{
- imgtoolerr_t err;
- imgtool::image &image(enumeration.image());
- prodos_direnum *appleenum;
- prodos_dirent pd_ent;
- uint32_t max_filesize;
-
- appleenum = (prodos_direnum *) enumeration.extra_bytes();
-
- do
- {
- err = prodos_get_next_dirent(image, appleenum, pd_ent);
- if (err)
- return err;
- }
- while(appleenum->block
- && !is_file_storagetype(pd_ent.storage_type)
- && !is_dir_storagetype(pd_ent.storage_type));
-
- /* end of file? */
- if (pd_ent.storage_type == 0x00)
- {
- ent.eof = 1;
- return IMGTOOLERR_SUCCESS;
- }
-
- strcpy(ent.filename, pd_ent.filename);
- ent.directory = is_dir_storagetype(pd_ent.storage_type);
- ent.creation_time = prodos_crack_time(pd_ent.creation_time);
- ent.lastmodified_time = prodos_crack_time(pd_ent.lastmodified_time);
-
- if (!ent.directory)
- {
- ent.filesize = pd_ent.filesize[0];
-
- max_filesize = prodos_get_storagetype_maxfilesize(pd_ent.storage_type);
- if (ent.filesize > max_filesize)
- {
- ent.corrupt = 1;
- ent.filesize = max_filesize;
- }
- }
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_read_file_tree(imgtool::image &image, uint32_t *filesize,
- uint32_t block, int nest_level, imgtool::stream &destf)
-{
- imgtoolerr_t err;
- prodos_diskinfo *di;
- uint8_t buffer[BLOCK_SIZE];
- uint16_t sub_block;
- size_t bytes_to_write;
- int i;
-
- /* check bounds */
- di = get_prodos_info(image);
- if (block >= di->total_blocks)
- return IMGTOOLERR_CORRUPTFILE;
-
- err = prodos_load_block(image, block, buffer);
- if (err)
- return err;
-
- if (nest_level > 0)
- {
- /* this is an index block */
- for (i = 0; i < 256; i++)
- {
- /* retrieve the block pointer; the two bytes are on either half
- * of the block */
- sub_block = buffer[i + 256];
- sub_block <<= 8;
- sub_block |= buffer[i + 0];
-
- if (sub_block != 0)
- {
- err = prodos_read_file_tree(image, filesize, sub_block, nest_level - 1, destf);
- if (err)
- return err;
- }
- }
- }
- else
- {
- /* this is a leaf block */
- bytes_to_write = std::min(size_t(*filesize), sizeof(buffer));
- destf.write(buffer, bytes_to_write);
- *filesize -= bytes_to_write;
- }
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_write_file_tree(imgtool::image &image, uint32_t *filesize,
- uint32_t block, int nest_level, imgtool::stream &sourcef)
-{
- imgtoolerr_t err;
- prodos_diskinfo *di;
- uint8_t buffer[BLOCK_SIZE];
- uint16_t sub_block;
- size_t bytes_to_read;
- int i;
-
- /* nothing more to read? bail */
- if (*filesize == 0)
- return IMGTOOLERR_SUCCESS;
-
- /* check bounds */
- di = get_prodos_info(image);
- if (block >= di->total_blocks)
- return IMGTOOLERR_CORRUPTFILE;
-
- err = prodos_load_block(image, block, buffer);
- if (err)
- return err;
-
- if (nest_level > 0)
- {
- for (i = 0; i < 256; i++)
- {
- sub_block = buffer[i + 256];
- sub_block <<= 8;
- sub_block |= buffer[i + 0];
-
- if (sub_block != 0)
- {
- err = prodos_write_file_tree(image, filesize, sub_block, nest_level - 1, sourcef);
- if (err)
- return err;
- }
- }
- }
- else
- {
- /* this is a leaf block */
- bytes_to_read = std::min(size_t(*filesize), sizeof(buffer));
- sourcef.read(buffer, bytes_to_read);
- *filesize -= bytes_to_read;
-
- err = prodos_save_block(image, block, buffer);
- if (err)
- return err;
- }
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_diskimage_freespace(imgtool::partition &partition, uint64_t *size)
-{
- imgtoolerr_t err;
- imgtool::image &image(partition.image());
- prodos_diskinfo *di;
- uint8_t *bitmap = NULL;
- uint16_t i;
-
- di = get_prodos_info(image);
- *size = 0;
-
- err = prodos_load_volume_bitmap(image, &bitmap);
- if (err)
- goto done;
-
- for (i = 0; i < di->total_blocks; i++)
- {
- if (!prodos_get_volume_bitmap_bit(bitmap, i))
- *size += BLOCK_SIZE;
- }
-
-done:
- if (bitmap)
- free(bitmap);
- return err;
-}
-
-
-
-static imgtoolerr_t prodos_diskimage_readfile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf)
-{
- imgtoolerr_t err;
- imgtool::image &image(partition.image());
- prodos_dirent ent;
- uint16_t key_pointer;
- int nest_level;
- mac_fork_t fork_num;
-
- err = prodos_lookup_path(image, filename, CREATE_NONE, NULL, &ent);
- if (err)
- return err;
-
- if (is_dir_storagetype(ent.storage_type))
- return IMGTOOLERR_FILENOTFOUND;
-
- err = mac_identify_fork(fork, &fork_num);
- if (err)
- return err;
-
- key_pointer = ent.key_pointer[fork_num];
- nest_level = ent.depth[fork_num] - 1;
-
- if (key_pointer != 0)
- {
- err = prodos_read_file_tree(image, &ent.filesize[fork_num], key_pointer,
- nest_level, destf);
- if (err)
- return err;
- }
-
- /* have we not actually received the correct amount of bytes? if not, fill in the rest */
- if (ent.filesize[fork_num] > 0)
- destf.fill(0, ent.filesize[fork_num]);
-
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_diskimage_writefile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *opts)
-{
- imgtoolerr_t err;
- imgtool::image &image(partition.image());
- prodos_dirent ent;
- prodos_direnum direnum;
- uint64_t file_size;
- mac_fork_t fork_num;
-
- file_size = sourcef.size();
-
- err = prodos_lookup_path(image, filename, CREATE_FILE, &direnum, &ent);
- if (err)
- return err;
-
- /* only work on files */
- if (is_dir_storagetype(ent.storage_type))
- return IMGTOOLERR_FILENOTFOUND;
-
- err = mac_identify_fork(fork, &fork_num);
- if (err)
- return err;
-
- /* set the file size */
- err = prodos_set_file_size(image, &direnum, &ent, fork_num, file_size);
- if (err)
- return err;
-
- err = prodos_write_file_tree(image, &ent.filesize[fork_num], ent.key_pointer[fork_num],
- ent.depth[fork_num] - 1, sourcef);
- if (err)
- return err;
-
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_diskimage_deletefile(imgtool::partition &partition, const char *path)
-{
- imgtoolerr_t err;
- imgtool::image &image(partition.image());
- prodos_dirent ent;
- prodos_direnum direnum;
-
- err = prodos_lookup_path(image, path, CREATE_NONE, &direnum, &ent);
- if (err)
- return err;
-
- /* only work on files */
- if (is_dir_storagetype(ent.storage_type))
- return IMGTOOLERR_FILENOTFOUND;
-
- /* empty out both forks */
- err = prodos_set_file_size(image, &direnum, &ent, 0, 0);
- if (err)
- return err;
- err = prodos_set_file_size(image, &direnum, &ent, 1, 0);
- if (err)
- return err;
-
- memset(&ent, 0, sizeof(ent));
- err = prodos_put_dirent(image, &direnum, &ent);
- if (err)
- return err;
-
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_diskimage_listforks(imgtool::partition &partition, const char *path, std::vector<imgtool::fork_entry> &forks)
-{
- imgtoolerr_t err;
- imgtool::image &image(partition.image());
- prodos_dirent ent;
- prodos_direnum direnum;
-
- err = prodos_lookup_path(image, path, CREATE_NONE, &direnum, &ent);
- if (err)
- return err;
-
- if (is_dir_storagetype(ent.storage_type))
- return IMGTOOLERR_FILENOTFOUND;
-
- // specify data fork
- forks.emplace_back(ent.filesize[0], imgtool::fork_entry::type_t::DATA);
-
- if (is_extendedfile_storagetype(ent.storage_type))
- {
- // specify the resource fork
- forks.emplace_back(ent.filesize[1], imgtool::fork_entry::type_t::RESOURCE);
- }
-
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_diskimage_createdir(imgtool::partition &partition, const char *path)
-{
- imgtoolerr_t err;
- imgtool::image &image(partition.image());
- prodos_dirent ent;
- prodos_direnum direnum;
-
- err = prodos_lookup_path(image, path, CREATE_DIR, &direnum, &ent);
- if (err)
- return err;
-
- /* only work on directories */
- if (!is_dir_storagetype(ent.storage_type))
- return IMGTOOLERR_FILENOTFOUND;
-
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_free_directory(imgtool::image &image, uint8_t *volume_bitmap, uint16_t key_pointer)
-{
- imgtoolerr_t err;
- prodos_diskinfo *di;
- int i;
- uint16_t next_block;
- uint32_t offset;
- uint8_t buffer[BLOCK_SIZE];
-
- di = get_prodos_info(image);
-
- if (key_pointer != 0)
- {
- err = prodos_load_block(image, key_pointer, buffer);
- if (err)
- return err;
-
- for (i = 0; i < di->dirents_per_block; i++)
- {
- offset = i * di->dirent_size + 4;
-
- if (is_file_storagetype(buffer[offset]) || is_file_storagetype(buffer[offset]))
- return IMGTOOLERR_DIRNOTEMPTY;
- }
-
- next_block = pick_integer_le(buffer, 2, 2);
-
- err = prodos_free_directory(image, volume_bitmap, next_block);
- if (err)
- return err;
-
- prodos_set_volume_bitmap_bit(volume_bitmap, key_pointer, 0);
- }
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_diskimage_deletedir(imgtool::partition &partition, const char *path)
-{
- imgtoolerr_t err;
- imgtool::image &image(partition.image());
- prodos_dirent ent;
- prodos_direnum direnum;
- uint8_t *volume_bitmap = NULL;
-
- err = prodos_lookup_path(image, path, CREATE_NONE, &direnum, &ent);
- if (err)
- goto done;
-
- /* only work on directories */
- if (!is_dir_storagetype(ent.storage_type))
- {
- err = IMGTOOLERR_FILENOTFOUND;
- goto done;
- }
-
- err = prodos_load_volume_bitmap(image, &volume_bitmap);
- if (err)
- goto done;
-
- err = prodos_free_directory(image, volume_bitmap, ent.key_pointer[0]);
- if (err)
- goto done;
-
- err = prodos_save_volume_bitmap(image, volume_bitmap);
- if (err)
- goto done;
-
- memset(&ent, 0, sizeof(ent));
- err = prodos_put_dirent(image, &direnum, &ent);
- if (err)
- goto done;
-
-done:
- if (volume_bitmap)
- free(volume_bitmap);
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_get_file_tree(imgtool::image &image, imgtool_chainent *chain, size_t chain_size,
- size_t *chain_pos, uint16_t block, uint8_t total_depth, uint8_t cur_depth)
-{
- imgtoolerr_t err;
- prodos_diskinfo *di;
- int i;
- uint16_t sub_block;
- uint8_t buffer[BLOCK_SIZE];
-
- if (block == 0)
- return IMGTOOLERR_SUCCESS;
- if (*chain_pos >= chain_size)
- return IMGTOOLERR_SUCCESS;
-
- /* check bounds */
- di = get_prodos_info(image);
- if (block >= di->total_blocks)
- return IMGTOOLERR_CORRUPTFILE;
-
- chain[*chain_pos].level = cur_depth;
- chain[*chain_pos].block = block;
- (*chain_pos)++;
-
- /* must we recurse into the tree? */
- if (cur_depth < total_depth)
- {
- err = prodos_load_block(image, block, buffer);
- if (err)
- return err;
-
- for (i = 0; i < 256; i++)
- {
- sub_block = buffer[i + 256];
- sub_block <<= 8;
- sub_block |= buffer[i + 0];
-
- err = prodos_get_file_tree(image, chain, chain_size, chain_pos, sub_block, total_depth, cur_depth + 1);
- if (err)
- return err;
- }
- }
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_diskimage_getattrs(imgtool::partition &partition, const char *path, const uint32_t *attrs, imgtool_attribute *values)
-{
- imgtoolerr_t err;
- imgtool::image &image(partition.image());
- prodos_dirent ent;
- int i;
-
- err = prodos_lookup_path(image, path, CREATE_NONE, NULL, &ent);
- if (err)
- return err;
-
- for (i = 0; attrs[i]; i++)
- {
- switch(attrs[i])
- {
- case IMGTOOLATTR_INT_MAC_TYPE:
- values[i].i = ent.file_type;
- break;
- case IMGTOOLATTR_INT_MAC_CREATOR:
- values[i].i = ent.file_creator;
- break;
- case IMGTOOLATTR_INT_MAC_FINDERFLAGS:
- values[i].i = ent.finder_flags;
- break;
- case IMGTOOLATTR_INT_MAC_COORDX:
- values[i].i = ent.coord_x;
- break;
- case IMGTOOLATTR_INT_MAC_COORDY:
- values[i].i = ent.coord_y;
- break;
- case IMGTOOLATTR_INT_MAC_FINDERFOLDER:
- values[i].i = ent.finder_folder;
- break;
- case IMGTOOLATTR_INT_MAC_ICONID:
- values[i].i = ent.icon_id;
- break;
- case IMGTOOLATTR_INT_MAC_SCRIPTCODE:
- values[i].i = ent.script_code;
- break;
- case IMGTOOLATTR_INT_MAC_EXTENDEDFLAGS:
- values[i].i = ent.extended_flags;
- break;
- case IMGTOOLATTR_INT_MAC_COMMENTID:
- values[i].i = ent.comment_id;
- break;
- case IMGTOOLATTR_INT_MAC_PUTAWAYDIRECTORY:
- values[i].i = ent.putaway_directory;
- break;
-
- case IMGTOOLATTR_TIME_CREATED:
- values[i].t = prodos_crack_time(ent.creation_time).to_time_t();
- break;
- case IMGTOOLATTR_TIME_LASTMODIFIED:
- values[i].t = prodos_crack_time(ent.lastmodified_time).to_time_t();
- break;
- }
- }
-
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_diskimage_setattrs(imgtool::partition &partition, const char *path, const uint32_t *attrs, const imgtool_attribute *values)
-{
- imgtoolerr_t err;
- imgtool::image &image(partition.image());
- prodos_dirent ent;
- prodos_direnum direnum;
- int i;
-
- err = prodos_lookup_path(image, path, CREATE_NONE, &direnum, &ent);
- if (err)
- return err;
-
- for (i = 0; attrs[i]; i++)
- {
- switch(attrs[i])
- {
- case IMGTOOLATTR_INT_MAC_TYPE:
- ent.file_type = values[i].i;
- break;
- case IMGTOOLATTR_INT_MAC_CREATOR:
- ent.file_creator = values[i].i;
- break;
- case IMGTOOLATTR_INT_MAC_FINDERFLAGS:
- ent.finder_flags = values[i].i;
- break;
- case IMGTOOLATTR_INT_MAC_COORDX:
- ent.coord_x = values[i].i;
- break;
- case IMGTOOLATTR_INT_MAC_COORDY:
- ent.coord_y = values[i].i;
- break;
- case IMGTOOLATTR_INT_MAC_FINDERFOLDER:
- ent.finder_folder = values[i].i;
- break;
- case IMGTOOLATTR_INT_MAC_ICONID:
- ent.icon_id = values[i].i;
- break;
- case IMGTOOLATTR_INT_MAC_SCRIPTCODE:
- ent.script_code = values[i].i;
- break;
- case IMGTOOLATTR_INT_MAC_EXTENDEDFLAGS:
- ent.extended_flags = values[i].i;
- break;
- case IMGTOOLATTR_INT_MAC_COMMENTID:
- ent.comment_id = values[i].i;
- break;
- case IMGTOOLATTR_INT_MAC_PUTAWAYDIRECTORY:
- ent.putaway_directory = values[i].i;
- break;
-
- case IMGTOOLATTR_TIME_CREATED:
- ent.creation_time = prodos_setup_time(values[i].t);
- break;
- case IMGTOOLATTR_TIME_LASTMODIFIED:
- ent.lastmodified_time = prodos_setup_time(values[i].t);
- break;
- }
- }
-
- err = prodos_put_dirent(image, &direnum, &ent);
- if (err)
- return err;
-
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_diskimage_suggesttransfer(imgtool::partition &partition, const char *path, imgtool_transfer_suggestion *suggestions, size_t suggestions_length)
-{
- imgtoolerr_t err;
- imgtool::image &image(partition.image());
- prodos_dirent ent;
- mac_filecategory_t file_category = MAC_FILECATEGORY_DATA;
-
- if (path)
- {
- err = prodos_lookup_path(image, path, CREATE_NONE, NULL, &ent);
- if (err)
- return err;
-
- file_category = is_extendedfile_storagetype(ent.storage_type)
- ? MAC_FILECATEGORY_FORKED : MAC_FILECATEGORY_DATA;
- }
-
- mac_suggest_transfer(file_category, suggestions, suggestions_length);
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static imgtoolerr_t prodos_diskimage_getchain(imgtool::partition &partition, const char *path, imgtool_chainent *chain, size_t chain_size)
-{
- imgtoolerr_t err;
- imgtool::image &image(partition.image());
- prodos_dirent ent;
- size_t chain_pos = 0;
- int fork_num;
-
- err = prodos_lookup_path(image, path, CREATE_NONE, NULL, &ent);
- if (err)
- return err;
-
- switch(ent.storage_type & 0xF0)
- {
- case 0x10:
- case 0x20:
- case 0x30:
- /* normal ProDOS file */
- err = prodos_get_file_tree(image, chain, chain_size, &chain_pos,
- ent.key_pointer[0], ent.depth[0] - 1, 0);
- if (err)
- return err;
- break;
-
- case 0x50:
- /* extended ProDOS file */
- chain[chain_pos].level = 0;
- chain[chain_pos].block = ent.extkey_pointer;
- chain_pos++;
-
- for (fork_num = 0; fork_num <= 1; fork_num++)
- {
- if (ent.key_pointer[fork_num])
- {
- err = prodos_get_file_tree(image, chain, chain_size, &chain_pos,
- ent.key_pointer[fork_num], ent.depth[fork_num] - 1, 1);
- if (err)
- return err;
- }
- }
- break;
-
- case 0xE0:
- /* directory */
- return IMGTOOLERR_UNIMPLEMENTED;
-
- default:
- return IMGTOOLERR_UNEXPECTED;
- }
-
- return IMGTOOLERR_SUCCESS;
-}
-
-
-
-static void generic_prodos_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info)
-{
- switch(state)
- {
- /* --- the following bits of info are returned as 64-bit signed integers --- */
- case IMGTOOLINFO_INT_INITIAL_PATH_SEPARATOR: info->i = 1; break;
- case IMGTOOLINFO_INT_OPEN_IS_STRICT: info->i = 1; break;
- case IMGTOOLINFO_INT_SUPPORTS_CREATION_TIME: info->i = 1; break;
- case IMGTOOLINFO_INT_SUPPORTS_LASTMODIFIED_TIME: info->i = 1; break;
- case IMGTOOLINFO_INT_WRITING_UNTESTED: info->i = 1; break;
- case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: info->i = sizeof(prodos_diskinfo); break;
- case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(prodos_direnum); break;
- case IMGTOOLINFO_INT_PATH_SEPARATOR: info->i = '/'; break;
-
- /* --- the following bits of info are returned as NULL-terminated strings --- */
- case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "ProDOS format"); break;
- case IMGTOOLINFO_STR_FILE: strcpy(info->s = imgtool_temp_str(), __FILE__); break;
- case IMGTOOLINFO_STR_EOLN: strcpy(info->s = imgtool_temp_str(), "\r"); break;
-
- /* --- the following bits of info are returned as pointers to data or functions --- */
- case IMGTOOLINFO_PTR_MAKE_CLASS: info->make_class = imgtool_floppy_make_class; break;
- case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = prodos_diskimage_beginenum; break;
- case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = prodos_diskimage_nextenum; break;
- case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = prodos_diskimage_freespace; break;
- case IMGTOOLINFO_PTR_READ_FILE: info->read_file = prodos_diskimage_readfile; break;
- case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = prodos_diskimage_writefile; break;
- case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = prodos_diskimage_deletefile; break;
- case IMGTOOLINFO_PTR_LIST_FORKS: info->list_forks = prodos_diskimage_listforks; break;
- case IMGTOOLINFO_PTR_CREATE_DIR: info->create_dir = prodos_diskimage_createdir; break;
- case IMGTOOLINFO_PTR_DELETE_DIR: info->delete_dir = prodos_diskimage_deletedir; break;
- case IMGTOOLINFO_PTR_GET_ATTRS: info->get_attrs = prodos_diskimage_getattrs; break;
- case IMGTOOLINFO_PTR_SET_ATTRS: info->set_attrs = prodos_diskimage_setattrs; break;
- case IMGTOOLINFO_PTR_SUGGEST_TRANSFER: info->suggest_transfer = prodos_diskimage_suggesttransfer; break;
- case IMGTOOLINFO_PTR_GET_CHAIN: info->get_chain = prodos_diskimage_getchain; break;
- }
-}
-
-
-
-void prodos_525_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info)
-{
- switch(state)
- {
- /* --- the following bits of info are returned as NULL-terminated strings --- */
- case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "prodos_525"); break;
-
- /* --- the following bits of info are returned as pointers to data or functions --- */
- case IMGTOOLINFO_PTR_FLOPPY_CREATE: info->create = prodos_diskimage_create_525; break;
- case IMGTOOLINFO_PTR_FLOPPY_OPEN: info->open = prodos_diskimage_open_525; break;
- // case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_apple2; break;
-
- default: generic_prodos_get_info(imgclass, state, info); break;
- }
-}
-
-
-
-void prodos_35_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info)
-{
- switch(state)
- {
- /* --- the following bits of info are returned as NULL-terminated strings --- */
- case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "prodos_35"); break;
-
- /* --- the following bits of info are returned as pointers to data or functions --- */
- case IMGTOOLINFO_PTR_FLOPPY_CREATE: info->create = prodos_diskimage_create_35; break;
- case IMGTOOLINFO_PTR_FLOPPY_OPEN: info->open = prodos_diskimage_open_35; break;
- // case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_apple35_iigs; break;
-
- default: generic_prodos_get_info(imgclass, state, info); break;
- }
-}