diff options
Diffstat (limited to 'src/tools/imgtool/modules')
26 files changed, 2136 insertions, 10227 deletions
diff --git a/src/tools/imgtool/modules/amiga.cpp b/src/tools/imgtool/modules/amiga.cpp index c1c5563012e..fcf1bd779a6 100644 --- a/src/tools/imgtool/modules/amiga.cpp +++ b/src/tools/imgtool/modules/amiga.cpp @@ -1,4 +1,4 @@ -// license:GPL-2.0+ +// license:BSD-3-Clause // copyright-holders:Dirk Best /**************************************************************************** @@ -13,14 +13,17 @@ Includes *****************************************************************************/ - -#include <time.h> -#include <string.h> -#include <ctype.h> - #include "imgtool.h" +#include "charconv.h" #include "iflopimg.h" -#include "formats/imageutl.h" + +#include "corestr.h" +#include "multibyte.h" +#include "opresolv.h" + +#include <cctype> +#include <cstring> +#include <ctime> @@ -252,15 +255,22 @@ static int intl_toupper(int c) /* Amiga filename case insensitive string compare */ -static int intl_stricmp(const char *s1, const char *s2) +static int intl_stricmp(std::string_view s1, std::string_view s2) { - for (;;) + auto s1_iter = s1.begin(); + auto s2_iter = s2.begin(); + while (true) { - int c1 = intl_toupper(*s1++); - int c2 = intl_toupper(*s2++); + if (s1.end() == s1_iter) + return (s2.end() == s2_iter) ? 0 : -1; + else if (s2.end() == s2_iter) + return 1; - if (c1 == 0 || c1 != c2) - return c1 - c2; + const int c1 = intl_toupper(uint8_t(*s1_iter++)); + const int c2 = intl_toupper(uint8_t(*s2_iter++)); + const int diff = c1 - c2; + if (diff) + return diff; } } @@ -388,7 +398,7 @@ static uint32_t block_checksum(uint8_t *buffer, int length) for (i = 0; i < length/4; i++) { - chksum += pick_integer_be(buffer, i*4, 4); + chksum += get_u32be(&buffer[i*4]); } return -chksum; @@ -464,7 +474,7 @@ static sec_type get_block_type(imgtool::image &img, int block) if (ret) return ST_INVALID; /* return type */ - switch ((int32_t) pick_integer_be(buffer, BSIZE-4, 4)) + switch (get_s32be(&buffer[BSIZE-4])) { case 1: return ST_ROOT; case 2: return ST_USERDIR; @@ -488,7 +498,7 @@ static imgtoolerr_t read_bitmap_block(imgtool::image &img, int block, bitmap_blo if (ret) return ret; /* fill in data */ - bm->chksum = pick_integer_be(buffer, 0, 4); + bm->chksum = get_u32be(&buffer[0]); copy_integer_array_be(bm->map, (uint32_t *) &buffer[4], MSIZE); return IMGTOOLERR_SUCCESS; @@ -502,7 +512,7 @@ static imgtoolerr_t write_bitmap_block(imgtool::image &img, int block, const bit uint8_t buffer[BSIZE]; /* Setup buffer */ - place_integer_be(buffer, 0, 4, bm->chksum); + put_u32be(&buffer[0], bm->chksum); copy_integer_array_be((uint32_t *) &buffer[4], bm->map, MSIZE); /* write block */ @@ -513,9 +523,8 @@ static imgtoolerr_t write_bitmap_block(imgtool::image &img, int block, const bit } -#ifdef UNUSED_FUNCTION /* Read a bitmap extended block */ -static imgtoolerr_t read_bitmap_ext_block(imgtool::image *img, int block, bitmap_ext_block *bm) +[[maybe_unused]] static imgtoolerr_t read_bitmap_ext_block(imgtool::image &img, int block, bitmap_ext_block *bm) { imgtoolerr_t ret; uint8_t buffer[BSIZE]; @@ -526,11 +535,10 @@ static imgtoolerr_t read_bitmap_ext_block(imgtool::image *img, int block, bitmap /* fill in data */ copy_integer_array_be(bm->map, (uint32_t *) &buffer, MSIZE); - bm->next = pick_integer_be(buffer, BSIZE-4, 4); + bm->next = get_u32be(&buffer[BSIZE-4]); return IMGTOOLERR_SUCCESS; } -#endif /* Read the root block */ @@ -546,17 +554,17 @@ static imgtoolerr_t read_root_block(imgtool::image &img, root_block *root) /* copy data to root_block */ memset(root, 0, sizeof(root_block)); - root->ht_size = pick_integer_be(buffer, 12, 4); - root->chksum = pick_integer_be(buffer, 20, 4); + root->ht_size = get_u32be(&buffer[12]); + root->chksum = get_u32be(&buffer[20]); copy_integer_array_be(root->ht, (uint32_t *) &buffer[24], TSIZE); - root->bm_flag = pick_integer_be(buffer, BSIZE-200, 4); + root->bm_flag = get_u32be(&buffer[BSIZE-200]); copy_integer_array_be(root->bm_pages, (uint32_t *) &buffer[BSIZE-196], 25); copy_date_be(&root->r, (uint32_t *) &buffer[BSIZE-92]); - root->name_len = pick_integer_be(buffer, BSIZE-80, 1); + root->name_len = buffer[BSIZE-80]; memcpy(root->diskname, &buffer[BSIZE-79], 30); copy_date_be(&root->v, (uint32_t *) &buffer[BSIZE-40]); copy_date_be(&root->c, (uint32_t *) &buffer[BSIZE-28]); - root->extension = pick_integer_be(buffer, BSIZE-8, 4); + root->extension = get_u32be(&buffer[BSIZE-8]); return IMGTOOLERR_SUCCESS; } @@ -570,25 +578,25 @@ static imgtoolerr_t write_root_block(imgtool::image &img, const root_block *root /* Setup buffer */ memset(buffer, 0, BSIZE); - place_integer_be(buffer, 0, 4, T_HEADER); - place_integer_be(buffer, 12, 4, root->ht_size); - place_integer_be(buffer, 20, 4, root->chksum); + put_u32be(&buffer[0], T_HEADER); + put_u32be(&buffer[12], root->ht_size); + put_u32be(&buffer[20], root->chksum); copy_integer_array_be((uint32_t *) &buffer[24], root->ht, TSIZE); - place_integer_be(buffer, BSIZE-200, 4, root->bm_flag); + put_u32be(&buffer[BSIZE-200], root->bm_flag); copy_integer_array_be((uint32_t *) &buffer[BSIZE-196], root->bm_pages, 25); - place_integer_be(buffer, BSIZE-92, 4, root->r.days); - place_integer_be(buffer, BSIZE-88, 4, root->r.mins); - place_integer_be(buffer, BSIZE-84, 4, root->r.ticks); - place_integer_be(buffer, BSIZE-80, 1, root->name_len); + put_u32be(&buffer[BSIZE-92], root->r.days); + put_u32be(&buffer[BSIZE-88], root->r.mins); + put_u32be(&buffer[BSIZE-84], root->r.ticks); + buffer[BSIZE-80] = root->name_len; memcpy(&buffer[BSIZE-79], root->diskname, root->name_len); - place_integer_be(buffer, BSIZE-40, 4, root->v.days); - place_integer_be(buffer, BSIZE-36, 4, root->v.mins); - place_integer_be(buffer, BSIZE-32, 4, root->v.ticks); - place_integer_be(buffer, BSIZE-28, 4, root->c.days); - place_integer_be(buffer, BSIZE-24, 4, root->c.mins); - place_integer_be(buffer, BSIZE-20, 4, root->c.ticks); - place_integer_be(buffer, BSIZE-8, 4, root->extension); - place_integer_be(buffer, BSIZE-4, 4, ST_ROOT); + put_u32be(&buffer[BSIZE-40], root->v.days); + put_u32be(&buffer[BSIZE-36], root->v.mins); + put_u32be(&buffer[BSIZE-32], root->v.ticks); + put_u32be(&buffer[BSIZE-28], root->c.days); + put_u32be(&buffer[BSIZE-24], root->c.mins); + put_u32be(&buffer[BSIZE-20], root->c.ticks); + put_u32be(&buffer[BSIZE-8], root->extension); + put_u32be(&buffer[BSIZE-4], ST_ROOT); /* write root block to image */ ret = write_block(img, get_total_blocks(img)/2, buffer); @@ -609,25 +617,25 @@ static imgtoolerr_t read_file_block(imgtool::image &img, int block, file_block * if (ret) return ret; /* fill in data */ - fb->header_key = pick_integer_be(buffer, 4, 4); - fb->high_seq = pick_integer_be(buffer, 8, 4); - fb->first_data = pick_integer_be(buffer, 16, 4); - fb->chksum = pick_integer_be(buffer, 20, 4); + fb->header_key = get_u32be(&buffer[4]); + fb->high_seq = get_u32be(&buffer[8]); + fb->first_data = get_u32be(&buffer[16]); + fb->chksum = get_u32be(&buffer[20]); copy_integer_array_be(fb->data_blocks, (uint32_t *) &buffer[24], TSIZE); - fb->uid = pick_integer_be(buffer, BSIZE-196, 2); - fb->gid = pick_integer_be(buffer, BSIZE-194, 2); - fb->protect = pick_integer_be(buffer, BSIZE-192, 4); - fb->byte_size = pick_integer_be(buffer, BSIZE-188, 4); - fb->comm_len = pick_integer_be(buffer, BSIZE-184, 1); + fb->uid = get_u16be(&buffer[BSIZE-196]); + fb->gid = get_u16be(&buffer[BSIZE-194]); + fb->protect = get_u32be(&buffer[BSIZE-192]); + fb->byte_size = get_u32be(&buffer[BSIZE-188]); + fb->comm_len = buffer[BSIZE-184]; memcpy(fb->comment, &buffer[BSIZE-183], 79); copy_date_be(&fb->date, (uint32_t *) &buffer[BSIZE-92]); - fb->name_len = pick_integer_be(buffer, BSIZE-80, 1); - memcpy(fb->filename, (uint32_t *) &buffer[BSIZE-79], 30); - fb->real_entry = pick_integer_be(buffer, BSIZE-44, 4); - fb->next_link = pick_integer_be(buffer, BSIZE-40, 4); - fb->hash_chain = pick_integer_be(buffer, BSIZE-16, 4); - fb->parent = pick_integer_be(buffer, BSIZE-12, 4); - fb->extension = pick_integer_be(buffer, BSIZE-8, 4); + fb->name_len = buffer[BSIZE-80]; + memcpy(fb->filename, &buffer[BSIZE-79], 30); + fb->real_entry = get_u32be(&buffer[BSIZE-44]); + fb->next_link = get_u32be(&buffer[BSIZE-40]); + fb->hash_chain = get_u32be(&buffer[BSIZE-16]); + fb->parent = get_u32be(&buffer[BSIZE-12]); + fb->extension = get_u32be(&buffer[BSIZE-8]); return IMGTOOLERR_SUCCESS; } @@ -643,12 +651,12 @@ static imgtoolerr_t read_file_ext_block(imgtool::image &img, int block, file_ext if (ret) return ret; /* fill in data */ - fe->header_key = pick_integer_be(buffer, 4, 4); - fe->high_seq = pick_integer_be(buffer, 8, 4); - fe->chksum = pick_integer_be(buffer, 20, 4); + fe->header_key = get_u32be(&buffer[4]); + fe->high_seq = get_u32be(&buffer[8]); + fe->chksum = get_u32be(&buffer[20]); copy_integer_array_be(fe->data_blocks, (uint32_t *) &buffer[24], TSIZE); - fe->parent = pick_integer_be(buffer, BSIZE-12, 4); - fe->extension = pick_integer_be(buffer, BSIZE-8, 4); + fe->parent = get_u32be(&buffer[BSIZE-12]); + fe->extension = get_u32be(&buffer[BSIZE-8]); return IMGTOOLERR_SUCCESS; } @@ -664,11 +672,11 @@ static imgtoolerr_t read_data_block(imgtool::image &img, int block, data_block * if (ret) return ret; /* fill in data */ - d->header_key = pick_integer_be(buffer, 4, 4); - d->seq_num = pick_integer_be(buffer, 8, 4); - d->data_size = pick_integer_be(buffer, 12, 4); - d->next_data = pick_integer_be(buffer, 16, 4); - d->chksum = pick_integer_be(buffer, 20, 4); + d->header_key = get_u32be(&buffer[4]); + d->seq_num = get_u32be(&buffer[8]); + d->data_size = get_u32be(&buffer[12]); + d->next_data = get_u32be(&buffer[16]); + d->chksum = get_u32be(&buffer[20]); memcpy(d->data, &buffer[24], BSIZE-24); return IMGTOOLERR_SUCCESS; @@ -686,21 +694,21 @@ static imgtoolerr_t read_dir_block(imgtool::image &img, int block, dir_block *db if (ret) return ret; /* fill in data */ - db->header_key = pick_integer_be(buffer, 4, 4); - db->chksum = pick_integer_be(buffer, 20, 4); + db->header_key = get_u32be(&buffer[4]); + db->chksum = get_u32be(&buffer[20]); copy_integer_array_be(db->ht, (uint32_t *) &buffer[24], TSIZE); - db->uid = pick_integer_be(buffer, BSIZE-196, 2); - db->gid = pick_integer_be(buffer, BSIZE-194, 2); - db->protect = pick_integer_be(buffer, BSIZE-192, 4); - db->comm_len = pick_integer_be(buffer, BSIZE-184, 1); + db->uid = get_u16be(&buffer[BSIZE-196]); + db->gid = get_u16be(&buffer[BSIZE-194]); + db->protect = get_u32be(&buffer[BSIZE-192]); + db->comm_len = buffer[BSIZE-184]; memcpy(db->comment, &buffer[BSIZE-183], 79); copy_date_be(&db->date, (uint32_t *) &buffer[BSIZE-92]); - db->name_len = pick_integer_be(buffer, BSIZE-80, 1); + db->name_len = buffer[BSIZE-80]; memcpy(db->dirname, (uint32_t *) &buffer[BSIZE-79], 30); - db->next_link = pick_integer_be(buffer, BSIZE-40, 4); - db->hash_chain = pick_integer_be(buffer, BSIZE-16, 4); - db->parent = pick_integer_be(buffer, BSIZE-12, 4); - db->extension = pick_integer_be(buffer, BSIZE-8, 4); + db->next_link = get_u32be(&buffer[BSIZE-40]); + db->hash_chain = get_u32be(&buffer[BSIZE-16]); + db->parent = get_u32be(&buffer[BSIZE-12]); + db->extension = get_u32be(&buffer[BSIZE-8]); return IMGTOOLERR_SUCCESS; } @@ -714,25 +722,25 @@ static imgtoolerr_t write_dir_block(imgtool::image &img, int block, const dir_bl memset(buffer, 0, BSIZE); /* Copy data */ - place_integer_be(buffer, 0, 4, T_HEADER); - place_integer_be(buffer, 4, 4, db->header_key); - place_integer_be(buffer, 20, 4, db->chksum); + put_u32be(&buffer[0], T_HEADER); + put_u32be(&buffer[4], db->header_key); + put_u32be(&buffer[20], db->chksum); copy_integer_array_be((uint32_t *) &buffer[24], db->ht, TSIZE); - place_integer_be(buffer, BSIZE-196, 2, db->uid); - place_integer_be(buffer, BSIZE-194, 2, db->gid); - place_integer_be(buffer, BSIZE-192, 4, db->protect); - place_integer_be(buffer, BSIZE-184, 1, db->comm_len); - memcpy((uint32_t *) &buffer[BSIZE-183], db->comment, db->comm_len); - place_integer_be(buffer, BSIZE-92, 4, db->date.days); - place_integer_be(buffer, BSIZE-88, 4, db->date.mins); - place_integer_be(buffer, BSIZE-84, 4, db->date.ticks); - place_integer_be(buffer, BSIZE-80, 1, db->name_len); - memcpy((uint32_t *) &buffer[BSIZE-79], db->dirname, db->name_len); - place_integer_be(buffer, BSIZE-40, 4, db->next_link); - place_integer_be(buffer, BSIZE-16, 4, db->hash_chain); - place_integer_be(buffer, BSIZE-12, 4, db->parent); - place_integer_be(buffer, BSIZE-8, 4, db->extension); - place_integer_be(buffer, BSIZE-4, 4, ST_USERDIR); + put_u16be(&buffer[BSIZE-196], db->uid); + put_u16be(&buffer[BSIZE-194], db->gid); + put_u32be(&buffer[BSIZE-192], db->protect); + buffer[BSIZE-184] = db->comm_len; + memcpy(&buffer[BSIZE-183], db->comment, db->comm_len); + put_u32be(&buffer[BSIZE-92], db->date.days); + put_u32be(&buffer[BSIZE-88], db->date.mins); + put_u32be(&buffer[BSIZE-84], db->date.ticks); + buffer[BSIZE-80] = db->name_len; + memcpy(&buffer[BSIZE-79], db->dirname, db->name_len); + put_u32be(&buffer[BSIZE-40], db->next_link); + put_u32be(&buffer[BSIZE-16], db->hash_chain); + put_u32be(&buffer[BSIZE-12], db->parent); + put_u32be(&buffer[BSIZE-8], db->extension); + put_u32be(&buffer[BSIZE-4], ST_USERDIR); /* Write block to disk */ return write_block(img, block, buffer); @@ -749,19 +757,19 @@ static imgtoolerr_t read_hardlink_block(imgtool::image &img, int block, hardlink if (ret) return ret; /* fill in data */ - hl->header_key = pick_integer_be(buffer, 4, 4); - hl->chksum = pick_integer_be(buffer, 20, 4); - hl->protect = pick_integer_be(buffer, BSIZE-192, 4); - hl->comm_len = pick_integer_be(buffer, BSIZE-184, 1); + hl->header_key = get_u32be(&buffer[4]); + hl->chksum = get_u32be(&buffer[20]); + hl->protect = get_u32be(&buffer[BSIZE-192]); + hl->comm_len = buffer[BSIZE-184]; memcpy(hl->comment, &buffer[BSIZE-183], 79); copy_date_be(&hl->date, (uint32_t *) &buffer[BSIZE-92]); - hl->name_len = pick_integer_be(buffer, BSIZE-80, 1); - memcpy(hl->hlname, (uint32_t *) &buffer[BSIZE-79], 30); - hl->real_entry = pick_integer_be(buffer, BSIZE-44, 4); - hl->next_link = pick_integer_be(buffer, BSIZE-40, 4); - hl->hash_chain = pick_integer_be(buffer, BSIZE-16, 4); - hl->parent = pick_integer_be(buffer, BSIZE-12, 4); - hl->sec_type = pick_integer_be(buffer, BSIZE-4, 4); + hl->name_len = buffer[BSIZE-80]; + memcpy(hl->hlname, &buffer[BSIZE-79], 30); + hl->real_entry = get_u32be(&buffer[BSIZE-44]); + hl->next_link = get_u32be(&buffer[BSIZE-40]); + hl->hash_chain = get_u32be(&buffer[BSIZE-16]); + hl->parent = get_u32be(&buffer[BSIZE-12]); + hl->sec_type = get_u32be(&buffer[BSIZE-4]); return IMGTOOLERR_SUCCESS; } @@ -777,17 +785,17 @@ static imgtoolerr_t read_softlink_block(imgtool::image &img, int block, softlink if (ret) return ret; /* fill in data */ - sl->header_key = pick_integer_be(buffer, 4, 4); - sl->chksum = pick_integer_be(buffer, 20, 4); + sl->header_key = get_u32be(&buffer[4]); + sl->chksum = get_u32be(&buffer[20]); memcpy(sl->symbolic_name, &buffer[24], BSIZE-224); - sl->protect = pick_integer_be(buffer, BSIZE-192, 4); - sl->comm_len = pick_integer_be(buffer, BSIZE-184, 1); + sl->protect = get_u32be(&buffer[BSIZE-192]); + sl->comm_len = buffer[BSIZE-184]; memcpy(sl->comment, &buffer[BSIZE-183], 79); copy_date_be(&sl->date, (uint32_t *) &buffer[BSIZE-92]); - sl->name_len = pick_integer_be(buffer, BSIZE-80, 1); - memcpy(sl->slname, (uint32_t *) &buffer[BSIZE-79], 30); - sl->hash_chain = pick_integer_be(buffer, BSIZE-16, 4); - sl->parent = pick_integer_be(buffer, BSIZE-12, 4); + sl->name_len = buffer[BSIZE-80]; + memcpy(sl->slname, &buffer[BSIZE-79], 30); + sl->hash_chain = get_u32be(&buffer[BSIZE-16]); + sl->parent = get_u32be(&buffer[BSIZE-12]); return IMGTOOLERR_SUCCESS; } @@ -837,16 +845,14 @@ static int is_intl(imgtool::image &img) t == DT_FFS_INTL_DIRC) ? true : false); } -#ifdef UNUSED_FUNCTION /* Returns true if the disk uses the directory cache mode */ -static int is_dirc(imgtool::image *img) +[[maybe_unused]] static int is_dirc(imgtool::image &img) { disk_type t = get_disk_type(img); return ((t == DT_OFS_INTL_DIRC || t == DT_FFS_INTL_DIRC) ? true : false); } -#endif static imgtoolerr_t get_hash_table(imgtool::image &img, int block, uint32_t *ht) { @@ -907,12 +913,10 @@ static imgtoolerr_t set_hash_table(imgtool::image &img, int block, const uint32_ return IMGTOOLERR_SUCCESS; } -#ifdef UNUSED_FUNCTION -static imgtoolerr_t get_root_hash_table(imgtool::image *img, uint32_t *ht) +[[maybe_unused]] static imgtoolerr_t get_root_hash_table(imgtool::image &img, uint32_t *ht) { return get_hash_table(img, get_total_blocks(img)/2, ht); } -#endif static imgtoolerr_t get_blockname(imgtool::image &img, int block, char *dest) { @@ -941,7 +945,7 @@ static imgtoolerr_t get_hash_chain(imgtool::image &img, int block, uint32_t *cha if (ret) return ret; /* Get chain value */ - *chain = pick_integer_be(buffer, BSIZE-16, 4); + *chain = get_u32be(&buffer[BSIZE-16]); return IMGTOOLERR_SUCCESS; } @@ -957,7 +961,7 @@ static imgtoolerr_t set_hash_chain(imgtool::image &img, int block, uint32_t chai if (ret) return ret; /* Copy new hash chain value into it */ - place_integer_be(buffer, BSIZE-16, 4, chain); + put_u32be(&buffer[BSIZE-16], chain); /* Write it back again */ ret = write_block(img, block, buffer); @@ -974,7 +978,7 @@ static imgtoolerr_t walk_hash_chain(imgtool::image &img, const char *path, int s char name[31]; /* choose compare function depending on intl mode */ - int (*cmp)(const char *, const char *) = is_intl(img) ? &intl_stricmp : &core_stricmp; + int (*cmp)(std::string_view, std::string_view) = is_intl(img) ? &intl_stricmp : &core_stricmp; /* initialize filenames */ memset(name, 0, sizeof(name)); @@ -1174,11 +1178,11 @@ static imgtoolerr_t fix_chksum(imgtool::image &img, int block, int bitmap) /* update checksum */ if (bitmap) { - place_integer_be(buffer, 0, 4, chksum); + put_u32be(&buffer[0], chksum); } else { - place_integer_be(buffer, 20, 4, chksum); + put_u32be(&buffer[20], chksum); } /* write back new block data */ @@ -1273,9 +1277,9 @@ static imgtoolerr_t update_block_modified_date(imgtool::image &img, int block) amiga_setup_time(now, &date); /* Write new time into block */ - place_integer_be(buffer, BSIZE-92, 4, date.days); - place_integer_be(buffer, BSIZE-88, 4, date.mins); - place_integer_be(buffer, BSIZE-84, 4, date.ticks); + put_u32be(&buffer[BSIZE-92], date.days); + put_u32be(&buffer[BSIZE-88], date.mins); + put_u32be(&buffer[BSIZE-84], date.ticks); /* Write block back to disk */ ret = write_block(img, block, buffer); @@ -1367,8 +1371,7 @@ static int get_first_bit(uint32_t *array, int size) } -#ifdef UNUSED_FUNCTION -static imgtoolerr_t walk_bitmap_ext_blocks(imgtool::image *img, int start, int *block) +[[maybe_unused]] static imgtoolerr_t walk_bitmap_ext_blocks(imgtool::image &img, int start, int *block) { imgtoolerr_t ret; bitmap_ext_block bm_ext; @@ -1400,7 +1403,6 @@ static imgtoolerr_t walk_bitmap_ext_blocks(imgtool::image *img, int start, int * /* else continue walking the list */ return walk_bitmap_ext_blocks(img, bm_ext.next, block); } -#endif /* Searches for a block marked as free @@ -1710,7 +1712,7 @@ static imgtoolerr_t write_file_ext_data(imgtool::image &img, int block, int *fil static imgtoolerr_t clear_file_ext_data(imgtool::image &img, int block, int *filesize) { - return walk_file_ext_data(img, block, filesize, NULL, false); + return walk_file_ext_data(img, block, filesize, nullptr, false); } @@ -1979,6 +1981,7 @@ static imgtoolerr_t amiga_image_nextenum(imgtool::directory &enumeration, imgtoo case ST_LINKDIR: ent.directory = 1; + [[fallthrough]]; case ST_LINKFILE: { @@ -2337,7 +2340,7 @@ static imgtoolerr_t amiga_image_geticoninfo(imgtool::partition &partition, const } -static imgtoolerr_t amiga_image_suggesttransfer(imgtool::partition &partition, const char *fname, imgtool_transfer_suggestion *suggestions, size_t suggestions_length) +static imgtoolerr_t amiga_image_suggesttransfer(imgtool::partition &partition, const char *fname, imgtool::transfer_suggestion *suggestions, size_t suggestions_length) { return IMGTOOLERR_UNIMPLEMENTED; } @@ -2384,7 +2387,7 @@ void amiga_floppy_get_info(const imgtool_class *imgclass, uint32_t state, union case IMGTOOLINFO_INT_SUPPORTS_LASTMODIFIED_TIME: info->i = 1; break; case IMGTOOLINFO_INT_PATH_SEPARATOR: info->i = '/'; break; - /* --- the following bits of info are returned as NULL-terminated strings --- */ + /* --- the following bits of info are returned as NUL-terminated strings --- */ case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "amiga_floppy"); break; case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "Amiga floppy disk image (OFS/FFS format)"); break; case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "adf"); break; diff --git a/src/tools/imgtool/modules/bml3.cpp b/src/tools/imgtool/modules/bml3.cpp index a1a3bdc203d..8c465032f28 100644 --- a/src/tools/imgtool/modules/bml3.cpp +++ b/src/tools/imgtool/modules/bml3.cpp @@ -18,12 +18,18 @@ - (used with MP-1802 floppy disk controller card) */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> #include "imgtool.h" +#include "filter.h" #include "iflopimg.h" +#include "corestr.h" +#include "multibyte.h" +#include "opresolv.h" + +#include <cstdio> +#include <cstdlib> +#include <cstring> + #define MAX_SECTOR_SIZE 256 struct bml3_diskinfo @@ -129,7 +135,7 @@ static floperr_t get_bml3_dirent(imgtool::image &f, int index_loc, struct bml3_d ent->ftype = buf[11]; ent->asciiflag = buf[12]; ent->first_granule = buf[13]; - ent->lastsectorbytes = (buf[14] << 8) | buf[15]; + ent->lastsectorbytes = get_u16be(&buf[14]); break; default: return FLOPPY_ERROR_INVALIDIMAGE; @@ -162,8 +168,7 @@ static floperr_t put_bml3_dirent(imgtool::image &f, int index_loc, const struct buf[11] = ent->ftype; buf[12] = ent->asciiflag; buf[13] = ent->first_granule; - buf[14] = ent->lastsectorbytes >> 8; - buf[15] = ent->lastsectorbytes & 0xff; + put_u16be(&buf[14], ent->lastsectorbytes); break; default: return FLOPPY_ERROR_INVALIDIMAGE; @@ -512,7 +517,10 @@ static imgtoolerr_t bml3_diskimage_open(imgtool::image &image, imgtool::stream:: ferr = callbacks->get_sector_length(floppy, 0, 20, 1, §or_length); if (ferr) return imgtool_floppy_error(ferr); - int sectors_per_track = callbacks->get_sectors_per_track(floppy, 0, 20); + + int sectors_per_track = -1; + if (callbacks->get_sectors_per_track) + sectors_per_track = callbacks->get_sectors_per_track(floppy, 0, 20); if (heads_per_disk == 2 && sector_length == 128 && sectors_per_track == 16) { // single-sided, single-density @@ -604,8 +612,8 @@ eof: get_dirent_fname(fname, &rsent); - snprintf(ent.filename, ARRAY_LENGTH(ent.filename), "%s", fname); - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "%d %c", (int) rsent.ftype, (char) (rsent.asciiflag + 'B')); + snprintf(ent.filename, std::size(ent.filename), "%s", fname); + snprintf(ent.attr, std::size(ent.attr), "%d %c", (int) rsent.ftype, (char) (rsent.asciiflag + 'B')); } return IMGTOOLERR_SUCCESS; } @@ -832,7 +840,7 @@ static imgtoolerr_t bml3_diskimage_deletefile(imgtool::partition &partition, con -static imgtoolerr_t bml3_diskimage_suggesttransfer(imgtool::partition &partition, const char *fname, imgtool_transfer_suggestion *suggestions, size_t suggestions_length) +static imgtoolerr_t bml3_diskimage_suggesttransfer(imgtool::partition &partition, const char *fname, imgtool::transfer_suggestion *suggestions, size_t suggestions_length) { imgtoolerr_t err; imgtool::image &image(partition.image()); @@ -848,27 +856,27 @@ static imgtoolerr_t bml3_diskimage_suggesttransfer(imgtool::partition &partition if (ent.asciiflag == 0xFF) { /* ASCII file */ - suggestions[0].viability = SUGGESTION_RECOMMENDED; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; suggestions[0].filter = filter_eoln_getinfo; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = NULL; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; + suggestions[1].filter = nullptr; } else if (ent.ftype == 0) { /* tokenized BASIC file */ - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[1].viability = SUGGESTION_POSSIBLE; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = nullptr; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; suggestions[1].filter = filter_bml3bas_getinfo; } } else { - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[1].viability = SUGGESTION_POSSIBLE; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = nullptr; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; suggestions[1].filter = filter_eoln_getinfo; - suggestions[2].viability = SUGGESTION_POSSIBLE; + suggestions[2].viability = imgtool::SUGGESTION_POSSIBLE; suggestions[2].filter = filter_bml3bas_getinfo; } @@ -903,9 +911,9 @@ void bml3_get_info(const imgtool_class *imgclass, uint32_t state, union imgtooli /* --- the following bits of info are returned as 64-bit signed integers --- */ case IMGTOOLINFO_INT_PREFER_UCASE: info->i = 1; break; case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: info->i = sizeof(bml3_diskinfo); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(struct bml3_direnum); break; + case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(struct bml3_direnum); break; - /* --- the following bits of info are returned as NULL-terminated strings --- */ + /* --- the following bits of info are returned as NUL-terminated strings --- */ case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "bml3"); break; case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "Basic Master Level 3 format"); break; case IMGTOOLINFO_STR_FILE: strcpy(info->s = imgtool_temp_str(), __FILE__); break; diff --git a/src/tools/imgtool/modules/concept.cpp b/src/tools/imgtool/modules/concept.cpp index 6bc0fe1bf22..da9689d455a 100644 --- a/src/tools/imgtool/modules/concept.cpp +++ b/src/tools/imgtool/modules/concept.cpp @@ -8,12 +8,15 @@ Raphael Nabet, 2003 */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <limits.h> #include "imgtool.h" +#include "opresolv.h" + +#include <climits> +#include <cstdio> +#include <cstdlib> +#include <cstring> + struct UINT16xE { uint8_t bytes[2]; @@ -201,7 +204,6 @@ static int read_physical_record(imgtool::stream &file_handle, int secnum, void * return 0; } -#ifdef UNUSED_FUNCTION /* write_physical_record @@ -213,7 +215,7 @@ static int read_physical_record(imgtool::stream &file_handle, int secnum, void * Return non-zero on error */ -static int write_physical_record(imgtool::stream *file_handle, int secnum, const void *src) +[[maybe_unused]] static int write_physical_record(imgtool::stream *file_handle, int secnum, const void *src) { int reply; @@ -228,7 +230,6 @@ static int write_physical_record(imgtool::stream *file_handle, int secnum, const return 0; } -#endif /* Search for a file name on a concept_image @@ -357,8 +358,8 @@ static imgtoolerr_t concept_image_nextenum(imgtool::directory &enumeration, imgt int len = iter->image->dev_dir.file_dir[iter->index].filename[0]; const char *type; - if (len > ARRAY_LENGTH(ent.filename)) - len = ARRAY_LENGTH(ent.filename); + if (len > std::size(ent.filename)) + len = std::size(ent.filename); memcpy(ent.filename, iter->image->dev_dir.file_dir[iter->index].filename + 1, len); ent.filename[len] = 0; @@ -382,7 +383,7 @@ static imgtoolerr_t concept_image_nextenum(imgtool::directory &enumeration, imgt type = "???"; break; } - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "%s", type); + snprintf(ent.attr, std::size(ent.attr), "%s", type); /* len in physrecs */ ent.filesize = get_UINT16xE(iter->image->dev_dir.vol_hdr.disk_flipped, iter->image->dev_dir.file_dir[iter->index].next_block) diff --git a/src/tools/imgtool/modules/cybiko.cpp b/src/tools/imgtool/modules/cybiko.cpp index 1b9f43ee298..bfe9bfdddb2 100644 --- a/src/tools/imgtool/modules/cybiko.cpp +++ b/src/tools/imgtool/modules/cybiko.cpp @@ -10,6 +10,9 @@ #include "imgtool.h" +#include "multibyte.h" +#include "opresolv.h" + #include <zlib.h> struct cybiko_file_system @@ -52,8 +55,8 @@ enum }; #define BLOCK_USED(x) (x[0] & 0x80) -#define BLOCK_FILE_ID(x) buffer_read_16_be( x + 2) -#define BLOCK_PART_ID(x) buffer_read_16_be( x + 4) +#define BLOCK_FILE_ID(x) get_u16be( x + 2) +#define BLOCK_PART_ID(x) get_u16be( x + 4) #define BLOCK_FILENAME(x) (char*)(x + 7) #define FILE_HEADER_SIZE 0x48 @@ -79,30 +82,6 @@ uint32_t cybiko_time_setup(const imgtool::datetime &t) return cybiko_time_point.time_since_epoch().count(); } -static uint32_t buffer_read_32_be( uint8_t *buffer) -{ - return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3] << 0); -} - -static uint16_t buffer_read_16_be( uint8_t *buffer) -{ - return (buffer[0] << 8) | (buffer[1] << 0); -} - -static void buffer_write_32_be( uint8_t *buffer, uint32_t data) -{ - buffer[0] = (data >> 24) & 0xFF; - buffer[1] = (data >> 16) & 0xFF; - buffer[2] = (data >> 8) & 0xFF; - buffer[3] = (data >> 0) & 0xFF; -} - -static void buffer_write_16_be( uint8_t *buffer, uint16_t data) -{ - buffer[0] = (data >> 8) & 0xFF; - buffer[1] = (data >> 0) & 0xFF; -} - // page = crc1 (4) + wcnt (2) + crc2 (2) + data (x) + unk (2) static uint32_t page_buffer_calc_checksum_1( uint8_t *buffer, uint32_t size, int block_type) @@ -113,9 +92,9 @@ static uint32_t page_buffer_calc_checksum_1( uint8_t *buffer, uint32_t size, int static uint16_t page_buffer_calc_checksum_2( uint8_t *buffer) { uint16_t val = 0xAF17; - val ^= buffer_read_16_be( buffer + 0); - val ^= buffer_read_16_be( buffer + 2); - val ^= buffer_read_16_be( buffer + 4); + val ^= get_u16be( buffer + 0); + val ^= get_u16be( buffer + 2); + val ^= get_u16be( buffer + 4); return swapendian_int16(val); } @@ -124,11 +103,11 @@ static int page_buffer_verify( uint8_t *buffer, uint32_t size, int block_type) uint32_t checksum_page, checksum_calc; // checksum 1 checksum_calc = page_buffer_calc_checksum_1( buffer, size, block_type); - checksum_page = buffer_read_32_be( buffer + 0); + checksum_page = get_u32be( buffer + 0); if (checksum_calc != checksum_page) return false; // checksum 2 checksum_calc = page_buffer_calc_checksum_2( buffer); - checksum_page = buffer_read_16_be( buffer + 6); + checksum_page = get_u16be( buffer + 6); if (checksum_calc != checksum_page) return false; // ok return true; @@ -198,10 +177,10 @@ static int cfs_block_write( cybiko_file_system *cfs, uint8_t *buffer, int block_ uint8_t buffer_page[MAX_PAGE_SIZE]; uint32_t page; memcpy( buffer_page + 8, buffer, cfs->page_size - 10); - buffer_write_32_be( buffer_page + 0, page_buffer_calc_checksum_1( buffer_page, cfs->page_size, block_type)); - buffer_write_16_be( buffer_page + 4, cfs->write_count++); - buffer_write_16_be( buffer_page + 6, page_buffer_calc_checksum_2( buffer_page)); - buffer_write_16_be( buffer_page + cfs->page_size - 2, 0xFFFF); + put_u32be( buffer_page + 0, page_buffer_calc_checksum_1( buffer_page, cfs->page_size, block_type)); + put_u16be( buffer_page + 4, cfs->write_count++); + put_u16be( buffer_page + 6, page_buffer_calc_checksum_2( buffer_page)); + put_u16be( buffer_page + cfs->page_size - 2, 0xFFFF); if (!cfs_block_to_page( cfs, block_type, block, &page)) return false; if (!cfs_page_write( cfs, buffer_page, page)) return false; return true; @@ -236,7 +215,7 @@ static int cfs_file_info( cybiko_file_system *cfs, uint16_t file_id, cfs_file *f if (BLOCK_PART_ID(buffer) == 0) { strcpy( file->name, BLOCK_FILENAME(buffer)); - file->date = buffer_read_32_be( buffer + 6 + FILE_HEADER_SIZE - 4); + file->date = get_u32be( buffer + 6 + FILE_HEADER_SIZE - 4); } file->size += buffer[1]; file->blocks++; @@ -499,13 +478,13 @@ static imgtoolerr_t cybiko_image_write_file(imgtool::partition &partition, const buffer[0] = 0x80; buffer[1] = cfs->page_size - 0x10 - ((part_id == 0) ? FILE_HEADER_SIZE : 0); if (bytes_left < buffer[1]) buffer[1] = bytes_left; - buffer_write_16_be( buffer + 2, file_id); - buffer_write_16_be( buffer + 4, part_id); + put_u16be( buffer + 2, file_id); + put_u16be( buffer + 4, part_id); if (part_id == 0) { buffer[6] = 0; strcpy(BLOCK_FILENAME(buffer), filename); - buffer_write_32_be(buffer + 6 + FILE_HEADER_SIZE - 4, cybiko_time_setup(imgtool::datetime::now(imgtool::datetime::datetime_type::LOCAL))); + put_u32be(buffer + 6 + FILE_HEADER_SIZE - 4, cybiko_time_setup(imgtool::datetime::now(imgtool::datetime::datetime_type::LOCAL))); sourcef.read(buffer + 6 + FILE_HEADER_SIZE, buffer[1]); } else diff --git a/src/tools/imgtool/modules/cybikoxt.cpp b/src/tools/imgtool/modules/cybikoxt.cpp index 8c2980de449..556f37fde76 100644 --- a/src/tools/imgtool/modules/cybikoxt.cpp +++ b/src/tools/imgtool/modules/cybikoxt.cpp @@ -10,6 +10,8 @@ #include "imgtool.h" +#include "multibyte.h" + #include <zlib.h> struct cybiko_file_system @@ -44,8 +46,8 @@ enum #define INVALID_FILE_ID 0xFFFF #define BLOCK_USED(x) (x[0] & 0x80) -#define BLOCK_FILE_ID(x) buffer_read_16_be( x + 2) -#define BLOCK_PART_ID(x) buffer_read_16_be( x + 4) +#define BLOCK_FILE_ID(x) get_u16be( x + 2) +#define BLOCK_PART_ID(x) get_u16be( x + 4) #define BLOCK_FILENAME(x) (char*)(x + 7) #define FILE_HEADER_SIZE 0x48 @@ -58,30 +60,6 @@ static cybiko_file_system *get_cfs(imgtool::image &image) extern imgtool::datetime cybiko_time_crack(uint32_t cfs_time); extern uint32_t cybiko_time_setup(const imgtool::datetime &t); -static uint32_t buffer_read_32_be( uint8_t *buffer) -{ - return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3] << 0); -} - -static uint16_t buffer_read_16_be( uint8_t *buffer) -{ - return (buffer[0] << 8) | (buffer[1] << 0); -} - -static void buffer_write_32_be( uint8_t *buffer, uint32_t data) -{ - buffer[0] = (data >> 24) & 0xFF; - buffer[1] = (data >> 16) & 0xFF; - buffer[2] = (data >> 8) & 0xFF; - buffer[3] = (data >> 0) & 0xFF; -} - -static void buffer_write_16_be( uint8_t *buffer, uint16_t data) -{ - buffer[0] = (data >> 8) & 0xFF; - buffer[1] = (data >> 0) & 0xFF; -} - // page = crc (2) + data (x) static uint16_t page_buffer_calc_checksum( uint8_t *data, uint32_t size) @@ -103,7 +81,7 @@ static int page_buffer_verify( uint8_t *buffer, uint32_t size, int block_type) { uint32_t checksum_page, checksum_calc; checksum_calc = page_buffer_calc_checksum( buffer + 2, size - 2); - checksum_page = buffer_read_16_be( buffer + 0); + checksum_page = get_u16be( buffer + 0); if (checksum_calc != checksum_page) return false; } // ok @@ -183,7 +161,7 @@ static int cfs_block_write( cybiko_file_system *cfs, uint8_t *buffer, int block_ { checksum = page_buffer_calc_checksum( buffer_page + 2, cfs->page_size - 2); } - buffer_write_16_be( buffer_page + 0, checksum); + put_u16be( buffer_page + 0, checksum); if (!cfs_block_to_page( cfs, block_type, block, &page)) return false; if (!cfs_page_write( cfs, buffer_page, page)) return false; return true; @@ -218,7 +196,7 @@ static int cfs_file_info( cybiko_file_system *cfs, uint16_t file_id, cfs_file *f if (BLOCK_PART_ID(buffer) == 0) { strcpy( file->name, BLOCK_FILENAME(buffer)); - file->date = buffer_read_32_be( buffer + 6 + FILE_HEADER_SIZE - 4); + file->date = get_u32be( buffer + 6 + FILE_HEADER_SIZE - 4); } file->size += buffer[1]; file->blocks++; @@ -460,13 +438,13 @@ static imgtoolerr_t cybiko_image_write_file(imgtool::partition &partition, const buffer[0] = 0x80; buffer[1] = (cfs->page_size - 2) - 6 - ((part_id == 0) ? FILE_HEADER_SIZE : 0); if (bytes_left < buffer[1]) buffer[1] = bytes_left; - buffer_write_16_be( buffer + 2, file_id); - buffer_write_16_be( buffer + 4, part_id); + put_u16be( buffer + 2, file_id); + put_u16be( buffer + 4, part_id); if (part_id == 0) { buffer[6] = 0x20; strcpy(BLOCK_FILENAME(buffer), filename); - buffer_write_32_be( buffer + 6 + FILE_HEADER_SIZE - 4, cybiko_time_setup(imgtool::datetime::now(imgtool::datetime::datetime_type::LOCAL))); + put_u32be( buffer + 6 + FILE_HEADER_SIZE - 4, cybiko_time_setup(imgtool::datetime::now(imgtool::datetime::datetime_type::LOCAL))); sourcef.read(buffer + 6 + FILE_HEADER_SIZE, buffer[1]); } else diff --git a/src/tools/imgtool/modules/dgndos.cpp b/src/tools/imgtool/modules/dgndos.cpp new file mode 100644 index 00000000000..692c010d057 --- /dev/null +++ b/src/tools/imgtool/modules/dgndos.cpp @@ -0,0 +1,1256 @@ +// license:BSD-3-Clause +// copyright-holders:tim lindner +/**************************************************************************** + + dgndos.cpp + + Dragon DOS disk images + + I am not happy with the sector allocation algorithm + +****************************************************************************/ + +#include "imgtool.h" +#include "filter.h" +#include "iflopimg.h" + +#include "formats/coco_dsk.h" +#include "corestr.h" +#include "opresolv.h" + +#include <cstdio> +#include <cstdlib> +#include <cstring> + +#ifdef _MSC_VER +#pragma pack(push,1) +#define A_PACKED +#else +#define A_PACKED __attribute__((packed)) +#endif + +typedef struct A_PACKED dngdos_sector_allocation_format { + uint16_t lsn; + uint8_t count; +} dngdos_sector_allocation_format; + +typedef struct A_PACKED dngdos_file_header_block { + char filename[11]; + dngdos_sector_allocation_format block[4]; +} dngdos_file_header_block; + +typedef struct A_PACKED dngdos_file_continuation_block { + dngdos_sector_allocation_format block[7]; + uint16_t unused; +} dngdos_file_continuation_block; + +struct A_PACKED dgndos_dirent +{ + unsigned char flag_byte; + union block { + dngdos_file_header_block header; + dngdos_file_continuation_block continuation; + } block; + uint8_t dngdos_last_or_next; +}; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif + +struct dgndos_direnum +{ + int index; + bool eof; +}; + +/********************************************************************* + Imgtool module code +*********************************************************************/ + +#define DGNDOS_OPTIONS_PROTECT 'P' +#define MAX_DIRENTS 160 +#define HEADER_EXTENTS_COUNT 4 +#define CONT_EXTENTS_COUNT 7 + +#define DGNDOS_DELETED_BIT 0x80 // deleted entry +#define DGNDOS_CONTINUED_BIT 0x20 // byte at offset 0x18 give next entry number +#define DGNDOS_END_BIT 0x08 // end of directory +#define DGNDOS_PROTECT_BIT 0x02 // ignored +#define DGNDOS_CONTINUATION_BIT 0x01 // this is a continuation block + +static imgtoolerr_t get_dgndos_dirent(uint8_t *track, int index_loc, dgndos_dirent &ent) +{ + if (index_loc >= MAX_DIRENTS) + return IMGTOOLERR_FILENOTFOUND; + + int sector = 3 + (index_loc / 10); + int offset = (index_loc * 25) % 250; + + memcpy( (void *)&ent, track + (256 * (sector-1)) + offset, sizeof(ent)); + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t put_dgndos_dirent(uint8_t *track, int index_loc, const dgndos_dirent &ent) +{ + if (index_loc >= MAX_DIRENTS) + return IMGTOOLERR_FILENOTFOUND; + + int sector = 3 + (index_loc / 10); + int offset = (index_loc * 25) % 250; + + memcpy( track + (256 * (sector-1)) + offset, (void *)&ent, sizeof(ent)); + + return IMGTOOLERR_SUCCESS; +} + +static std::string get_dirent_fname(const dgndos_dirent &ent) +{ + return extract_padded_filename(ent.block.header.filename, 8, 3, '\0'); +} + +static bool dgndos_real_file( dgndos_dirent &ent ) +{ + if( ent.flag_byte & DGNDOS_DELETED_BIT) return false; + if( ent.flag_byte & DGNDOS_CONTINUATION_BIT) return false; + + return true; +} + +static imgtoolerr_t lookup_dgndos_file(uint8_t *entire_track, const char *fname, dgndos_dirent &ent, int *position = nullptr) +{ + int i = 0; + imgtoolerr_t err; + std::string fnamebuf; + + do + { + do + { + err = get_dgndos_dirent( entire_track, i++, ent ); + if( err ) return err; + + if( ent.flag_byte & DGNDOS_END_BIT ) return IMGTOOLERR_FILENOTFOUND; + } + while( ! dgndos_real_file(ent) ); + + fnamebuf = get_dirent_fname(ent); + } + while(core_stricmp(fnamebuf, fname)); + + if (position) + *position = i - 1; + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t dgndos_get_geometry(uint8_t *entire_track, int *bitmap_count, int *heads, int *tracks_on_disk, int *sectors_per_track) +{ + unsigned int tod, spt, sides; + + tod = entire_track[0xfc]; + spt = entire_track[0xfd]; + + if( (~tod & 0xff) != entire_track[0xfe]) + { +// fprintf( stderr, "tracks_on_disk check failed: %u == %u\n", (~tod & 0xff), entire_track[0xfe] ); + return IMGTOOLERR_CORRUPTIMAGE; + } + + if( (~spt & 0xff) != entire_track[0xff]) + { +// fprintf( stderr, "sectors_per_track check failed: %u == %u\n", (~spt & 0xff), entire_track[0xff] ); + return IMGTOOLERR_CORRUPTIMAGE; + } + + if(spt == 36) + { + sides = 1; + } + else if(spt == 18 ) + { + sides = 0; + } + else + { +// fprintf( stderr, "sides check failed\n" ); + return IMGTOOLERR_CORRUPTIMAGE; + } + + if( heads ) *heads = sides; + if( tracks_on_disk) *tracks_on_disk = tod; + if( sectors_per_track ) *sectors_per_track = spt; + if( bitmap_count ) *bitmap_count = (tod * sides * 18) + (tod * 18); + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t dgndos_convert_lsn(uint8_t *entire_track, int lsn, int *head, int *track, int *sector ) +{ + int tracks_on_disk; + int sectors_per_track; + int sides; + + imgtoolerr_t err = dgndos_get_geometry(entire_track, nullptr, &sides, &tracks_on_disk, §ors_per_track); + if(err) return err; + + if( sides == 0 ) + { + *head = 0; + *track = lsn / 18; + *sector = (lsn % 18) + 1; + } + else + { + *head = (lsn / 18) % 2; + *track = lsn / 36; + *sector = (lsn % 18) + 1; + } + + return IMGTOOLERR_SUCCESS; +} + +#define ALLOCATE_BIT 1 +#define QUERY_BIT 0 +#define DEALLOCATE_BIT -1 + +static int dgndos_set_reset_bitmap( uint8_t *entire_track, int lsn, int set ) +{ + int startbyte = lsn / 8; + int startbit = lsn % 8; + + if( lsn > 1439 ) startbyte += 76; + + if(set > QUERY_BIT) // ALLOCATE_BIT + { + // 0 = used, 1 = free + entire_track[startbyte] &= ~(1 << startbit); + } + else if( set < QUERY_BIT ) // DEALLOCATE_BIT + { + // 0 = used, 1 = free + entire_track[startbyte] |= (1 << startbit); + } + + // 0 = used, 1 = free + return (entire_track[startbyte] & (1 << startbit)) != 0; +} + +static int dgndos_is_sector_avaiable(uint8_t *entire_track, int lsn) +{ + return dgndos_set_reset_bitmap( entire_track, lsn, QUERY_BIT ); +} + +static int dgndos_fat_allocate_sector(uint8_t *entire_track, int lsn) +{ + return dgndos_set_reset_bitmap( entire_track, lsn, ALLOCATE_BIT ); +} + +static int dgndos_fat_deallocate_sector(uint8_t *entire_track, int lsn) +{ + return dgndos_set_reset_bitmap( entire_track, lsn, DEALLOCATE_BIT ); +} + +static int dgndos_fat_deallocate_span(uint8_t *entire_track, int lsn, int count) +{ + int value = 0; + + for( int i=lsn; i<lsn+count; i++) + { + value = dgndos_fat_deallocate_sector(entire_track, i); + } + + return value; +} + +static imgtoolerr_t dgndos_get_avaiable_dirent_position(uint8_t *entire_track, int *position ) +{ + int i; + imgtoolerr_t err; + dgndos_dirent ent; + + for( i=0; i<MAX_DIRENTS; i++ ) + { + err = get_dgndos_dirent(entire_track, i, ent); + if( err ) return err; + + if( ent.flag_byte & DGNDOS_DELETED_BIT) break; + + if( ent.flag_byte & DGNDOS_END_BIT) break; + } + + if( i == MAX_DIRENTS ) + { + return IMGTOOLERR_NOSPACE; + } + + if( position ) *position = i; + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t dgndos_get_avaiable_dirent(uint8_t *entire_track, dgndos_dirent &ent, int *position ) +{ + int i; + imgtoolerr_t err; + + for( i=0; i<MAX_DIRENTS; i++ ) + { + err = get_dgndos_dirent(entire_track, i, ent); + if( err ) return err; + + if( ent.flag_byte & DGNDOS_DELETED_BIT) break; + + if( ent.flag_byte & DGNDOS_END_BIT) break; + } + + if( i == MAX_DIRENTS ) + { + return IMGTOOLERR_NOSPACE; + } + + if( position ) *position = i; + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t dgndos_get_avaiable_sector( uint8_t *entire_track, int *lsn ) +{ + int bitmap_count, i; + int pos_diff = 18; + int neg_diff = 36; + int start = 360; + + imgtoolerr_t err = dgndos_get_geometry(entire_track, &bitmap_count, nullptr, nullptr, nullptr); + if(err) return err; + + do + { + i = start; + while ( i >= 0 ) + { + if( dgndos_is_sector_avaiable(entire_track, i) ) + { + *lsn = i; + return IMGTOOLERR_SUCCESS; + } + + i -= neg_diff; + } + + i = start; + while( i < bitmap_count ) + { + if( dgndos_is_sector_avaiable(entire_track, i) ) + { + *lsn = i; + return IMGTOOLERR_SUCCESS; + } + + i += pos_diff; + } + + start--; + } + while( start >= 335 ); + + return IMGTOOLERR_NOSPACE; +} + +static imgtoolerr_t dgndos_count_dirents(uint8_t *entire_track, dgndos_dirent dgnent, int *result) +{ + imgtoolerr_t err = IMGTOOLERR_SUCCESS; + *result = 1; + + while( (dgnent.flag_byte & DGNDOS_CONTINUED_BIT) && *result < MAX_DIRENTS ) + { + (*result)++; + err = get_dgndos_dirent(entire_track, dgnent.dngdos_last_or_next, dgnent); + } + + return err; +} + +static imgtoolerr_t dgndos_get_file_size(uint8_t *entire_track, dgndos_dirent dgnent, size_t &filesize) +{ + imgtoolerr_t err; + int directory_entry_count = 0; + int extent = 0; + int block_size; + int done; + int count; + int i; + + filesize = 0; + + do + { + if(directory_entry_count>MAX_DIRENTS) return IMGTOOLERR_CORRUPTDIR; + + count = dgnent.flag_byte & DGNDOS_CONTINUATION_BIT ? dgnent.block.continuation.block[extent].count : dgnent.block.header.block[extent].count; + + if( count == 0 ) break; + + i = 0; + + // count extents except last sector + while (i < count - 1) + { + filesize += 256; + i++; + } + + block_size = 256; + done = false; + + if( extent < (dgnent.flag_byte & DGNDOS_CONTINUATION_BIT ? CONT_EXTENTS_COUNT : HEADER_EXTENTS_COUNT) - 1 ) + { + if( (dgnent.flag_byte & DGNDOS_CONTINUATION_BIT ? dgnent.block.continuation.block[extent+1].count : dgnent.block.header.block[extent+1].count) == 0 ) + { + // not last extent, and yes continuation + if( dgnent.dngdos_last_or_next == 0 ) + block_size = 256; + else + block_size = dgnent.dngdos_last_or_next; + + done = true; + } + } + else if( extent == (dgnent.flag_byte & DGNDOS_CONTINUATION_BIT ? CONT_EXTENTS_COUNT : HEADER_EXTENTS_COUNT) - 1) + { + if( !(dgnent.flag_byte & DGNDOS_CONTINUED_BIT) ) + { + // is last extent, and no continuation + if( dgnent.dngdos_last_or_next == 0 ) + block_size = 256; + else + block_size = dgnent.dngdos_last_or_next; + + done = true; + } + } + + filesize += block_size; + + extent++; + + if( extent == (dgnent.flag_byte & DGNDOS_CONTINUATION_BIT ? CONT_EXTENTS_COUNT : HEADER_EXTENTS_COUNT) ) + { + if( dgnent.flag_byte & DGNDOS_CONTINUED_BIT) + { + err = get_dgndos_dirent(entire_track, dgnent.dngdos_last_or_next, *(&dgnent) ); + if(err) return err; + + extent = 0; + directory_entry_count++; + } + } + } + while( !done ); + + return IMGTOOLERR_SUCCESS; +} + +static floperr_t dgndos_get_directory_track( imgtool::image &image, int track, uint8_t *buffer ) +{ + floperr_t ferr; + + for(int i=1; i<=18; i++ ) + { + ferr = floppy_read_sector(imgtool_floppy(image), 0, track, i, 0, &(buffer[(i-1)*256]), 256); + if(ferr) break; + } + + return ferr; +} + +static floperr_t dgndos_put_directory_track( imgtool::image &image, int track, uint8_t *buffer ) +{ + floperr_t ferr; + + for(int i=1; i<=18; i++ ) + { + ferr = floppy_write_sector(imgtool_floppy(image), 0, track, i, 0, &(buffer[(i-1)*256]), 256, 0); + if(ferr) break; + } + + return ferr; +} + +static imgtoolerr_t dgndos_diskimage_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent) +{ + floperr_t ferr; + imgtoolerr_t err; + size_t filesize; + dgndos_direnum *dgnenum; + dgndos_dirent dgnent; + int dir_ent_count; + + imgtool::image &image(enumeration.image()); + + uint8_t entire_track20[18*256]; + + ferr = dgndos_get_directory_track( image, 20, entire_track20 ); + if (ferr) return imgtool_floppy_error(ferr); + + dgnenum = (dgndos_direnum *) enumeration.extra_bytes(); + + /* Did we hit the end of file before? */ + if (dgnenum->eof) return IMGTOOLERR_SUCCESS; + + do + { + if (dgnenum->index >= MAX_DIRENTS) + { + dgnenum->eof = 1; + ent.eof = 1; + return IMGTOOLERR_SUCCESS; + } + + err = get_dgndos_dirent(entire_track20, dgnenum->index++, dgnent); + if (err) return err; + + if( dgndos_real_file( dgnent ) ) break; + } + while( ! (dgnent.flag_byte & DGNDOS_END_BIT) ); + + // now are we at the eof point? + if (dgnent.flag_byte & DGNDOS_END_BIT) + { + dgnenum->eof = 1; + ent.eof = 1; + } + else + { + err = dgndos_get_file_size(entire_track20, dgnent, filesize); + if (err) return err; + + if (filesize == ((size_t) -1)) + { + /* corrupt! */ + ent.filesize = 0; + ent.corrupt = 1; + } + else + { + ent.filesize = filesize; + ent.corrupt = 0; + } + ent.eof = 0; + + std::string fname = get_dirent_fname(dgnent); + + err = dgndos_count_dirents(entire_track20, dgnent, &dir_ent_count); + if (err) return err; + + snprintf(ent.filename, std::size(ent.filename), "%s", fname.c_str()); + snprintf(ent.attr, std::size(ent.attr), "%c (%03d)", + (char) (dgnent.flag_byte & DGNDOS_PROTECT_BIT ? 'P' : '.'), + dir_ent_count); + } + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t dgndos_diskimage_freespace(imgtool::partition &partition, uint64_t *size) +{ + floperr_t ferr; + imgtool::image &image(partition.image()); + int bitmap_count(0); + + uint8_t entire_track20[18*256]; + + ferr = dgndos_get_directory_track( image, 20, entire_track20 ); + if (ferr) return imgtool_floppy_error(ferr); + + *size = 0; + + dgndos_get_geometry(entire_track20, &bitmap_count, nullptr, nullptr, nullptr); + + for( int i=0; i<bitmap_count; i++ ) + { + if (dgndos_is_sector_avaiable(entire_track20, i)) + { + *size += 256; + } + } + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t dgndos_diskimage_readfile(imgtool::partition &partition, const char *fname, const char *fork, imgtool::stream &destf) +{ + floperr_t ferr; + imgtoolerr_t err; + dgndos_dirent ent; + imgtool::image &image(partition.image()); + int directory_entry_count = 0; + int head, track, sector; + int position; + int extent = 0; + int block_size; + int done; + int lsn; + int count; + int i; + + uint8_t entire_track20[18*256]; + + ferr = dgndos_get_directory_track( image, 20, entire_track20 ); + if (ferr) return imgtool_floppy_error(ferr); + + err = lookup_dgndos_file(entire_track20, fname, ent, &position); + if (err) return err; + + do + { + if(directory_entry_count>MAX_DIRENTS) return IMGTOOLERR_CORRUPTDIR; + + lsn = big_endianize_int16( ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[extent].lsn : ent.block.header.block[extent].lsn ); + count = ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[extent].count : ent.block.header.block[extent].count; + + if( count == 0 ) break; + + i = 0; + + // get extents except last sector + while (i < count - 1) + { + err = dgndos_convert_lsn(entire_track20, lsn + i, &head, &track, §or ); + if(err) return err; + + err = imgtool_floppy_read_sector_to_stream(image, head, track, sector, 0, 256, destf); + if (err) return err; + + i++; + } + + block_size = 256; + done = false; + + if( extent < (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? CONT_EXTENTS_COUNT : HEADER_EXTENTS_COUNT) - 1 ) + { + if( (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[extent+1].count : ent.block.header.block[extent+1].count) == 0 ) + { + // not last extent, and yes continuation + if( ent.dngdos_last_or_next == 0 ) + block_size = 256; + else + block_size = ent.dngdos_last_or_next; + + done = true; + } + } + else if( extent == (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? CONT_EXTENTS_COUNT : HEADER_EXTENTS_COUNT) - 1) + { + if( !(ent.flag_byte & DGNDOS_CONTINUED_BIT) ) + { + // is last extent, and no continuation + if( ent.dngdos_last_or_next == 0 ) + block_size = 256; + else + block_size = ent.dngdos_last_or_next; + + done = true; + } + } + + err = dgndos_convert_lsn(entire_track20, lsn + i, &head, &track, §or ); + if(err) return err; + + err = imgtool_floppy_read_sector_to_stream(image, head, track, sector, 0, block_size, destf); + if (err) return err; + + extent++; + + if( extent == (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? CONT_EXTENTS_COUNT : HEADER_EXTENTS_COUNT) ) + { + if( ent.flag_byte & DGNDOS_CONTINUED_BIT) + { + position = ent.dngdos_last_or_next; + err = get_dgndos_dirent(entire_track20, ent.dngdos_last_or_next, ent ); + if(err) return err; + + extent = 0; + directory_entry_count++; + } + } + } + while( !done ); + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t dgndos_diskimage_deletefile(imgtool::partition &partition, const char *fname) +{ + imgtoolerr_t err; + floperr_t ferr; + imgtool::image &image(partition.image()); + int pos; + struct dgndos_dirent ent; + int directory_entry_count = 0; + + uint8_t entire_track20[18*256]; + uint8_t entire_track16[18*256]; + bool write_20_to_16; + + ferr = dgndos_get_directory_track( image, 20, entire_track20 ); + if (ferr) return imgtool_floppy_error(ferr); + + ferr = dgndos_get_directory_track( image, 16, entire_track16 ); + if (ferr) return imgtool_floppy_error(ferr); + + write_20_to_16 = memcmp(entire_track20, entire_track16, 256*18 ); + + err = lookup_dgndos_file(entire_track20, fname, ent, &pos); + if (err) return err; + + ent.flag_byte |= DGNDOS_DELETED_BIT; + ent.flag_byte &= ~DGNDOS_PROTECT_BIT; + + for( int i=0; i<HEADER_EXTENTS_COUNT; i++) + { + if( ent.block.header.block[i].count != 0) + { + dgndos_fat_deallocate_span(entire_track20, big_endianize_int16(ent.block.header.block[i].lsn), ent.block.header.block[i].count); + + ent.block.header.block[i].lsn = 0; + ent.block.header.block[i].count = 0; + } + else break; + } + + int continue_flag = ent.flag_byte & DGNDOS_CONTINUED_BIT; + int continue_dirent_index = ent.dngdos_last_or_next; + + ent.dngdos_last_or_next = 0; + err = put_dgndos_dirent(entire_track20, pos, ent); + if (err) return err; + + while( continue_flag ) + { + if( directory_entry_count > MAX_DIRENTS ) return IMGTOOLERR_CORRUPTDIR; + + int dirent_index = continue_dirent_index; + err = get_dgndos_dirent(entire_track20, dirent_index, ent); + if (err) return err; + + for( int i=0; i<CONT_EXTENTS_COUNT; i++) + { + if(ent.block.continuation.block[i].count !=0) + { + dgndos_fat_deallocate_span(entire_track20, big_endianize_int16(ent.block.continuation.block[i].lsn), ent.block.continuation.block[i].count); + + ent.block.continuation.block[i].lsn = 0; + ent.block.continuation.block[i].count = 0; + } + else break; + } + + ent.flag_byte |= DGNDOS_DELETED_BIT; + continue_flag = ent.flag_byte & DGNDOS_CONTINUED_BIT; + continue_dirent_index = ent.dngdos_last_or_next; + + ent.dngdos_last_or_next = 0; + err = put_dgndos_dirent(entire_track20, dirent_index, ent); + if (err) return err; + + directory_entry_count++; + } + + ferr = dgndos_put_directory_track( image, 20, entire_track20 ); + if (ferr) return imgtool_floppy_error(ferr); + + if( write_20_to_16 ) + { + ferr = dgndos_put_directory_track( image, 16, entire_track20 ); + if (ferr) return imgtool_floppy_error(ferr); + } + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t dgndos_prepare_dirent(uint8_t *track, dgndos_dirent &ent, const char *fname) +{ + const char *fname_end; + const char *fname_ext; + int fname_ext_len; + + memset(&ent, '\0', sizeof(ent)); + + fname_end = strchr(fname, '.'); + if (fname_end) + fname_ext = fname_end + 1; + else + fname_end = fname_ext = fname + strlen(fname); + + fname_ext_len = strlen(fname_ext); + + // we had better be an 8.3 filename + if (((fname_end - fname) > 8) || (fname_ext_len > 3)) + return IMGTOOLERR_BADFILENAME; + + memcpy(&ent.block.header.filename[0], fname, fname_end - fname); + memcpy(&ent.block.header.filename[8], fname_ext, fname_ext_len); + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t dgndos_diskimage_writefile(imgtool::partition &partition, const char *fname, const char *fork, imgtool::stream &sourcef, util::option_resolution *writeoptions) +{ + floperr_t ferr; + imgtoolerr_t err; + imgtool::image &image(partition.image()); + dgndos_dirent ent; + int position; + uint64_t written = 0; + int fat_block, first_lsn, sectors_avaiable, current_sector_index; + int last_sector_size = 0; + int bitmap_count; + + if( sourcef.size() == 0 ) return IMGTOOLERR_BUFFERTOOSMALL; + + uint8_t entire_track20[18*256]; + uint8_t entire_track16[18*256]; + bool write_20_to_16; + + ferr = dgndos_get_directory_track( image, 20, entire_track20 ); + if (ferr) return imgtool_floppy_error(ferr); + + ferr = dgndos_get_directory_track( image, 16, entire_track16 ); + if (ferr) return imgtool_floppy_error(ferr); + + write_20_to_16 = memcmp(entire_track20, entire_track16, 18*256 ); + + err = dgndos_get_geometry(entire_track20, &bitmap_count, nullptr, nullptr, nullptr); + if(err) return err; + + // find directory entry with same file name + err = lookup_dgndos_file(entire_track20, fname, ent, &position); + + if( err == IMGTOOLERR_FILENOTFOUND ) + { + int new_lsn; + + // get new directory entry + err = dgndos_get_avaiable_dirent(entire_track20, ent, &position); + if (err) return err; + + err = dgndos_prepare_dirent(entire_track20, ent, fname); + if(err) return err; + + err = dgndos_get_avaiable_sector( entire_track20, &new_lsn ); + if (err) + { + return err; + } + + dgndos_fat_allocate_sector(entire_track20, new_lsn); + + ent.block.header.block[0].lsn = big_endianize_int16(new_lsn); + ent.block.header.block[0].count = 1; + + err = put_dgndos_dirent(entire_track20, position, ent); + if(err) return err; + } + else if(err != IMGTOOLERR_SUCCESS ) + { + return err; + } + + if( writeoptions->lookup_int(DGNDOS_OPTIONS_PROTECT)) + { + ent.flag_byte |= DGNDOS_PROTECT_BIT; + } + else + { + ent.flag_byte &= ~DGNDOS_PROTECT_BIT; + } + + fat_block = 0; + + /* get next available fat entry */ + first_lsn = big_endianize_int16(ent.block.header.block[fat_block].lsn); + sectors_avaiable = ent.block.header.block[fat_block].count; + current_sector_index = 0; + + do + { + while ((current_sector_index < sectors_avaiable) && (written < sourcef.size())) + { + int head, track, sector, write_count; + + err = dgndos_convert_lsn(entire_track20, first_lsn + current_sector_index, &head, &track, §or ); + if (err) return err; + + if( sourcef.size() - written > 256 ) + { + write_count = 256; + } + else if( sourcef.size() - written == 256 ) + { + write_count = 256; + last_sector_size = 0; + } + else + { + write_count = sourcef.size() - written; + last_sector_size = write_count; + } + + err = imgtool_floppy_write_sector_from_stream(image, head, track, sector, 0, write_count, sourcef); + if (err) return err; + + current_sector_index++; + written += write_count; + } + + if( written == sourcef.size()) // are we are done writing file + { + int de_count = 0; + int de_dont_delete = position; + int lsn, count; + int save_next_de; + + save_next_de = ent.dngdos_last_or_next; + ent.dngdos_last_or_next = last_sector_size; + + // yes, truncate this allocation block if necessary + if( ent.flag_byte & DGNDOS_CONTINUATION_BIT) + { + for( int i = current_sector_index; i < ent.block.continuation.block[fat_block].count; i++) + { + dgndos_fat_deallocate_sector(entire_track20, first_lsn + i); + } + + ent.block.continuation.block[fat_block].count = current_sector_index; + } + else + { + for( int i = current_sector_index; i < ent.block.header.block[fat_block].count; i++) + { + dgndos_fat_deallocate_sector(entire_track20, first_lsn + i); + } + + ent.block.header.block[fat_block].count = current_sector_index; + } + + do // check remaining allocation blocks and zero them + { + fat_block++; + + if( (fat_block < (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? CONT_EXTENTS_COUNT : HEADER_EXTENTS_COUNT)) ) + { + lsn = big_endianize_int16( ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[fat_block].lsn : ent.block.header.block[fat_block].lsn ); + count = ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[fat_block].count : ent.block.header.block[fat_block].count; + + if( count > 0 ) + { + dgndos_fat_deallocate_span(entire_track20, lsn, count); + + (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[fat_block].lsn : ent.block.header.block[fat_block].lsn) = 0; + (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[fat_block].count : ent.block.header.block[fat_block].count) = 0; + } + } + else + { + uint8_t save_flag = ent.flag_byte; + + ent.flag_byte &= ~DGNDOS_CONTINUED_BIT; + + if( ent.flag_byte & DGNDOS_CONTINUATION_BIT ) + { + if( de_dont_delete != position ) + { + ent.flag_byte |= DGNDOS_DELETED_BIT; + } + } + + err = put_dgndos_dirent(entire_track20, position, ent); + if (err) return err; + + if( save_flag & DGNDOS_CONTINUED_BIT ) + { + position = save_next_de; + + err = get_dgndos_dirent(entire_track20, position, ent); + if (err) return err; + + save_next_de = ent.dngdos_last_or_next; + fat_block = -1; + } + else + { + break; + } + } + + de_count++; + } + while( de_count < MAX_DIRENTS ); + + if( de_count == MAX_DIRENTS ) return IMGTOOLERR_CORRUPTDIR; + } + else // more to write + { + // check if I can extend the allocation count + if( (current_sector_index < 254) && (first_lsn + current_sector_index < bitmap_count) && (dgndos_is_sector_avaiable( entire_track20, first_lsn + current_sector_index )) ) + { + sectors_avaiable++; + + (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[fat_block].count : ent.block.header.block[fat_block].count) = sectors_avaiable; + + dgndos_fat_allocate_sector( entire_track20, first_lsn + current_sector_index ); + } + else // this allocation list is full - check next allocation list + { + fat_block++; + + if( fat_block == (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? CONT_EXTENTS_COUNT : HEADER_EXTENTS_COUNT)) + { + if( ent.flag_byte & DGNDOS_CONTINUED_BIT) + { + // go to next directory entry. + err = put_dgndos_dirent(entire_track20, position, ent); + if (err) return err; + + position = ent.dngdos_last_or_next; + err = get_dgndos_dirent(entire_track20, position, ent); + if (err) + { + return err; + } + + fat_block = 0; + } + else + { + // need a or another continuation directory entry + int save_position = position, new_lsn; + + err = put_dgndos_dirent(entire_track20, position, ent); + if (err) return err; + + err = dgndos_get_avaiable_dirent_position( entire_track20, &position ); + if (err) + { + return err; + } + + ent.flag_byte |= DGNDOS_CONTINUED_BIT; + ent.dngdos_last_or_next = position; + err = put_dgndos_dirent(entire_track20, save_position, ent); + if (err) return err; + + err = get_dgndos_dirent(entire_track20, position, ent); + if (err) + { + return err; + } + + memset( (void *)&ent, 0, sizeof(dgndos_dirent) ); + ent.flag_byte |= DGNDOS_CONTINUATION_BIT; + fat_block = 0; + + err = dgndos_get_avaiable_sector( entire_track20, &new_lsn ); + if (err) + { + return err; + } + } + } + + sectors_avaiable = ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[fat_block].count : ent.block.header.block[fat_block].count; + + // check if this block is empty + if( sectors_avaiable == 0) + { + int new_lsn; + + err = dgndos_get_avaiable_sector( entire_track20, &new_lsn ); + if (err) return err; + + (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[fat_block].lsn : ent.block.header.block[fat_block].lsn) = big_endianize_int16(new_lsn); + (ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[fat_block].count : ent.block.header.block[fat_block].count) = 1; + + dgndos_fat_allocate_sector(entire_track20, new_lsn); + } + + first_lsn = ent.flag_byte & DGNDOS_CONTINUATION_BIT ? big_endianize_int16(ent.block.continuation.block[fat_block].lsn) : big_endianize_int16(ent.block.header.block[fat_block].lsn); + sectors_avaiable = ent.flag_byte & DGNDOS_CONTINUATION_BIT ? ent.block.continuation.block[fat_block].count : ent.block.header.block[fat_block].count; + current_sector_index = 0; + } + } + } + while( written < sourcef.size() ); + + ferr = dgndos_put_directory_track( image, 20, entire_track20 ); + if (ferr) return imgtool_floppy_error(ferr); + + if( write_20_to_16 ) + { + ferr = dgndos_put_directory_track( image, 16, entire_track20 ); + if (ferr) return imgtool_floppy_error(ferr); + } + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t dgndos_diskimage_suggesttransfer(imgtool::partition &partition, const char *fname, imgtool::transfer_suggestion *suggestions, size_t suggestions_length) +{ + floperr_t ferr; + imgtoolerr_t err; + imgtool::image &image(partition.image()); + struct dgndos_dirent ent; + int pos; + + uint8_t entire_track20[18*256]; + + ferr = dgndos_get_directory_track( image, 20, entire_track20 ); + if (ferr) return imgtool_floppy_error(ferr); + + if (fname) + { + err = lookup_dgndos_file(entire_track20, fname, ent, &pos); + if (err) + return err; + + if (strcmp(ent.block.header.filename+8,"DAT") == 0) + { + /* ASCII file */ + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = filter_eoln_getinfo; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; + suggestions[1].filter = nullptr; + } + else if (strcmp(ent.block.header.filename+8,"BAS") == 0) + { + /* tokenized BASIC file */ + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = nullptr; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; + suggestions[1].filter = filter_dragonbas_getinfo; + } + } + else + { + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = nullptr; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; + suggestions[1].filter = filter_eoln_getinfo; + suggestions[2].viability = imgtool::SUGGESTION_POSSIBLE; + suggestions[2].filter = filter_dragonbas_getinfo; + } + + return IMGTOOLERR_SUCCESS; +} + +static imgtoolerr_t dgndos_diskimage_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *opts) +{ + imgtoolerr_t err; + uint32_t heads, tracks, sectors, first_sector_id, sector_bytes, total_sector_count; + uint8_t sector[512]; + struct dgndos_dirent *ents; + + heads = opts->lookup_int('H'); + tracks = opts->lookup_int('T'); + sectors = opts->lookup_int('S'); + first_sector_id = opts->lookup_int('F'); + sector_bytes = opts->lookup_int('L'); + + if(sector_bytes!=256) return IMGTOOLERR_UNIMPLEMENTED; + + // create FAT sectors + memset( sector, 0, 512 ); + + total_sector_count = (heads * tracks * sectors); + + for( int i=0; i<total_sector_count; i++ ) + { + dgndos_fat_deallocate_sector(sector, i); + } + + sector[0xfc] = tracks; + sector[0xfd] = heads == 1 ? (sectors) : (sectors * 2); + sector[0xfe] = ~sector[0xfc]; + sector[0xff] = ~sector[0xfd]; + + // allocate sectors + for( int i=0; i<18; i++ ) + { + dgndos_fat_allocate_sector(sector, (20 * 18 * heads) + i); + dgndos_fat_allocate_sector(sector, (16 * 18 * heads) + i); + } + + // write fat sectors + err = (imgtoolerr_t)floppy_write_sector(imgtool_floppy(image), 0, 20, first_sector_id, 0, §or[0], sector_bytes, 0); + if (err) return err; + err = (imgtoolerr_t)floppy_write_sector(imgtool_floppy(image), 0, 20, first_sector_id+1, 0, §or[256], sector_bytes, 0); + if (err) return err; + + err = (imgtoolerr_t)floppy_write_sector(imgtool_floppy(image), 0, 16, first_sector_id, 0, §or[0], sector_bytes, 0); + if (err) return err; + err = (imgtoolerr_t)floppy_write_sector(imgtool_floppy(image), 0, 16, first_sector_id+1, 0, §or[256], sector_bytes, 0); + if (err) return err; + + // create empty directory entries + memset( sector, 0, 512 ); + ents = (struct dgndos_dirent *)sector; + + for( int i=0; i<10; i++ ) + { + ents[i].flag_byte = 0x89; + } + + // write directory entires to disk + for( int i=3; i<19; i++) + { + err = (imgtoolerr_t)floppy_write_sector(imgtool_floppy(image), 0, 20, i, 0, §or[0], sector_bytes, 0); + if (err) return err; + err = (imgtoolerr_t)floppy_write_sector(imgtool_floppy(image), 0, 16, i, 0, §or[0], sector_bytes, 0); + if (err) return err; + } + + return IMGTOOLERR_SUCCESS; +} + +/********************************************************************* + Imgtool module declaration +*********************************************************************/ + +OPTION_GUIDE_START( dragon_dgndos_writefile_optionguide ) + OPTION_ENUM_START( DGNDOS_OPTIONS_PROTECT, "prot", "Protect file" ) + OPTION_ENUM( 0, "no", "No" ) + OPTION_ENUM( 1, "yes", "Yes" ) + OPTION_ENUM_END +OPTION_GUIDE_END + +void dgndos_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_PREFER_UCASE: info->i = 1; break; + case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(struct dgndos_direnum); break; + + /* --- the following bits of info are returned as NUL-terminated strings --- */ + case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "dgndos"); break; + case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "Dragon DOS 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; + case IMGTOOLINFO_STR_WRITEFILE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), "P[0]-1"); 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_FLOPPY_CREATE: info->create = dgndos_diskimage_create; break; + case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = dgndos_diskimage_nextenum; break; + case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = dgndos_diskimage_freespace; break; + case IMGTOOLINFO_PTR_READ_FILE: info->read_file = dgndos_diskimage_readfile; break; + case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = dgndos_diskimage_writefile; break; + case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = dgndos_diskimage_deletefile; break; + case IMGTOOLINFO_PTR_SUGGEST_TRANSFER: info->suggest_transfer = dgndos_diskimage_suggesttransfer; break; + case IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE: info->writefile_optguide = &dragon_dgndos_writefile_optionguide; break; + case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_coco; break; + } +} diff --git a/src/tools/imgtool/modules/fat.cpp b/src/tools/imgtool/modules/fat.cpp index 029050d1e9c..d6611932c0d 100644 --- a/src/tools/imgtool/modules/fat.cpp +++ b/src/tools/imgtool/modules/fat.cpp @@ -134,13 +134,17 @@ ****************************************************************************/ -#include <time.h> -#include <ctype.h> -#include "imgtool.h" -#include "formats/imageutl.h" -#include "unicode.h" #include "fat.h" +#include "corestr.h" +#include "multibyte.h" +#include "unicode.h" + +#include <algorithm> +#include <cctype> +#include <cstdio> +#include <ctime> + #define FAT_DIRENT_SIZE 32 #define FAT_SECLEN 512 @@ -176,6 +180,18 @@ struct fat_file struct fat_dirent { + fat_dirent() : + directory(0), + eof(0), + filesize(0), + first_cluster(0), + dirent_sector_index(0), + dirent_sector_offset(0) + { + std::fill(std::begin(long_filename), std::end(long_filename), 0); + std::fill(std::begin(short_filename), std::end(short_filename), 0); + } + char long_filename[512]; char short_filename[13]; unsigned int directory : 1; @@ -364,14 +380,12 @@ static imgtoolerr_t fat_write_sector(imgtool::partition &partition, uint32_t sec } -#ifdef UNUSED_FUNCTION -static imgtoolerr_t fat_clear_sector(imgtool::partition &partition, uint32_t sector_index, uint8_t data) +[[maybe_unused]] static imgtoolerr_t fat_clear_sector(imgtool::partition &partition, uint32_t sector_index, uint8_t data) { char buf[FAT_SECLEN]; memset(buf, data, sizeof(buf)); return fat_write_sector(partition, sector_index, 0, buf, sizeof(buf)); } -#endif static imgtoolerr_t fat_partition_open(imgtool::partition &partition, uint64_t first_block, uint64_t block_count) @@ -410,19 +424,19 @@ static imgtoolerr_t fat_partition_open(imgtool::partition &partition, uint64_t f } info->fat_bits = fat_bits; - sector_size = pick_integer_le(header, 11, 2); - info->sectors_per_cluster = pick_integer_le(header, 13, 1); - info->reserved_sectors = pick_integer_le(header, 14, 2); - info->fat_count = pick_integer_le(header, 16, 1); - info->root_entries = pick_integer_le(header, 17, 2); - total_sectors_l = pick_integer_le(header, 19, 2); - info->sectors_per_fat = pick_integer_le(header, 22, 2); - total_sectors_h = pick_integer_le(header, 32, 4); + sector_size = get_u16le(&header[11]); + info->sectors_per_cluster = header[13]; + info->reserved_sectors = get_u16le(&header[14]); + info->fat_count = header[16]; + info->root_entries = get_u16le(&header[17]); + total_sectors_l = get_u16le(&header[19]); + info->sectors_per_fat = get_u16le(&header[22]); + total_sectors_h = get_u32le(&header[32]); if (info->sectors_per_cluster == 0) return IMGTOOLERR_CORRUPTIMAGE; - info->total_sectors = total_sectors_l + (((uint64_t) total_sectors_h) << 16); + info->total_sectors = total_sectors_l + (uint64_t(total_sectors_h) << 16); available_sectors = info->total_sectors - info->reserved_sectors - (info->sectors_per_fat * info->fat_count) - (info->root_entries * FAT_DIRENT_SIZE + FAT_SECLEN - 1) / FAT_SECLEN; @@ -520,24 +534,24 @@ static imgtoolerr_t fat_partition_create(imgtool::image &image, uint64_t first_b /* prepare the header */ memset(header, 0, sizeof(header)); memcpy(&header[3], "IMGTOOL ", 8); - place_integer_le(header, 11, 2, FAT_SECLEN); - place_integer_le(header, 13, 1, sectors_per_cluster); - place_integer_le(header, 14, 1, reserved_sectors); - place_integer_le(header, 16, 1, fat_count); - place_integer_le(header, 17, 2, root_dir_count); - place_integer_le(header, 19, 2, (uint16_t) (block_count >> 0)); - place_integer_le(header, 21, 1, media_descriptor); - place_integer_le(header, 22, 2, sectors_per_fat); - place_integer_le(header, 24, 2, sectors_per_track); - place_integer_le(header, 26, 2, heads); - place_integer_le(header, 28, 4, hidden_sectors); - place_integer_le(header, 32, 4, (uint32_t) (block_count >> 16)); - place_integer_le(header, 36, 1, 0xFF); - place_integer_le(header, 38, 1, 0x28); - place_integer_le(header, 39, 1, std::rand()); - place_integer_le(header, 40, 1, std::rand()); - place_integer_le(header, 41, 1, std::rand()); - place_integer_le(header, 42, 1, std::rand()); + put_u16le(&header[11], FAT_SECLEN); + header[13] = sectors_per_cluster; + header[14] = reserved_sectors; + header[16] = fat_count; + put_u16le(&header[17], root_dir_count); + put_u16le(&header[19], uint16_t(block_count >> 0)); + header[21] = media_descriptor; + put_u16le(&header[22], sectors_per_fat); + put_u16le(&header[24], sectors_per_track); + put_u16le(&header[26], heads); + put_u32le(&header[28], hidden_sectors); + put_u32le(&header[32], uint32_t(block_count >> 16)); + header[36] = 0xFF; + header[38] = 0x28; + header[39] = std::rand(); + header[40] = std::rand(); + header[41] = std::rand(); + header[42] = std::rand(); memcpy(&header[43], " ", 11); memcpy(&header[54], fat_bits_string, 8); @@ -553,14 +567,14 @@ static imgtoolerr_t fat_partition_create(imgtool::image &image, uint64_t first_b if (boot_sector_offset <= 129) { header[0] = 0xEB; /* JMP rel8 */ - header[1] = (uint8_t) (boot_sector_offset - 2); /* (offset) */ + header[1] = uint8_t(boot_sector_offset - 2); /* (offset) */ header[2] = 0x90; /* NOP */ } else { header[0] = 0xE9; /* JMP rel16 */ - header[1] = (uint8_t) ((boot_sector_offset - 2) >> 0); /* (offset) */ - header[2] = (uint8_t) ((boot_sector_offset - 2) >> 8); /* (offset) */ + header[1] = uint8_t((boot_sector_offset - 2) >> 0); /* (offset) */ + header[2] = uint8_t((boot_sector_offset - 2) >> 8); /* (offset) */ } err = image.write_block(first_block, header); @@ -578,9 +592,9 @@ static imgtoolerr_t fat_partition_create(imgtool::image &image, uint64_t first_b // FIXME: this causes a corrupt PC floppy image since it doubles the FAT partition header - works without it though #if 0 /* set first two FAT entries */ - first_fat_entries = ((uint64_t) media_descriptor) | 0xFFFFFF00; - first_fat_entries &= (((uint64_t) 1) << fat_bits) - 1; - first_fat_entries |= ((((uint64_t) 1) << fat_bits) - 1) << fat_bits; + first_fat_entries = uint64_t(media_descriptor) | 0xFFFFFF00; + first_fat_entries &= (uint64_t(1) << fat_bits) - 1; + first_fat_entries |= ((uint64_t(1) << fat_bits) - 1) << fat_bits; first_fat_entries = little_endianize_int64(first_fat_entries); for (i = 0; i < fat_count; i++) @@ -706,8 +720,8 @@ static uint32_t fat_get_fat_entry(imgtool::partition &partition, const uint8_t * entry &= bit_mask; if (i == 0) - last_entry = (uint32_t) entry; - else if (last_entry != (uint32_t) entry) + last_entry = uint32_t(entry); + else if (last_entry != uint32_t(entry)) return 1; /* if the FATs disagree; mark this as reserved */ } @@ -739,8 +753,8 @@ static void fat_set_fat_entry(imgtool::partition &partition, uint8_t *fat_table, * disk_info->sectors_per_fat) + (bit_index / 8), sizeof(entry)); entry = little_endianize_int64(entry); - entry &= (~((uint64_t) 0xFFFFFFFF >> (32 - disk_info->fat_bits)) << (bit_index % 8)) | ((1 << (bit_index % 8)) - 1); - entry |= ((uint64_t) value) << (bit_index % 8); + entry &= (~(uint64_t(0xFFFFFFFF) >> (32 - disk_info->fat_bits)) << (bit_index % 8)) | ((1 << (bit_index % 8)) - 1); + entry |= uint64_t(value) << (bit_index % 8); entry = little_endianize_int64(entry); memcpy(fat_table + (i * FAT_SECLEN @@ -1080,8 +1094,8 @@ static imgtoolerr_t fat_set_file_size(imgtool::partition &partition, fat_file *f } /* record the new file size */ - place_integer_le(dirent, 26, 2, file->first_cluster); - place_integer_le(dirent, 28, 4, new_size); + put_u16le(&dirent[26], file->first_cluster); + put_u32le(&dirent[28], new_size); /* delete the file, if appropriate */ if (delete_file) @@ -1228,7 +1242,7 @@ static void fat_canonicalize_sfn(char *sfn, const uint8_t *sfn_bytes) memcpy(sfn, sfn_bytes, 8); rtrim(sfn); if (sfn[0] == 0x05) - sfn[0] = (char) 0xE5; + sfn[0] = char(0xE5); if ((sfn_bytes[8] != ' ') || (sfn_bytes[9] != ' ') || (sfn_bytes[10] != ' ')) { strcat(sfn, "."); @@ -1272,15 +1286,16 @@ static uint32_t fat_setup_time(time_t ansi_time) -static imgtoolerr_t fat_read_dirent(imgtool::partition &partition, fat_file *file, - fat_dirent &ent, fat_freeentry_info *freeent) +static imgtoolerr_t fat_read_dirent( + imgtool::partition &partition, + fat_file *file, + fat_dirent &ent, + fat_freeentry_info *freeent) { imgtoolerr_t err; //const fat_partition_info *disk_info; uint8_t entry[FAT_DIRENT_SIZE]; size_t bytes_read; - int i, j; - char32_t ch; char16_t lfn_buf[512]; size_t lfn_len = 0; int lfn_lastentry = 0; @@ -1289,7 +1304,7 @@ static imgtoolerr_t fat_read_dirent(imgtool::partition &partition, fat_file *fil assert(file->directory); lfn_buf[0] = '\0'; - memset(&ent, 0, sizeof(ent)); + ent = fat_dirent(); //disk_info = fat_get_partition_info(partition); /* The first eight bytes of a FAT directory entry is a blank padded name @@ -1326,11 +1341,11 @@ static imgtoolerr_t fat_read_dirent(imgtool::partition &partition, fat_file *fil lfn_checksum = entry[13]; } lfn_lastentry = entry[0] & 0x3F; - prepend_lfn_bytes(lfn_buf, ARRAY_LENGTH(lfn_buf), + prepend_lfn_bytes(lfn_buf, std::size(lfn_buf), &lfn_len, entry, 28, 2); - prepend_lfn_bytes(lfn_buf, ARRAY_LENGTH(lfn_buf), + prepend_lfn_bytes(lfn_buf, std::size(lfn_buf), &lfn_len, entry, 14, 6); - prepend_lfn_bytes(lfn_buf, ARRAY_LENGTH(lfn_buf), + prepend_lfn_bytes(lfn_buf, std::size(lfn_buf), &lfn_len, entry, 1, 5); } else if (freeent && (freeent->position == ~0)) @@ -1350,7 +1365,7 @@ static imgtoolerr_t fat_read_dirent(imgtool::partition &partition, fat_file *fil } } } - while((entry[0] == 0x2E) || (entry[0] == 0xE5) || (entry[11] == 0x0F)); + while ((entry[0] == 0x2E) || (entry[0] == 0xE5) || (entry[11] == 0x0F)); /* no more directory entries? */ if (entry[0] == '\0') @@ -1368,25 +1383,25 @@ static imgtoolerr_t fat_read_dirent(imgtool::partition &partition, fat_file *fil /* only use the LFN if the checksum passes */ if (lfn_checksum == fat_calc_filename_checksum(entry)) { - i = 0; - j = 0; + int i = 0, j = 0; + char32_t ch; do { - i += uchar_from_utf16(&ch, &lfn_buf[i], ARRAY_LENGTH(lfn_buf) - i); - j += utf8_from_uchar(&ent.long_filename[j], ARRAY_LENGTH(ent.long_filename) - j, ch); + i += uchar_from_utf16(&ch, &lfn_buf[i], std::size(lfn_buf) - i); + j += utf8_from_uchar(&ent.long_filename[j], std::size(ent.long_filename) - j, ch); } - while(ch != 0); + while (ch != 0); } } /* other attributes */ - ent.filesize = pick_integer_le(entry, 28, 4); + ent.filesize = get_u32le(&entry[28]); ent.directory = (entry[11] & 0x10) ? 1 : 0; - ent.first_cluster = pick_integer_le(entry, 26, 2); + ent.first_cluster = get_u16le(&entry[26]); ent.dirent_sector_index = entry_sector_index; ent.dirent_sector_offset = entry_sector_offset; - ent.creation_time = fat_crack_time(pick_integer_le(entry, 14, 4)); - ent.lastmodified_time = fat_crack_time(pick_integer_le(entry, 22, 4)); + ent.creation_time = fat_crack_time(get_u32le(&entry[14])); + ent.lastmodified_time = fat_crack_time(get_u32le(&entry[22])); return IMGTOOLERR_SUCCESS; } @@ -1440,9 +1455,9 @@ static imgtoolerr_t fat_construct_dirent(const char *filename, creation_policy_t /* set up file dates in the new dirent */ now = fat_setup_time(time(NULL)); - place_integer_le(created_entry, 14, 4, now); - place_integer_le(created_entry, 18, 2, now); - place_integer_le(created_entry, 22, 4, now); + put_u32le(&created_entry[14], now); + put_u16le(&created_entry[18], now); + put_u32le(&created_entry[22], now); while(*filename) { @@ -1451,13 +1466,13 @@ static imgtoolerr_t fat_construct_dirent(const char *filename, creation_policy_t /* append to short filename, if possible */ if ((ch < 32) || (ch > 128)) short_char = '\0'; - else if (isalnum((char) ch)) - short_char = toupper((char) ch); - else if (strchr(".!#$%^()-@^_`{}~", (char) ch)) - short_char = (char) ch; + else if (isalnum(char(ch))) + short_char = toupper(char(ch)); + else if (strchr(".!#$%^()-@^_`{}~", char(ch))) + short_char = char(ch); else short_char = '\0'; /* illegal SFN char */ - canonical_short_char = fat_canonicalize_sfn_char((char) ch); + canonical_short_char = fat_canonicalize_sfn_char(char(ch)); if (!short_char || (short_char != canonical_short_char)) { if (toupper(short_char) == toupper(canonical_short_char)) @@ -1605,7 +1620,7 @@ static void fat_bump_dirent(imgtool::partition &partition, uint8_t *entry, size_ sfn_entry = &entry[entry_len - FAT_DIRENT_SIZE]; digit_place = 1; - for (pos = 7; (pos >= 0) && isdigit((char) sfn_entry[pos]); pos--) + for (pos = 7; (pos >= 0) && isdigit(char(sfn_entry[pos])); pos--) { val += (sfn_entry[pos] - '0') * digit_place; digit_place *= 10; @@ -1834,7 +1849,7 @@ static imgtoolerr_t fat_partition_nextenum(imgtool::directory &enumeration, imgt return err; /* copy stuff from the FAT dirent to the Imgtool dirent */ - snprintf(ent.filename, ARRAY_LENGTH(ent.filename), "%s", fatent.long_filename[0] + snprintf(ent.filename, std::size(ent.filename), "%s", fatent.long_filename[0] ? fatent.long_filename : fatent.short_filename); ent.filesize = fatent.filesize; ent.directory = fatent.directory; @@ -1945,7 +1960,7 @@ static imgtoolerr_t fat_partition_writefile(imgtool::partition &partition, const if (file.directory) return IMGTOOLERR_FILENOTFOUND; - bytes_left = (uint32_t) sourcef.size(); + bytes_left = uint32_t(sourcef.size()); err = fat_set_file_size(partition, &file, bytes_left); if (err) @@ -2051,11 +2066,11 @@ static imgtoolerr_t fat_partition_createdir(imgtool::partition &partition, const /* set up the two directory entries in all directories */ memset(initial_data, 0, sizeof(initial_data)); memcpy(&initial_data[0], ". ", 11); - place_integer_le(initial_data, 11, 1, 0x10); - place_integer_le(initial_data, 26, 2, file.first_cluster); + initial_data[11] = 0x10; + put_u16le(&initial_data[26], file.first_cluster); memcpy(&initial_data[32], ". ", 11); - place_integer_le(initial_data, 43, 1, 0x10); - place_integer_le(initial_data, 58, 2, file.parent_first_cluster); + initial_data[43] = 0x10; + put_u16le(&initial_data[58], file.parent_first_cluster); err = fat_write_file(partition, &file, initial_data, sizeof(initial_data), NULL); if (err) diff --git a/src/tools/imgtool/modules/fat.h b/src/tools/imgtool/modules/fat.h index 77c56f5f9f1..8e7c60d89af 100644 --- a/src/tools/imgtool/modules/fat.h +++ b/src/tools/imgtool/modules/fat.h @@ -1,3 +1,6 @@ // license:BSD-3-Clause // copyright-holders:Raphael Nabet + +#include "imgtool.h" + void fat_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info); diff --git a/src/tools/imgtool/modules/hp48.cpp b/src/tools/imgtool/modules/hp48.cpp index 4d237f3c470..4a008adaeb5 100644 --- a/src/tools/imgtool/modules/hp48.cpp +++ b/src/tools/imgtool/modules/hp48.cpp @@ -86,6 +86,8 @@ #include "imgtool.h" +#include "opresolv.h" + /***************************************************************************** diff --git a/src/tools/imgtool/modules/hp85_tape.cpp b/src/tools/imgtool/modules/hp85_tape.cpp index dada87e290a..319f1e3f10c 100644 --- a/src/tools/imgtool/modules/hp85_tape.cpp +++ b/src/tools/imgtool/modules/hp85_tape.cpp @@ -7,12 +7,19 @@ HP-85 tape format *********************************************************************/ - #include "imgtool.h" -#include "formats/imageutl.h" + #include "formats/hti_tape.h" + +#include "ioprocs.h" +#include "multibyte.h" +#include "opresolv.h" +#include "strformat.h" + +#include <cstdio> #include <iostream> + // Constants static constexpr unsigned CHARS_PER_FNAME = 6; // Characters in a filename static constexpr unsigned CHARS_PER_EXT = 4; // Characters in (simulated) file extension @@ -109,9 +116,9 @@ private: // Content std::vector<sif_file_ptr_t> content; // First file on track 1 - file_no_t file_track_1; + file_no_t file_track_1{}; // No. of first record on track 1 - uint16_t record_track_1; + uint16_t record_track_1 = 0; bool dec_rec_header(const tape_word_t *hdr , file_no_t& file_no , uint16_t& rec_no , bool& has_body , unsigned& body_len); bool load_whole_tape(); @@ -145,7 +152,7 @@ typedef struct { tape_image_85::tape_image_85(void) : dirty(false) { - image.set_bits_per_word(16); + image.set_image_format(hti_format_t::HTI_DELTA_MOD_16_BITS); } void tape_image_85::format_img(void) @@ -158,48 +165,13 @@ void tape_image_85::format_img(void) finalize_allocation(); } -namespace { - int my_seekproc(void *file, int64_t offset, int whence) - { - reinterpret_cast<imgtool::stream *>(file)->seek(offset, whence); - return 0; - } - - size_t my_readproc(void *file, void *buffer, size_t length) - { - return reinterpret_cast<imgtool::stream *>(file)->read(buffer, length); - } - - size_t my_writeproc(void *file, const void *buffer, size_t length) - { - reinterpret_cast<imgtool::stream *>(file)->write(buffer, length); - return length; - } - - uint64_t my_filesizeproc(void *file) - { - return reinterpret_cast<imgtool::stream *>(file)->size(); - } - - const struct io_procs my_stream_procs = { - nullptr, - my_seekproc, - my_readproc, - my_writeproc, - my_filesizeproc - }; -} - imgtoolerr_t tape_image_85::load_from_file(imgtool::stream *stream) { - io_generic io; - io.file = (void *)stream; - io.procs = &my_stream_procs; - io.filler = 0; - - if (!image.load_tape(&io)) { + auto io = imgtool::stream_read(*stream, 0); + if (!io || !image.load_tape(*io)) { return IMGTOOLERR_READERROR; } + io.reset(); // Prevent track boundary crossing when reading directory file_track_1 = 0; @@ -422,12 +394,7 @@ imgtoolerr_t tape_image_85::save_to_file(imgtool::stream *stream) file_0.clear(); save_sif_file(track , pos , dir.size() + 1 , file_0); - io_generic io; - io.file = (void *)stream; - io.procs = &my_stream_procs; - io.filler = 0; - - image.save_tape(&io); + image.save_tape(*imgtool::stream_read_write(*stream, 0)); return IMGTOOLERR_SUCCESS; } @@ -667,7 +634,7 @@ bool tape_image_85::decode_dir(const sif_file_t& file_0) // Get FL1TK1 file_track_1 = file_0[ 0xfd ]; - record_track_1 = pick_integer_le(file_0.data() , 0xfe , 2); + record_track_1 = get_u16le(&file_0[ 0xfe ]); file_no_t file_no = 1; @@ -698,10 +665,10 @@ bool tape_image_85::decode_dir(const sif_file_t& file_0) new_entry.file_no = file_no++; // Physical records - new_entry.n_recs = pick_integer_le(p , 8 , 2); + new_entry.n_recs = get_u16le(&p[ 8 ]); // Bytes per logical record - new_entry.record_len = pick_integer_le(p , 10 , 2); + new_entry.record_len = get_u16le(&p[ 10 ]); if (new_entry.record_len < 4 || new_entry.record_len >= 32768) { return false; } @@ -722,8 +689,8 @@ void tape_image_85::encode_dir(sif_file_t& file_0) const file_0[ 0x1fc ] = 1; // Set FL1TK1 file_0[ 0xfd ] = file_0[ 0x1fd ] = file_track_1; - place_integer_le(file_0.data() , 0xfe , 2 , record_track_1); - place_integer_le(file_0.data() , 0x1fe , 2 , record_track_1); + put_u16le(&file_0[ 0xfe ] , record_track_1); + put_u16le(&file_0[ 0x1fe ] , record_track_1); unsigned i = 0; file_no_t file_no = 1; @@ -736,8 +703,8 @@ void tape_image_85::encode_dir(sif_file_t& file_0) const memcpy(&p_entry[ 0 ] , &entry->filename[ 0 ] , CHARS_PER_FNAME); p_entry[ 6 ] = file_no; p_entry[ 7 ] = entry->filetype; - place_integer_le(p_entry , 8 , 2 , entry->n_recs); - place_integer_le(p_entry , 10 , 2 , entry->record_len); + put_u16le(&p_entry[ 8 ] , entry->n_recs); + put_u16le(&p_entry[ 10 ] , entry->record_len); } if (file_no <= MAX_FILE_NO) { @@ -866,7 +833,7 @@ namespace { tape_image_85& get_tape_image(tape_state_t& ts) { if (ts.img == nullptr) { - ts.img = global_alloc(tape_image_85); + ts.img = new tape_image_85; } return *(ts.img); @@ -916,7 +883,7 @@ namespace { delete state.stream; // Free tape_image - global_free(&tape_image); + delete &tape_image; } imgtoolerr_t hp85_tape_begin_enum (imgtool::directory &enumeration, const char *path) diff --git a/src/tools/imgtool/modules/hp9845_tape.cpp b/src/tools/imgtool/modules/hp9845_tape.cpp index d3416deaefd..26cb2f4eb1c 100644 --- a/src/tools/imgtool/modules/hp9845_tape.cpp +++ b/src/tools/imgtool/modules/hp9845_tape.cpp @@ -108,12 +108,20 @@ these special characters. *********************************************************************/ -#include <bitset> - #include "imgtool.h" -#include "formats/imageutl.h" +#include "filter.h" + #include "formats/hti_tape.h" +#include "corefile.h" +#include "ioprocs.h" +#include "multibyte.h" +#include "opresolv.h" + +#include <bitset> +#include <cstdio> + + // Constants #define SECTOR_LEN 256 // Bytes in a sector #define WORDS_PER_SECTOR (SECTOR_LEN / 2) // 16-bit words in a sector payload @@ -291,49 +299,16 @@ void tape_image_t::format_img(void) dirty = true; } -static int my_seekproc(void *file, int64_t offset, int whence) -{ - reinterpret_cast<imgtool::stream *>(file)->seek(offset, whence); - return 0; -} - -static size_t my_readproc(void *file, void *buffer, size_t length) -{ - return reinterpret_cast<imgtool::stream *>(file)->read(buffer, length); -} - -static size_t my_writeproc(void *file, const void *buffer, size_t length) -{ - reinterpret_cast<imgtool::stream *>(file)->write(buffer, length); - return length; -} - -static uint64_t my_filesizeproc(void *file) -{ - return reinterpret_cast<imgtool::stream *>(file)->size(); -} - -static const struct io_procs my_stream_procs = { - nullptr, - my_seekproc, - my_readproc, - my_writeproc, - my_filesizeproc -}; - imgtoolerr_t tape_image_t::load_from_file(imgtool::stream *stream) { hti_format_t inp_image; - inp_image.set_bits_per_word(16); + inp_image.set_image_format(hti_format_t::HTI_DELTA_MOD_16_BITS); - io_generic io; - io.file = (void *)stream; - io.procs = &my_stream_procs; - io.filler = 0; - - if (!inp_image.load_tape(&io)) { + auto io = imgtool::stream_read(*stream, 0); + if (!io || !inp_image.load_tape(*io)) { return IMGTOOLERR_READERROR; } + io.reset(); unsigned exp_sector = 0; unsigned last_sector_on_track = SECTORS_PER_TRACK; @@ -523,12 +498,7 @@ imgtoolerr_t tape_image_t::save_to_file(imgtool::stream *stream) } } - io_generic io; - io.file = (void *)stream; - io.procs = &my_stream_procs; - io.filler = 0; - - out_image.save_tape(&io); + out_image.save_tape(*imgtool::stream_read_write(*stream, 0)); return IMGTOOLERR_SUCCESS; } @@ -985,7 +955,7 @@ static tape_state_t& get_tape_state(imgtool::image &img) static tape_image_t& get_tape_image(tape_state_t& ts) { if (ts.img == nullptr) { - ts.img = global_alloc(tape_image_t); + ts.img = new tape_image_t; } return *(ts.img); @@ -1034,7 +1004,7 @@ static void hp9845_tape_close(imgtool::image &image) delete state.stream; // Free tape_image - global_free(&tape_image); + delete &tape_image; } static imgtoolerr_t hp9845_tape_begin_enum (imgtool::directory &enumeration, const char *path) @@ -1374,7 +1344,7 @@ static imgtoolerr_t hp9845data_read_file(imgtool::partition &partition, const ch if (!get_record_part(*inp_data , tmp , 2)) { return IMGTOOLERR_READERROR; } - rec_type = (uint16_t)pick_integer_be(tmp , 0 , 2); + rec_type = get_u16be(&tmp[ 0 ]); switch (rec_type) { case REC_TYPE_EOR: // End of record: just skip it @@ -1397,7 +1367,7 @@ static imgtoolerr_t hp9845data_read_file(imgtool::partition &partition, const ch if (!get_record_part(*inp_data , tmp , 2)) { return IMGTOOLERR_READERROR; } - tmp_len = (unsigned)pick_integer_be(tmp , 0 , 2); + tmp_len = get_u16be(&tmp [ 0 ]); if (rec_type == REC_TYPE_FULLSTR || rec_type == REC_TYPE_1STSTR) { accum_len = tmp_len; @@ -1445,7 +1415,7 @@ static bool split_string_n_dump(const char *s , imgtool::stream &dest) unsigned free_len = len_to_eor(dest); if (free_len <= 4) { // Not enough free space at end of current record: fill with EORs - place_integer_be(tmp , 0 , 2 , REC_TYPE_EOR); + put_u16be(&tmp[ 0 ] , REC_TYPE_EOR); while (free_len) { if (dest.write(tmp , 2) != 2) { return false; @@ -1458,8 +1428,8 @@ static bool split_string_n_dump(const char *s , imgtool::stream &dest) // Free space to EOR enough for what's left of string break; } - place_integer_be(tmp , 0 , 2 , rec_type); - place_integer_be(tmp , 2 , 2 , s_len); + put_u16be(&tmp[ 0 ] , rec_type); + put_u16be(&tmp[ 2 ] , s_len); if (dest.write(tmp , 4) != 4 || dest.write(s, s_part_len) != s_part_len) { return false; @@ -1471,8 +1441,8 @@ static bool split_string_n_dump(const char *s , imgtool::stream &dest) } } - place_integer_be(tmp , 0 , 2 , at_least_one ? REC_TYPE_ENDSTR : REC_TYPE_FULLSTR); - place_integer_be(tmp , 2 , 2 , s_len); + put_u16be(&tmp[ 0 ] , at_least_one ? REC_TYPE_ENDSTR : REC_TYPE_FULLSTR); + put_u16be(&tmp[ 2 ] , s_len); if (dest.write(tmp , 4) != 4 || dest.write(s , s_len) != s_len) { return false; @@ -1528,7 +1498,7 @@ static imgtoolerr_t hp9845data_write_file(imgtool::partition &partition, const c // Fill free space of last record with EOFs unsigned free_len = len_to_eor(*out_data); uint8_t tmp[ 2 ]; - place_integer_be(tmp , 0 , 2 , REC_TYPE_EOF); + put_u16be(&tmp[ 0 ] , REC_TYPE_EOF); while (free_len) { if (out_data->write(tmp , 2 ) != 2) { @@ -1544,7 +1514,7 @@ static imgtoolerr_t hp9845data_write_file(imgtool::partition &partition, const c return res; } -void filter_hp9845data_getinfo(uint32_t state, union filterinfo *info) +void filter_hp9845data_getinfo(uint32_t state, imgtool::filterinfo *info) { switch (state) { case FILTINFO_PTR_READFILE: diff --git a/src/tools/imgtool/modules/mac.cpp b/src/tools/imgtool/modules/mac.cpp deleted file mode 100644 index 90c68323f76..00000000000 --- a/src/tools/imgtool/modules/mac.cpp +++ /dev/null @@ -1,6439 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/**************************************************************************** - - mac.c - - Handlers for Classic MacOS images (MFS and HFS formats). - - Raphael Nabet, 2003 - - TODO: - * add support for HFS write - -***************************************************************************** - - terminology: - disk block: 512-byte logical block. With sectors of 512 bytes, one logical - block is equivalent to one sector; when the sector size is not 512 - bytes, sectors are split or grouped to make 512-byte disk blocks. - allocation block: The File Manager always allocates logical disk blocks to - a file in groups called allocation blocks; an allocation block is - simply a group of consecutive logical blocks. The size of a volume's - allocation blocks depends on the capacity of the volume; there can be - at most 4094 (MFS) or 65535 (HFS) allocation blocks on a volume. - MFS (Macintosh File System): File system used by the early Macintosh. This - File system does not support folders (you may create folders on a MFS - disk, but such folders are not implemented on File System level but in - the Desktop file, and they are just a hint of how programs should list - files, i.e. you can't have two files with the same name on a volume - even if they are in two different folders), and it is not adequate for - large volumes. - HFS (Hierarchical File System): File system introduced with the HD20 - harddisk, the Macintosh Plus ROMs, and system 3.2 (IIRC). Contrary to - MFS, it supports hierarchical folders. Also, it is suitable for larger - volumes. - HFS+ (HFS Plus): New file system introduced with MacOS 8.1. It has a lot - in common with HFS, but it supports more allocation blocks (up to 4 - billions IIRC), and many extra features, including longer file names - (up to 255 UTF-16 Unicode chars). - tag data: with the GCR encoding, each disk block is associated with a 12 - (3.5" floppies) or 20 (HD20) byte tag record. This tag record contains - information on the block allocation status (whether it is allocated - in a file or free, which file is it belongs to, what offset the block - has in the file). This enables to recover all files whose data blocks - are still on the disk surface even if the disk catalog has been trashed - completely (though most file properties, like the name, type and - logical EOF, are not saved in the tag record and cannot be recovered). - - Organization of an MFS volume: - - Logical Contents Allocation block - block - - 0 - 1: System startup information - 2 - m: Master directory block (MDB) - + allocation block link pointers - m+1 - n: Directory file - n+1 - p-2: Other files and free space 0 - ((p-2)-(n+1))/k - p-1: Alternate MDB - p: Not used - usually, k = 2, m = 3, n = 16, p = 799 (SSDD 3.5" floppy) - with DSDD 3.5" floppy, I assume that p = 1599, but I don't know the other - values - - - Master Directory Block: - - Offset Length Description - ------ ------ ----------- - 0 2 Volume Signature - 2 4 Creation Date - 6 4 Last Modification Date - 10 2 Volume Attributes - 12 2 Number of Files In Root Directory - 14 2 First Block of Volume Bitmap - ... - - Links: - http://developer.apple.com/documentation/mac/Files/Files-99.html - http://developer.apple.com/documentation/mac/Files/Files-100.html - http://developer.apple.com/documentation/mac/Files/Files-101.html - http://developer.apple.com/documentation/mac/Files/Files-102.html - http://developer.apple.com/documentation/mac/Files/Files-103.html - http://developer.apple.com/documentation/mac/Files/Files-104.html - http://developer.apple.com/documentation/mac/Files/Files-105.html - http://developer.apple.com/documentation/mac/Files/Files-106.html - http://developer.apple.com/documentation/mac/Devices/Devices-121.html#MARKER-2-169 - http://developer.apple.com/documentation/mac/MoreToolbox/MoreToolbox-99.html - -*****************************************************************************/ - -#include <ctype.h> -#include <string.h> -#include <time.h> -#include <limits.h> -#include <stddef.h> - -#include "formats/imageutl.h" -#include "imgtool.h" -#include "macutil.h" -#include "iflopimg.h" -#include "formats/ap_dsk35.h" - -/* if 1, check consistency of B-Tree (most of the checks will eventually be - suppressed when the image is opened as read-only and only enabled when - the image is opened as read/write) */ -#define BTREE_CHECKS 1 -/* if 1, check consistency of tag data when we are at risk of corrupting the - disk (file write and allocation) */ -#define TAG_CHECKS 1 -/* if 1, check consistency of tag data when reading files (not recommended - IMHO) */ -#define TAG_EXTRA_CHECKS 0 - -#if 0 -#pragma mark MISCELLANEOUS UTILITIES -#endif - -struct UINT16BE -{ - uint8_t bytes[2]; -}; - -struct UINT24BE -{ - uint8_t bytes[3]; -}; - -struct UINT32BE -{ - uint8_t bytes[4]; -}; - -static inline uint16_t get_UINT16BE(UINT16BE word) -{ - return (word.bytes[0] << 8) | word.bytes[1]; -} - -static inline void set_UINT16BE(UINT16BE *word, uint16_t data) -{ - word->bytes[0] = (data >> 8) & 0xff; - word->bytes[1] = data & 0xff; -} - -#if 0 -static inline uint32_t get_UINT24BE(UINT24BE word) -{ - return (word.bytes[0] << 16) | (word.bytes[1] << 8) | word.bytes[2]; -} - -static inline void set_UINT24BE(UINT24BE *word, uint32_t data) -{ - word->bytes[0] = (data >> 16) & 0xff; - word->bytes[1] = (data >> 8) & 0xff; - word->bytes[2] = data & 0xff; -} -#endif - -static inline uint32_t get_UINT32BE(UINT32BE word) -{ - return (word.bytes[0] << 24) | (word.bytes[1] << 16) | (word.bytes[2] << 8) | word.bytes[3]; -} - -static inline void set_UINT32BE(UINT32BE *word, uint32_t data) -{ - word->bytes[0] = (data >> 24) & 0xff; - word->bytes[1] = (data >> 16) & 0xff; - word->bytes[2] = (data >> 8) & 0xff; - word->bytes[3] = data & 0xff; -} - -/* - Macintosh string: first byte is length -*/ -typedef uint8_t mac_str27[28]; -typedef uint8_t mac_str31[32]; -typedef uint8_t mac_str63[64]; -typedef uint8_t mac_str255[256]; - -/* - Macintosh type/creator code: 4 char value -*/ -typedef UINT32BE mac_type; - -/* - point record, with the y and x coordinates -*/ -struct mac_point -{ - UINT16BE v; /* actually signed */ - UINT16BE h; /* actually signed */ -}; - -/* - rect record, with the corner coordinates -*/ -struct mac_rect -{ - UINT16BE top; /* actually signed */ - UINT16BE left; /* actually signed */ - UINT16BE bottom;/* actually signed */ - UINT16BE right; /* actually signed */ -}; - -/* - FInfo (Finder file info) record -*/ -struct mac_FInfo -{ - mac_type type; /* file type */ - mac_type creator; /* file creator */ - UINT16BE flags; /* Finder flags */ - mac_point location; /* file's location in window */ - /* If set to {0, 0}, and the inited flag is - clear, the Finder will place the item - automatically */ - UINT16BE fldr; /* MFS: window that contains file */ - /* -3: trash */ - /* -2: desktop */ - /* -1: new folder template?????? */ - /* 0: disk window ("root") */ - /* > 0: specific folder, index of FOBJ resource??? */ - /* The FOBJ resource contains some folder info; - the name of the resource is the folder name. */ - /* HFS & HFS+: - System 7: The window in which the file???s icon appears - System 8: reserved (set to 0) */ -}; - -/* - FXInfo (Finder extended file info) record -- not found in MFS -*/ -struct mac_FXInfo -{ - UINT16BE iconID; /* System 7: An ID number for the file???s icon; the - numbers that identify icons are assigned by the - Finder */ - /* System 8: Reserved (set to 0) */ - UINT16BE reserved[3]; /* Reserved (set to 0) */ - uint8_t script; /* System 7: if high-bit is set, the script code - for displaying the file name; ignored otherwise */ - /* System 8: Extended flags MSB(?) */ - uint8_t XFlags; /* Extended flags */ - UINT16BE comment; /* System 7: Comment ID if high-bit is clear */ - /* System 8: Reserved (set to 0) */ - UINT32BE putAway; /* Put away folder ID (i.e. if the user moves the - file onto the desktop, the directory ID of the - folder from which the user moves the file is - saved here) */ -}; - -/* - DInfo (Finder folder info) record -- not found in MFS -*/ -struct mac_DInfo -{ - mac_rect rect; /* Folder's window bounds */ - UINT16BE flags; /* Finder flags, e.g. kIsInvisible, kNameLocked, etc */ - mac_point location; /* Location of the folder in parent window */ - /* If set to {0, 0}, and the initied flag is - clear, the Finder will place the item - automatically */ - UINT16BE view; /* System 7: The manner in which folders are - displayed */ - /* System 8: reserved (set to 0) */ -}; - -/* - DXInfo (Finder extended folder info) record -- not found in MFS -*/ -struct mac_DXInfo -{ - mac_point scroll; /* Scroll position */ - UINT32BE openChain; /* System 7: chain of directory IDs for open folders */ - /* System 8: reserved (set to 0) */ - uint8_t script; /* System 7: if high-bit is set, the script code - for displaying the folder name; ignored otherwise */ - /* System 8: Extended flags MSB(?) */ - uint8_t XFlags; /* Extended flags */ - UINT16BE comment; /* System 7: Comment ID if high-bit is clear */ - /* System 8: Reserved (set to 0) */ - UINT32BE putAway; /* Put away folder ID (i.e. if the user moves the - folder onto the desktop, the directory ID of - the folder from which the user moves it is - saved here) */ -}; - -/* - defines for FInfo & DInfo flags fields -*/ -enum -{ - fif_isOnDesk = 0x0001, /* System 6: set if item is located on desktop (files and folders) */ - /* System 7: Unused (set to 0) */ - fif_color = 0x000E, /* color coding (files and folders) */ - fif_colorReserved = 0x0010, /* System 6: reserved??? */ - /* System 7: Unused (set to 0) */ - fif_requiresSwitchLaunch= 0x0020, /* System 6: ??? */ - /* System 7: Unused (set to 0) */ - fif_isShared = 0x0040, /* Applications files: if set, the */ - /* application can be executed by */ - /* multiple users simultaneously. */ - /* Otherwise, set to 0. */ - fif_hasNoINITs = 0x0080, /* Extensions/Control Panels: if set(?), */ - /* this file contains no INIT */ - /* resource */ - /* Otherwise, set to 0. */ - fif_hasBeenInited = 0x0100, /* System 6: The Finder has recorded information from - the file???s bundle resource into the desktop - database and given the file or folder a - position on the desktop. */ - /* System 7? 8?: Clear if the file contains desktop database */ - /* resources ('BNDL', 'FREF', 'open', 'kind'...) */ - /* that have not been added yet. Set only by the Finder */ - /* Reserved for folders - make sure this bit is cleared for folders */ - - /* bit 0x0200 was at a point (AOCE for system 7.x?) the letter bit for - AOCE, but was reserved before and it is reserved again in recent MacOS - releases. */ - - fif_hasCustomIcon = 0x0400, /* (files and folders) */ - fif_isStationery = 0x0800, /* System 7: (files only) */ - fif_nameLocked = 0x1000, /* (files and folders) */ - fif_hasBundle = 0x2000, /* Files only */ - fif_isInvisible = 0x4000, /* (files and folders) */ - fif_isAlias = 0x8000 /* System 7: (files only) */ -}; - -/* - mac_to_c_strncpy() - - Encode a macintosh string as a C string. The NUL character is escaped, - using the "%00" sequence. To avoid any ambiguity, '%' is escaped with - '%25'. - - dst (O): C string - n (I): length of buffer pointed to by dst - src (I): macintosh string (first byte is length) -*/ -static void mac_to_c_strncpy(char *dst, int n, uint8_t *src) -{ - size_t len = src[0]; - int i, j; - - i = j = 0; - while ((i < len) && (j < n-1)) - { - switch (src[i+1]) - { - case '\0': - if (j >= n-3) - goto exit; - dst[j] = '%'; - dst[j+1] = '0'; - dst[j+2] = '0'; - j += 3; - break; - - case '%': - if (j >= n-3) - goto exit; - dst[j] = '%'; - dst[j+1] = '2'; - dst[j+2] = '5'; - j += 3; - break; - - default: - dst[j] = src[i+1]; - j++; - break; - } - i++; - } - -exit: - if (n > 0) - dst[j] = '\0'; -} - -/* - c_to_mac_strncpy() - - Decode a C string to a macintosh string. The NUL character is escaped, - using the "%00" sequence. To avoid any ambiguity, '%' is escaped with - '%25'. - - dst (O): macintosh string (first byte is length) - src (I): C string - n (I): length of string pointed to by src -*/ -static void c_to_mac_strncpy(mac_str255 dst, const char *src, int n) -{ - size_t len; - int i; - char buf[3]; - - - len = 0; - i = 0; - while ((i < n) && (len < 255)) - { - switch (src[i]) - { - case '%': - if (i >= n-2) - goto exit; - buf[0] = src[i+1]; - buf[1] = src[i+2]; - buf[2] = '\0'; - dst[len+1] = strtoul(buf, NULL, 16); - i += 3; - break; - - default: - dst[len+1] = src[i]; - i++; - break; - } - len++; - } - -exit: - dst[0] = len; -} - -/* - mac_strcmp() - - Compare two macintosh strings - - s1 (I): the string to compare - s2 (I): the comparison string - - Return a zero if s1 and s2 are equal, a negative value if s1 is less than - s2, and a positive value if s1 is greater than s2. -*/ -#ifdef UNUSED_FUNCTION -static int mac_strcmp(const uint8_t *s1, const uint8_t *s2) -{ - size_t common_len; - - common_len = (s1[0] <= s2[0]) ? s1[0] : s2[0]; - - return memcmp(s1+1, s2+1, common_len) || ((int)s1[0] - s2[0]); -} -#endif - -/* - mac_stricmp() - - Compare two macintosh strings in a manner compatible with the macintosh HFS - file system. - - This functions emulates the way HFS (and MFS???) sorts string: this is - equivalent to the RelString macintosh toolbox call with the caseSensitive - parameter as false and the diacSensitive parameter as true. - - s1 (I): the string to compare - s2 (I): the comparison string - - Return a zero if s1 and s2 are equal, a negative value if s1 is less than - s2, and a positive value if s1 is greater than s2. - -Known issues: - Using this function makes sense with the MacRoman encoding, as it means the - computer will regard "DeskTop File", "Desktop File", "Desktop file", etc, - as the same file. (UNIX users will probably regard this as an heresy, but - you must consider that, unlike UNIX, the Macintosh was not designed for - droids, but error-prone human beings that may forget about case.) - - (Also, letters with diatrical signs follow the corresponding letters - without diacritical signs in the HFS catalog file. This does not matter, - though, since the Finder will not display files in the HFS catalog order, - but it will instead sort files according to whatever order is currently - selected in the View menu.) - - However, with other text encodings, the behavior will be completely absurd. - For instance, with the Greek encoding, it will think that the degree symbol - is the same letter (with different case) as the upper-case Psi, so that if - a program asks for a file called "90??" on a greek HFS volume, and there is - a file called "90??" on this volume, file "90??" will be opened. - Results will probably be even weirder with 2-byte scripts like Japanese or - Chinese. Of course, we are not going to fix this issue, since doing so - would break the compatibility with the original Macintosh OS. -*/ - -static int mac_stricmp(const uint8_t *s1, const uint8_t *s2) -{ - static const unsigned char mac_char_sort_table[256] = - { - /* \x00 \x01 \x02 \x03 \x04 \x05 \x06 \x07 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - /* \x08 \x09 \x0a \x0b \x0c \x0d \x0e \x0f */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - /* \x10 \x11 \x12 \x13 \x14 \x15 \x16 \x17 */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - /* \x18 \x19 \x1a \x1b \x1c \x1d \x1e \x1f */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - /* \x20 \x21 \x22 \x23 \x24 \x25 \x26 \x27 */ - 0x20, 0x21, 0x22, 0x27, 0x28, 0x29, 0x2a, 0x2b, - /* \x28 \x29 \x2a \x2b \x2c \x2d \x2e \x2f */ - 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, - /* \x30 \x31 \x32 \x33 \x34 \x35 \x36 \x37 */ - 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, - /* \x38 \x39 \x3a \x3b \x3c \x3d \x3e \x3f */ - 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, - /* \x40 \x41 \x42 \x43 \x44 \x45 \x46 \x47 */ - 0x46, 0x47, 0x51, 0x52, 0x54, 0x55, 0x5a, 0x5b, - /* \x48 \x49 \x4a \x4b \x4c \x4d \x4e \x4f */ - 0x5c, 0x5d, 0x62, 0x63, 0x64, 0x65, 0x66, 0x68, - /* \x50 \x51 \x52 \x53 \x54 \x55 \x56 \x57 */ - 0x71, 0x72, 0x73, 0x74, 0x76, 0x77, 0x7c, 0x7d, - /* \x58 \x59 \x5a \x5b \x5c \x5d \x5e \x5f */ - 0x7e, 0x7f, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, - /* \x60 \x61 \x62 \x63 \x64 \x65 \x66 \x67 */ - 0x4d, 0x47, 0x51, 0x52, 0x54, 0x55, 0x5a, 0x5b, - /* \x68 \x69 \x6a \x6b \x6c \x6d \x6e \x6f */ - 0x5c, 0x5d, 0x62, 0x63, 0x64, 0x65, 0x66, 0x68, - /* \x70 \x71 \x72 \x73 \x74 \x75 \x76 \x77 */ - 0x71, 0x72, 0x73, 0x74, 0x76, 0x77, 0x7c, 0x7d, - /* \x78 \x79 \x7a \x7b \x7c \x7d \x7e \x7f */ - 0x7e, 0x7f, 0x81, 0x87, 0x88, 0x89, 0x8a, 0x8b, - /* \x80 \x81 \x82 \x83 \x84 \x85 \x86 \x87 */ - 0x49, 0x4b, 0x53, 0x56, 0x67, 0x69, 0x78, 0x4e, - /* \x88 \x89 \x8a \x8b \x8c \x8d \x8e \x8f */ - 0x48, 0x4f, 0x49, 0x4a, 0x4b, 0x53, 0x56, 0x57, - /* \x90 \x91 \x92 \x93 \x94 \x95 \x96 \x97 */ - 0x58, 0x59, 0x5e, 0x5f, 0x60, 0x61, 0x67, 0x6d, - /* \x98 \x99 \x9a \x9b \x9c \x9d \x9e \x9f */ - 0x6e, 0x6f, 0x69, 0x6a, 0x79, 0x7a, 0x7b, 0x78, - /* \xa0 \xa1 \xa2 \xa3 \xa4 \xa5 \xa6 \xa7 */ - 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x75, - /* \xa8 \xa9 \xaa \xab \xac \xad \xae \xaf */ - 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x4c, 0x6b, - /* \xb0 \xb1 \xb2 \xb3 \xb4 \xb5 \xb6 \xb7 */ - 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, - /* \xb8 \xb9 \xba \xbb \xbc \xbd \xbe \xbf */ - 0xa1, 0xa2, 0xa3, 0x50, 0x70, 0xa4, 0x4c, 0x6b, - /* \xc0 \xc1 \xc2 \xc3 \xc4 \xc5 \xc6 \xc7 */ - 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0x25, - /* \xc8 \xc9 \xca \xcb \xcc \xcd \xce \xcf */ - 0x26, 0xac, 0x20, 0x48, 0x4a, 0x6a, 0x6c, 0x6c, - /* \xd0 \xd1 \xd2 \xd3 \xd4 \xd5 \xd6 \xd7 */ - 0xad, 0xae, 0x23, 0x24, 0x2c, 0x2d, 0xaf, 0xb0, - /* \xd8 \xd9 \xda \xdb \xdc \xdd \xde \xdf */ - 0x80, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, - /* \xe0 \xe1 \xe2 \xe3 \xe4 \xe5 \xe6 \xe7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, - /* \xe8 \xe9 \xea \xeb \xec \xed \xee \xef */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - /* \xf0 \xf1 \xf2 \xf3 \xf4 \xf5 \xf6 \xf7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, - /* \xf8 \xf9 \xfa \xfb \xfc \xfd \xfe \xff */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7 - }; - - size_t common_len; - int i; - int c1, c2; - - common_len = (s1[0] <= s2[0]) ? s1[0] : s2[0]; - - for (i=0; i<common_len; i++) - { - c1 = mac_char_sort_table[s1[i+1]]; - c2 = mac_char_sort_table[s2[i+1]]; - if (c1 != c2) - return c1 - c2; - } - - return ((int)s1[0] - s2[0]); -} - -/* - mac_strcpy() - - Copy a macintosh string - - dst (O): dest macintosh string - src (I): source macintosh string (first byte is length) - - Return a zero if s1 and s2 are equal, a negative value if s1 is less than - s2, and a positive value if s1 is greater than s2. -*/ -static inline void mac_strcpy(uint8_t *dest, const uint8_t *src) -{ - memcpy(dest, src, src[0]+1); -} - -#ifdef UNUSED_FUNCTION -/* - mac_strncpy() - - Copy a macintosh string - - dst (O): dest macintosh string - n (I): max string length for dest (range 0-255, buffer length + 1) - src (I): source macintosh string (first byte is length) -*/ -static void mac_strncpy(uint8_t *dest, int n, const uint8_t *src) -{ - size_t len; - - len = src[0]; - if (len > n) - len = n; - dest[0] = len; - memcpy(dest+1, src+1, len); -} -#endif - -/* - disk image reference -*/ -struct mac_l1_imgref -{ - imgtool::image *image; - uint32_t heads; -}; - - - -static imgtoolerr_t mac_find_block(mac_l1_imgref *image, int block, - uint32_t *track, uint32_t *head, uint32_t *sector) -{ - *track = 0; - while(block >= (apple35_sectors_per_track(imgtool_floppy(*image->image), *track) * image->heads)) - { - block -= (apple35_sectors_per_track(imgtool_floppy(*image->image), (*track)++) * image->heads); - if (*track >= 80) - return IMGTOOLERR_SEEKERROR; - } - - *head = block / apple35_sectors_per_track(imgtool_floppy(*image->image), *track); - *sector = block % apple35_sectors_per_track(imgtool_floppy(*image->image), *track); - return IMGTOOLERR_SUCCESS; -} - - - -/* - image_read_block() - - Read one 512-byte block of data from a macintosh disk image - - image (I/O): level-1 image reference - block (I): address of block to read - dest (O): buffer where block data should be stored - - Return imgtool error code -*/ -static imgtoolerr_t image_read_block(mac_l1_imgref *image, uint32_t block, void *dest) -{ - imgtoolerr_t err; - floperr_t ferr; - uint32_t track, head, sector; - - err = mac_find_block(image, block, &track, &head, §or); - if (err) - return err; - - ferr = floppy_read_sector(imgtool_floppy(*image->image), head, track, sector, 0, dest, 512); - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - -/* - image_write_block() - - Read one 512-byte block of data from a macintosh disk image - - image (I/O): level-1 image reference - block (I): address of block to write - src (I): buffer with the block data - - Return imgtool error code -*/ -static imgtoolerr_t image_write_block(mac_l1_imgref *image, uint32_t block, const void *src) -{ - imgtoolerr_t err; - floperr_t ferr; - uint32_t track, head, sector; - - err = mac_find_block(image, block, &track, &head, §or); - if (err) - return err; - - ferr = floppy_write_sector(imgtool_floppy(*image->image), head, track, sector, 0, src, 512, 0); /* TODO: pass ddam argument from imgtool */ - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - -/* - image_get_tag_len() - - Get length of tag data (12 for GCR floppies, 20 for HD20, 0 otherwise) - - image (I/O): level-1 image reference - - Return tag length -*/ -static inline int image_get_tag_len(mac_l1_imgref *image) -{ - return 0; -} - - - -/* - image_read_tag() - - Read a 12- or 20-byte tag record associated with a disk block - - image (I/O): level-1 image reference - block (I): address of block to read - dest (O): buffer where tag data should be stored - - Return imgtool error code -*/ -static imgtoolerr_t image_read_tag(mac_l1_imgref *image, uint32_t block, void *dest) -{ - return IMGTOOLERR_UNEXPECTED; -} - -/* - image_write_tag() - - Write a 12- or 20-byte tag record associated with a disk block - - image (I/O): level-1 image reference - block (I): address of block to write - src (I): buffer with the tag data - - Return imgtool error code -*/ -static imgtoolerr_t image_write_tag(mac_l1_imgref *image, uint32_t block, const void *src) -{ - return IMGTOOLERR_UNEXPECTED; -} - -#if 0 -#pragma mark - -#pragma mark MFS/HFS WRAPPERS -#endif - -enum mac_format -{ - L2I_MFS, - L2I_HFS -}; - -enum mac_forkID { data_fork = 0x00, rsrc_fork = 0xff }; - -/* - MFS image ref -*/ -struct mfs_l2_imgref -{ - uint16_t dir_num_files; - uint16_t dir_start; - uint16_t dir_blk_len; - - uint16_t ABStart; - - mac_str27 volname; - - unsigned char ABlink_dirty[13]; /* dirty flag for each disk block in the ABlink array */ - uint8_t ABlink[6141]; -}; - -/* - HFS extent descriptor -*/ -struct hfs_extent -{ - UINT16BE stABN; /* first allocation block */ - UINT16BE numABlks; /* number of allocation blocks */ -}; - -/* - HFS likes to group extents by 3 (it is 8 with HFS+), so we create a - specific type. -*/ -typedef hfs_extent hfs_extent_3[3]; - -/* - MFS open file ref -*/ -struct mfs_fileref -{ - uint16_t stBlk; /* first allocation block of file */ -}; - -/* - HFS open file ref -*/ -struct hfs_fileref -{ - hfs_extent_3 extents; /* first 3 file extents */ - - uint32_t parID; /* CNID of parent directory (undefined for extent & catalog files) */ - mac_str31 filename; /* file name (undefined for extent & catalog files) */ -}; - -struct mac_l2_imgref; - -/* - MFS/HFS open file ref -*/ -struct mac_fileref -{ - struct mac_l2_imgref *l2_img; /* image pointer */ - - uint32_t fileID; /* file ID (a.k.a. CNID in HFS/HFS+) */ - - mac_forkID forkType; /* 0x00 for data, 0xff for resource */ - - uint32_t eof; /* logical end-of-file */ - uint32_t pLen; /* physical end-of-file */ - - uint32_t crPs; /* current position in file */ - - uint8_t reload_buf; - uint8_t block_buffer[512]; /* buffer with current file block */ - - union - { - mfs_fileref mfs; - hfs_fileref hfs; - }; -}; - -/* - open BT ref -*/ -struct mac_BTref -{ - struct mac_fileref fileref; /* open B-tree file ref */ - - uint16_t nodeSize; /* size of a node, in bytes */ - uint32_t rootNode; /* node number of root node */ - uint32_t firstLeafNode; /* node number of first leaf node */ - uint32_t attributes; /* persistent attributes about the tree */ - uint16_t treeDepth; /* maximum height (usually leaf nodes) */ - uint16_t maxKeyLength; /* maximum key length */ - - /* function to compare keys during tree searches */ - int (*key_compare_func)(const void *key1, const void *key2); - - void *node_buf; /* current node buffer */ -}; - -/* - Constants for BTHeaderRec attributes field -*/ -enum -{ - btha_badCloseMask = 0x00000001, /* reserved */ - btha_bigKeysMask = 0x00000002, /* key length field is 16 bits */ - btha_variableIndexKeysMask = 0x00000004 /* keys in index nodes are variable length */ -}; - -/* - HFS image ref -*/ -struct hfs_l2_imgref -{ - uint16_t VBM_start; - - uint16_t ABStart; - - mac_str27 volname; - - mac_BTref extents_BT; - mac_BTref cat_BT; - - uint8_t VBM[8192]; -}; - -/* - MFS/HFS image ref -*/ -struct mac_l2_imgref -{ - mac_l1_imgref l1_img; - - uint16_t numABs; - uint16_t blocksperAB; - - uint16_t freeABs; - - uint32_t nxtCNID; /* nxtFNum in MFS, nxtCNID in HFS */ - - mac_format format; - union - { - mfs_l2_imgref mfs; - hfs_l2_imgref hfs; - } u; -}; - -/* - MFS Master Directory Block -*/ -struct mfs_mdb -{ - uint8_t sigWord[2]; /* volume signature - always $D2D7 */ - UINT32BE crDate; /* date and time of volume creation */ - UINT32BE lsMod/*lsBkUp???*/;/* date and time of last modification (backup???) */ - UINT16BE atrb; /* volume attributes (0x0000) */ - /* bit 15 is set if volume is locked by software */ - UINT16BE nmFls; /* number of files in directory */ - UINT16BE dirSt; /* first block of directory */ - - UINT16BE blLn; /* length of directory in blocks (0x000C) */ - UINT16BE nmAlBlks; /* number of allocation blocks in volume (0x0187) */ - UINT32BE alBlkSiz; /* size (in bytes) of allocation blocks (0x00000400) */ - UINT32BE clpSiz; /* default clump size - number of bytes to allocate - when a file grows (0x00002000) */ - UINT16BE alBlSt; /* first allocation block in volume (0x0010) */ - - UINT32BE nxtFNum; /* next unused file number */ - UINT16BE freeABs; /* number of unused allocation blocks */ - - mac_str27 VN; /* volume name */ - - uint8_t ABlink[512-64];/* Link array for file ABs. Array of nmAlBlks - 12-bit-long entries, indexed by AB address. If an - AB belongs to no file, the entry is 0; if an AB is - the last in any file, the entry is 1; if an AB - belongs to a file and is not the last one, the - entry is the AB address of the next file AB plus 1. - Note that the array extends on as many consecutive - disk blocks as needed (usually the MDB block plus - the next one). Incidentally, this array is not - saved in the secondary MDB: presumably, the idea - was that the disk utility could rely on the tag - data to rebuild the link array if it should ever - be corrupted. */ -}; - -/* - HFS Master Directory Block -*/ -struct hfs_mdb -{ -/* First fields are similar to MFS, though several fields have a different meaning */ - uint8_t sigWord[2]; /* volume signature - always $D2D7 */ - UINT32BE crDate; /* date and time of volume creation */ - UINT32BE lsMod; /* date and time of last modification */ - UINT16BE atrb; /* volume attributes (0x0000) */ - /* bit 15 is set if volume is locked by software */ - UINT16BE nmFls; /* number of files in root folder */ - UINT16BE VBMSt; /* first block of volume bitmap */ - UINT16BE allocPtr; /* start of next allocation search */ - - UINT16BE nmAlBlks; /* number of allocation blocks in volume */ - UINT32BE alBlkSiz; /* size (in bytes) of allocation blocks */ - UINT32BE clpSiz; /* default clump size - number of bytes to allocate - when a file grows */ - UINT16BE alBlSt; /* first allocation block in volume (0x0010) */ - UINT32BE nxtCNID; /* next unused catalog node ID */ - UINT16BE freeABs; /* number of unused allocation blocks */ - mac_str27 VN; /* volume name */ - -/* next fields are HFS-specific */ - - UINT32BE volBkUp; /* date and time of last backup */ - UINT16BE vSeqNum; /* volume backup sequence number */ - UINT32BE wrCnt; /* volume write count */ - UINT32BE xtClpSiz; /* clump size for extents overflow file */ - UINT32BE ctClpSiz; /* clump size for catalog file */ - UINT16BE nmRtDirs; /* number of directories in root folder */ - UINT32BE filCnt; /* number of files in volume */ - UINT32BE dirCnt; /* number of directories in volume */ - uint8_t fndrInfo[32]; /* information used by the Finder */ - - union - { - struct - { - UINT16BE VCSize; /* size (in blocks) of volume cache */ - UINT16BE VBMCSize; /* size (in blocks) of volume bitmap cache */ - UINT16BE ctlCSize; /* size (in blocks) of common volume cache */ - }; - struct - { - UINT16BE embedSigWord; /* embedded volume signature */ - hfs_extent embedExtent; /* embedded volume location and size */ - } v2; - } u; - - UINT32BE xtFlSize; /* size (in bytes) of extents overflow file */ - hfs_extent_3 xtExtRec; /* extent record for extents overflow file */ - UINT32BE ctFlSize; /* size (in bytes) of catalog file */ - hfs_extent_3 ctExtRec; /* extent record for catalog file */ -}; - -/* to save a little stack space, we use the same buffer for MDB and next blocks */ -union img_open_buf -{ - struct mfs_mdb mfs_mdb; - struct hfs_mdb hfs_mdb; - uint8_t raw[512]; -}; - -/* - Information extracted from catalog/directory -*/ -struct mac_dirent -{ - uint16_t dataRecType; /* type of data record */ - - mac_FInfo flFinderInfo; /* information used by the Finder */ - mac_FXInfo flXFinderInfo; /* information used by the Finder */ - - uint8_t flags; /* bit 0=1 if file locked */ - - uint32_t fileID; /* file ID in directory/catalog */ - - uint32_t dataLogicalSize; /* logical EOF of data fork */ - uint32_t dataPhysicalSize; /* physical EOF of data fork */ - uint32_t rsrcLogicalSize; /* logical EOF of resource fork */ - uint32_t rsrcPhysicalSize; /* physical EOF of resource fork */ - - uint32_t createDate; /* date and time of creation */ - uint32_t modifyDate; /* date and time of last modification */ -}; - -/* - Tag record for GCR floppies (12 bytes) - - And, no, I don't know the format of the 20-byte tag record of the HD20 -*/ -struct floppy_tag_record -{ - UINT32BE fileID; /* a.k.a. CNID */ - /* a value of 1 seems to be the default for non-AB blocks, but this is not consistent */ - uint8_t ftype; /* bit 1 = 1 if resource fork */ - /* bit 0 = 1 if block is allocated to user file (i.e. it is not - in HFS extent & catalog, and not in non-AB blocks such - as MDB and MFS directory)??? */ - /* bit 7 seems to be used, but I don't know what it means */ - /* a value of $FF seems to be the default for non-AB blocks, but this is not consistent */ - uint8_t fattr; /* bit 0 = 1 if locked(?) */ - /* a value of $FF seems to be the default for non-AB blocks, but this is not consistent */ - UINT16BE fblock; /* relative file block number (enough for any volume up to 32 MBytes in size) */ - UINT32BE wrCnt; /* MFS: date and time of last write */ - /* HFS: seems related to the wrCnt field in the mdb, i.e. - each time a volume is written to, the current value of - wrCnt is written in the tag field, then it is incremented */ - /* (DV17 says "disk block number", but it cannot be true) */ -}; - -#ifdef UNUSED_FUNCTION -static void hfs_image_close(struct mac_l2_imgref *l2_img); -#endif -static imgtoolerr_t mfs_file_get_nth_block_address(struct mac_fileref *fileref, uint32_t block_num, uint32_t *block_address); -static imgtoolerr_t hfs_file_get_nth_block_address(struct mac_fileref *fileref, uint32_t block_num, uint32_t *block_address); -static imgtoolerr_t mfs_lookup_path(struct mac_l2_imgref *l2_img, const char *fpath, mac_str255 filename, mac_dirent *cat_info, int create_it); -static imgtoolerr_t hfs_lookup_path(struct mac_l2_imgref *l2_img, const char *fpath, uint32_t *parID, mac_str255 filename, mac_dirent *cat_info); -static imgtoolerr_t mfs_file_open(struct mac_l2_imgref *l2_img, const mac_str255 filename, mac_forkID fork, struct mac_fileref *fileref); -static imgtoolerr_t hfs_file_open(struct mac_l2_imgref *l2_img, uint32_t parID, const mac_str255 filename, mac_forkID fork, struct mac_fileref *fileref); -static imgtoolerr_t mfs_file_setABeof(struct mac_fileref *fileref, uint32_t newABeof); -static imgtoolerr_t mfs_dir_update(struct mac_fileref *fileref); - -static struct mac_l2_imgref *get_imgref(imgtool::image &img) -{ - return (struct mac_l2_imgref *) imgtool_floppy_extrabytes(img); -} - - -#ifdef UNUSED_FUNCTION -/* - mac_image_close - - Close a macintosh image. - - l2_img (I/O): level-2 image reference -*/ -static void mac_image_close(struct mac_l2_imgref *l2_img) -{ - switch (l2_img->format) - { - case L2I_MFS: - break; - - case L2I_HFS: - hfs_image_close(l2_img); - break; - } -} -#endif - -/* - mac_lookup_path - - Resolve a file path, and translate it to a parID + filename pair that enables - to do an efficient file search on a HFS volume (and an inefficient one on - MFS, but it is not an issue as MFS volumes typically have a few dozens - files, vs. possibly thousands with HFS volumes). - - l2_img (I/O): level-2 image reference - fpath (I): file path (C string) - parID (O): set to the CNID of the parent directory if the volume is in HFS - format (reserved for MFS volumes) - filename (O): set to the actual name of the file, with capitalization matching - the one on the volume rather than the one in the fpath parameter (Mac - string) - cat_info (O): catalog info for this file extracted from the catalog file - (may be NULL) - - Return imgtool error code -*/ -static imgtoolerr_t mac_lookup_path(struct mac_l2_imgref *l2_img, const char *fpath, uint32_t *parID, mac_str255 filename, mac_dirent *cat_info, int create_it) -{ - imgtoolerr_t err = IMGTOOLERR_UNEXPECTED; - - switch (l2_img->format) - { - case L2I_MFS: - *parID = 0; - err = mfs_lookup_path(l2_img, fpath, filename, cat_info, create_it); - break; - - case L2I_HFS: - err = hfs_lookup_path(l2_img, fpath, parID, filename, cat_info); - break; - } - return err; -} - -/* - mac_file_open - - Open a file located on a macintosh image - - l2_img (I/O): level-2 image reference - parID (I): CNID of the parent directory if the volume is in HFS format - (reserved for MFS volumes) - filename (I): name of the file (Mac string) - mac_forkID (I): tells which fork should be opened - fileref (O): mac file reference to open - - Return imgtool error code -*/ -static imgtoolerr_t mac_file_open(struct mac_l2_imgref *l2_img, uint32_t parID, const mac_str255 filename, mac_forkID fork, struct mac_fileref *fileref) -{ - switch (l2_img->format) - { - case L2I_MFS: - return mfs_file_open(l2_img, filename, fork, fileref); - - case L2I_HFS: - return hfs_file_open(l2_img, parID, filename, fork, fileref); - } - - return IMGTOOLERR_UNEXPECTED; -} - -/* - mac_file_read - - Read data from an open mac file, starting at current position in file - - fileref (I/O): mac file reference - len (I): number of bytes to read - dest (O): destination buffer - - Return imgtool error code -*/ -static imgtoolerr_t mac_file_read(struct mac_fileref *fileref, uint32_t len, void *dest) -{ - uint32_t block = 0; - floppy_tag_record tag; - int run_len; - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - - if ((fileref->crPs + len) > fileref->eof) - /* EOF */ - return IMGTOOLERR_UNEXPECTED; - - while (len > 0) - { - if (fileref->reload_buf) - { - switch (fileref->l2_img->format) - { - case L2I_MFS: - err = mfs_file_get_nth_block_address(fileref, fileref->crPs/512, &block); - break; - - case L2I_HFS: - err = hfs_file_get_nth_block_address(fileref, fileref->crPs/512, &block); - break; - } - if (err) - return err; - err = image_read_block(&fileref->l2_img->l1_img, block, fileref->block_buffer); - if (err) - return err; - fileref->reload_buf = false; - - if (TAG_EXTRA_CHECKS) - { - /* optional check */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - err = image_read_tag(&fileref->l2_img->l1_img, block, &tag); - if (err) - return err; - - if ((get_UINT32BE(tag.fileID) != fileref->fileID) - || (((tag.ftype & 2) != 0) != (fileref->forkType == rsrc_fork)) - || (get_UINT16BE(tag.fblock) != ((fileref->crPs/512) & 0xffff))) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - } - } - } - run_len = 512 - (fileref->crPs % 512); - if (run_len > len) - run_len = len; - - memcpy(dest, fileref->block_buffer+(fileref->crPs % 512), run_len); - len -= run_len; - dest = (uint8_t *)dest + run_len; - fileref->crPs += run_len; - if ((fileref->crPs % 512) == 0) - fileref->reload_buf = true; - } - - return IMGTOOLERR_SUCCESS; -} - -/* - mac_file_write - - Write data to an open mac file, starting at current position in file - - fileref (I/O): mac file reference - len (I): number of bytes to read - dest (O): destination buffer - - Return imgtool error code -*/ -static imgtoolerr_t mac_file_write(struct mac_fileref *fileref, uint32_t len, const void *src) -{ - uint32_t block = 0; - floppy_tag_record tag; - int run_len; - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - - if ((fileref->crPs + len) > fileref->eof) - /* EOF */ - return IMGTOOLERR_UNEXPECTED; - - while (len > 0) - { - switch (fileref->l2_img->format) - { - case L2I_MFS: - err = mfs_file_get_nth_block_address(fileref, fileref->crPs/512, &block); - break; - - case L2I_HFS: - err = hfs_file_get_nth_block_address(fileref, fileref->crPs/512, &block); - break; - } - if (err) - return err; - - if (TAG_CHECKS) - { - /* optional check */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - err = image_read_tag(&fileref->l2_img->l1_img, block, &tag); - if (err) - return err; - - if ((get_UINT32BE(tag.fileID) != fileref->fileID) - || (((tag.ftype & 2) != 0) != (fileref->forkType == rsrc_fork)) - || (get_UINT16BE(tag.fblock) != ((fileref->crPs/512) & 0xffff))) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - } - } - - if (fileref->reload_buf) - { - err = image_read_block(&fileref->l2_img->l1_img, block, fileref->block_buffer); - if (err) - return err; - fileref->reload_buf = false; - } - run_len = 512 - (fileref->crPs % 512); - if (run_len > len) - run_len = len; - - memcpy(fileref->block_buffer+(fileref->crPs % 512), src, run_len); - err = image_write_block(&fileref->l2_img->l1_img, block, fileref->block_buffer); - if (err) - return err; - /* update tag data */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - if (!TAG_CHECKS) - { - err = image_read_tag(&fileref->l2_img->l1_img, block, &tag); - if (err) - return err; - } - - switch (fileref->l2_img->format) - { - case L2I_MFS: - set_UINT32BE(&tag.wrCnt, mac_time_now()); - break; - - case L2I_HFS: - /*set_UINT32BE(&tag.wrCnt, ++fileref->l2_img.u.hfs.wrCnt);*/ /* ***TODO*** */ - break; - } - - err = image_write_tag(&fileref->l2_img->l1_img, block, &tag); - if (err) - return err; - } - len -= run_len; - src = (const uint8_t *)src + run_len; - fileref->crPs += run_len; - if ((fileref->crPs % 512) == 0) - fileref->reload_buf = true; - } - - return IMGTOOLERR_SUCCESS; -} - -#ifdef UNUSED_FUNCTION -/* - mac_file_tell - - Get current position in an open mac file - - fileref (I/O): mac file reference - filePos (O): current position in file - - Return imgtool error code -*/ -static imgtoolerr_t mac_file_tell(struct mac_fileref *fileref, uint32_t *filePos) -{ - *filePos = fileref->crPs; - - return IMGTOOLERR_SUCCESS; -} -#endif - -/* - mac_file_seek - - Set current position in an open mac file - - fileref (I/O): mac file reference - filePos (I): new position in file - - Return imgtool error code -*/ -static imgtoolerr_t mac_file_seek(struct mac_fileref *fileref, uint32_t filePos) -{ - if ((fileref->crPs / 512) != (filePos / 512)) - fileref->reload_buf = true; - - fileref->crPs = filePos; - - return IMGTOOLERR_SUCCESS; -} - -/* - mac_file_seteof - - Set the position of the EOF in an open mac file - - fileref (I/O): mac file reference - newEof (I): new position of EOF in file - - Return imgtool error code -*/ -static imgtoolerr_t mac_file_seteof(struct mac_fileref *fileref, uint32_t newEof) -{ - uint32_t newABEof; - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - - newABEof = (newEof + fileref->l2_img->blocksperAB * 512 - 1) / (fileref->l2_img->blocksperAB * 512); - -#if 0 - if (fileref->pLen % (fileref->l2_img->blocksperAB * 512)) - return IMGTOOLERR_CORRUPTIMAGE; -#endif - - if (newEof < fileref->eof) - fileref->eof = newEof; - - switch (fileref->l2_img->format) - { - case L2I_MFS: - err = mfs_file_setABeof(fileref, newABEof); - break; - - case L2I_HFS: - err = IMGTOOLERR_UNIMPLEMENTED; - break; - } - if (err) - return err; - - fileref->eof = newEof; - - err = mfs_dir_update(fileref); - if (err) - return err; - - /* update current pos if beyond new EOF */ -#if 0 - if (fileref->crPs > newEof) - { - if ((fileref->crPs / 512) != (newEof / 512)) - fileref->reload_buf = true; - - fileref->crPs = newEof; - } -#endif - - return IMGTOOLERR_SUCCESS; -} - -#if 0 -#pragma mark - -#pragma mark MFS IMPLEMENTATION -#endif - -/* - directory entry for use in the directory file - - Note the structure is variable length. It is always word-aligned, and - cannot cross block boundaries. - - Note that the directory does not seem to be sorted: the order in which - files appear does not match file names, and it does not always match file - IDs. -*/ -struct mfs_dir_entry -{ - uint8_t flags; /* bit 7=1 if entry used, bit 0=1 if file locked */ - /* 0x00 means end of block: if we are not done - with reading the directory, the remnants will - be read from next block */ - uint8_t flVersNum; /* version number (usually 0x00, but I don't - have the IM volume that describes it) */ - mac_FInfo flFinderInfo; /* information used by the Finder */ - - UINT32BE fileID; /* file ID */ - - UINT16BE dataStartBlock; /* first allocation block of data fork */ - UINT32BE dataLogicalSize; /* logical EOF of data fork */ - UINT32BE dataPhysicalSize; /* physical EOF of data fork */ - UINT16BE rsrcStartBlock; /* first allocation block of resource fork */ - UINT32BE rsrcLogicalSize; /* logical EOF of resource fork */ - UINT32BE rsrcPhysicalSize; /* physical EOF of resource fork */ - - UINT32BE createDate; /* date and time of creation */ - UINT32BE modifyDate; /* date and time of last modification */ - - uint8_t name[1]; /* first char is length of file name */ - /* next chars are file name - 255 chars at most */ - /* IIRC, Finder 7 only supports 31 chars, - wheareas earlier versions support 63 chars */ -}; - -/* - FOBJ desktop resource: describes a folder, or the location of the volume - icon. - - In typical Apple manner, this resource is not documented. However, I have - managed to reverse engineer some parts of it. -*/ -struct mfs_FOBJ -{ - uint8_t unknown0[2]; /* $00: $0004 for disk, $0008 for folder??? */ - mac_point location; /* $02: location in parent window */ - uint8_t unknown1[4]; /* $06: ??? */ - uint8_t view; /* $0A: manner in which folders are displayed??? */ - uint8_t unknown2; /* $0B: ??? */ - UINT16BE par_fldr; /* $0C: parent folder ID */ - uint8_t unknown3[10]; /* $0E: ??? */ - UINT16BE unknown4; /* $18: ??? */ - UINT32BE createDate; /* $1A: date and time of creation */ - UINT32BE modifyDate; /* $1E: date and time of last modification */ - UINT16BE unknown5; /* $22: put-away folder ID?????? */ - uint8_t unknown6[8]; /* $24: ??? */ - mac_rect bounds; /* $2C: window bounds */ - mac_point scroll; /* $34: current scroll offset??? */ - union - { /* I think there are two versions of the structure */ - struct - { - UINT16BE item_count; /* number of items (folders and files) in - this folder */ - UINT32BE item_descs[1]; /* this variable-length array has - item_count entries - meaning of entry is unknown */ - } v1; - struct - { - UINT16BE zerofill; /* always 0? */ - UINT16BE unknown0; /* always 0??? */ - UINT16BE item_count; /* number of items (folders and files) in - this folder */ - uint8_t unknown1[20]; /* ??? */ - uint8_t name[1]; /* variable-length macintosh string */ - } v2; - } u; -}; - -/* - MFS open dir ref -*/ -struct mfs_dirref -{ - struct mac_l2_imgref *l2_img; /* image pointer */ - uint16_t index; /* current file index in the disk directory */ - uint16_t cur_block; /* current block offset in directory file */ - uint16_t cur_offset; /* current byte offset in current block of directory file */ - uint8_t block_buffer[512]; /* buffer with current directory block */ -}; - - - -static imgtoolerr_t mfs_image_create(imgtool::image &image, imgtool::stream::ptr &&dummy, util::option_resolution *opts) -{ - imgtoolerr_t err; - uint8_t buffer[512]; - uint32_t heads, tracks, sector_bytes, i; - uint32_t total_disk_blocks, total_allocation_blocks, allocation_block_size; - uint32_t free_allocation_blocks; - - heads = opts->lookup_int('H'); - tracks = opts->lookup_int('T'); - sector_bytes = opts->lookup_int('L'); - - get_imgref(image)->l1_img.image = ℑ - get_imgref(image)->l1_img.heads = heads; - - if (sector_bytes != 512) - return IMGTOOLERR_UNEXPECTED; - - /* computation */ - allocation_block_size = 1024; - total_disk_blocks = 0; - for (i = 0; i < tracks; i++) - total_disk_blocks += heads * apple35_sectors_per_track(imgtool_floppy(image), i) * sector_bytes / 512; - total_allocation_blocks = total_disk_blocks / (allocation_block_size / 512); - free_allocation_blocks = total_allocation_blocks - 3; - - /* write master directory block */ - memset(buffer, 0, sizeof(buffer)); - place_integer_be(buffer, 0, 2, 0xd2d7); /* signature */ - place_integer_be(buffer, 2, 4, mac_time_now()); /* creation date */ - place_integer_be(buffer, 6, 4, mac_time_now()); /* last modified date */ - place_integer_be(buffer, 10, 2, 0); /* volume attributes */ - place_integer_be(buffer, 12, 2, 0); /* number of files in directory */ - place_integer_be(buffer, 14, 2, 4); /* first block of directory */ - place_integer_be(buffer, 16, 2, 12); /* length of directory in blocks */ - place_integer_be(buffer, 18, 2, total_allocation_blocks); /* allocation blocks on volume count */ - place_integer_be(buffer, 20, 4, allocation_block_size); /* allocation block size */ - place_integer_be(buffer, 24, 4, 8192); /* default clumping size */ - place_integer_be(buffer, 28, 2, 16); /* first allocation block on volume */ - place_integer_be(buffer, 30, 4, 2); /* next unused catalog node */ - place_integer_be(buffer, 34, 2, free_allocation_blocks); /* free allocation block count */ - pascal_from_c_string(&buffer[36], 28, "Untitled"); /* volume title */ - - err = image_write_block(&get_imgref(image)->l1_img, 2, buffer); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -/* - mfs_image_open - - Open a MFS image. Image must already be open on level 1. This function - should not be called directly: call mac_image_open() instead. - - l2_img (I/O): level-2 image reference to open (l1_img and format fields - must be initialized) - img_open_buf (I): buffer with the MDB block - - Return imgtool error code -*/ -static imgtoolerr_t mfs_image_open(imgtool::image &image, imgtool::stream::ptr &&dummy) -{ - imgtoolerr_t err; - struct mac_l2_imgref *l2_img; - img_open_buf buf_local; - img_open_buf *buf; - - l2_img = get_imgref(image); - l2_img->l1_img.image = ℑ - l2_img->l1_img.heads = 1; - l2_img->format = L2I_MFS; - - /* read MDB */ - err = image_read_block(&l2_img->l1_img, 2, &buf_local.raw); - if (err) - return err; - buf = &buf_local; - - /* check signature word */ - if ((buf->mfs_mdb.sigWord[0] != 0xd2) || (buf->mfs_mdb.sigWord[1] != 0xd7) - || (buf->mfs_mdb.VN[0] > 27)) - return IMGTOOLERR_CORRUPTIMAGE; - - l2_img->u.mfs.dir_num_files = get_UINT16BE(buf->mfs_mdb.nmFls); - l2_img->u.mfs.dir_start = get_UINT16BE(buf->mfs_mdb.dirSt); - l2_img->u.mfs.dir_blk_len = get_UINT16BE(buf->mfs_mdb.blLn); - - l2_img->numABs = get_UINT16BE(buf->mfs_mdb.nmAlBlks); - if ((get_UINT32BE(buf->mfs_mdb.alBlkSiz) % 512) || (get_UINT32BE(buf->mfs_mdb.alBlkSiz) == 0)) - return IMGTOOLERR_CORRUPTIMAGE; - l2_img->blocksperAB = get_UINT32BE(buf->mfs_mdb.alBlkSiz) / 512; - l2_img->u.mfs.ABStart = get_UINT16BE(buf->mfs_mdb.alBlSt); - - l2_img->nxtCNID = get_UINT32BE(buf->mfs_mdb.nxtFNum); - - l2_img->freeABs = get_UINT16BE(buf->mfs_mdb.freeABs); - - mac_strcpy(l2_img->u.mfs.volname, buf->mfs_mdb.VN); - - if (l2_img->numABs > 4094) - return IMGTOOLERR_CORRUPTIMAGE; - - /* extract link array */ - { - int byte_len = l2_img->numABs + ((l2_img->numABs + 1) >> 1); - int cur_byte; - int cur_block; - int block_len = sizeof(buf->mfs_mdb.ABlink); - - /* clear dirty flags */ - for (cur_block=0; cur_block<13; cur_block++) - l2_img->u.mfs.ABlink_dirty[cur_block] = 0; - - /* append the chunk after MDB to link array */ - cur_byte = 0; - if (block_len > (byte_len - cur_byte)) - block_len = byte_len - cur_byte; - memcpy(l2_img->u.mfs.ABlink+cur_byte, buf->mfs_mdb.ABlink, block_len); - cur_byte += block_len; - cur_block = 2; - while (cur_byte < byte_len) - { - /* read next block */ - cur_block++; - err = image_read_block(&l2_img->l1_img, cur_block, buf->raw); - if (err) - return err; - block_len = 512; - - /* append this block to link array */ - if (block_len > (byte_len - cur_byte)) - block_len = byte_len - cur_byte; - memcpy(l2_img->u.mfs.ABlink+cur_byte, buf->raw, block_len); - cur_byte += block_len; - } - /* check that link array and directory don't overlap */ - if (cur_block >= l2_img->u.mfs.dir_start) - return IMGTOOLERR_CORRUPTIMAGE; - } - - return IMGTOOLERR_SUCCESS; -} - -/* - mfs_update_mdb - - Update MDB on disk - - l2_img (I/O): level-2 image reference - - Return imgtool error code -*/ -static imgtoolerr_t mfs_update_mdb(struct mac_l2_imgref *l2_img) -{ - imgtoolerr_t err; - union - { - struct mfs_mdb mfs_mdb; - uint8_t raw[512]; - } buf; - - assert(l2_img->format == L2I_MFS); - - /* read MDB */ - err = image_read_block(&l2_img->l1_img, 2, &buf.mfs_mdb); - if (err) - return err; - - set_UINT16BE(&buf.mfs_mdb.nmFls, l2_img->u.mfs.dir_num_files); -#if 0 /* these fields are never changed */ - set_UINT16BE(&buf.mfs_mdb.dirSt, l2_img->u.mfs.dir_start); - set_UINT16BE(&buf.mfs_mdb.blLn, l2_img->u.mfs.dir_blk_len); - - set_UINT16BE(&buf.mfs_mdb.nmAlBlks, l2_img->numABs); - set_UINT32BE(&buf.mfs_mdb.alBlkSiz, l2_img->blocksperAB*512); - set_UINT16BE(&buf.mfs_mdb.alBlSt, l2_img->u.mfs.ABStart); -#endif - - set_UINT32BE(&buf.mfs_mdb.nxtFNum, l2_img->nxtCNID); - - set_UINT16BE(&buf.mfs_mdb.freeABs, l2_img->freeABs); - -#if 0 /* these fields are never changed */ - mac_strcpy(buf.mfs_mdb.VN, l2_img->u.mfs.volname); -#endif - - /* save link array */ - { - int byte_len = l2_img->numABs + ((l2_img->numABs + 1) >> 1); - int cur_byte = 0; - int cur_block = 2; - int block_len = sizeof(buf.mfs_mdb.ABlink); - - /* update the chunk of link array after the MDB */ - if (block_len > (byte_len - cur_byte)) - block_len = byte_len - cur_byte; - memcpy(buf.mfs_mdb.ABlink, l2_img->u.mfs.ABlink+cur_byte, block_len); - cur_byte += block_len; - - if (block_len < sizeof(buf.mfs_mdb.ABlink)) - memset(buf.mfs_mdb.ABlink+block_len, 0, sizeof(buf.mfs_mdb.ABlink)-block_len); - - l2_img->u.mfs.ABlink_dirty[0] = 0; - - /* write back modified MDB+link */ - err = image_write_block(&l2_img->l1_img, 2, &buf.mfs_mdb); - if (err) - return err; - - while (cur_byte < byte_len) - { - /* advance to next block */ - cur_block++; - block_len = 512; - - /* extract the current chunk of link array */ - if (block_len > (byte_len - cur_byte)) - block_len = byte_len - cur_byte; - - if (l2_img->u.mfs.ABlink_dirty[cur_block-2]) - { - memcpy(buf.raw, l2_img->u.mfs.ABlink+cur_byte, block_len); - if (block_len < 512) - memset(buf.raw+block_len, 0, 512-block_len); - /* write back link array */ - err = image_write_block(&l2_img->l1_img, cur_block, buf.raw); - if (err) - return err; - l2_img->u.mfs.ABlink_dirty[cur_block-2] = 0; - } - - cur_byte += block_len; - } - } - - return IMGTOOLERR_SUCCESS; -} - -/* - mfs_dir_open - - Open the directory file - - l2_img (I/O): level-2 image reference - dirref (O): open directory file reference - - Return imgtool error code -*/ -static imgtoolerr_t mfs_dir_open(struct mac_l2_imgref *l2_img, const char *path, mfs_dirref *dirref) -{ - imgtoolerr_t err; - - assert(l2_img->format == L2I_MFS); - - if (path[0]) - return IMGTOOLERR_PATHNOTFOUND; - - dirref->l2_img = l2_img; - dirref->index = 0; - - dirref->cur_block = 0; - dirref->cur_offset = 0; - err = image_read_block(&l2_img->l1_img, l2_img->u.mfs.dir_start + dirref->cur_block, dirref->block_buffer); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - -/* - mfs_dir_read - - Read one entry of directory file - - dirref (I/O): open directory file reference - dir_entry (O): set to point to the entry read: set to NULL if EOF or error - - Return imgtool error code -*/ -static imgtoolerr_t mfs_dir_read(mfs_dirref *dirref, mfs_dir_entry **dir_entry) -{ - mfs_dir_entry *cur_dir_entry; - size_t cur_dir_entry_len; - imgtoolerr_t err; - - - if (dir_entry) - *dir_entry = NULL; - - if (dirref->index == dirref->l2_img->u.mfs.dir_num_files) - /* EOF */ - return IMGTOOLERR_SUCCESS; - - /* get cat entry pointer */ - cur_dir_entry = (mfs_dir_entry *) (dirref->block_buffer + dirref->cur_offset); - while ((dirref->cur_offset == 512) || ! (cur_dir_entry->flags & 0x80)) - { - dirref->cur_block++; - dirref->cur_offset = 0; - if (dirref->cur_block > dirref->l2_img->u.mfs.dir_blk_len) - /* aargh! */ - return IMGTOOLERR_CORRUPTIMAGE; - err = image_read_block(&dirref->l2_img->l1_img, dirref->l2_img->u.mfs.dir_start + dirref->cur_block, dirref->block_buffer); - if (err) - return err; - cur_dir_entry = (mfs_dir_entry *) (dirref->block_buffer + dirref->cur_offset); - } - - cur_dir_entry_len = offsetof(mfs_dir_entry, name) + cur_dir_entry->name[0] + 1; - - if ((dirref->cur_offset + cur_dir_entry_len) > 512) - /* aargh! */ - return IMGTOOLERR_CORRUPTIMAGE; - - /* entry looks valid: set pointer to entry */ - if (dir_entry) - *dir_entry = cur_dir_entry; - - /* update offset in block */ - dirref->cur_offset += cur_dir_entry_len; - /* align to word boundary */ - dirref->cur_offset = (dirref->cur_offset + 1) & ~1; - - /* update file count */ - dirref->index++; - - return IMGTOOLERR_SUCCESS; -} - -/* - mfs_dir_insert - - Add an entry in the directory file - - l2_img (I/O): level-2 image reference - dirref (I/O): open directory file reference - filename (I): name of the file for which an entry is created (Mac string) - dir_entry (O): set to point to the created entry: set to NULL if EOF or - error - - Return imgtool error code -*/ -static imgtoolerr_t mfs_dir_insert(struct mac_l2_imgref *l2_img, mfs_dirref *dirref, const uint8_t *new_fname, mfs_dir_entry **dir_entry) -{ - size_t new_dir_entry_len; - mfs_dir_entry *cur_dir_entry; - size_t cur_dir_entry_len; - uint32_t cur_date; - imgtoolerr_t err; - - dirref->l2_img = l2_img; - dirref->index = 0; - - new_dir_entry_len = offsetof(mfs_dir_entry, name) + new_fname[0] + 1; - - for (dirref->cur_block = 0; dirref->cur_block < dirref->l2_img->u.mfs.dir_blk_len; dirref->cur_block++) - { - /* read current block */ - err = image_read_block(&dirref->l2_img->l1_img, dirref->l2_img->u.mfs.dir_start + dirref->cur_block, dirref->block_buffer); - if (err) - return err; - - /* get free chunk in this block */ - dirref->cur_offset = 0; - cur_dir_entry = (mfs_dir_entry *) (dirref->block_buffer + dirref->cur_offset); - while ((dirref->cur_offset < 512) && (cur_dir_entry->flags & 0x80)) - { /* skip cur_dir_entry */ - cur_dir_entry_len = offsetof(mfs_dir_entry, name) + cur_dir_entry->name[0] + 1; - /* update offset in block */ - dirref->cur_offset += cur_dir_entry_len; - /* align to word boundary */ - dirref->cur_offset = (dirref->cur_offset + 1) & ~1; - /* update entry pointer */ - cur_dir_entry = (mfs_dir_entry *) (dirref->block_buffer + dirref->cur_offset); - /* update file index (useless, but can't harm) */ - dirref->index++; - } - - if (new_dir_entry_len <= (/*512*/510 - dirref->cur_offset)) - { - /*memcpy(cur_dir_entry, new_dir_entry, new_dir_entry_len);*/ - cur_dir_entry->flags = 0x80; - cur_dir_entry->flVersNum = 0x00; - memset(&cur_dir_entry->flFinderInfo, 0, sizeof(cur_dir_entry->flFinderInfo)); - set_UINT32BE(&cur_dir_entry->fileID, dirref->l2_img->nxtCNID++); - set_UINT16BE(&cur_dir_entry->dataStartBlock, 1); - set_UINT32BE(&cur_dir_entry->dataLogicalSize, 0); - set_UINT32BE(&cur_dir_entry->dataPhysicalSize, 0); - set_UINT16BE(&cur_dir_entry->rsrcStartBlock, 1); - set_UINT32BE(&cur_dir_entry->rsrcLogicalSize, 0); - set_UINT32BE(&cur_dir_entry->rsrcPhysicalSize, 0); - cur_date = mac_time_now(); - set_UINT32BE(&cur_dir_entry->createDate, cur_date); - set_UINT32BE(&cur_dir_entry->modifyDate, cur_date); - mac_strcpy(cur_dir_entry->name, new_fname); - - /* update offset in block */ - dirref->cur_offset += new_dir_entry_len; - /* align to word boundary */ - dirref->cur_offset = (dirref->cur_offset + 1) & ~1; - if (dirref->cur_offset < 512) - /* mark remaining space as free record */ - dirref->block_buffer[dirref->cur_offset] = 0; - /* write back directory */ - err = image_write_block(&dirref->l2_img->l1_img, dirref->l2_img->u.mfs.dir_start + dirref->cur_block, dirref->block_buffer); - if (err) - return err; - /* update file count */ - dirref->l2_img->u.mfs.dir_num_files++; - - /* update MDB (nxtCNID & dir_num_files fields) */ - err = mfs_update_mdb(dirref->l2_img); - if (err) - return err; - - if (dir_entry) - *dir_entry = cur_dir_entry; - return IMGTOOLERR_SUCCESS; - } - } - - return IMGTOOLERR_NOSPACE; -} - -/* - mfs_dir_update - - Update one entry of directory file - - fileref (I/O): open file reference - - Return imgtool error code -*/ -static imgtoolerr_t mfs_dir_update(struct mac_fileref *fileref) -{ - uint16_t cur_block; - uint16_t cur_offset; - uint8_t block_buffer[512]; - mfs_dir_entry *cur_dir_entry; - size_t cur_dir_entry_len; - imgtoolerr_t err; - - for (cur_block = 0; cur_block < fileref->l2_img->u.mfs.dir_blk_len; cur_block++) - { - /* read current block */ - err = image_read_block(&fileref->l2_img->l1_img, fileref->l2_img->u.mfs.dir_start + cur_block, block_buffer); - if (err) - return err; - - /* get free chunk in this block */ - cur_offset = 0; - cur_dir_entry = (mfs_dir_entry *) (block_buffer + cur_offset); - while ((cur_offset < 512) && (cur_dir_entry->flags & 0x80)) - { - if (get_UINT32BE(cur_dir_entry->fileID) == fileref->fileID) - { /* found it: update directory entry */ - switch (fileref->forkType) - { - case data_fork: - set_UINT16BE(&cur_dir_entry->dataStartBlock, fileref->mfs.stBlk); - set_UINT32BE(&cur_dir_entry->dataLogicalSize, fileref->eof); - set_UINT32BE(&cur_dir_entry->dataPhysicalSize, fileref->pLen); - break; - - case rsrc_fork: - set_UINT16BE(&cur_dir_entry->rsrcStartBlock, fileref->mfs.stBlk); - set_UINT32BE(&cur_dir_entry->rsrcLogicalSize, fileref->eof); - set_UINT32BE(&cur_dir_entry->rsrcPhysicalSize, fileref->pLen); - break; - } - /* write back directory */ - err = image_write_block(&fileref->l2_img->l1_img, fileref->l2_img->u.mfs.dir_start + cur_block, block_buffer); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; - } - /* skip cur_dir_entry */ - cur_dir_entry_len = offsetof(mfs_dir_entry, name) + cur_dir_entry->name[0] + 1; - /* update offset in block */ - cur_offset += cur_dir_entry_len; - /* align to word boundary */ - cur_offset = (cur_offset + 1) & ~1; - /* update entry pointer */ - cur_dir_entry = (mfs_dir_entry *) (block_buffer + cur_offset); - } - } - - return IMGTOOLERR_UNEXPECTED; -} - - -/* - mfs_find_dir_entry - - Find a file in an MFS directory - - dirref (I/O): open directory file reference - filename (I): file name (Mac string) - dir_entry (O): set to point to the entry read: set to NULL if EOF or error - - Return imgtool error code -*/ -static imgtoolerr_t mfs_find_dir_entry(mfs_dirref *dirref, const mac_str255 filename, mfs_dir_entry **dir_entry) -{ - mfs_dir_entry *cur_dir_entry; - imgtoolerr_t err; - - if (dir_entry) - *dir_entry = NULL; - - /* scan dir for file */ - while (1) - { - err = mfs_dir_read(dirref, &cur_dir_entry); - if (err) - return err; - if (!cur_dir_entry) - /* EOF */ - break; - if ((! mac_stricmp(filename, cur_dir_entry->name)) && (cur_dir_entry->flVersNum == 0)) - { /* file found */ - - if (dir_entry) - *dir_entry = cur_dir_entry; - - return IMGTOOLERR_SUCCESS; - } - } - - return IMGTOOLERR_FILENOTFOUND; -} - -/* - mfs_lookup_path - - Resolve a file path for MFS volumes. This function should not be called - directly: call mac_lookup_path instead. - - l2_img (I/O): level-2 image reference - fpath (I): file path (C string) - filename (O): set to the actual name of the file, with capitalization matching - the one on the volume rather than the one in the fpath parameter (Mac - string) - cat_info (I/O): on output, catalog info for this file extracted from the - catalog file (may be NULL) - If create_it is true, created info will first be set according to the - data from cat_info - create_it (I): true if entry should be created if not found - - Return imgtool error code -*/ -static imgtoolerr_t mfs_lookup_path(struct mac_l2_imgref *l2_img, const char *fpath, mac_str255 filename, mac_dirent *cat_info, int create_it) -{ - mfs_dirref dirref; - mfs_dir_entry *dir_entry; - imgtoolerr_t err; - - /* rapid check */ - if (strchr(fpath, ':')) - return IMGTOOLERR_BADFILENAME; - - /* extract file name */ - c_to_mac_strncpy(filename, fpath, strlen(fpath)); - - /* open dir */ - mfs_dir_open(l2_img, "", &dirref); - - /* find file */ - err = mfs_find_dir_entry(&dirref, filename, &dir_entry); - if ((err == IMGTOOLERR_FILENOTFOUND) && create_it) - err = mfs_dir_insert(l2_img, &dirref, filename, &dir_entry); - if (err) - return err; - - mac_strcpy(filename, dir_entry->name); - - if (create_it && cat_info) - { - dir_entry->flFinderInfo = cat_info->flFinderInfo; - dir_entry->flags = (dir_entry->flags & 0x80) | (cat_info->flags & 0x7f); - set_UINT32BE(&dir_entry->createDate, cat_info->createDate); - set_UINT32BE(&dir_entry->modifyDate, cat_info->modifyDate); - - /* write current directory block */ - err = image_write_block(&l2_img->l1_img, l2_img->u.mfs.dir_start + dirref.cur_block, dirref.block_buffer); - if (err) - return err; - } - - if (cat_info) - { - cat_info->flFinderInfo = dir_entry->flFinderInfo; - memset(&cat_info->flXFinderInfo, 0, sizeof(cat_info->flXFinderInfo)); - cat_info->flags = dir_entry->flags; - cat_info->fileID = get_UINT32BE(dir_entry->fileID); - cat_info->dataLogicalSize = get_UINT32BE(dir_entry->dataLogicalSize); - cat_info->dataPhysicalSize = get_UINT32BE(dir_entry->dataPhysicalSize); - cat_info->rsrcLogicalSize = get_UINT32BE(dir_entry->rsrcLogicalSize); - cat_info->rsrcPhysicalSize = get_UINT32BE(dir_entry->rsrcPhysicalSize); - cat_info->createDate = get_UINT32BE(dir_entry->createDate); - cat_info->modifyDate = get_UINT32BE(dir_entry->modifyDate); - cat_info->dataRecType = 0x200; /* hcrt_File */ - } - - return IMGTOOLERR_SUCCESS; -} - -/* - mfs_file_open_internal - - Open a file fork, given its directory entry. This function should not be - called directly: call mfs_file_open instead. - - l2_img (I/O): level-2 image reference - dir_entry (I): directory entry for the file to open - mac_forkID (I): tells which fork should be opened - fileref (O): mac file reference to open - - Return imgtool error code -*/ -static imgtoolerr_t mfs_file_open_internal(struct mac_l2_imgref *l2_img, const mfs_dir_entry *dir_entry, mac_forkID fork, struct mac_fileref *fileref) -{ - assert(l2_img->format == L2I_MFS); - - fileref->l2_img = l2_img; - - fileref->fileID = get_UINT32BE(dir_entry->fileID); - fileref->forkType = fork; - - switch (fork) - { - case data_fork: - fileref->mfs.stBlk = get_UINT16BE(dir_entry->dataStartBlock); - fileref->eof = get_UINT32BE(dir_entry->dataLogicalSize); - fileref->pLen = get_UINT32BE(dir_entry->dataPhysicalSize); - break; - - case rsrc_fork: - fileref->mfs.stBlk = get_UINT16BE(dir_entry->rsrcStartBlock); - fileref->eof = get_UINT32BE(dir_entry->rsrcLogicalSize); - fileref->pLen = get_UINT32BE(dir_entry->rsrcPhysicalSize); - break; - } - - fileref->crPs = 0; - - fileref->reload_buf = true; - - return IMGTOOLERR_SUCCESS; -} - -/* - mfs_file_open - - Open a file located on a MFS volume. This function should not be called - directly: call mac_file_open instead. - - l2_img (I/O): level-2 image reference - filename (I): name of the file (Mac string) - mac_forkID (I): tells which fork should be opened - fileref (O): mac file reference to open - - Return imgtool error code -*/ -static imgtoolerr_t mfs_file_open(struct mac_l2_imgref *l2_img, const mac_str255 filename, mac_forkID fork, struct mac_fileref *fileref) -{ - mfs_dirref dirref; - mfs_dir_entry *dir_entry; - imgtoolerr_t err; - - /* open dir */ - mfs_dir_open(l2_img, "", &dirref); - - /* find file */ - err = mfs_find_dir_entry(&dirref, filename, &dir_entry); - if (err) - return err; - - /* open it */ - return mfs_file_open_internal(l2_img, dir_entry, fork, fileref); -} - -/* - mfs_get_ABlink - - Read one entry of the Allocation Bitmap link array, on an MFS volume. - - l2_img (I/O): level-2 image reference - AB_address (I): index in the array, which is an AB address - - Returns the 12-bit value read in array. -*/ -static uint16_t mfs_get_ABlink(struct mac_l2_imgref *l2_img, uint16_t AB_address) -{ - uint16_t reply; - int base; - - assert(l2_img->format == L2I_MFS); - - base = (AB_address >> 1) * 3; - - if (! (AB_address & 1)) - reply = (l2_img->u.mfs.ABlink[base] << 4) | ((l2_img->u.mfs.ABlink[base+1] >> 4) & 0x0f); - else - reply = ((l2_img->u.mfs.ABlink[base+1] << 8) & 0xf00) | l2_img->u.mfs.ABlink[base+2]; - - return reply; -} - -/* - mfs_set_ABlink - - Set one entry of the Allocation Bitmap link array, on an MFS volume. - - l2_img (I/O): level-2 image reference - AB_address (I): index in the array, which is an AB address - data (I): 12-bit value to write in array -*/ -static void mfs_set_ABlink(struct mac_l2_imgref *l2_img, uint16_t AB_address, uint16_t data) -{ - int base; - - assert(l2_img->format == L2I_MFS); - - base = (AB_address >> 1) * 3; - - if (! (AB_address & 1)) - { - l2_img->u.mfs.ABlink[base] = (data >> 4) & 0xff; - l2_img->u.mfs.ABlink[base+1] = (l2_img->u.mfs.ABlink[base+1] & 0x0f) | ((data << 4) & 0xf0); - - l2_img->u.mfs.ABlink_dirty[(base+64)/512] = 1; - l2_img->u.mfs.ABlink_dirty[(base+1+64)/512] = 1; - } - else - { - l2_img->u.mfs.ABlink[base+1] = (l2_img->u.mfs.ABlink[base+1] & 0xf0) | ((data >> 8) & 0x0f); - l2_img->u.mfs.ABlink[base+2] = data & 0xff; - - l2_img->u.mfs.ABlink_dirty[(base+1+64)/512] = 1; - l2_img->u.mfs.ABlink_dirty[(base+2+64)/512] = 1; - } -} - -/* - mfs_file_get_nth_block_address - - Get the disk block address of a given block in an open file on a MFS image. - Called by macintosh file code. - - fileref (I/O): open mac file reference - block_num (I): file block index - block_address (O): disk block address for the file block - - Return imgtool error code -*/ -static imgtoolerr_t mfs_file_get_nth_block_address(struct mac_fileref *fileref, uint32_t block_num, uint32_t *block_address) -{ - uint32_t AB_num; - uint32_t i; - uint16_t AB_address; - - assert(fileref->l2_img->format == L2I_MFS); - - AB_num = block_num / fileref->l2_img->blocksperAB; - - AB_address = fileref->mfs.stBlk; - if ((AB_address == 0) || (AB_address >= fileref->l2_img->numABs+2)) - /* 0 -> ??? */ - return IMGTOOLERR_CORRUPTIMAGE; - if (AB_address == 1) - /* EOF */ - return IMGTOOLERR_UNEXPECTED; - AB_address -= 2; - for (i=0; i<AB_num; i++) - { - AB_address = mfs_get_ABlink(fileref->l2_img, AB_address); - if ((AB_address == 0) || (AB_address >= fileref->l2_img->numABs+2)) - /* 0 -> empty block: there is no way an empty block could make it - into the link chain!!! */ - return IMGTOOLERR_CORRUPTIMAGE; - if (AB_address == 1) - /* EOF */ - return IMGTOOLERR_UNEXPECTED; - AB_address -= 2; - } - - *block_address = fileref->l2_img->u.mfs.ABStart + AB_address * fileref->l2_img->blocksperAB - + block_num % fileref->l2_img->blocksperAB; - - return IMGTOOLERR_SUCCESS; -} - -/* - mfs_file_allocABs - - Allocate a chunk of ABs - - fileref (I/O): open mac file reference - lastAB (I): AB address on disk of last file AB (only if - fileref->mfs.stBlk != 1) - allocABs (I): number of ABs to allocate in addition to the current file - allocation - fblock (I): first file block to allocate (used for tag data) - - Return imgtool error code -*/ -static imgtoolerr_t mfs_file_allocABs(struct mac_fileref *fileref, uint16_t lastAB, uint32_t allocABs, uint32_t fblock) -{ - int numABs = fileref->l2_img->numABs; - int free_ABs; - int i, j; - floppy_tag_record tag; - int extentBaseAB, extentABlen; - int firstBestExtentBaseAB = 0, firstBestExtentABlen; - int secondBestExtentBaseAB = 0, secondBestExtentABlen; - imgtoolerr_t err; - - /* return if done */ - if (! allocABs) - return IMGTOOLERR_SUCCESS; - - /* compute free space */ - free_ABs = 0; - for (i=0; i<numABs; i++) - { - if (mfs_get_ABlink(fileref->l2_img, i) == 0) - { - if (TAG_CHECKS) - { - /* optional check */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - for (j=0; j<fileref->l2_img->blocksperAB; j++) - { - err = image_read_tag(&fileref->l2_img->l1_img, fileref->l2_img->u.mfs.ABStart + i * fileref->l2_img->blocksperAB + j, &tag); - if (err) - return err; - - if (get_UINT32BE(tag.fileID) != 0) - { - /*return IMGTOOLERR_CORRUPTIMAGE;*/ - goto corrupt_free_block; - } - } - } - } - - free_ABs++; - } -corrupt_free_block: - ; - } - - /* check we have enough free space */ - if (free_ABs < allocABs) - return IMGTOOLERR_NOSPACE; - - if (fileref->mfs.stBlk != 1) - { /* try to extend last file extent */ - /* append free ABs after last AB */ - for (i=lastAB+1; (mfs_get_ABlink(fileref->l2_img, i) == 0) && (allocABs > 0) && (i < numABs); i++) - { - if (TAG_CHECKS) - { - /* optional check */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - for (j=0; j<fileref->l2_img->blocksperAB; j++) - { - err = image_read_tag(&fileref->l2_img->l1_img, fileref->l2_img->u.mfs.ABStart + i * fileref->l2_img->blocksperAB + j, &tag); - if (err) - return err; - - if (get_UINT32BE(tag.fileID) != 0) - { - /*return IMGTOOLERR_CORRUPTIMAGE;*/ - goto corrupt_free_block2; - } - } - } - } - - mfs_set_ABlink(fileref->l2_img, lastAB, i+2); - lastAB = i; - allocABs--; - free_ABs--; - } -corrupt_free_block2: - /* return if done */ - if (! allocABs) - { - mfs_set_ABlink(fileref->l2_img, lastAB, 1); - fileref->l2_img->freeABs = free_ABs; - return IMGTOOLERR_SUCCESS; /* done */ - } - } - - while (allocABs) - { - /* find smallest data block at least nb_alloc_physrecs in length, and largest data block less than nb_alloc_physrecs in length */ - firstBestExtentABlen = INT_MAX; - secondBestExtentABlen = 0; - for (i=0; i<numABs; i++) - { - if (mfs_get_ABlink(fileref->l2_img, i) == 0) - { /* found one free block */ - /* compute its length */ - extentBaseAB = i; - extentABlen = 0; - while ((i<numABs) && (mfs_get_ABlink(fileref->l2_img, i) == 0)) - { - if (TAG_CHECKS) - { - /* optional check */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - for (j=0; j<fileref->l2_img->blocksperAB; j++) - { - err = image_read_tag(&fileref->l2_img->l1_img, fileref->l2_img->u.mfs.ABStart + i * fileref->l2_img->blocksperAB + j, &tag); - if (err) - return err; - - if (get_UINT32BE(tag.fileID) != 0) - { - /*return IMGTOOLERR_CORRUPTIMAGE;*/ - goto corrupt_free_block3; - } - } - } - } - - extentABlen++; - i++; - } -corrupt_free_block3: - /* compare to previous best and second-best blocks */ - if ((extentABlen < firstBestExtentABlen) && (extentABlen >= allocABs)) - { - firstBestExtentBaseAB = extentBaseAB; - firstBestExtentABlen = extentABlen; - if (extentABlen == allocABs) - /* no need to search further */ - break; - } - else if ((extentABlen > secondBestExtentABlen) && (extentABlen < allocABs)) - { - secondBestExtentBaseAB = extentBaseAB; - secondBestExtentABlen = extentABlen; - } - } - } - - if (firstBestExtentABlen != INT_MAX) - { /* found one contiguous block which can hold it all */ - extentABlen = allocABs; - for (i=0; i<allocABs; i++) - { - if (fileref->mfs.stBlk != 1) - mfs_set_ABlink(fileref->l2_img, lastAB, firstBestExtentBaseAB+i+2); - else - fileref->mfs.stBlk = firstBestExtentBaseAB+i+2; - lastAB = firstBestExtentBaseAB+i; - free_ABs--; - /* set tag to allocated */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - set_UINT32BE(&tag.fileID, fileref->fileID); - tag.ftype = 1; - if ((fileref->forkType) == rsrc_fork) - tag.ftype |= 2; - tag.fattr = /*fattr*/ 0; /* ***TODO*** */ - for (j=0; j<fileref->l2_img->blocksperAB; j++) - { - set_UINT16BE(&tag.fblock, fblock & 0xffff); - set_UINT32BE(&tag.wrCnt, mac_time_now()); - err = image_write_tag(&fileref->l2_img->l1_img, fileref->l2_img->u.mfs.ABStart + lastAB * fileref->l2_img->blocksperAB + j, &tag); - if (err) - { - mfs_set_ABlink(fileref->l2_img, lastAB, 1); - fileref->l2_img->freeABs = free_ABs; - return err; - } - fblock++; - } - } - } - allocABs = 0; - mfs_set_ABlink(fileref->l2_img, lastAB, 1); - fileref->l2_img->freeABs = free_ABs; - /*return IMGTOOLERR_SUCCESS;*/ /* done */ - } - else if (secondBestExtentABlen != 0) - { /* jeez, we need to fragment it. We use the largest smaller block to limit fragmentation. */ - for (i=0; i<secondBestExtentABlen; i++) - { - if (fileref->mfs.stBlk != 1) - mfs_set_ABlink(fileref->l2_img, lastAB, secondBestExtentBaseAB+i+2); - else - fileref->mfs.stBlk = secondBestExtentBaseAB+i+2; - lastAB = secondBestExtentBaseAB+i; - free_ABs--; - /* set tag to allocated */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - set_UINT32BE(&tag.fileID, fileref->fileID); - tag.ftype = 1; - if ((fileref->forkType) == rsrc_fork) - tag.ftype |= 2; - tag.fattr = /*fattr*/ 0; /* ***TODO*** */ - for (j=0; j<fileref->l2_img->blocksperAB; j++) - { - set_UINT16BE(&tag.fblock, fblock & 0xffff); - set_UINT32BE(&tag.wrCnt, mac_time_now()); - err = image_write_tag(&fileref->l2_img->l1_img, fileref->l2_img->u.mfs.ABStart + lastAB * fileref->l2_img->blocksperAB + j, &tag); - if (err) - { - mfs_set_ABlink(fileref->l2_img, lastAB, 1); - fileref->l2_img->freeABs = free_ABs; - return err; - } - fblock++; - } - } - } - allocABs -= secondBestExtentABlen; - } - else - { - mfs_set_ABlink(fileref->l2_img, lastAB, 1); - return IMGTOOLERR_NOSPACE; /* This should never happen, as we pre-check that there is enough free space */ - } - } - - return IMGTOOLERR_SUCCESS; -} - -/* - mfs_file_setABeof - - Set physical file EOF in ABs - - fileref (I/O): open mac file reference - newABeof (I): desired number of allocated ABs for this file - - Return imgtool error code -*/ -static imgtoolerr_t mfs_file_setABeof(struct mac_fileref *fileref, uint32_t newABeof) -{ - uint16_t AB_address = 0; - uint16_t AB_link; - int i, j; - floppy_tag_record tag; - int MDB_dirty = 0; - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - - - assert(fileref->l2_img->format == L2I_MFS); - - /* run through link chain until we reach the old or the new EOF */ - AB_link = fileref->mfs.stBlk; - if ((AB_link == 0) || (AB_link >= fileref->l2_img->numABs+2)) - /* 0 -> ??? */ - return IMGTOOLERR_CORRUPTIMAGE; - for (i=0; (i<newABeof) && (AB_link!=1); i++) - { - AB_address = AB_link - 2; - AB_link = mfs_get_ABlink(fileref->l2_img, AB_address); - if ((AB_link == 0) || (AB_link >= fileref->l2_img->numABs+2)) - /* 0 -> empty block: there is no way an empty block could make it - into the link chain!!! */ - return IMGTOOLERR_CORRUPTIMAGE; - - if (TAG_CHECKS) - { - /* optional check */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - for (j=0; j<fileref->l2_img->blocksperAB; j++) - { - err = image_read_tag(&fileref->l2_img->l1_img, fileref->l2_img->u.mfs.ABStart + AB_address * fileref->l2_img->blocksperAB + j, &tag); - if (err) - return err; - - if ((get_UINT32BE(tag.fileID) != fileref->fileID) - || (((tag.ftype & 2) != 0) != (fileref->forkType == rsrc_fork)) - || (get_UINT16BE(tag.fblock) != ((i * fileref->l2_img->blocksperAB + j) & 0xffff))) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - } - } - } - } - - if (i == newABeof) - { /* new EOF is shorter than old one */ - /* mark new eof */ - if (i==0) - fileref->mfs.stBlk = 1; - else - { - mfs_set_ABlink(fileref->l2_img, AB_address, 1); - MDB_dirty = 1; - } - - /* free all remaining blocks */ - while (AB_link != 1) - { - AB_address = AB_link - 2; - AB_link = mfs_get_ABlink(fileref->l2_img, AB_address); - if ((AB_link == 0) || (AB_link >= fileref->l2_img->numABs+2)) - { /* 0 -> empty block: there is no way an empty block could make - it into the link chain!!! */ - if (MDB_dirty) - { /* update MDB (freeABs field) and ABLink array */ - err = mfs_update_mdb(fileref->l2_img); - if (err) - return err; - } - return IMGTOOLERR_CORRUPTIMAGE; - } - - if (TAG_CHECKS) - { - /* optional check */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - for (j=0; j<fileref->l2_img->blocksperAB; j++) - { - err = image_read_tag(&fileref->l2_img->l1_img, fileref->l2_img->u.mfs.ABStart + AB_address * fileref->l2_img->blocksperAB + j, &tag); - if (err) - return err; - - if ((get_UINT32BE(tag.fileID) != fileref->fileID) - || (((tag.ftype & 2) != 0) != (fileref->forkType == rsrc_fork)) - || (get_UINT16BE(tag.fblock) != ((i * fileref->l2_img->blocksperAB + j) & 0xffff))) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - } - } - } - - mfs_set_ABlink(fileref->l2_img, AB_address, 0); - fileref->l2_img->freeABs++; - MDB_dirty = 1; - /* set tag to free */ - if (image_get_tag_len(&fileref->l2_img->l1_img) == 12) - { - memset(&tag, 0, sizeof(tag)); - for (j=0; j<fileref->l2_img->blocksperAB; j++) - { - err = image_write_tag(&fileref->l2_img->l1_img, fileref->l2_img->u.mfs.ABStart + AB_address * fileref->l2_img->blocksperAB + j, &tag); - if (err) - return err; - } - } - i++; - } - } - else - { /* new EOF is larger than old one */ - err = mfs_file_allocABs(fileref, AB_address, newABeof - i, i * fileref->l2_img->blocksperAB); - if (err) - return err; - MDB_dirty = 1; - } - - if (MDB_dirty) - { /* update MDB (freeABs field) and ABLink array */ - err = mfs_update_mdb(fileref->l2_img); - if (err) - return err; - } - - fileref->pLen = newABeof * (fileref->l2_img->blocksperAB * 512); - - return IMGTOOLERR_SUCCESS; -} - -#ifdef UNUSED_FUNCTION -/* - mfs_hashString - - Hash a string: under MFS, this provides the resource ID of the comment - resource associated with the file whose name is provided (FCMT resource - type). - - Ripped from Apple technote TB06 (converted from 68k ASM to C) - - string (I): string to hash - - Returns hash value -*/ -static int mfs_hashString(const mac_str255 string) -{ - int reply; - int len; - int i; - - len = string[0]; - - reply = 0; - for (i=0; i<len; i++) - { - reply ^= string[i+1]; - if (reply & 1) - reply = ((reply >> 1) & 0x7fff) | ~0x7fff; - else - reply = ((reply >> 1) & 0x7fff); - if (! (reply & 0x8000)) - reply = - reply; - } - - return reply; -} -#endif - -#if 0 -#pragma mark - -#pragma mark HFS IMPLEMENTATION -#endif - -/* - HFS extents B-tree key -*/ -struct hfs_extentKey -{ - uint8_t keyLength; /* length of key, excluding this field */ - uint8_t forkType; /* 0 = data fork, FF = resource fork */ - UINT32BE fileID; /* file ID */ - UINT16BE startBlock; /* first file allocation block number in this extent */ -}; -enum -{ - keyLength_hfs_extentKey = sizeof(hfs_extentKey) - sizeof(uint8_t) -}; - -/* - HFS catalog B-tree key -*/ -struct hfs_catKey -{ - uint8_t keyLen; /* key length */ - uint8_t resrv1; /* reserved */ - UINT32BE parID; /* parent directory ID */ - mac_str31 cName; /* catalog node name */ - /* note that in index nodes, it is a mac_str31, but - in leaf keys it's a variable-length string */ -}; - -/* - HFS catalog data record for a folder - 70 bytes -*/ -struct hfs_catFolderData -{ - UINT16BE recordType; /* record type */ - UINT16BE flags; /* folder flags */ - UINT16BE valence; /* folder valence */ - UINT32BE folderID; /* folder ID */ - UINT32BE createDate; /* date and time of creation */ - UINT32BE modifyDate; /* date and time of last modification */ - UINT32BE backupDate; /* date and time of last backup */ - mac_DInfo userInfo; /* Finder information */ - mac_DXInfo finderInfo; /* additional Finder information */ - UINT32BE reserved[4]; /* reserved - set to zero */ -}; - -/* - HFS catalog data record for a file - 102 bytes -*/ -struct hfs_catFileData -{ - UINT16BE recordType; /* record type */ - uint8_t flags; /* file flags */ - uint8_t fileType; /* file type (reserved, always 0?) */ - mac_FInfo userInfo; /* Finder information */ - UINT32BE fileID; /* file ID */ - UINT16BE dataStartBlock; /* not used - set to zero */ - UINT32BE dataLogicalSize; /* logical EOF of data fork */ - UINT32BE dataPhysicalSize; /* physical EOF of data fork */ - UINT16BE rsrcStartBlock; /* not used - set to zero */ - UINT32BE rsrcLogicalSize; /* logical EOF of resource fork */ - UINT32BE rsrcPhysicalSize; /* physical EOF of resource fork */ - UINT32BE createDate; /* date and time of creation */ - UINT32BE modifyDate; /* date and time of last modification */ - UINT32BE backupDate; /* date and time of last backup */ - mac_FXInfo finderInfo; /* additional Finder information */ - UINT16BE clumpSize; /* file clump size (not used) */ - hfs_extent_3 dataExtents; /* first data fork extent record */ - hfs_extent_3 rsrcExtents; /* first resource fork extent record */ - UINT32BE reserved; /* reserved - set to zero */ -}; - -/* - HFS catalog data record for a thread - 46 bytes - - The key for a thread record features the CNID of the item and an empty - name, instead of the CNID of the parent and the item name. -*/ -struct hfs_catThreadData -{ - UINT16BE recordType; /* record type */ - UINT32BE reserved[2]; /* reserved - set to zero */ - UINT32BE parID; /* parent ID for this catalog node */ - mac_str31 nodeName; /* name of this catalog node */ -}; - -/* - union for all types at once -*/ -union hfs_catData -{ - UINT16BE dataType; - hfs_catFolderData folder; - hfs_catFileData file; - hfs_catThreadData thread; -}; - -/* - HFS catalog record types -*/ -enum -{ - hcrt_Folder = 0x0100, /* Folder record */ - hcrt_File = 0x0200, /* File record */ - hcrt_FolderThread = 0x0300, /* Folder thread record */ - hcrt_FileThread = 0x0400 /* File thread record */ -}; - -/* - Catalog file record flags - - This is similar to the MFS catalog flag field, but the "thread exists" flag - (0x02) is specific to HFS/HFS+, whereas the "Record in use" flag (0x80) is - only used by MFS. -*/ -enum -{ - cfrf_fileLocked = 0x01, /* file is locked and cannot be written to */ - cfrf_threadExists = 0x02 /* a file thread record exists for this file */ -}; - -/* - BT functions used by HFS functions -*/ -struct BT_leaf_rec_enumerator -{ - mac_BTref *BTref; - uint32_t cur_node; - int cur_rec; -}; - -static imgtoolerr_t BT_open(mac_BTref *BTref, int (*key_compare_func)(const void *key1, const void *key2), int is_extent); -static void BT_close(mac_BTref *BTref); -static imgtoolerr_t BT_search_leaf_rec(mac_BTref *BTref, const void *search_key, - uint32_t *node_ID, int *record_ID, - void **record_ptr, int *record_len, - int search_exact_match, int *match_found); -static imgtoolerr_t BT_get_keyed_record_data(mac_BTref *BTref, void *rec_ptr, int rec_len, void **data_ptr, int *data_len); -static imgtoolerr_t BT_leaf_rec_enumerator_open(mac_BTref *BTref, BT_leaf_rec_enumerator *enumerator); -static imgtoolerr_t BT_leaf_rec_enumerator_read(BT_leaf_rec_enumerator *enumerator, void **record_ptr, int *rec_len); - -struct hfs_cat_enumerator -{ - struct mac_l2_imgref *l2_img; - BT_leaf_rec_enumerator BT_enumerator; - uint32_t parID; -}; - -/* - hfs_open_extents_file - - Open the file extents B-tree file - - l2_img (I/O): level-2 image reference - mdb (I): copy of the MDB block - fileref (O): mac open file reference - - Return imgtool error code -*/ -static imgtoolerr_t hfs_open_extents_file(struct mac_l2_imgref *l2_img, const struct hfs_mdb *mdb, struct mac_fileref *fileref) -{ - assert(l2_img->format == L2I_HFS); - - fileref->l2_img = l2_img; - - fileref->fileID = 3; - fileref->forkType = (mac_forkID)0x00; - - fileref->eof = fileref->pLen = get_UINT32BE(mdb->xtFlSize); - memcpy(fileref->hfs.extents, mdb->xtExtRec, sizeof(hfs_extent_3)); - - fileref->crPs = 0; - - fileref->reload_buf = true; - - return IMGTOOLERR_SUCCESS; -} - -/* - hfs_open_cat_file - - Open the disk catalog B-tree file - - l2_img (I/O): level-2 image reference - mdb (I): copy of the MDB block - fileref (O): mac open file reference - - Return imgtool error code -*/ -static imgtoolerr_t hfs_open_cat_file(struct mac_l2_imgref *l2_img, const struct hfs_mdb *mdb, struct mac_fileref *fileref) -{ - assert(l2_img->format == L2I_HFS); - - fileref->l2_img = l2_img; - - fileref->fileID = 4; - fileref->forkType = (mac_forkID)0x00; - - fileref->eof = fileref->pLen = get_UINT32BE(mdb->ctFlSize); - memcpy(fileref->hfs.extents, mdb->ctExtRec, sizeof(hfs_extent_3)); - - fileref->crPs = 0; - - fileref->reload_buf = true; - - return IMGTOOLERR_SUCCESS; -} - -/* - hfs_extentKey_compare - - key compare function for file extents B-tree - - p1 (I): pointer to first key - p2 (I): pointer to second key - - Return a zero the two keys are equal, a negative value if the key pointed - to by p1 is less than the key pointed to by p2, and a positive value if the - key pointed to by p1 is greater than the key pointed to by p2. -*/ -static int hfs_extentKey_compare(const void *p1, const void *p2) -{ - const hfs_extentKey *key1 = (const hfs_extentKey*)p1; - const hfs_extentKey *key2 = (const hfs_extentKey*)p2; - - /* let's keep it simple for now */ - return memcmp(key1, key2, sizeof(hfs_extentKey)); -} - -/* - hfs_catKey_compare - - key compare function for disk catalog B-tree - - p1 (I): pointer to first key - p2 (I): pointer to second key - - Return a zero the two keys are equal, a negative value if the key pointed - to by p1 is less than the key pointed to by p2, and a positive value if the - key pointed to by p1 is greater than the key pointed to by p2. -*/ -static int hfs_catKey_compare(const void *p1, const void *p2) -{ - const hfs_catKey *key1 = (const hfs_catKey *)p1; - const hfs_catKey *key2 = (const hfs_catKey *)p2; - - if (get_UINT32BE(key1->parID) != get_UINT32BE(key2->parID)) - return (get_UINT32BE(key1->parID) < get_UINT32BE(key2->parID)) ? -1 : +1; - - return mac_stricmp(key1->cName, key2->cName); -} - -/* - hfs_image_open - - Open a HFS image. Image must already be open on level 1. - - l2_img (I/O): level-2 image reference to open (l1_img and format fields - must be initialized) - img_open_buf (I): buffer with the MDB block - - Return imgtool error code -*/ -static imgtoolerr_t hfs_image_open(imgtool::image &image, imgtool::stream::ptr &&stream) -{ - imgtoolerr_t err; - struct mac_l2_imgref *l2_img; - img_open_buf buf_local; - img_open_buf *buf; - - l2_img = get_imgref(image); - l2_img->l1_img.image = ℑ - l2_img->l1_img.heads = 2; - l2_img->format = L2I_HFS; - - /* read MDB */ - err = image_read_block(&l2_img->l1_img, 2, &buf_local.raw); - if (err) - return err; - buf = &buf_local; - - /* check signature word */ - if ((buf->hfs_mdb.sigWord[0] != 0x42) || (buf->hfs_mdb.sigWord[1] != 0x44) - || (buf->hfs_mdb.VN[0] > 27)) - return IMGTOOLERR_CORRUPTIMAGE; - - l2_img->u.hfs.VBM_start = get_UINT16BE(buf->hfs_mdb.VBMSt); - - l2_img->numABs = get_UINT16BE(buf->hfs_mdb.nmAlBlks); - if (get_UINT32BE(buf->hfs_mdb.alBlkSiz) % 512) - return IMGTOOLERR_CORRUPTIMAGE; - l2_img->blocksperAB = get_UINT32BE(buf->hfs_mdb.alBlkSiz) / 512; - l2_img->u.hfs.ABStart = get_UINT16BE(buf->hfs_mdb.alBlSt); - - l2_img->nxtCNID = get_UINT32BE(buf->hfs_mdb.nxtCNID); - - l2_img->freeABs = get_UINT16BE(buf->hfs_mdb.freeABs); - - mac_strcpy(l2_img->u.hfs.volname, buf->hfs_mdb.VN); - - /* open extents and catalog BT */ - err = hfs_open_extents_file(l2_img, &buf->hfs_mdb, &l2_img->u.hfs.extents_BT.fileref); - if (err) - return err; - err = BT_open(&l2_img->u.hfs.extents_BT, hfs_extentKey_compare, true); - if (err) - return err; - if ((l2_img->u.hfs.extents_BT.attributes & btha_bigKeysMask) - /*|| (l2_img->u.hfs.extents_BT.attributes & kBTVariableIndexKeysMask)*/ - || (l2_img->u.hfs.extents_BT.maxKeyLength != 7)) - { /* This is not supported by the HFS format */ - /* Variable Index keys are not supported either, but hopefully it will - not break this imgtool module if it set (though it would probably break - a real macintosh) */ - BT_close(&l2_img->u.hfs.extents_BT); - return IMGTOOLERR_CORRUPTIMAGE; - } - err = hfs_open_cat_file(l2_img, &buf->hfs_mdb, &l2_img->u.hfs.cat_BT.fileref); - if (err) - { - BT_close(&l2_img->u.hfs.extents_BT); - return err; - } - err = BT_open(&l2_img->u.hfs.cat_BT, hfs_catKey_compare, false); - if (err) - { - return err; - } - if ((l2_img->u.hfs.cat_BT.attributes & btha_bigKeysMask) - /*|| (l2_img->u.hfs.cat_BT.attributes & kBTVariableIndexKeysMask)*/ - || (l2_img->u.hfs.cat_BT.maxKeyLength != 37)) - { /* This is not supported by the HFS format */ - /* Variable Index keys are not supported either, but hopefully it will - not break this imgtool module if it set (though it would probably break - a real macintosh) */ - BT_close(&l2_img->u.hfs.extents_BT); - BT_close(&l2_img->u.hfs.cat_BT); - return IMGTOOLERR_CORRUPTIMAGE; - } - - /* extract volume bitmap */ - { - int byte_len = (l2_img->numABs + 7) / 8; - int cur_byte = 0; - int cur_block = l2_img->u.hfs.VBM_start; - - while (cur_byte < byte_len) - { - /* read next block */ - err = image_read_block(&l2_img->l1_img, cur_block, buf->raw); - if (err) - return err; - cur_block++; - - /* append this block to VBM */ - memcpy(l2_img->u.hfs.VBM+cur_byte, buf->raw, 512); - cur_byte += 512; - } - } - - return IMGTOOLERR_SUCCESS; -} - -#ifdef UNUSED_FUNCTION -/* - hfs_image_close - - Close a HFS image. - - l2_img (I/O): level-2 image reference -*/ -static void hfs_image_close(struct mac_l2_imgref *l2_img) -{ - assert(l2_img->format == L2I_HFS); - - BT_close(&l2_img->u.hfs.extents_BT); - BT_close(&l2_img->u.hfs.cat_BT); -} -#endif - -/* - hfs_get_cat_record_data - - extract data from a catalog B-tree leaf record - - l2_img (I/O): level-2 image reference - rec_raw (I): pointer to record key and data, as returned by - BT_node_get_keyed_record - rec_len (I): total length of record, as returned by - BT_node_get_keyed_record - rec_key (O): set to point to record key - rec_data (O): set to point to record data - - Return imgtool error code -*/ -static imgtoolerr_t hfs_get_cat_record_data(struct mac_l2_imgref *l2_img, void *rec_raw, int rec_len, hfs_catKey **rec_key, hfs_catData **rec_data) -{ - hfs_catKey *lrec_key; - void *rec_data_raw; - hfs_catData *lrec_data; - int rec_data_len; - int min_data_size; - imgtoolerr_t err; - - - assert(l2_img->format == L2I_HFS); - - lrec_key = (hfs_catKey*)rec_raw; - /* check that key is long enough to hold it all */ - if ((lrec_key->keyLen+1) < (offsetof(hfs_catKey, cName) + lrec_key->cName[0] + 1)) - return IMGTOOLERR_CORRUPTIMAGE; - - /* get pointer to record data */ - err = BT_get_keyed_record_data(&l2_img->u.hfs.cat_BT, rec_raw, rec_len, &rec_data_raw, &rec_data_len); - if (err) - return err; - lrec_data = (hfs_catData*)rec_data_raw; - - /* extract record type */ - if (rec_data_len < 2) - return IMGTOOLERR_CORRUPTIMAGE; - - /* check that the record is large enough for its type */ - switch (get_UINT16BE(lrec_data->dataType)) - { - case hcrt_Folder: - min_data_size = sizeof(hfs_catFolderData); - break; - - case hcrt_File: - min_data_size = sizeof(hfs_catFileData); - break; - - case hcrt_FolderThread: - case hcrt_FileThread: - min_data_size = sizeof(hfs_catThreadData); - break; - - default: - /* records of unknown type can be safely ignored */ - min_data_size = 0; - break; - } - - if (rec_data_len < min_data_size) - return IMGTOOLERR_CORRUPTIMAGE; - - if (rec_key) - *rec_key = lrec_key; - if (rec_data) - *rec_data = lrec_data; - - return IMGTOOLERR_SUCCESS; -} - -/* - hfs_cat_open - - Open an enumerator on the disk catalog - - l2_img (I/O): level-2 image reference - enumerator (O): open catalog enumerator reference - - Return imgtool error code -*/ -static imgtoolerr_t hfs_cat_open(struct mac_l2_imgref *l2_img, const char *path, hfs_cat_enumerator *enumerator) -{ - imgtoolerr_t err; - uint32_t parID; - mac_str255 filename; - mac_dirent cat_info; - - assert(l2_img->format == L2I_HFS); - - /* resolve path and fetch file info from directory/catalog */ - err = mac_lookup_path(l2_img, path, &parID, filename, &cat_info, false); - if (err) - return err; - if (cat_info.dataRecType != hcrt_Folder) - return IMGTOOLERR_FILENOTFOUND; - - enumerator->l2_img = l2_img; - enumerator->parID = parID; - - return BT_leaf_rec_enumerator_open(&l2_img->u.hfs.cat_BT, &enumerator->BT_enumerator); -} - -/* - hfs_cat_read - - Enumerate the disk catalog - - enumerator (I/O): open catalog enumerator reference - rec_key (O): set to point to record key - rec_data (O): set to point to record data - - Return imgtool error code -*/ -static imgtoolerr_t hfs_cat_read(hfs_cat_enumerator *enumerator, hfs_catKey **rec_key, hfs_catData **rec_data) -{ - void *rec; - int rec_len = 0; - imgtoolerr_t err; - - - *rec_key = NULL; - *rec_data = NULL; - - /* read next record */ - err = BT_leaf_rec_enumerator_read(&enumerator->BT_enumerator, &rec, &rec_len); - if (err) - return err; - - /* check EOList condition */ - if (rec == NULL) - return IMGTOOLERR_SUCCESS; - - /* extract record data */ - err = hfs_get_cat_record_data(enumerator->l2_img, rec, rec_len, rec_key, rec_data); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - -/* - hfs_cat_search - - Search the catalog for a given file - - l2_img (I/O): level-2 image reference - parID (I): CNID of file parent directory - cName (I): file name - rec_key (O): set to point to record key - rec_data (O): set to point to record data - - Return imgtool error code -*/ -static imgtoolerr_t hfs_cat_search(struct mac_l2_imgref *l2_img, uint32_t parID, const mac_str31 cName, hfs_catKey **rec_key, hfs_catData **rec_data) -{ - hfs_catKey search_key; - void *rec; - int rec_len; - imgtoolerr_t err; - - assert(l2_img->format == L2I_HFS); - - if (cName[0] > 31) - return IMGTOOLERR_UNEXPECTED; - - /* generate search key */ - search_key.keyLen = search_key.resrv1 = 0; /* these fields do not matter - to the compare function, so we - don't fill them */ - set_UINT32BE(&search_key.parID, parID); - mac_strcpy(search_key.cName, cName); - - /* search key */ - err = BT_search_leaf_rec(&l2_img->u.hfs.cat_BT, &search_key, NULL, NULL, &rec, &rec_len, true, NULL); - if (err) - return err; - - /* extract record data */ - err = hfs_get_cat_record_data(l2_img, rec, rec_len, rec_key, rec_data); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - -/* - hfs_lookup_path - - Resolve a file path - - l2_img (I/O): level-2 image reference - fpath (I): file path (C string) - parID (O): set to the CNID of the file parent directory - filename (O): set to the actual name of the file, with capitalization matching - the one on the volume rather than the one in the fpath parameter (Mac - string) - cat_info (O): catalog info for this file extracted from the catalog file - (may be NULL) - - Return imgtool error code -*/ -static imgtoolerr_t hfs_lookup_path(struct mac_l2_imgref *l2_img, const char *fpath, uint32_t *parID, mac_str255 filename, mac_dirent *cat_info) -{ - const char *element_start; - int element_len; - mac_str255 mac_element_name; - //int level; - imgtoolerr_t err; - hfs_catKey *catrec_key = NULL; - hfs_catData *catrec_data = NULL; - uint16_t dataRecType = hcrt_Folder; - - /* iterate each path element */ - element_start = fpath; - //level = 0; - *parID = 2; /* root parID is 2 */ - - while(*element_start) - { - /* find next path element */ - element_len = strlen(element_start); - /* decode path element name */ - c_to_mac_strncpy(mac_element_name, element_start, element_len); - - err = hfs_cat_search(l2_img, *parID, mac_element_name, &catrec_key, &catrec_data); - if (err) - return err; - - dataRecType = get_UINT16BE(catrec_data->dataType); - - /* regular folder/file name */ - if (dataRecType == hcrt_Folder) - *parID = get_UINT32BE(catrec_data->folder.folderID); - else if (element_start[element_len + 1]) - return IMGTOOLERR_BADFILENAME; - - /* iterate */ - element_start += element_len + 1; - } - - if (catrec_key && (dataRecType == hcrt_File)) - { - /* save ref */ - *parID = get_UINT32BE(catrec_key->parID); - mac_strcpy(filename, catrec_key->cName); - } - - if (cat_info) - { - if (catrec_data && (dataRecType == hcrt_File)) - { - cat_info->flFinderInfo = catrec_data->file.userInfo; - cat_info->flXFinderInfo = catrec_data->file.finderInfo; - cat_info->flags = catrec_data->file.flags; - cat_info->fileID = get_UINT32BE(catrec_data->file.fileID); - cat_info->dataLogicalSize = get_UINT32BE(catrec_data->file.dataLogicalSize); - cat_info->dataPhysicalSize = get_UINT32BE(catrec_data->file.dataPhysicalSize); - cat_info->rsrcLogicalSize = get_UINT32BE(catrec_data->file.rsrcLogicalSize); - cat_info->rsrcPhysicalSize = get_UINT32BE(catrec_data->file.rsrcPhysicalSize); - cat_info->createDate = get_UINT32BE(catrec_data->file.createDate); - cat_info->modifyDate = get_UINT32BE(catrec_data->file.modifyDate); - } - else - { - memset(cat_info, 0, sizeof(*cat_info)); - } - cat_info->dataRecType = dataRecType; - } - - return IMGTOOLERR_SUCCESS; -} - -/* - hfs_file_open_internal - - Open a file fork, given its catalog entry. This function should not be - called directly: call hfs_file_open instead. - - l2_img (I/O): level-2 image reference - file_rec (I): catalog entry for the file to open - mac_forkID (I): tells which fork should be opened - fileref (O): mac file reference to open - - Return imgtool error code -*/ -static imgtoolerr_t hfs_file_open_internal(struct mac_l2_imgref *l2_img, const hfs_catFileData *file_rec, mac_forkID fork, struct mac_fileref *fileref) -{ - assert(l2_img->format == L2I_HFS); - - fileref->l2_img = l2_img; - - fileref->fileID = get_UINT32BE(file_rec->fileID); - fileref->forkType = fork; - - switch (fork) - { - case data_fork: - fileref->eof = get_UINT32BE(file_rec->dataLogicalSize); - fileref->pLen = get_UINT32BE(file_rec->dataPhysicalSize); - memcpy(fileref->hfs.extents, file_rec->dataExtents, sizeof(hfs_extent_3)); - break; - - case rsrc_fork: - fileref->eof = get_UINT32BE(file_rec->rsrcLogicalSize); - fileref->pLen = get_UINT32BE(file_rec->rsrcPhysicalSize); - memcpy(fileref->hfs.extents, file_rec->rsrcExtents, sizeof(hfs_extent_3)); - break; - } - - fileref->crPs = 0; - - fileref->reload_buf = true; - - return IMGTOOLERR_SUCCESS; -} - -/* - hfs_file_open - - Open a file located on a HFS volume. This function should not be called - directly: call mac_file_open instead. - - l2_img (I/O): level-2 image reference - parID (I): CNID of file parent directory - filename (I): name of the file (Mac string) - mac_forkID (I): tells which fork should be opened - fileref (O): mac file reference to open - - Return imgtool error code -*/ -static imgtoolerr_t hfs_file_open(struct mac_l2_imgref *l2_img, uint32_t parID, const mac_str255 filename, mac_forkID fork, struct mac_fileref *fileref) -{ - hfs_catKey *catrec_key; - hfs_catData *catrec_data; - uint16_t dataRecType; - imgtoolerr_t err; - - /* lookup file in catalog */ - err = hfs_cat_search(l2_img, parID, filename, &catrec_key, &catrec_data); - if (err) - return err; - - dataRecType = get_UINT16BE(catrec_data->dataType); - - /* file expected */ - if (dataRecType != hcrt_File) - return IMGTOOLERR_BADFILENAME; - - fileref->hfs.parID = get_UINT32BE(catrec_key->parID); - mac_strcpy(fileref->hfs.filename, catrec_key->cName); - - /* open it */ - return hfs_file_open_internal(l2_img, &catrec_data->file, fork, fileref); -} - -/* - hfs_file_get_nth_block_address - - Get the disk block address of a given block in an open file on a MFS image. - Called by macintosh file code. - - fileref (I/O): open mac file reference - block_num (I): file block index - block_address (O): disk block address for the file block - - Return imgtool error code -*/ -static imgtoolerr_t hfs_file_get_nth_block_address(struct mac_fileref *fileref, uint32_t block_num, uint32_t *block_address) -{ - uint32_t AB_num; - uint32_t cur_AB; - uint32_t i; - void *cur_extents_raw; - hfs_extent *cur_extents; - int cur_extents_len; - void *extents_BT_rec; - int extents_BT_rec_len; - imgtoolerr_t err; - uint16_t AB_address; - - assert(fileref->l2_img->format == L2I_HFS); - - AB_num = block_num / fileref->l2_img->blocksperAB; - cur_AB = 0; - cur_extents = fileref->hfs.extents; - - /* first look in catalog tree extents */ - for (i=0; i<3; i++) - { - if (AB_num < cur_AB+get_UINT16BE(cur_extents[i].numABlks)) - break; - cur_AB += get_UINT16BE(cur_extents[i].numABlks); - } - if (i == 3) - { - /* extent not found: read extents record from extents BT */ - hfs_extentKey search_key; - hfs_extentKey *found_key; - - search_key.keyLength = keyLength_hfs_extentKey; - search_key.forkType = fileref->forkType; - set_UINT32BE(&search_key.fileID, fileref->fileID); - set_UINT16BE(&search_key.startBlock, AB_num); - - /* search for the record with the largest key lower than or equal to - search_key. The keys are constructed in such a way that, if a record - includes AB_num, it is that one. */ - err = BT_search_leaf_rec(&fileref->l2_img->u.hfs.extents_BT, &search_key, - NULL, NULL, &extents_BT_rec, &extents_BT_rec_len, - false, NULL); - if (err) - return err; - - if (extents_BT_rec == NULL) - return IMGTOOLERR_CORRUPTIMAGE; - - found_key = (hfs_extentKey*)extents_BT_rec; - /* check that this record concerns the correct file */ - if ((found_key->forkType != fileref->forkType) - || (get_UINT32BE(found_key->fileID) != fileref->fileID)) - return IMGTOOLERR_CORRUPTIMAGE; - - /* extract start AB */ - cur_AB = get_UINT16BE(found_key->startBlock); - /* get extents pointer */ - err = BT_get_keyed_record_data(&fileref->l2_img->u.hfs.extents_BT, extents_BT_rec, extents_BT_rec_len, &cur_extents_raw, &cur_extents_len); - if (err) - return err; - if (cur_extents_len < 3*sizeof(hfs_extent)) - return IMGTOOLERR_CORRUPTIMAGE; - cur_extents = (hfs_extent*)cur_extents_raw; - - /* pick correct extent in record */ - for (i=0; i<3; i++) - { - if (AB_num < cur_AB+get_UINT16BE(cur_extents[i].numABlks)) - break; - cur_AB += get_UINT16BE(cur_extents[i].numABlks); - } - if (i == 3) - /* extent not found */ - return IMGTOOLERR_CORRUPTIMAGE; - } - - AB_address = get_UINT16BE(cur_extents[i].stABN) + (AB_num-cur_AB); - - if (AB_address >= fileref->l2_img->numABs) - return IMGTOOLERR_CORRUPTIMAGE; - - *block_address = fileref->l2_img->u.hfs.ABStart + AB_address * fileref->l2_img->blocksperAB - + block_num % fileref->l2_img->blocksperAB; - - return IMGTOOLERR_SUCCESS; -} - -#if 0 -#pragma mark - -#pragma mark B-TREE IMPLEMENTATION -#endif - -/* - B-tree (Balanced search tree) files are used by the HFS and HFS+ file - systems: the Extents and Catalog files are both B-Tree. - - Note that these B-trees are B+-trees: data is only on the leaf level, and - nodes located on the same level are also linked sequentially, which allows - fast sequenctial access to the catalog file. - - These files are normal files, except for the fact that they are not - referenced from the catalog but the MDB. They are allocated in fixed-size - records of 512 bytes (HFS). (HFS+ supports any power of two from 512 - through 32768, and uses a default of 1024 for Extents, and 4096 for both - Catalog and Attributes.) - - Nodes can contain any number of records. The nodes can be of any of four - types: header node (unique node with b-tree information, pointer to root - node and start of the node allocation bitmap), map nodes (which are created - when the node allocation bitmap outgrows the header node), index nodes - (root and branch node that enable to efficiently search the leaf nodes for - a specific key value), and leaf nodes (which hold the actual user data - records with keys and data). The first node is always a header node. - Other nodes can be of any of the 3 other type, or they can be free. -*/ - -/* - BTNodeHeader - - Header of a node record -*/ -struct BTNodeHeader -{ - UINT32BE fLink; /* (index of) next node at this level */ - UINT32BE bLink; /* (index of) previous node at this level */ - uint8_t kind; /* kind of node (leaf, index, header, map) */ - uint8_t height; /* zero for header, map; 1 for leaf, 2 through - treeDepth for index (child is one LESS than - parent, whatever IM says) */ - UINT16BE numRecords; /* number of records in this node */ - UINT16BE reserved; /* reserved; set to zero */ -}; - -/* - Constants for BTNodeHeader kind field -*/ -enum -{ - btnk_leafNode = 0xff, /* leaf nodes hold the actual user data records - with keys and data */ - btnk_indexNode = 0, /* root and branch node that enable to efficiently - search the leaf nodes for a specific key value */ - btnk_headerNode = 1, /* unique node with b-tree information, pointer to - root node and start of the node allocation - bitmap */ - btnk_mapNode = 2 /* map nodes are created when the node allocation - bitmap outgrows the header node */ -}; - -/* - BTHeaderRecord: first record of a B-tree header node (second record is - unused, and third is node allocation bitmap). -*/ -struct BTHeaderRecord -{ - UINT16BE treeDepth; /* maximum height (usually leaf nodes) */ - UINT32BE rootNode; /* node number of root node */ - UINT32BE leafRecords; /* number of leaf records in all leaf nodes */ - UINT32BE firstLeafNode; /* node number of first leaf node */ - UINT32BE lastLeafNode; /* node number of last leaf node */ - UINT16BE nodeSize; /* size of a node, in bytes */ - UINT16BE maxKeyLength; /* maximum length of data (index + leaf) record keys; - length of all index record keys if - btha_variableIndexKeysMask attribute flag is not set */ - UINT32BE totalNodes; /* total number of nodes in tree */ - UINT32BE freeNodes; /* number of unused (free) nodes in tree */ - - UINT16BE reserved1; /* unused */ - UINT32BE clumpSize; /* used in some HFS implementations? (reserved in - early HFS implementations, and in HFS Plus) */ - uint8_t btreeType; /* reserved - set to 0 */ - uint8_t reserved2; /* reserved */ - UINT32BE attributes; /* persistent attributes about the tree */ - UINT32BE reserved3[16]; /* reserved */ -}; - -static imgtoolerr_t BT_check(mac_BTref *BTref, int is_extent); - -/* - BT_open - - Open a file as a B-tree. The file must be already open as a macintosh - file. - - BTref (I/O): B-tree file handle to open (BTref->fileref must have been - open previously) - key_compare_func (I): function that compares two keys - is_extent (I): true if we are opening the extent B-tree (we want to do - extra checks in this case because the extent B-Tree may include extent - records for the extent B-tree itself, and if an extent record for the - extent B-tree is located in an extent that has not been defined by - previous extent records, then we can never retreive this extent record) - - Return imgtool error code -*/ -static imgtoolerr_t BT_open(mac_BTref *BTref, int (*key_compare_func)(const void *key1, const void *key2), int is_extent) -{ - imgtoolerr_t err; - BTNodeHeader node_header; - BTHeaderRecord header_rec; - - /* seek to node 0 */ - err = mac_file_seek(&BTref->fileref, 0); - if (err) - return err; - - /* read node header */ - err = mac_file_read(&BTref->fileref, sizeof(node_header), &node_header); - if (err) - return err; - - if ((node_header.kind != btnk_headerNode) || (get_UINT16BE(node_header.numRecords) < 3) - || (node_header.height != 0)) - return IMGTOOLERR_CORRUPTIMAGE; /* right??? */ - - /* CHEESY HACK: we assume that the header record immediately follows the - node header. This is because we need to know the node length to know where - the record pointers are located, but we need to read the header record to - know the node length. */ - err = mac_file_read(&BTref->fileref, sizeof(header_rec), &header_rec); - if (err) - return err; - - BTref->nodeSize = get_UINT16BE(header_rec.nodeSize); - BTref->rootNode = get_UINT32BE(header_rec.rootNode); - BTref->firstLeafNode = get_UINT32BE(header_rec.firstLeafNode); - BTref->attributes = get_UINT32BE(header_rec.attributes); - BTref->treeDepth = get_UINT16BE(header_rec.treeDepth); - BTref->maxKeyLength = get_UINT16BE(header_rec.maxKeyLength); - - BTref->key_compare_func = key_compare_func; - - BTref->node_buf = malloc(BTref->nodeSize); - if (!BTref->node_buf) - return IMGTOOLERR_OUTOFMEMORY; - - if (BTREE_CHECKS) - { - /* optional: check integrity of B-tree */ - err = BT_check(BTref, is_extent); - if (err) - return err; - } - - return IMGTOOLERR_SUCCESS; -} - -/* - BT_close - - Close a B-tree - - BTref (I/O): open B-tree file handle -*/ -static void BT_close(mac_BTref *BTref) -{ - free(BTref->node_buf); -} - -/* - BT_read_node - - Read a node from a B-tree - - BTref (I/O): open B-tree file handle - node_ID (I): index of the node to read - expected_kind (I): kind of the node to read - expected_depth (I): depth of the node to read - dest (O): destination buffer - - Return imgtool error code -*/ -static imgtoolerr_t BT_read_node(mac_BTref *BTref, uint32_t node_ID, int expected_kind, int expected_depth, void *dest) -{ - imgtoolerr_t err; - - /* seek to node */ - err = mac_file_seek(&BTref->fileref, node_ID*BTref->nodeSize); - if (err) - return err; - - /* read it */ - err = mac_file_read(&BTref->fileref, BTref->nodeSize, dest); - if (err) - return err; - - /* check node kind and depth */ - if ((((BTNodeHeader *) dest)->kind != expected_kind) - || (((BTNodeHeader *) dest)->height != expected_depth)) - return IMGTOOLERR_CORRUPTIMAGE; - - return IMGTOOLERR_SUCCESS; -} - -/* - BT_node_get_record - - Extract a raw record from a B-tree node - - BTref (I/O): open B-tree file handle - node_buf (I): buffer with the node the record should be extracted from - recnum (I): index of record to read - rec_ptr (O): set to point to start of record (key + data) - rec_len (O): set to total length of record (key + data) - - Return imgtool error code -*/ -static imgtoolerr_t BT_node_get_record(mac_BTref *BTref, void *node_buf, unsigned recnum, void **rec_ptr, int *rec_len) -{ - uint16_t node_numRecords = get_UINT16BE(((BTNodeHeader *) node_buf)->numRecords); - uint16_t offset; - uint16_t next_offset; - - if (recnum >= node_numRecords) - return IMGTOOLERR_UNEXPECTED; - - int recnum_s = (int)recnum; - offset = get_UINT16BE(((UINT16BE *)((uint8_t *) node_buf + BTref->nodeSize))[-recnum_s - 1]); - next_offset = get_UINT16BE(((UINT16BE *)((uint8_t *) node_buf + BTref->nodeSize))[-recnum_s - 2]); - - if ((offset < sizeof(BTNodeHeader)) || (offset > BTref->nodeSize-2*node_numRecords) - || (next_offset < sizeof(BTNodeHeader)) || (next_offset > BTref->nodeSize-2*node_numRecords) - || (offset & 1) || (next_offset & 1) - || (offset > next_offset)) - return IMGTOOLERR_CORRUPTIMAGE; - - *rec_ptr = (uint8_t *)node_buf + offset; - *rec_len = next_offset - offset; - - return IMGTOOLERR_SUCCESS; -} - -/* - BT_node_get_keyed_record - - Extract a keyed record from a B-tree node. Equivalent to - BT_node_get_record, only we do extra checks. - - BTref (I/O): open B-tree file handle - node_buf (I): buffer with the node the record should be extracted from - node_is_index (I): true if node is index node - recnum (I): index of record to read - rec_ptr (O): set to point to start of record (key + data) - rec_len (O): set to total length of record (key + data) - - Return imgtool error code -*/ -static imgtoolerr_t BT_node_get_keyed_record(mac_BTref *BTref, void *node_buf, int node_is_index, unsigned recnum, void **rec_ptr, int *rec_len) -{ - imgtoolerr_t err; - void *lrec_ptr; - int lrec_len; - int key_len; - - /* extract record */ - err = BT_node_get_record(BTref, node_buf, recnum, &lrec_ptr, &lrec_len); - if (err) - return err; - - /* read key len */ - key_len = (BTref->attributes & btha_bigKeysMask) - ? get_UINT16BE(* (UINT16BE *)lrec_ptr) - : (* (uint8_t *)lrec_ptr); - - /* check that key fits in record */ - if ((key_len + ((BTref->attributes & btha_bigKeysMask) ? 2 : 1)) > lrec_len) - /* hurk! */ - return IMGTOOLERR_CORRUPTIMAGE; - - if (key_len > BTref->maxKeyLength) - return IMGTOOLERR_CORRUPTIMAGE; - - if (node_is_index && (! (BTref->attributes & btha_variableIndexKeysMask)) && (key_len != BTref->maxKeyLength)) - return IMGTOOLERR_CORRUPTIMAGE; - - if (rec_ptr) - *rec_ptr = lrec_ptr; - if (rec_len) - *rec_len = lrec_len; - - return IMGTOOLERR_SUCCESS; -} - -/* - BT_get_keyed_record_data - - extract data from a keyed record - - BTref (I/O): open B-tree file handle - rec_ptr (I): point to start of record (key + data) - rec_len (I): total length of record (key + data) - data_ptr (O): set to point to record data - data_len (O): set to length of record data - - Return imgtool error code -*/ -static imgtoolerr_t BT_get_keyed_record_data(mac_BTref *BTref, void *rec_ptr, int rec_len, void **data_ptr, int *data_len) -{ - int lkey_len; - int data_offset; - - /* read key len */ - lkey_len = (BTref->attributes & btha_bigKeysMask) - ? get_UINT16BE(* (UINT16BE *)rec_ptr) - : (* (uint8_t *)rec_ptr); - - /* compute offset to data record */ - data_offset = lkey_len + ((BTref->attributes & btha_bigKeysMask) ? 2 : 1); - if (data_offset > rec_len) - /* hurk! */ - return IMGTOOLERR_CORRUPTIMAGE; - /* fix alignment */ - if (data_offset & 1) - data_offset++; - - if (data_ptr) - *data_ptr = (uint8_t *)rec_ptr + data_offset; - if (data_len) - *data_len = (rec_len > data_offset) ? rec_len-data_offset : 0; - - return IMGTOOLERR_SUCCESS; -} - -/* - BT_check - - Check integrity of a complete B-tree - - BTref (I/O): open B-tree file handle - is_extent (I): true if we are opening the extent B-tree (we want to do - extra checks in this case because the extent B-Tree may include extent - records for the extent B-tree itself, and if an extent record for the - extent B-tree is located in an extent that has not been defined by - previous extent records, then we can never retreive this extent record) - - Return imgtool error code -*/ -struct data_nodes_t -{ - void *buf; - uint32_t node_num; - uint32_t cur_rec; - uint32_t num_recs; -}; -static imgtoolerr_t BT_check(mac_BTref *BTref, int is_extent) -{ - uint16_t node_numRecords; - BTHeaderRecord *header_rec; - uint8_t *bitmap; - - data_nodes_t *data_nodes; - int i, j; - uint32_t cur_node, prev_node; - void *rec1, *rec2; - int rec1_len, rec2_len; - void *rec1_data; - int rec1_data_len; - uint32_t totalNodes, lastLeafNode; - uint32_t freeNodes; - int compare_result; - uint32_t map_count, map_len; - uint32_t run_len; - uint32_t run_bit_len; - uint32_t actualFreeNodes; - imgtoolerr_t err; - uint32_t maxExtentAB = 0, maxExtentNode = 0, extentEOL = 0; /* if is_extent is true */ - - if (is_extent) - { - switch (BTref->fileref.l2_img->format) - { - case L2I_MFS: - /* MFS does not feature any extents B-tree! */ - return IMGTOOLERR_UNEXPECTED; - - case L2I_HFS: - maxExtentAB = 0; - for (j=0; j<3; j++) - maxExtentAB += get_UINT16BE(BTref->fileref.hfs.extents[j].numABlks); - maxExtentNode = (uint64_t)maxExtentAB * 512 * BTref->fileref.l2_img->blocksperAB - / BTref->nodeSize; - extentEOL = false; - break; - } - } - - /* read header node */ - if ((! is_extent) || (0 < maxExtentNode)) - err = BT_read_node(BTref, 0, btnk_headerNode, 0, BTref->node_buf); - else - err = IMGTOOLERR_CORRUPTIMAGE; - if (err) - return err; - - /* check we have enough records */ - node_numRecords = get_UINT16BE(((BTNodeHeader *) BTref->node_buf)->numRecords); - if (node_numRecords < 3) - return IMGTOOLERR_CORRUPTIMAGE; - - /* get header record */ - err = BT_node_get_record(BTref, BTref->node_buf, 0, &rec1, &rec1_len); - if (err) - return err; - header_rec = (BTHeaderRecord *)rec1; - - /* check length of header record */ - if (rec1_len < sizeof(BTHeaderRecord)) - return IMGTOOLERR_CORRUPTIMAGE; - - totalNodes = get_UINT32BE(header_rec->totalNodes); - if (totalNodes == 0) - /* we need at least one header node */ - return IMGTOOLERR_CORRUPTIMAGE; - lastLeafNode = get_UINT32BE(header_rec->lastLeafNode); - freeNodes = get_UINT32BE(header_rec->freeNodes); - - /* check file length */ - if ((BTref->nodeSize * totalNodes) > BTref->fileref.pLen) - return IMGTOOLERR_CORRUPTIMAGE; - - /* initialize for the function postlog ("bail:" tag) */ - err = IMGTOOLERR_SUCCESS; - bitmap = NULL; - data_nodes = NULL; - - /* alloc buffer for reconstructed bitmap */ - map_len = (totalNodes + 7) / 8; - bitmap = (uint8_t*)malloc(map_len); - if (! bitmap) - return IMGTOOLERR_OUTOFMEMORY; - memset(bitmap, 0, map_len); - - /* check B-tree data nodes (i.e. index and leaf nodes) */ - if (BTref->treeDepth == 0) - { - /* B-tree is empty */ - if (BTref->rootNode || BTref->firstLeafNode || lastLeafNode) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto bail; - } - } - else - { - /* alloc array of buffers for catalog data nodes */ - data_nodes = (data_nodes_t *)malloc(sizeof(data_nodes_t) * BTref->treeDepth); - if (! data_nodes) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto bail; - } - for (i=0; i<BTref->treeDepth; i++) - data_nodes[i].buf = NULL; /* required for function postlog to work should next loop fail */ - for (i=0; i<BTref->treeDepth; i++) - { - data_nodes[i].buf = malloc(BTref->nodeSize); - if (!data_nodes[i].buf) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto bail; - } - } - - /* read first data nodes */ - cur_node = BTref->rootNode; - for (i=BTref->treeDepth-1; i>=0; i--) - { - /* check node index */ - if (cur_node >= totalNodes) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - /* check that node has not been used for another purpose */ - /* this check is unecessary because the current consistency checks - that forward and back linking match and that node height is correct - are enough to detect such errors */ -#if 0 - if (bitmap[cur_node >> 3] & (0x80 >> (cur_node & 7))) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } -#endif - /* add node in bitmap */ - bitmap[cur_node >> 3] |= (0x80 >> (cur_node & 7)); - /* read node */ - if ((! is_extent) || (cur_node < maxExtentNode)) - err = BT_read_node(BTref, cur_node, i ? btnk_indexNode : btnk_leafNode, i+1, data_nodes[i].buf); - else - err = IMGTOOLERR_CORRUPTIMAGE; - if (err) - goto bail; - /* check that it is the first node at this level */ - if (get_UINT32BE(((BTNodeHeader *) data_nodes[i].buf)->bLink)) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - /* fill other fields */ - data_nodes[i].node_num = cur_node; - data_nodes[i].cur_rec = 0; - data_nodes[i].num_recs = get_UINT16BE(((BTNodeHeader *) data_nodes[i].buf)->numRecords); - /* check that there is at least one record */ - if (data_nodes[i].num_recs == 0) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - - /* iterate to next level if applicable */ - if (i != 0) - { - /* extract first record */ - err = BT_node_get_keyed_record(BTref, data_nodes[i].buf, true, 0, &rec1, &rec1_len); - if (err) - goto bail; - - /* extract record data ptr */ - err = BT_get_keyed_record_data(BTref, rec1, rec1_len, &rec1_data, &rec1_data_len); - if (err) - goto bail; - if (rec1_data_len < sizeof(UINT32BE)) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - - /* iterate to next level */ - cur_node = get_UINT32BE(* (UINT32BE *)rec1_data); - } - } - - /* check that a) the root node has no successor, and b) that we have really - read the first leaf node */ - if (get_UINT32BE(((BTNodeHeader *) data_nodes[BTref->treeDepth-1].buf)->fLink) - || (cur_node != BTref->firstLeafNode)) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - - /* check that keys are ordered correctly */ - while (1) - { - /* iterate through parent nodes */ - i = 0; - while ((i<BTref->treeDepth) && ((data_nodes[i].cur_rec == 0) || (data_nodes[i].cur_rec == data_nodes[i].num_recs))) - { - /* read next node if necessary */ - if (data_nodes[i].cur_rec == data_nodes[i].num_recs) - { - /* get link to next node */ - cur_node = get_UINT32BE(((BTNodeHeader *) data_nodes[i].buf)->fLink); - if (cur_node == 0) - { - if (i == 0) - /* normal End of List */ - goto end_of_list; - else - { - /* error */ - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - } - /* add node in bitmap */ - bitmap[cur_node >> 3] |= (0x80 >> (cur_node & 7)); - /* read node */ - if ((! is_extent) || (cur_node < maxExtentNode)) - err = BT_read_node(BTref, cur_node, i ? btnk_indexNode : btnk_leafNode, i+1, data_nodes[i].buf); - else - err = IMGTOOLERR_CORRUPTIMAGE; - if (err) - goto bail; - /* check that backward linking match forward linking */ - if (get_UINT32BE(((BTNodeHeader *) data_nodes[i].buf)->bLink) != data_nodes[i].node_num) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - /* fill other fields */ - data_nodes[i].node_num = cur_node; - data_nodes[i].cur_rec = 0; - data_nodes[i].num_recs = get_UINT16BE(((BTNodeHeader *) data_nodes[i].buf)->numRecords); - /* check that there is at least one record */ - if (data_nodes[i].num_recs == 0) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - /* next test is not necessary because we have checked that - the root node has no successor */ -#if 0 - if (i < BTref->treeDepth-1) - { -#endif - data_nodes[i+1].cur_rec++; -#if 0 - } - else - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } -#endif - } - i++; - } - - if (is_extent && !extentEOL) - { - /* extract current leaf record and update maxExtentAB and - maxExtentNode */ - hfs_extentKey *extentKey; - hfs_extent *extentData; - - /* extract current leaf record */ - err = BT_node_get_keyed_record(BTref, data_nodes[0].buf, false, data_nodes[0].cur_rec, &rec1, &rec1_len); - if (err) - goto bail; - - extentKey = (hfs_extentKey*)rec1; - if ((extentKey->keyLength < 7) || (extentKey->forkType != 0) || (get_UINT32BE(extentKey->fileID) != 3) - || (get_UINT16BE(extentKey->startBlock) != maxExtentAB)) - /* the key is corrupt or does not concern the extent - B-tree: set the extentEOL flag so that we stop looking for - further extent records for the extent B-tree */ - extentEOL = true; - else - { /* this key concerns the extent B-tree: update maxExtentAB - and maxExtentNode */ - /* extract record data ptr */ - err = BT_get_keyed_record_data(BTref, rec1, rec1_len, &rec1_data, &rec1_data_len); - if (err) - goto bail; - if (rec1_data_len < sizeof(hfs_extent)*3) - /* the record is corrupt: set the extentEOL flag so - that we stop looking for further extent records for the - extent B-tree */ - extentEOL = true; - else - { - extentData = (hfs_extent*)rec1_data; - - for (j=0; j<3; j++) - maxExtentAB += get_UINT16BE(extentData[j].numABlks); - maxExtentNode = (uint64_t)maxExtentAB * 512 * BTref->fileref.l2_img->blocksperAB - / BTref->nodeSize; - } - } - if (extentEOL) - { - /* check that the extent B-Tree has been defined entirely */ - if (maxExtentNode < totalNodes) - { /* no good */ - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - } - } - - if (i<BTref->treeDepth) - { - /* extract current record */ - err = BT_node_get_keyed_record(BTref, data_nodes[i].buf, i > 0, data_nodes[i].cur_rec, &rec1, &rec1_len); - if (err) - goto bail; - - /* extract previous record */ - err = BT_node_get_keyed_record(BTref, data_nodes[i].buf, i > 0, data_nodes[i].cur_rec-1, &rec2, &rec2_len); - if (err) - goto bail; - - /* check that it is sorted correctly */ - compare_result = (*BTref->key_compare_func)(rec1, rec2); - if (compare_result <= 0) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - - i--; - } - else - { - i--; - if (i>0) - { /* extract first record of root if it is an index node */ - err = BT_node_get_keyed_record(BTref, data_nodes[i].buf, true, data_nodes[i].cur_rec, &rec1, &rec1_len); - if (err) - goto bail; - } - i--; - } - - while (i>=0) - { - /* extract first record of current level */ - err = BT_node_get_keyed_record(BTref, data_nodes[i].buf, i > 0, data_nodes[i].cur_rec, &rec2, &rec2_len); - if (err) - goto bail; - - /* compare key with key of current record of upper level */ - compare_result = (*BTref->key_compare_func)(rec1, rec2); - if (compare_result != 0) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - - /* extract record data ptr */ - err = BT_get_keyed_record_data(BTref, rec1, rec1_len, &rec1_data, &rec1_data_len); - if (err) - goto bail; - if (rec1_data_len < sizeof(UINT32BE)) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - cur_node = get_UINT32BE(* (UINT32BE *)rec1_data); - - /* compare node index with data of current record of upper - level */ - if (cur_node != data_nodes[i].node_num) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - - /* iterate to next level */ - rec1 = rec2; - rec1_len = rec2_len; - i--; - } - - /* next leaf record */ - data_nodes[0].cur_rec++; - } - -end_of_list: - /* check that we are at the end of list for each index level */ - for (i=1; i<BTref->treeDepth; i++) - { - if ((data_nodes[i].cur_rec != (data_nodes[i].num_recs-1)) - || get_UINT32BE(((BTNodeHeader *) data_nodes[i].buf)->fLink)) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - } - /* check that the last leaf node is what it is expected to be */ - if (data_nodes[0].node_num != lastLeafNode) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - } - - /* check map node chain */ - cur_node = 0; /* node 0 is the header node... */ - bitmap[0] |= 0x80; - /* check back linking */ - if (get_UINT32BE(((BTNodeHeader *) BTref->node_buf)->bLink)) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - /* get pointer to next node */ - cur_node = get_UINT32BE(((BTNodeHeader *) BTref->node_buf)->fLink); - while (cur_node != 0) - { - /* save node address */ - prev_node = cur_node; - /* check that node has not been used for another purpose */ - /* this check is unecessary because the current consistency checks that - forward and back linking match and that node height is correct are - enough to detect such errors */ -#if 0 - if (bitmap[cur_node >> 3] & (0x80 >> (cur_node & 7))) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } -#endif - /* add node in bitmap */ - bitmap[cur_node >> 3] |= (0x80 >> (cur_node & 7)); - /* read map node */ - if ((! is_extent) || (cur_node < maxExtentNode)) - err = BT_read_node(BTref, cur_node, btnk_mapNode, 0, BTref->node_buf); - else - err = IMGTOOLERR_CORRUPTIMAGE; - if (err) - goto bail; - /* check back linking */ - if (get_UINT32BE(((BTNodeHeader *) BTref->node_buf)->bLink) != prev_node) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - /* get pointer to next node */ - cur_node = get_UINT32BE(((BTNodeHeader *) BTref->node_buf)->fLink); - } - - /* re-read header node */ - err = BT_read_node(BTref, 0, btnk_headerNode, 0, BTref->node_buf); - if (err) - goto bail; - - /* get header bitmap record */ - err = BT_node_get_record(BTref, BTref->node_buf, 2, &rec1, &rec1_len); - if (err) - goto bail; - - /* check bitmap, iterating map nodes */ - map_count = 0; - actualFreeNodes = 0; - while (map_count < map_len) - { - /* compute compare len */ - run_len = rec1_len; - if (run_len > (map_len-map_count)) - run_len = map_len-map_count; - /* check that all used nodes are marked as such in the B-tree bitmap */ - for (i=0; i<run_len; i++) - if (bitmap[map_count+i] & ~((uint8_t *)rec1)[i]) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - /* count free nodes */ - run_bit_len = rec1_len*8; - if (run_bit_len > (totalNodes-map_count*8)) - run_bit_len = totalNodes-map_count*8; - for (i=0; i<run_bit_len; i++) - if (! (((uint8_t *)rec1)[i>>3] & (0x80 >> (i & 7)))) - actualFreeNodes++; - map_count += run_len; - /* read next map node if required */ - if (map_count < map_len) - { - /* get pointer to next node */ - cur_node = get_UINT32BE(((BTNodeHeader *) BTref->node_buf)->fLink); - if (cur_node == 0) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - /* read map node */ - err = BT_read_node(BTref, cur_node, btnk_mapNode, 0, BTref->node_buf); - if (err) - goto bail; - /* get map record */ - err = BT_node_get_record(BTref, BTref->node_buf, 0, &rec1, &rec1_len); - if (err) - goto bail; - header_rec = (BTHeaderRecord *)rec1; - } - } - - /* check free node count */ - if (freeNodes != actualFreeNodes) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto bail; - } - -bail: - /* free buffers */ - if (data_nodes) - { - for (i=0; i<BTref->treeDepth; i++) - if (data_nodes[i].buf) - free(data_nodes[i].buf); - free(data_nodes); - } - if (bitmap) - free(bitmap); - - return err; -} - -/* - BT_search_leaf_rec - - Search for a given key in a B-Tree. If exact match found, returns - corresponding leaf record. Otherwise, may return the greatest record less - than the requested key (of course, this will fail if the key is lower than - all keys in the B-Tree). - - BTref (I/O): open B-tree file handle - search_key (I): key to search the B-Tree for - node_ID (O): set to the node ID of the node the record is located in (may - be NULL) - record_ID (O): set to the index of the record in the node (may be NULL) - record_ptr (O): set to point to record in node buffer (may be NULL) - record_len (O): set to total record len (may be NULL) - search_exact_match (I): if true, the function will search for a record - equal to search_key; if false, the function will search for the - greatest record less than or equal to search_key - match_found (O): set to true if an exact match for search_key has been - found (only makes sense if search_exact_match is false) (may be NULL) - - Return imgtool error code -*/ -static imgtoolerr_t BT_search_leaf_rec(mac_BTref *BTref, const void *search_key, - uint32_t *node_ID, int *record_ID, - void **record_ptr, int *record_len, - int search_exact_match, int *match_found) -{ - imgtoolerr_t err; - int i; - uint32_t cur_node; - void *cur_rec; - int cur_rec_len; - void *last_rec; - int last_rec_len = 0; - void *rec_data; - int rec_data_len; - int depth; - uint16_t node_numRecords; - int compare_result = 0; - - /* start with root node */ - if ((BTref->rootNode == 0) || (BTref->treeDepth == 0)) - /* tree is empty */ - return ((BTref->rootNode == 0) == (BTref->treeDepth == 0)) - ? IMGTOOLERR_FILENOTFOUND - : IMGTOOLERR_CORRUPTIMAGE; - - cur_node = BTref->rootNode; - depth = BTref->treeDepth; - - while (1) - { - /* read current node */ - err = BT_read_node(BTref, cur_node, (depth > 1) ? btnk_indexNode : btnk_leafNode, depth, BTref->node_buf); - if (err) - return err; - - /* search for key */ - node_numRecords = get_UINT16BE(((BTNodeHeader *) BTref->node_buf)->numRecords); - last_rec = cur_rec = NULL; - for (i=0; i<node_numRecords; i++) - { - err = BT_node_get_keyed_record(BTref, BTref->node_buf, depth > 1, i, &cur_rec, &cur_rec_len); - if (err) - return err; - - compare_result = (*BTref->key_compare_func)(cur_rec, search_key); - if (compare_result > 0) - break; - last_rec = cur_rec; - last_rec_len = cur_rec_len; - if (compare_result == 0) - break; - } - - if (! last_rec) - { /* all keys are greater than the search key: the search key is - nowhere in the tree */ - if (search_exact_match) - return IMGTOOLERR_FILENOTFOUND; - - if (match_found) - *match_found = false; - - if (node_ID) - *node_ID = 0; - - if (record_ID) - *record_ID = -1; - - if (record_ptr) - *record_ptr = NULL; - - return IMGTOOLERR_SUCCESS; - } - - if (((BTNodeHeader *) BTref->node_buf)->kind == btnk_leafNode) - /* leaf node -> end of search */ - break; - - /* extract record data ptr */ - err = BT_get_keyed_record_data(BTref, last_rec, last_rec_len, &rec_data, &rec_data_len); - if (err) - return err; - if (rec_data_len < sizeof(UINT32BE)) - return IMGTOOLERR_CORRUPTIMAGE; - - /* iterate to next level */ - cur_node = get_UINT32BE(* (UINT32BE *)rec_data); - depth--; - } - - if (compare_result != 0) - /* key not found */ - if (search_exact_match) - return IMGTOOLERR_FILENOTFOUND; - - if (match_found) - *match_found = (compare_result == 0); - - if (node_ID) - *node_ID = cur_node; - - if (record_ID) - *record_ID = i; - - if (record_ptr) - *record_ptr = last_rec; - - if (record_len) - *record_len = last_rec_len; - - return IMGTOOLERR_SUCCESS; -} - -/* - BT_leaf_rec_enumerator_open - - Open enumerator for leaf records of a B-Tree - - BTref (I/O): open B-tree file handle - enumerator (O): B-Tree enumerator to open - - Return imgtool error code -*/ -static imgtoolerr_t BT_leaf_rec_enumerator_open(mac_BTref *BTref, BT_leaf_rec_enumerator *enumerator) -{ - enumerator->BTref = BTref; - enumerator->cur_node = BTref->firstLeafNode; - enumerator->cur_rec = 0; - - return IMGTOOLERR_SUCCESS; -} - -/* - BT_leaf_rec_enumerator_read - - Read next leaf record of a B-Tree - - enumerator (I/O): open B-Tree enumerator - - Return imgtool error code -*/ -static imgtoolerr_t BT_leaf_rec_enumerator_read(BT_leaf_rec_enumerator *enumerator, void **record_ptr, int *rec_len) -{ - uint16_t node_numRecords; - imgtoolerr_t err; - - - *record_ptr = NULL; - - /* check EOList condition */ - if (enumerator->cur_node == 0) - return IMGTOOLERR_SUCCESS; - - /* read current node */ - err = BT_read_node(enumerator->BTref, enumerator->cur_node, btnk_leafNode, 1, enumerator->BTref->node_buf); - if (err) - return err; - node_numRecords = get_UINT16BE(((BTNodeHeader *) enumerator->BTref->node_buf)->numRecords); - - /* skip nodes until we find a record */ - while ((enumerator->cur_rec >= node_numRecords) && (enumerator->cur_node != 0)) - { - enumerator->cur_node = get_UINT32BE(((BTNodeHeader *) enumerator->BTref->node_buf)->fLink); - enumerator->cur_rec = 0; - - /* read node */ - err = BT_read_node(enumerator->BTref, enumerator->cur_node, btnk_leafNode, 1, enumerator->BTref->node_buf); - if (err) - return err; - node_numRecords = get_UINT16BE(((BTNodeHeader *) enumerator->BTref->node_buf)->numRecords); - } - - /* check EOList condition */ - if (enumerator->cur_node == 0) - return IMGTOOLERR_SUCCESS; - - /* get current record */ - err = BT_node_get_keyed_record(enumerator->BTref, enumerator->BTref->node_buf, false, enumerator->cur_rec, record_ptr, rec_len); - if (err) - return err; - - /* iterate to next record */ - enumerator->cur_rec++; - if (enumerator->cur_rec >= node_numRecords) - { /* iterate to next node if last record (not required, but will improve - performance on next iteration) */ - enumerator->cur_node = get_UINT32BE(((BTNodeHeader *) enumerator->BTref->node_buf)->fLink); - enumerator->cur_rec = 0; - } - return IMGTOOLERR_SUCCESS; -} - -/* - B-Tree extend EOF algorithm: - * see if the bitmap will need to be extended - * extend EOF by min 1 (if bitmap is large engough) or 2 (if bitmap needs - to be extended) and max ClumpSiz (see extClpSiz and ctClpSiz in MDB) - ***If we are extending the extent B-Tree, we need to defer the possible - creation of an additional extent record, or we might enter an endless - recursion loop*** - - Empty node alloc algorithm: - - * see if there is any free node in B-tree bitmap - * optionally, try to compact the B-tree if file is full - * if file is still full, extend EOF and try again - * mark new block as used and return its index - - - Empty node delete algorithm: - - * remove node from link list - * mark node as free in the B-tree bitmap - * optionally, if more than N% of the B-tree is free, compact the B-tree and - free some disk space - * Count nodes on this level; if there is only one left, delete parent index - node and mark the relaining node as root; if it was the last leaf node, - update header node with an empty B-tree; in either case, decrement tree - depth - - - Record shifting algorithm: - - For a given node and its first non-empty successor node: - - * compute how much free room there is in the node - * see if the first record of the first non-empty successor can fit - * if so, move it (i.e. delete the first record of the later node, and add a - copy of it to the end of the former) - - - Node merging algorithm - - * Consider node and its predecessor. If there is room, shift all records - from later to former, then delete empty later node, and delete later - record from parent index node. - - - Node splitting algorithm (non-first) - - * Consider node and its predecessor. Create new middle node and split - records in 3 even sets. Update record for last node and insert record - for middle node in parent index node. - - - Node splitting algorithm (first node) - - * Create new successor node, and split records in 2 1/3 and 2/3 sets. - Insert record for later node in parent index node. - - - Record delete algorithm: - - * remove record from node - * if record was first in node, test if node is now empty - * if node is not empty, substitute key of deleted record with key of - new head record in index tree - * if node is empty, delete key of deleted record in index tree, then - delete empty node - * optionally, look the predecessor node. Merge the two nodes if possible. - - - Record insert algorithm: - - * if there room, just insert new record in node; if new record is in first - position, update record in parent index node - * else consider predecessor: see if we can make enough room by shifting - records. If so, do shift records, insert new record, update record in - parent index node - * else split the nodes and insert record -*/ -/* - Possible additions: - - Node compaction algorithm: - - This algorithm can be executed with a specific start point and max number - of nodes, or with all nodes on a level. - - * see how many nodes we can save by shifting records left - * if we will save at least one node, do shift as many records as possible - (try to leave free space split homogeneously???) -*/ - -/*static void*/ - -#if 0 -#pragma mark - -#pragma mark RESOURCE IMPLEMENTATION -#endif - -/* - Resource manager - - The resource manager stores arbitrary chunks of data (resource) identified - by a type/id pair. The resource type is a 4-char code, which generally - implies the format of the data (e.g. 'PICT' is for a quickdraw picture, - 'STR ' for a macintosh string, 'CODE' for 68k machine code, etc). The - resource id is a signed 16-bit number that uniquely identifies each - resource of a given type. Note that, with most resource types, resources - with id < 128 are system resources that are available to all applications, - whereas resources with id >= 128 are application resources visible only to - the application that defines them. - - Each resource can optionally have a resource name, which is a macintosh - string of 255 chars at most. - - Limits: - 16MBytes of data - 64kbytes of type+reference lists - 64kbytes of resource names - - The Macintosh toolbox can open several resource files simulteanously to - overcome these restrictions. - - Resources are used virtually everywhere in the Macintosh Toolbox, so it is - no surprise that file comments and MFS folders are stored in resource files. -*/ - -/* - Resource header -*/ -struct rsrc_header -{ - UINT32BE data_offs; /* Offset from beginning of resource fork to resource data */ - UINT32BE map_offs; /* Offset from beginning of resource fork to resource map */ - UINT32BE data_len; /* Length of resource data */ - UINT32BE map_len; /* Length of resource map */ -}; - -/* - Resource data: each data entry is preceded by its len (UINT32BE) - Offset to specific data fields are gotten from the resource map -*/ - -/* - Resource map: -*/ -struct rsrc_map_header -{ - rsrc_header reserved0; /* Reserved for copy of resource header */ - UINT32BE reserved1; /* Reserved for handle to next resource map */ - UINT16BE reserved2; /* Reserved for file reference number */ - - UINT16BE attr; /* Resource fork attributes */ - UINT16BE typelist_offs; /* Offset from beginning of map to resource type list */ - UINT16BE namelist_offs; /* Offset from beginning of map to resource name list */ - UINT16BE type_count; /* Number of types in the map minus 1 */ - /* This is actually part of the type list, which matters for offsets */ -}; - -/* - Resource type list entry -*/ -struct rsrc_type_entry -{ - UINT32BE type; /* Resource type */ - UINT16BE ref_count; /* Number of resources of this type in map minus 1 */ - UINT16BE ref_offs; /* Offset from beginning of resource type list to reference list for this type */ -}; - -/* - Resource reference list entry -*/ -struct rsrc_ref_entry -{ - UINT16BE id; /* Resource ID */ - UINT16BE name_offs; /* Offset from beginning of resource name list to resource name */ - /* (-1 if none) */ - uint8_t attr; /* Resource attributes */ - UINT24BE data_offs; /* Offset from beginning of resource data to data for this resource */ - UINT32BE reserved; /* Reserved for handle to resource */ -}; - -/* - Resource name list entry: this is just a standard macintosh string -*/ - -struct mac_resfileref -{ - mac_fileref fileref; /* open resource fork ref (you may open resources - files in data fork, too, if you ever need to, - but Classic MacOS never does such a thing - (MacOS X often does so, though)) */ - uint32_t data_offs; /* Offset from beginning of resource file to resource data */ - uint32_t map_offs; /* Offset from beginning of resource file to resource data */ - - uint16_t typelist_offs; /* Offset from beginning of map to resource type list */ - uint16_t namelist_offs; /* Offset from beginning of map to resource name list */ - uint16_t type_count; /* Number of types in the map minus 1 */ - /* This is actually part of the type list, which matters for offsets */ -}; - -#ifdef UNUSED_FUNCTION -/* - resfile_open - - Open a file as a resource file. The file must be already open as a - macintosh file. - - resfileref (I/O): resource file handle to open (resfileref->fileref must - have been opened previously) - - Return imgtool error code -*/ -static imgtoolerr_t resfile_open(mac_resfileref *resfileref) -{ - imgtoolerr_t err; - rsrc_header header; - rsrc_map_header map_header; - - /* seek to resource header */ - err = mac_file_seek(&resfileref->fileref, 0); - if (err) - return err; - - err = mac_file_read(&resfileref->fileref, sizeof(header), &header); - if (err) - return err; - - resfileref->data_offs = get_UINT32BE(header.data_offs); - resfileref->map_offs = get_UINT32BE(header.map_offs); - - /* seek to resource map header */ - err = mac_file_seek(&resfileref->fileref, resfileref->map_offs); - if (err) - return err; - - err = mac_file_read(&resfileref->fileref, sizeof(map_header), &map_header); - if (err) - return err; - - resfileref->typelist_offs = get_UINT16BE(map_header.typelist_offs); - resfileref->namelist_offs = get_UINT16BE(map_header.namelist_offs); - resfileref->type_count = get_UINT16BE(map_header.type_count); - - return IMGTOOLERR_SUCCESS; -} - -/* - resfile_get_entry - - Get the resource entry in the resource map associated with a given type/id - pair. - - resfileref (I/O): open resource file handle - type (I): type of the resource - id (I): id of the resource - entry (O): resource entry that has been read - - Return imgtool error code -*/ -static imgtoolerr_t resfile_get_entry(mac_resfileref *resfileref, uint32_t type, uint16_t id, rsrc_ref_entry *entry) -{ - imgtoolerr_t err; - rsrc_type_entry type_entry; - uint16_t ref_count; - int i; - - /* seek to resource type list in resource map */ - err = mac_file_seek(&resfileref->fileref, resfileref->map_offs+resfileref->typelist_offs+2); - if (err) - return err; - - if (resfileref->type_count == 0xffff) - /* type list is empty */ - return IMGTOOLERR_FILENOTFOUND; - - for (i=0; i<=resfileref->type_count; i++) - { - err = mac_file_read(&resfileref->fileref, sizeof(type_entry), &type_entry); - if (err) - return err; - if (type == get_UINT32BE(type_entry.type)) - break; - } - if (i > resfileref->type_count) - /* type not found in list */ - return IMGTOOLERR_FILENOTFOUND; - - ref_count = get_UINT16BE(type_entry.ref_count); - - /* seek to resource ref list for this type in resource map */ - err = mac_file_seek(&resfileref->fileref, resfileref->map_offs+resfileref->typelist_offs+get_UINT16BE(type_entry.ref_offs)); - if (err) - return err; - - if (ref_count == 0xffff) - /* ref list is empty */ - return IMGTOOLERR_FILENOTFOUND; - - for (i=0; i<=ref_count; i++) - { - err = mac_file_read(&resfileref->fileref, sizeof(*entry), entry); - if (err) - return err; - if (id == get_UINT16BE(entry->id)) - break; - } - if (i > ref_count) - /* id not found in list */ - return IMGTOOLERR_FILENOTFOUND; - - /* type+id have been found... */ - return IMGTOOLERR_SUCCESS; -} - -/* - resfile_get_resname - - Get the name of a resource. - - resfileref (I/O): open resource file handle - entry (I): resource entry in the resource map (returned by - resfile_get_entry) - string (O): resource name - - Return imgtool error code -*/ -static imgtoolerr_t resfile_get_resname(mac_resfileref *resfileref, const rsrc_ref_entry *entry, mac_str255 string) -{ - imgtoolerr_t err; - uint16_t name_offs; - uint8_t len; - - name_offs = get_UINT16BE(entry->name_offs); - - if (name_offs == 0xffff) - /* ref list is empty */ - return IMGTOOLERR_UNEXPECTED; - - /* seek to resource name in name list in resource map */ - err = mac_file_seek(&resfileref->fileref, resfileref->map_offs+name_offs); - if (err) - return err; - - /* get string length */ - err = mac_file_read(&resfileref->fileref, 1, &len); - if (err) - return err; - - string[0] = len; - - /* get string data */ - err = mac_file_read(&resfileref->fileref, len, string+1); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - -/* - resfile_get_reslen - - Get the data length for a given resource. - - resfileref (I/O): open resource file handle - entry (I): resource entry in the resource map (returned by - resfile_get_entry) - len (O): resource length - - Return imgtool error code -*/ -static imgtoolerr_t resfile_get_reslen(mac_resfileref *resfileref, const rsrc_ref_entry *entry, uint32_t *len) -{ - imgtoolerr_t err; - uint32_t data_offs; - UINT32BE llen; - - data_offs = get_UINT24BE(entry->data_offs); - - /* seek to resource data in resource data section */ - err = mac_file_seek(&resfileref->fileref, resfileref->data_offs+data_offs); - if (err) - return err; - - /* get data length */ - err = mac_file_read(&resfileref->fileref, sizeof(llen), &llen); - if (err) - return err; - - *len = get_UINT32BE(llen); - - return IMGTOOLERR_SUCCESS; -} - -/* - resfile_get_resdata - - Get the data for a given resource. - - resfileref (I/O): open resource file handle - entry (I): resource entry in the resource map (returned by - resfile_get_entry) - offset (I): offset the data should be read from, usually 0 - len (I): length of the data to read, usually the value returned by - resfile_get_reslen - dest (O): resource data - - Return imgtool error code -*/ -static imgtoolerr_t resfile_get_resdata(mac_resfileref *resfileref, const rsrc_ref_entry *entry, uint32_t offset, uint32_t len, void *dest) -{ - imgtoolerr_t err; - uint32_t data_offs; - UINT32BE llen; - - data_offs = get_UINT24BE(entry->data_offs); - - /* seek to resource data in resource data section */ - err = mac_file_seek(&resfileref->fileref, resfileref->data_offs+data_offs); - if (err) - return err; - - /* get data length */ - err = mac_file_read(&resfileref->fileref, sizeof(llen), &llen); - if (err) - return err; - - /* check that we do not ask to read more data than avalaible */ - if ((offset + len) > get_UINT32BE(llen)) - return IMGTOOLERR_UNEXPECTED; - - if (offset) - { /* seek to resource data offset in resource data section */ - err = mac_file_seek(&resfileref->fileref, resfileref->data_offs+data_offs+4+offset); - if (err) - return err; - } - - /* get data */ - err = mac_file_read(&resfileref->fileref, len, dest); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} -#endif - -#if 0 -#pragma mark - -#pragma mark DESKTOP FILE IMPLEMENTATION -#endif -/* - All macintosh volumes have information stored in the desktop file or the - desktop database. - - Such information include file comments, copy of BNDL and FREF resources - that describes supported file types for each application on the volume, - copy of icons for each file type registered by each application on the - volume, etc. On MFS volumes, the list of folders is stored in the desktop - file as well. - - - There have been two implementations of the desktop metadata: - - * The original desktop file. The database is stored in the resource fork - of a (usually invisible) file called "Desktop" (case may change - according to system versions), located at the root of the volume. The - desktop file is used by System 6 and earlier for all volumes (unless - Appleshare 2 is installed and the volume is shared IIRC), and by System - 7 and later for volumes smaller than 2MBytes (so that floppy disks - remain fully compatible with earlier versions of system). The desktop - file is incompletely documented by Apple technote TB06. - - * The desktop database. The database is stored in the resource fork is - stored in the data fork of two (usually invisible) files called - "Desktop DF" and "Desktop DF". The desktop database is used for - volumes shared by Appleshare 2, and for most volumes under System 7 and - later. The format of these file is not documented AFAIK. - - - The reasons for the introduction of the desktop database were: - * the macintosh resource manager cannot share resource files, which was - a problem for Appleshare - * the macintosh resource manager is pretty limited (+/-16MByte of data and - 2727 resources at most), which was a problem for large hard disks with - many programs/comments -*/ - -#ifdef UNUSED_FUNCTION -/* - get_comment - - Get a comment from the Desktop file - - l2_img (I): macintosh image the data should be read from - id (I): comment id (from mfs_hashString(), or HFS FXInfo/DXInfo records) - comment (O): comment that has been read - - Return imgtool error code -*/ -static imgtoolerr_t get_comment(struct mac_l2_imgref *l2_img, uint16_t id, mac_str255 comment) -{ - static const uint8_t desktop_fname[] = {'\7','D','e','s','k','t','o','p'}; - #define restype_FCMT (('F' << 24) | ('C' << 16) | ('M' << 8) | 'T') - mac_resfileref resfileref; - rsrc_ref_entry resentry; - uint32_t reslen; - imgtoolerr_t err; - - /* open rsrc fork of file Desktop in root directory */ - err = mac_file_open(l2_img, 2, desktop_fname, rsrc_fork, &resfileref.fileref); - if (err) - return err; - - /* open resource structures */ - err = resfile_open(&resfileref); - if (err) - return err; - - /* look for resource FCMT #id */ - err = resfile_get_entry(&resfileref, restype_FCMT, id, &resentry); - if (err) - return err; - - /* extract comment len */ - err = resfile_get_reslen(&resfileref, &resentry, &reslen); - if (err) - return err; - - /* check comment len */ - if (reslen > 256) - /* hurk */ - /*return IMGTOOLERR_CORRUPTIMAGE;*/ - /* people willing to extend the MFM comment field (you know, the kind - of masochists that try to support 20-year-old OSes) might append extra - fields, so we just truncate the resource */ - reslen = 256; - - /* extract comment data */ - err = resfile_get_resdata(&resfileref, &resentry, 0, reslen, comment); - if (err) - return err; - - /* phew, we are done! */ - return IMGTOOLERR_SUCCESS; -} -#endif - -#if 0 -#pragma mark - -#pragma mark IMGTOOL MODULE IMPLEMENTATION -#endif - -#ifdef UNUSED_FUNCTION -static void mac_image_exit(imgtool::image *img); -#endif -static void mac_image_info(imgtool::image &img, std::ostream &stream); -static imgtoolerr_t mac_image_beginenum(imgtool::directory &enumeration, const char *path); -static imgtoolerr_t mac_image_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent); -static imgtoolerr_t mac_image_freespace(imgtool::partition &partition, uint64_t *size); -static imgtoolerr_t mac_image_readfile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf); -static imgtoolerr_t mac_image_writefile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *writeoptions); - -#ifdef UNUSED_FUNCTION -/* - close a mfs/hfs image -*/ -static void mac_image_exit(imgtool::image *img) -{ - struct mac_l2_imgref *image = get_imgref(img); - - mac_image_close(image); -} -#endif - -/* - get basic information on a mfs/hfs image - - Currently returns the volume name -*/ -static void mac_image_info(imgtool::image &img, std::ostream &stream) -{ - char buffer[256] = { 0, }; - struct mac_l2_imgref *image = get_imgref(img); - - switch (image->format) - { - case L2I_MFS: - mac_to_c_strncpy(buffer, ARRAY_LENGTH(buffer), image->u.mfs.volname); - break; - - case L2I_HFS: - mac_to_c_strncpy(buffer, ARRAY_LENGTH(buffer), image->u.hfs.volname); - break; - } - - stream << buffer; -} - -/* - MFS/HFS catalog iterator, used when imgtool reads the catalog -*/ -struct mac_iterator -{ - mac_format format; - struct mac_l2_imgref *l2_img; - union - { - struct - { - mfs_dirref dirref; /* open directory reference */ - } mfs; - struct - { - hfs_cat_enumerator catref; /* catalog file enumerator */ - } hfs; - } u; -}; - -/* - Open the disk catalog for enumeration -*/ -static imgtoolerr_t mac_image_beginenum(imgtool::directory &enumeration, const char *path) -{ - struct mac_l2_imgref *image = get_imgref(enumeration.image()); - mac_iterator *iter = (mac_iterator *) enumeration.extra_bytes(); - imgtoolerr_t err = IMGTOOLERR_UNEXPECTED; - - iter->format = image->format; - iter->l2_img = image; - - switch (iter->format) - { - case L2I_MFS: - err = mfs_dir_open(image, path, &iter->u.mfs.dirref); - break; - - case L2I_HFS: - err = hfs_cat_open(image, path, &iter->u.hfs.catref); - break; - } - - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - -/* - Enumerate disk catalog next entry (MFS) -*/ -static imgtoolerr_t mfs_image_nextenum(mac_iterator *iter, imgtool_dirent &ent) -{ - mfs_dir_entry *cur_dir_entry; - imgtoolerr_t err; - - - assert(iter->format == L2I_MFS); - - ent.corrupt = 0; - ent.eof = 0; - - err = mfs_dir_read(&iter->u.mfs.dirref, &cur_dir_entry); - if (err) - { - /* error */ - ent.corrupt = 1; - return err; - } - else if (!cur_dir_entry) - { - /* EOF */ - ent.eof = 1; - return IMGTOOLERR_SUCCESS; - } - - /* copy info */ - mac_to_c_strncpy(ent.filename, ARRAY_LENGTH(ent.filename), cur_dir_entry->name); - ent.filesize = get_UINT32BE(cur_dir_entry->dataPhysicalSize) - + get_UINT32BE(cur_dir_entry->rsrcPhysicalSize); - - return IMGTOOLERR_SUCCESS; -} - -#if 0 -/* - Concatenate path elements in the reverse order - - dest (O): destination buffer - dest_cur_pos (I/O): current position in destination buffer (buffer is - filled from end to start) - dest_max_len (I): length of destination buffer (use length minus one if you - want to preserve a trailing NUL character) - src (I): source C string -*/ -static void concat_fname(char *dest, int *dest_cur_pos, int dest_max_len, const char *src) -{ - static const char ellipsis[] = { '.', '.', '.' }; - int src_len = strlen(src); /* number of chars from src to insert */ - - if (src_len <= *dest_cur_pos) - { - *dest_cur_pos -= src_len; - memcpy(dest + *dest_cur_pos, src, src_len); - } - else - { - memcpy(dest, src + src_len - *dest_cur_pos, *dest_cur_pos); - *dest_cur_pos = 0; - memcpy(dest, ellipsis, (sizeof(ellipsis) <= dest_max_len) - ? sizeof(ellipsis) - : dest_max_len); - } -} -#endif - -/* - Enumerate disk catalog next entry (HFS) -*/ -static imgtoolerr_t hfs_image_nextenum(mac_iterator *iter, imgtool_dirent &ent) -{ - hfs_catKey *catrec_key; - hfs_catData *catrec_data; - uint16_t dataRecType; - imgtoolerr_t err; - /* currently, the mac->C conversion transcodes one mac char with at most 3 - C chars */ - int cur_name_head; - - assert(iter->format == L2I_HFS); - - ent.corrupt = 0; - ent.eof = 0; - - do - { - err = hfs_cat_read(&iter->u.hfs.catref, &catrec_key, &catrec_data); - if (err) - { - /* error */ - ent.corrupt = 1; - return err; - } - else if (!catrec_key) - { - /* EOF */ - ent.eof = 1; - return IMGTOOLERR_SUCCESS; - } - dataRecType = get_UINT16BE(catrec_data->dataType); - } while (((dataRecType != hcrt_Folder) && (dataRecType != hcrt_File)) - || (get_UINT32BE(catrec_key->parID) != iter->u.hfs.catref.parID)); - - /* copy info */ - switch (get_UINT16BE(catrec_data->dataType)) - { - case hcrt_Folder: - ent.directory = 1; - ent.filesize = 0; - break; - - case hcrt_File: - ent.directory = 0; - ent.filesize = get_UINT32BE(catrec_data->file.dataPhysicalSize) - + get_UINT32BE(catrec_data->file.rsrcPhysicalSize); - break; - } - - /* initialize file path buffer */ - cur_name_head = ARRAY_LENGTH(ent.filename); - if (cur_name_head > 0) - { - cur_name_head--; - ent.filename[cur_name_head] = '\0'; - } - - /* insert folder/file name in buffer */ - mac_to_c_strncpy(ent.filename, ARRAY_LENGTH(ent.filename), catrec_key->cName); -// concat_fname(ent.filename, &cur_name_head, ARRAY_LENGTH(ent.filename) - 1, buf); - -#if 0 - /* extract parent directory ID */ - parID = get_UINT32BE(catrec_key->parID); - - /* looping while (parID != 1) will display the volume name; looping while - (parID != 2) won't */ - while (parID != /*1*/2) - { - /* search catalog for folder thread */ - err = hfs_cat_search(iter->l2_img, parID, mac_empty_str, &catrec_key, &catrec_data); - if (err) - { - /* error */ - concat_fname(ent.filename, &cur_name_head, ARRAY_LENGTH(ent.filename) - 1, ":"); - concat_fname(ent.filename, &cur_name_head, ARRAY_LENGTH(ent.filename) - 1, "???"); - - memmove(ent.filename, ent.filename+cur_name_head, ARRAY_LENGTH(ent.filename) - cur_name_head); - ent.corrupt = 1; - return err; - } - - dataRecType = get_UINT16BE(catrec_data->dataType); - - if (dataRecType != hcrt_FolderThread) - { - /* error */ - concat_fname(ent.filename, &cur_name_head, ARRAY_LENGTH(ent.filename)-1, ":"); - concat_fname(ent.filename, &cur_name_head, ARRAY_LENGTH(ent.filename)-1, "???"); - - memmove(ent.filename, ent.filename+cur_name_head, ARRAY_LENGTH(ent.filename)-cur_name_head); - ent.corrupt = 1; - return IMGTOOLERR_CORRUPTIMAGE; - } - - /* got folder thread record: insert the folder name at the start of - file path, then iterate */ - mac_to_c_strncpy(buf, sizeof(buf), catrec_data->thread.nodeName); - concat_fname(ent.filename, &cur_name_head, ARRAY_LENGTH(ent.filename) - 1, ":"); - concat_fname(ent.filename, &cur_name_head, ARRAY_LENGTH(ent.filename) - 1, buf); - - /* extract parent directory ID */ - parID = get_UINT32BE(catrec_data->thread.parID); - } - memmove(ent.filename, ent.filename+cur_name_head, ARRAY_LENGTH(ent.filename) -cur_name_head); -#endif - return IMGTOOLERR_SUCCESS; -} - -/* - Enumerate disk catalog next entry -*/ -static imgtoolerr_t mac_image_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent) -{ - imgtoolerr_t err; - mac_iterator *iter = (mac_iterator *) enumeration.extra_bytes(); - - switch (iter->format) - { - case L2I_MFS: - err = mfs_image_nextenum(iter, ent); - break; - - case L2I_HFS: - err = hfs_image_nextenum(iter, ent); - break; - - default: - assert(1); - err = IMGTOOLERR_UNEXPECTED; - break; - } - return err; -} - -/* - Compute free space on disk image in bytes -*/ -static imgtoolerr_t mac_image_freespace(imgtool::partition &partition, uint64_t *size) -{ - imgtool::image &image(partition.image()); - *size = ((uint64_t) get_imgref(image)->freeABs) * 512; - return IMGTOOLERR_SUCCESS; -} - -#ifdef UNUSED_FUNCTION -static imgtoolerr_t mac_get_comment(struct mac_l2_imgref *image, mac_str255 filename, const mac_dirent *cat_info, mac_str255 comment) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - uint16_t commentID; - - comment[0] = '\0'; - - /* get comment from Desktop file */ - switch (image->format) - { - case L2I_MFS: - commentID = mfs_hashString(filename); - err = get_comment(image, commentID, comment); - break; - - case L2I_HFS: - /* This is the way to get Finder comments in system <= 7. Attached - comments use another method, and Finder 8 uses yet another one. */ - commentID = get_UINT16BE(cat_info->flXFinderInfo.comment); - if (commentID) - err = get_comment(image, commentID, comment); - break; - } - return err; -} -#endif - - -/* - Extract a file from a disk image. -*/ -static imgtoolerr_t mac_image_readfile(imgtool::partition &partition, const char *fpath, const char *fork, imgtool::stream &destf) -{ - imgtoolerr_t err; - imgtool::image &img(partition.image()); - struct mac_l2_imgref *image = get_imgref(img); - uint32_t parID; - mac_str255 filename; - mac_dirent cat_info; - mac_fileref fileref; - uint8_t buf[512]; - uint32_t i, run_len, data_len; - mac_fork_t fork_num; - - err = mac_identify_fork(fork, &fork_num); - if (err) - return err; - - /* resolve path and fetch file info from directory/catalog */ - err = mac_lookup_path(image, fpath, &parID, filename, &cat_info, false); - if (err) - return err; - if (cat_info.dataRecType != hcrt_File) - return IMGTOOLERR_FILENOTFOUND; - - /* open file */ - err = mac_file_open(image, parID, filename, fork_num ? rsrc_fork : data_fork, &fileref); - if (err) - return err; - - data_len = fork_num ? cat_info.rsrcLogicalSize : cat_info.dataLogicalSize; - - /* extract DF */ - i = 0; - while(i < data_len) - { - run_len = std::min(size_t(data_len - i), sizeof(buf)); - - err = mac_file_read(&fileref, run_len, buf); - if (err) - return err; - if (destf.write(buf, run_len) != run_len) - return IMGTOOLERR_WRITEERROR; - i += run_len; - } - - return IMGTOOLERR_SUCCESS; -} - -/* - Add a file to a disk image. -*/ -static imgtoolerr_t mac_image_writefile(imgtool::partition &partition, const char *fpath, const char *fork, imgtool::stream &sourcef, util::option_resolution *writeoptions) -{ - imgtool::image &img(partition.image()); - struct mac_l2_imgref *image = get_imgref(img); - uint32_t parID; - mac_str255 filename; - mac_dirent cat_info; - mac_fileref fileref; - uint32_t fork_len; - /*uint16_t commentID;*/ - /*mac_str255 comment;*/ - uint8_t buf[512]; - uint32_t i, run_len; - imgtoolerr_t err; - mac_fork_t fork_num; - - (void) writeoptions; - - if (image->format == L2I_HFS) - return IMGTOOLERR_UNIMPLEMENTED; - - err = mac_identify_fork(fork, &fork_num); - if (err) - return err; - -#if 0 - if (header.version_old != 0) - return IMGTOOLERR_UNIMPLEMENTED; -#endif - /*mac_strcpy(filename, header.filename);*/ - memset(&cat_info, 0, sizeof(cat_info)); - set_UINT32BE(&cat_info.flFinderInfo.type, 0x3F3F3F3F); - set_UINT32BE(&cat_info.flFinderInfo.creator, 0x3F3F3F3F); - fork_len = sourcef.size(); - /*comment[0] = get_UINT16BE(header.comment_len);*/ /* comment length */ - /* Next two fields are set to 0 with MFS volumes. IIRC, 0 normally - means system script: I don't think MFS stores the file name script code - anywhere on disk, so it should be a reasonable approximation. */ - - /* create file */ - /* clear inited flag and file location in window */ - set_UINT16BE(&cat_info.flFinderInfo.flags, get_UINT16BE(cat_info.flFinderInfo.flags) & ~fif_hasBeenInited); - set_UINT16BE(&cat_info.flFinderInfo.location.v, 0); - set_UINT16BE(&cat_info.flFinderInfo.location.h, 0); - - /* resolve path and create file */ - err = mac_lookup_path(image, fpath, &parID, filename, &cat_info, true); - if (err) - return err; - - /* open file fork */ - err = mac_file_open(image, parID, filename, (fork_num ? rsrc_fork : data_fork), &fileref); - if (err) - return err; - - err = mac_file_seteof(&fileref, fork_len); - if (err) - return err; - - /* extract fork */ - for (i=0; i<fork_len;) - { - run_len = fork_len - i; - if (run_len > 512) - run_len = 512; - if (sourcef.read(buf, run_len) != run_len) - return IMGTOOLERR_READERROR; - err = mac_file_write(&fileref, run_len, buf); - if (err) - return err; - i += run_len; - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t mac_image_listforks(imgtool::partition &partition, const char *path, std::vector<imgtool::fork_entry> &forks) -{ - imgtoolerr_t err; - uint32_t parID; - mac_str255 filename; - mac_dirent cat_info; - imgtool::image &img(partition.image()); - struct mac_l2_imgref *image = get_imgref(img); - - /* resolve path and fetch file info from directory/catalog */ - err = mac_lookup_path(image, path, &parID, filename, &cat_info, false); - if (err) - return err; - if (cat_info.dataRecType != hcrt_File) - return IMGTOOLERR_FILENOTFOUND; - - // specify data fork - forks.emplace_back(cat_info.dataLogicalSize, imgtool::fork_entry::type_t::DATA); - - if (cat_info.rsrcLogicalSize > 0) - { - // specify the resource fork - forks.emplace_back(cat_info.rsrcLogicalSize, imgtool::fork_entry::type_t::RESOURCE); - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t mac_image_getattrs(imgtool::partition &partition, const char *path, const uint32_t *attrs, imgtool_attribute *values) -{ - imgtoolerr_t err; - imgtool::image &img(partition.image()); - uint32_t parID; - mac_str255 filename; - mac_dirent cat_info; - struct mac_l2_imgref *image = get_imgref(img); - int i; - - /* resolve path and fetch file info from directory/catalog */ - err = mac_lookup_path(image, path, &parID, filename, &cat_info, false); - if (err) - return err; - if (cat_info.dataRecType != hcrt_File) - return IMGTOOLERR_FILENOTFOUND; - - for (i = 0; attrs[i]; i++) - { - switch(attrs[i]) - { - case IMGTOOLATTR_INT_MAC_TYPE: - values[i].i = get_UINT32BE(cat_info.flFinderInfo.type); - break; - case IMGTOOLATTR_INT_MAC_CREATOR: - values[i].i = get_UINT32BE(cat_info.flFinderInfo.creator); - break; - case IMGTOOLATTR_INT_MAC_FINDERFLAGS: - values[i].i = get_UINT16BE(cat_info.flFinderInfo.flags); - break; - case IMGTOOLATTR_INT_MAC_COORDX: - values[i].i = get_UINT16BE(cat_info.flFinderInfo.location.h); - break; - case IMGTOOLATTR_INT_MAC_COORDY: - values[i].i = get_UINT16BE(cat_info.flFinderInfo.location.v); - break; - case IMGTOOLATTR_INT_MAC_FINDERFOLDER: - values[i].i = get_UINT16BE(cat_info.flFinderInfo.fldr); - break; - case IMGTOOLATTR_INT_MAC_ICONID: - values[i].i = get_UINT16BE(cat_info.flXFinderInfo.iconID); - break; - case IMGTOOLATTR_INT_MAC_SCRIPTCODE: - values[i].i = cat_info.flXFinderInfo.script; - break; - case IMGTOOLATTR_INT_MAC_EXTENDEDFLAGS: - values[i].i = cat_info.flXFinderInfo.XFlags; - break; - case IMGTOOLATTR_INT_MAC_COMMENTID: - values[i].i = get_UINT16BE(cat_info.flXFinderInfo.comment); - break; - case IMGTOOLATTR_INT_MAC_PUTAWAYDIRECTORY: - values[i].i = get_UINT32BE(cat_info.flXFinderInfo.putAway); - break; - - case IMGTOOLATTR_TIME_CREATED: - values[i].t = mac_crack_time(cat_info.createDate).to_time_t(); - break; - case IMGTOOLATTR_TIME_LASTMODIFIED: - values[i].t = mac_crack_time(cat_info.modifyDate).to_time_t(); - break; - } - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t mac_image_setattrs(imgtool::partition &partition, const char *path, const uint32_t *attrs, const imgtool_attribute *values) -{ - imgtoolerr_t err; - uint32_t parID; - mac_str255 filename; - mac_dirent cat_info; - imgtool::image &img(partition.image()); - struct mac_l2_imgref *image = get_imgref(img); - int i; - - /* resolve path and fetch file info from directory/catalog */ - err = mac_lookup_path(image, path, &parID, filename, &cat_info, false); - if (err) - return err; - if (cat_info.dataRecType != hcrt_File) - return IMGTOOLERR_FILENOTFOUND; - - for (i = 0; attrs[i]; i++) - { - switch(attrs[i]) - { - case IMGTOOLATTR_INT_MAC_TYPE: - set_UINT32BE(&cat_info.flFinderInfo.type, values[i].i); - break; - case IMGTOOLATTR_INT_MAC_CREATOR: - set_UINT32BE(&cat_info.flFinderInfo.creator, values[i].i); - break; - case IMGTOOLATTR_INT_MAC_FINDERFLAGS: - set_UINT16BE(&cat_info.flFinderInfo.flags, values[i].i); - break; - case IMGTOOLATTR_INT_MAC_COORDX: - set_UINT16BE(&cat_info.flFinderInfo.location.h, values[i].i); - break; - case IMGTOOLATTR_INT_MAC_COORDY: - set_UINT16BE(&cat_info.flFinderInfo.location.v, values[i].i); - break; - case IMGTOOLATTR_INT_MAC_FINDERFOLDER: - set_UINT16BE(&cat_info.flFinderInfo.fldr, values[i].i); - break; - case IMGTOOLATTR_INT_MAC_ICONID: - set_UINT16BE(&cat_info.flXFinderInfo.iconID, values[i].i); - break; - case IMGTOOLATTR_INT_MAC_SCRIPTCODE: - cat_info.flXFinderInfo.script = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_EXTENDEDFLAGS: - cat_info.flXFinderInfo.XFlags = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_COMMENTID: - set_UINT16BE(&cat_info.flXFinderInfo.comment, values[i].i); - break; - case IMGTOOLATTR_INT_MAC_PUTAWAYDIRECTORY: - set_UINT32BE(&cat_info.flXFinderInfo.putAway, values[i].i); - break; - - case IMGTOOLATTR_TIME_CREATED: - cat_info.createDate = mac_setup_time(values[i].t); - break; - case IMGTOOLATTR_TIME_LASTMODIFIED: - cat_info.modifyDate = mac_setup_time(values[i].t); - break; - } - } - - /* resolve path and fetch file info from directory/catalog */ - err = mac_lookup_path(image, path, &parID, filename, &cat_info, true); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -/************************************* - * - * Our very own resource manager - * - *************************************/ - -static const void *mac_walk_resources(const void *resource_fork, size_t resource_fork_length, - uint32_t resource_type, - int (*discriminator)(const void *resource, uint16_t id, uint32_t length, void *param_), - void *param, uint16_t *resource_id, uint32_t *resource_length) -{ - uint32_t resource_data_offset, resource_data_length; - uint32_t resource_map_offset, resource_map_length; - uint32_t resource_typelist_count, resource_typelist_offset; - uint32_t resource_entry_offset, resource_entry_count; - uint32_t i, this_resource_type; - uint32_t this_resource_data, this_resource_length; - uint16_t this_resource_id; - const void *this_resource_ptr; - - if (resource_fork_length < 16) - return NULL; - - /* read resource header; its ok if anything past this point fails */ - resource_data_offset = pick_integer_be(resource_fork, 0, 4); - resource_map_offset = pick_integer_be(resource_fork, 4, 4); - resource_data_length = pick_integer_be(resource_fork, 8, 4); - resource_map_length = pick_integer_be(resource_fork, 12, 4); - if ((resource_data_offset + resource_data_length) > resource_fork_length) - return NULL; - if ((resource_map_offset + resource_map_length) > resource_fork_length) - return NULL; - if (resource_map_length < 30) - return NULL; - - /* read resource map and locate the resource type list */ - resource_typelist_offset = pick_integer_be(resource_fork, - resource_map_offset + 24, 2) + resource_map_offset; - if ((resource_typelist_offset + 2) > resource_fork_length) - return NULL; - resource_typelist_count = pick_integer_be(resource_fork, - resource_typelist_offset, 2) + 1; - if ((resource_typelist_offset + resource_typelist_count * 16 + 2) > resource_fork_length) - return NULL; - - /* scan the resource type list and locate the entries for this type */ - resource_entry_count = 0; - resource_entry_offset = 0; - for (i = 0; i < resource_typelist_count; i++) - { - this_resource_type = pick_integer_be(resource_fork, resource_typelist_offset - + (i * 8) + 2 + 0, 4); - if (this_resource_type == resource_type) - { - resource_entry_count = pick_integer_be(resource_fork, resource_typelist_offset - + (i * 8) + 2 + 4, 2) + 1; - resource_entry_offset = pick_integer_be(resource_fork, resource_typelist_offset - + (i * 8) + 2 + 6, 2) + resource_typelist_offset; - break; - } - } - - /* scan the resource entries, and find the correct resource */ - for (i = 0; i < resource_entry_count; i++) - { - this_resource_id = pick_integer_be(resource_fork, resource_entry_offset - + (i * 12) + 0, 2); - this_resource_data = pick_integer_be(resource_fork, resource_entry_offset - + (i * 12) + 5, 3) + resource_data_offset; - if ((this_resource_data + 4) > resource_fork_length) - return NULL; - - /* gauge the length */ - this_resource_length = pick_integer_be(resource_fork, this_resource_data, 4); - this_resource_data += 4; - if ((this_resource_data + this_resource_length) > resource_fork_length) - return NULL; - - this_resource_ptr = ((const uint8_t *) resource_fork) + this_resource_data; - if (discriminator(this_resource_ptr, this_resource_id, - this_resource_length, param)) - { - if (resource_length) - *resource_length = this_resource_length; - if (resource_id) - *resource_id = this_resource_id; - return this_resource_ptr; - } - } - - return NULL; -} - - - -static int get_resource_discriminator(const void *resource, uint16_t id, uint32_t length, void *param) -{ - const uint16_t *id_ptr = (const uint16_t *) param; - return id == *id_ptr; -} - - - -static const void *mac_get_resource(const void *resource_fork, size_t resource_fork_length, - uint32_t resource_type, uint16_t resource_id, uint32_t *resource_length) -{ - return mac_walk_resources(resource_fork, resource_fork_length, - resource_type, get_resource_discriminator, &resource_id, NULL, resource_length); -} - - - -/************************************* - * - * Custom icons - * - *************************************/ - -static int bundle_discriminator(const void *resource, uint16_t id, uint32_t length, void *param) -{ - uint32_t this_creator_code = pick_integer_be(resource, 0, 4); - uint32_t desired_creator_code = *((uint32_t *) param); - return this_creator_code == desired_creator_code; -} - - - -static uint8_t get_pixel(const uint8_t *src, int width, int height, int bpp, - int x, int y) -{ - uint8_t byte, mask; - int bit_position; - - byte = src[(y * width + x) * bpp / 8]; - bit_position = 8 - ((x % (8 / bpp)) + 1) * bpp; - mask = (1 << bpp) - 1; - return (byte >> bit_position) & mask; -} - - - -static bool load_icon(uint32_t *dest, const void *resource_fork, uint64_t resource_fork_length, - uint32_t resource_type, uint16_t resource_id, int width, int height, int bpp, - const uint32_t *palette, bool has_mask) -{ - bool success = false; - uint32_t frame_length = width * height * bpp / 8; - uint32_t total_length = frame_length * (has_mask ? 2 : 1); - uint32_t resource_length; - - // attempt to fetch resource - const uint8_t *src = (const uint8_t*)mac_get_resource(resource_fork, resource_fork_length, resource_type, - resource_id, &resource_length); - if (src && (resource_length == total_length)) - { - for (int y = 0; y < height; y++) - { - for (int x = 0; x < width; x ++) - { - // check the color - uint8_t color = get_pixel(src, width, height, bpp, x, y); - - // then check the mask - bool is_masked = has_mask - ? get_pixel(src + frame_length, width, height, bpp, x, y) != 0 - : dest[y * width + x] >= 0x80000000; - - // is this actually masked? (note there is a special case when bpp == 1; Mac B&W icons - // had a XOR effect, and this cannot be blocked by the mask) - uint32_t pixel; - if (is_masked || (color && bpp == 1)) - { - // mask is ok; check the actual icon - pixel = palette[color] | 0xFF000000; - } - else - { - // masked out; nothing - pixel = 0x00000000; - } - - dest[y * width + x] = pixel; - } - } - success = true; - } - return success; -} - - - -static imgtoolerr_t mac_image_geticoninfo(imgtool::partition &partition, const char *path, imgtool_iconinfo *iconinfo) -{ - static const uint32_t mac_palette_1bpp[2] = { 0xFFFFFF, 0x000000 }; - - static const uint32_t mac_palette_4bpp[16] = - { - 0xFFFFFF, 0xFCF305, 0xFF6402, 0xDD0806, 0xF20884, 0x4600A5, - 0x0000D4, 0x02ABEA, 0x1FB714, 0x006411, 0x562C05, 0x90713A, - 0xC0C0C0, 0x808080, 0x404040, 0x000000 - }; - - static const uint32_t mac_palette_8bpp[256] = - { - 0xFFFFFF, 0xFFFFCC, 0xFFFF99, 0xFFFF66, 0xFFFF33, 0xFFFF00, - 0xFFCCFF, 0xFFCCCC, 0xFFCC99, 0xFFCC66, 0xFFCC33, 0xFFCC00, - 0xFF99FF, 0xFF99CC, 0xFF9999, 0xFF9966, 0xFF9933, 0xFF9900, - 0xFF66FF, 0xFF66CC, 0xFF6699, 0xFF6666, 0xFF6633, 0xFF6600, - 0xFF33FF, 0xFF33CC, 0xFF3399, 0xFF3366, 0xFF3333, 0xFF3300, - 0xFF00FF, 0xFF00CC, 0xFF0099, 0xFF0066, 0xFF0033, 0xFF0000, - 0xCCFFFF, 0xCCFFCC, 0xCCFF99, 0xCCFF66, 0xCCFF33, 0xCCFF00, - 0xCCCCFF, 0xCCCCCC, 0xCCCC99, 0xCCCC66, 0xCCCC33, 0xCCCC00, - 0xCC99FF, 0xCC99CC, 0xCC9999, 0xCC9966, 0xCC9933, 0xCC9900, - 0xCC66FF, 0xCC66CC, 0xCC6699, 0xCC6666, 0xCC6633, 0xCC6600, - 0xCC33FF, 0xCC33CC, 0xCC3399, 0xCC3366, 0xCC3333, 0xCC3300, - 0xCC00FF, 0xCC00CC, 0xCC0099, 0xCC0066, 0xCC0033, 0xCC0000, - 0x99FFFF, 0x99FFCC, 0x99FF99, 0x99FF66, 0x99FF33, 0x99FF00, - 0x99CCFF, 0x99CCCC, 0x99CC99, 0x99CC66, 0x99CC33, 0x99CC00, - 0x9999FF, 0x9999CC, 0x999999, 0x999966, 0x999933, 0x999900, - 0x9966FF, 0x9966CC, 0x996699, 0x996666, 0x996633, 0x996600, - 0x9933FF, 0x9933CC, 0x993399, 0x993366, 0x993333, 0x993300, - 0x9900FF, 0x9900CC, 0x990099, 0x990066, 0x990033, 0x990000, - 0x66FFFF, 0x66FFCC, 0x66FF99, 0x66FF66, 0x66FF33, 0x66FF00, - 0x66CCFF, 0x66CCCC, 0x66CC99, 0x66CC66, 0x66CC33, 0x66CC00, - 0x6699FF, 0x6699CC, 0x669999, 0x669966, 0x669933, 0x669900, - 0x6666FF, 0x6666CC, 0x666699, 0x666666, 0x666633, 0x666600, - 0x6633FF, 0x6633CC, 0x663399, 0x663366, 0x663333, 0x663300, - 0x6600FF, 0x6600CC, 0x660099, 0x660066, 0x660033, 0x660000, - 0x33FFFF, 0x33FFCC, 0x33FF99, 0x33FF66, 0x33FF33, 0x33FF00, - 0x33CCFF, 0x33CCCC, 0x33CC99, 0x33CC66, 0x33CC33, 0x33CC00, - 0x3399FF, 0x3399CC, 0x339999, 0x339966, 0x339933, 0x339900, - 0x3366FF, 0x3366CC, 0x336699, 0x336666, 0x336633, 0x336600, - 0x3333FF, 0x3333CC, 0x333399, 0x333366, 0x333333, 0x333300, - 0x3300FF, 0x3300CC, 0x330099, 0x330066, 0x330033, 0x330000, - 0x00FFFF, 0x00FFCC, 0x00FF99, 0x00FF66, 0x00FF33, 0x00FF00, - 0x00CCFF, 0x00CCCC, 0x00CC99, 0x00CC66, 0x00CC33, 0x00CC00, - 0x0099FF, 0x0099CC, 0x009999, 0x009966, 0x009933, 0x009900, - 0x0066FF, 0x0066CC, 0x006699, 0x006666, 0x006633, 0x006600, - 0x0033FF, 0x0033CC, 0x003399, 0x003366, 0x003333, 0x003300, - 0x0000FF, 0x0000CC, 0x000099, 0x000066, 0x000033, 0xEE0000, - 0xDD0000, 0xBB0000, 0xAA0000, 0x880000, 0x770000, 0x550000, - 0x440000, 0x220000, 0x110000, 0x00EE00, 0x00DD00, 0x00BB00, - 0x00AA00, 0x008800, 0x007700, 0x005500, 0x004400, 0x002200, - 0x001100, 0x0000EE, 0x0000DD, 0x0000BB, 0x0000AA, 0x000088, - 0x000077, 0x000055, 0x000044, 0x000022, 0x000011, 0xEEEEEE, - 0xDDDDDD, 0xBBBBBB, 0xAAAAAA, 0x888888, 0x777777, 0x555555, - 0x444444, 0x222222, 0x111111, 0x000000 - }; - - static const uint32_t attrs[4] = - { - IMGTOOLATTR_INT_MAC_TYPE, - IMGTOOLATTR_INT_MAC_CREATOR, - IMGTOOLATTR_INT_MAC_FINDERFLAGS - }; - - imgtoolerr_t err; - imgtool_attribute attr_values[3]; - uint32_t type_code, creator_code, finder_flags; - imgtool::stream::ptr stream; - const void *resource_fork; - uint64_t resource_fork_length; - const void *bundle; - uint32_t bundle_length, pos, fref_pos, icn_pos, i; - uint16_t local_id = 0, resource_id; - uint32_t fref_bundleentry_length, icn_bundleentry_length; - const void *fref; - uint32_t resource_length; - - assert((ARRAY_LENGTH(attrs) - 1) - == ARRAY_LENGTH(attr_values)); - - /* first retrieve type and creator code */ - err = mac_image_getattrs(partition, path, attrs, attr_values); - if (err) - return err; - type_code = (uint32_t) attr_values[0].i; - creator_code = (uint32_t) attr_values[1].i; - finder_flags = (uint32_t) attr_values[2].i; - - /* check the bundle bit; if clear (and the type is not 'APPL'), use the - * desktop file */ - if (!(finder_flags & 0x2000) && (type_code != /* APPL */ 0x4150504C)) - path = "Desktop\0"; - - stream = imgtool::stream::open_mem(NULL, 0); - if (!stream) - return IMGTOOLERR_SUCCESS; - - /* read in the resource fork */ - err = mac_image_readfile(partition, path, "RESOURCE_FORK", *stream); - if (err) - return err; - resource_fork = stream->getptr(); - resource_fork_length = stream->size(); - - /* attempt to look up the bundle */ - bundle = mac_walk_resources(resource_fork, resource_fork_length, /* BNDL */ 0x424E444C, - bundle_discriminator, &creator_code, NULL, &bundle_length); - if (!bundle) - return err; - - /* find the FREF and the icon family */ - pos = 8; - fref_pos = icn_pos = 0; - fref_bundleentry_length = icn_bundleentry_length = 0; - while((pos + 10) <= bundle_length) - { - uint32_t this_bundleentry_type = pick_integer_be(bundle, pos + 0, 4); - uint32_t this_bundleentry_length = pick_integer_be(bundle, pos + 4, 2) + 1; - - if (this_bundleentry_type == /* FREF */ 0x46524546) - { - fref_pos = pos; - fref_bundleentry_length = this_bundleentry_length; - } - if (this_bundleentry_type == /* ICN# */ 0x49434E23) - { - icn_pos = pos; - icn_bundleentry_length = this_bundleentry_length; - } - pos += 6 + this_bundleentry_length * 4; - } - if (!fref_pos || !icn_pos) - return err; - - /* look up the FREF */ - for (i = 0; i < fref_bundleentry_length; i++) - { - local_id = pick_integer_be(bundle, fref_pos + (i * 4) + 6, 2); - resource_id = pick_integer_be(bundle, fref_pos + (i * 4) + 8, 2); - - fref = mac_get_resource(resource_fork, resource_fork_length, - /* FREF */ 0x46524546, resource_id, &resource_length); - if (fref && (resource_length >= 7)) - { - if (pick_integer_be(fref, 0, 4) == type_code) - break; - } - } - if (i >= fref_bundleentry_length) - return err; - - /* now look up the icon family */ - resource_id = 0; - for (i = 0; i < icn_bundleentry_length; i++) - { - if (pick_integer_be(bundle, icn_pos + (i * 4) + 6, 2) == local_id) - { - resource_id = pick_integer_be(bundle, icn_pos + (i * 4) + 8, 2); - break; - } - } - if (i >= icn_bundleentry_length) - return err; - - /* fetch 32x32 icons (ICN#, icl4, icl8) */ - if (load_icon((uint32_t *) iconinfo->icon32x32, resource_fork, resource_fork_length, - /* ICN# */ 0x49434E23, resource_id, 32, 32, 1, mac_palette_1bpp, true)) - { - iconinfo->icon32x32_specified = 1; - - load_icon((uint32_t *) iconinfo->icon32x32, resource_fork, resource_fork_length, - /* icl4 */ 0x69636C34, resource_id, 32, 32, 4, mac_palette_4bpp, false); - load_icon((uint32_t *) iconinfo->icon32x32, resource_fork, resource_fork_length, - /* icl8 */ 0x69636C38, resource_id, 32, 32, 8, mac_palette_8bpp, false); - } - - /* fetch 16x16 icons (ics#, ics4, ics8) */ - if (load_icon((uint32_t *) iconinfo->icon16x16, resource_fork, resource_fork_length, - /* ics# */ 0x69637323, resource_id, 16, 16, 1, mac_palette_1bpp, true)) - { - iconinfo->icon16x16_specified = 1; - - load_icon((uint32_t *) iconinfo->icon32x32, resource_fork, resource_fork_length, - /* ics4 */ 0x69637334, resource_id, 32, 32, 4, mac_palette_4bpp, false); - load_icon((uint32_t *) iconinfo->icon32x32, resource_fork, resource_fork_length, - /* ics8 */ 0x69637338, resource_id, 32, 32, 8, mac_palette_8bpp, false); - } - - return err; -} - - - -/************************************* - * - * File transfer suggestions - * - *************************************/ - -static imgtoolerr_t mac_image_suggesttransfer(imgtool::partition &partition, const char *path, imgtool_transfer_suggestion *suggestions, size_t suggestions_length) -{ - imgtoolerr_t err; - uint32_t parID; - mac_str255 filename; - mac_dirent cat_info; - imgtool::image &img(partition.image()); - struct mac_l2_imgref *image = get_imgref(img); - mac_filecategory_t file_category = MAC_FILECATEGORY_DATA; - - if (path) - { - /* resolve path and fetch file info from directory/catalog */ - err = mac_lookup_path(image, path, &parID, filename, &cat_info, false); - if (err) - return err; - if (cat_info.dataRecType != hcrt_File) - return IMGTOOLERR_FILENOTFOUND; - - file_category = (cat_info.rsrcLogicalSize > 0) ? MAC_FILECATEGORY_FORKED : MAC_FILECATEGORY_DATA; - } - - mac_suggest_transfer(file_category, suggestions, suggestions_length); - return IMGTOOLERR_SUCCESS; -} - - - -/************************************* -* -* MacOS Roman Conversion -* -*************************************/ - -static const char32_t macos_roman_code_page[128] = -{ - // 0x80 - 0x8F - 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1, 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8, - // 0x90 - 0x9F - 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3, 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC, - // 0xA0 - 0xAF - 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF, 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8, - // 0xB0 - 0xBF - 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211, 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8, - // 0xC0 - 0xCF - 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB, 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153, - // 0xD0 - 0xDF - 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA, 0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02, - // 0xE0 - 0xEF - 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1, 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4, - // 0xF0 - 0xFF - 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC, 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7 -}; - -static imgtool::simple_charconverter charconverter_macos_roman(macos_roman_code_page); - - -/************************************* - * - * Module population - * - *************************************/ - -static void generic_mac_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_OPEN_IS_STRICT: info->i = 1; break; - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: info->i = sizeof(struct mac_l2_imgref); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(struct mac_iterator); break; - case IMGTOOLINFO_INT_PATH_SEPARATOR: info->i = ':'; break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - 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_CLOSE: /* info->close = mac_image_exit */; break; - case IMGTOOLINFO_PTR_INFO: info->info = mac_image_info; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = mac_image_beginenum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = mac_image_nextenum; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = mac_image_freespace; break; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = mac_image_readfile; break; - case IMGTOOLINFO_PTR_LIST_FORKS: info->list_forks = mac_image_listforks; break; - case IMGTOOLINFO_PTR_GET_ATTRS: info->get_attrs = mac_image_getattrs; break; - case IMGTOOLINFO_PTR_SET_ATTRS: info->set_attrs = mac_image_setattrs; break; - case IMGTOOLINFO_PTR_GET_ICON_INFO: info->get_iconinfo = mac_image_geticoninfo; break; - case IMGTOOLINFO_PTR_SUGGEST_TRANSFER: info->suggest_transfer = mac_image_suggesttransfer; break; - case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_apple35_mac; break; - case IMGTOOLINFO_PTR_CHARCONVERTER: info->charconverter = &charconverter_macos_roman; break; - } -} - - - -void mac_mfs_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(), "mac_mfs"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "Mac MFS Floppy"); break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case IMGTOOLINFO_PTR_FLOPPY_CREATE: info->create = mfs_image_create; break; - case IMGTOOLINFO_PTR_FLOPPY_OPEN: info->open = mfs_image_open; break; - case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = mac_image_writefile; break; - - default: generic_mac_get_info(imgclass, state, info); break; - } -} - - - -void mac_hfs_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(), "mac_hfs"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "Mac HFS Floppy"); break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case IMGTOOLINFO_PTR_FLOPPY_OPEN: info->open = hfs_image_open; break; - - default: generic_mac_get_info(imgclass, state, info); break; - } -} diff --git a/src/tools/imgtool/modules/macbin.cpp b/src/tools/imgtool/modules/macbin.cpp deleted file mode 100644 index 30400dffdbb..00000000000 --- a/src/tools/imgtool/modules/macbin.cpp +++ /dev/null @@ -1,381 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/**************************************************************************** - - macbin.cpp - - MacBinary filter for use with Mac and ProDOS drivers - -***************************************************************************** - - MacBinary file format - - Offset Length Description - ------ ------ ----------- - 0 1 [I] Magic byte (0x00) - 1 64 [I] File name (Pascal String) - 65 4 [I] File Type Code - 69 4 [I] File Creator Code - 73 1 [I] Finder Flags (bits 15-8) - 74 1 [I] Magic byte (0x00) - 75 2 [I] File Vertical Position - 77 2 [I] File Horizontal Position - 79 2 [I] Window/Folder ID - 81 1 [I] Protected (bit 0) - 82 1 [I] Magic byte (0x00) - 83 4 [I] Data Fork Length - 87 4 [I] Resource Fork Length - 91 4 [I] Creation Date - 95 4 [I] Last Modified Date - 99 2 [I] "Get Info" comment length - 101 1 [II] Finder Flags (bits 7-0) - 102 4 [III] MacBinary III Signature 'mBIN' - 106 1 [III] Script of Filename - 107 1 [III] Extended Finder Flags - 116 4 [II] Unpacked Length - 120 2 [II] Secondary Header Length - 122 1 [II] MacBinary II Version Number (II: 0x81, III: 0x82) - 123 1 [II] Minimum Compatible MacBinary II Version Number (0x81) - 124 2 [II] CRC of previous 124 bytes - - For more information, consult http://www.lazerware.com/formats/macbinary.html - - TODO: I believe that the script code is some sort of identifier identifying - the character set used for the filename. If this is true, we are not - handling that properly - -*****************************************************************************/ - -#include <string.h> - -#include "imgtool.h" -#include "formats/imageutl.h" -#include "macutil.h" - - - -static uint32_t pad128(uint32_t length) -{ - if (length % 128) - length += 128 - (length % 128); - return length; -} - - - -static imgtoolerr_t macbinary_readfile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf) -{ - static const uint32_t attrs[] = - { - IMGTOOLATTR_TIME_CREATED, - IMGTOOLATTR_TIME_LASTMODIFIED, - IMGTOOLATTR_INT_MAC_TYPE, - IMGTOOLATTR_INT_MAC_CREATOR, - IMGTOOLATTR_INT_MAC_FINDERFLAGS, - IMGTOOLATTR_INT_MAC_COORDX, - IMGTOOLATTR_INT_MAC_COORDY, - IMGTOOLATTR_INT_MAC_FINDERFOLDER, - IMGTOOLATTR_INT_MAC_SCRIPTCODE, - IMGTOOLATTR_INT_MAC_EXTENDEDFLAGS, - 0 - }; - imgtoolerr_t err; - uint8_t header[128]; - const char *basename; - - uint32_t type_code = 0x3F3F3F3F; - uint32_t creator_code = 0x3F3F3F3F; - uint16_t finder_flags = 0; - uint16_t coord_x = 0; - uint16_t coord_y = 0; - uint16_t finder_folder = 0; - uint8_t script_code = 0; - uint8_t extended_flags = 0; - - uint32_t creation_time = 0; - uint32_t lastmodified_time = 0; - imgtool_attribute attr_values[10]; - - // get the forks - std::vector<imgtool::fork_entry> fork_entries; - err = partition.list_file_forks(filename, fork_entries); - if (err) - return err; - - const imgtool::fork_entry *data_fork = nullptr; - const imgtool::fork_entry *resource_fork = nullptr; - for (const auto &entry : fork_entries) - { - switch (entry.type()) - { - case imgtool::fork_entry::type_t::DATA: - data_fork = &entry; - break; - case imgtool::fork_entry::type_t::RESOURCE: - resource_fork = &entry; - break; - default: - // do nothing - break; - } - } - - /* get the attributes */ - err = partition.get_file_attributes(filename, attrs, attr_values); - if (err && (ERRORCODE(err) != IMGTOOLERR_UNIMPLEMENTED)) - return err; - if (err == IMGTOOLERR_SUCCESS) - { - creation_time = mac_setup_time(attr_values[0].t); - lastmodified_time = mac_setup_time(attr_values[1].t); - type_code = attr_values[2].i; - creator_code = attr_values[3].i; - finder_flags = attr_values[4].i; - coord_x = attr_values[5].i; - coord_y = attr_values[6].i; - finder_folder = attr_values[7].i; - script_code = attr_values[8].i; - extended_flags = attr_values[9].i; - } - - memset(header, 0, sizeof(header)); - - /* place filename */ - basename = filename; - while(basename[strlen(basename) + 1]) - basename += strlen(basename) + 1; - pascal_from_c_string((unsigned char *) &header[1], 64, basename); - - place_integer_be(header, 65, 4, type_code); - place_integer_be(header, 69, 4, creator_code); - place_integer_be(header, 73, 1, (finder_flags >> 8) & 0xFF); - place_integer_be(header, 75, 2, coord_x); - place_integer_be(header, 77, 2, coord_y); - place_integer_be(header, 79, 2, finder_folder); - place_integer_be(header, 83, 4, data_fork ? data_fork->size() : 0); - place_integer_be(header, 87, 4, resource_fork ? resource_fork->size() : 0); - place_integer_be(header, 91, 4, creation_time); - place_integer_be(header, 95, 4, lastmodified_time); - place_integer_be(header, 101, 1, (finder_flags >> 0) & 0xFF); - place_integer_be(header, 102, 4, 0x6D42494E); - place_integer_be(header, 106, 1, script_code); - place_integer_be(header, 107, 1, extended_flags); - place_integer_be(header, 122, 1, 0x82); - place_integer_be(header, 123, 1, 0x81); - place_integer_be(header, 124, 2, ccitt_crc16(0, header, 124)); - - destf.write(header, sizeof(header)); - - if (data_fork) - { - err = partition.read_file(filename, "", destf, NULL); - if (err) - return err; - - destf.fill(0, pad128(data_fork->size())); - } - - if (resource_fork) - { - err = partition.read_file(filename, "RESOURCE_FORK", destf, NULL); - if (err) - return err; - - destf.fill(0, pad128(resource_fork->size())); - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t write_fork(imgtool::partition &partition, const char *filename, const char *fork, - imgtool::stream &sourcef, uint64_t pos, uint64_t fork_len, util::option_resolution *opts) -{ - imgtoolerr_t err; - imgtool::stream::ptr mem_stream; - size_t len; - - if (fork_len > 0) - { - mem_stream = imgtool::stream::open_mem(nullptr, 0); - if (!mem_stream) - return IMGTOOLERR_OUTOFMEMORY; - - sourcef.seek(pos, SEEK_SET); - len = imgtool::stream::transfer(*mem_stream, sourcef, fork_len); - if (len < fork_len) - mem_stream->fill(0, fork_len); - - mem_stream->seek(0, SEEK_SET); - err = partition.write_file(filename, fork, *mem_stream, opts, NULL); - if (err) - return err; - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t macbinary_writefile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) -{ - static const uint32_t attrs[] = - { - IMGTOOLATTR_TIME_CREATED, - IMGTOOLATTR_TIME_LASTMODIFIED, - IMGTOOLATTR_INT_MAC_TYPE, - IMGTOOLATTR_INT_MAC_CREATOR, - IMGTOOLATTR_INT_MAC_FINDERFLAGS, - IMGTOOLATTR_INT_MAC_COORDX, - IMGTOOLATTR_INT_MAC_COORDY, - IMGTOOLATTR_INT_MAC_FINDERFOLDER, - IMGTOOLATTR_INT_MAC_SCRIPTCODE, - IMGTOOLATTR_INT_MAC_EXTENDEDFLAGS, - 0 - }; - imgtoolerr_t err; - imgtool::image *image = &partition.image(); - uint8_t header[128]; - uint32_t datafork_size; - uint32_t resourcefork_size; - uint64_t total_size; - uint32_t creation_time; - uint32_t lastmodified_time; - //int version; - imgtool_attribute attr_values[10]; - - uint32_t type_code; - uint32_t creator_code; - uint16_t finder_flags; - uint16_t coord_x; - uint16_t coord_y; - uint16_t finder_folder; - uint8_t script_code = 0; - uint8_t extended_flags = 0; - - /* read in the header */ - memset(header, 0, sizeof(header)); - sourcef.read(header, sizeof(header)); - - /* check magic and zero fill bytes */ - if (header[0] != 0x00) - return IMGTOOLERR_CORRUPTFILE; - if (header[74] != 0x00) - return IMGTOOLERR_CORRUPTFILE; - if (header[82] != 0x00) - return IMGTOOLERR_CORRUPTFILE; - - datafork_size = pick_integer_be(header, 83, 4); - resourcefork_size = pick_integer_be(header, 87, 4); - total_size = sourcef.size(); - - /* size of a MacBinary header is always 128 bytes */ - if (total_size - pad128(datafork_size) - pad128(resourcefork_size) != 128) - return IMGTOOLERR_CORRUPTFILE; - - /* check filename length byte */ - if ((header[1] <= 0x00) || (header[1] > 0x3F)) - return IMGTOOLERR_CORRUPTFILE; - - /* check the CRC */ - if (pick_integer_be(header, 124, 2) != ccitt_crc16(0, header, 124)) - { - /* the CRC does not match; this file is MacBinary I */ - //version = 1; - } - else if (pick_integer_be(header, 102, 4) != 0x6D42494E) - { - /* did not see 'mBIN'; this file is MacBinary II */ - if (header[122] < 0x81) - return IMGTOOLERR_CORRUPTFILE; - if (header[123] < 0x81) - return IMGTOOLERR_CORRUPTFILE; - //version = 2; - } - else - { - /* we did see 'mBIN'; this file is MacBinary III */ - if (header[122] < 0x82) - return IMGTOOLERR_CORRUPTFILE; - if (header[123] < 0x81) - return IMGTOOLERR_CORRUPTFILE; - //version = 3; - } - - type_code = pick_integer_be(header, 65, 4); - creator_code = pick_integer_be(header, 69, 4); - finder_flags = pick_integer_be(header, 73, 1) << 8; - coord_x = pick_integer_be(header, 75, 2); - coord_y = pick_integer_be(header, 77, 2); - finder_folder = pick_integer_be(header, 79, 2); - creation_time = pick_integer_be(header, 91, 4); - lastmodified_time = pick_integer_be(header, 95, 4); - - if (image) - { - /* write out both forks */ - err = write_fork(partition, filename, "", sourcef, sizeof(header), datafork_size, opts); - if (err) - return err; - err = write_fork(partition, filename, "RESOURCE_FORK", sourcef, sizeof(header) + pad128(datafork_size), resourcefork_size, opts); - if (err) - return err; - - /* set up attributes */ - attr_values[0].t = mac_crack_time(creation_time).to_time_t(); - attr_values[1].t = mac_crack_time(lastmodified_time).to_time_t(); - attr_values[2].i = type_code; - attr_values[3].i = creator_code; - attr_values[4].i = finder_flags; - attr_values[5].i = coord_x; - attr_values[6].i = coord_y; - attr_values[7].i = finder_folder; - attr_values[8].i = script_code; - attr_values[9].i = extended_flags; - - err = partition.put_file_attributes(filename, attrs, attr_values); - if (err) - return err; - } - - return IMGTOOLERR_SUCCESS; -} - - -// this was completely broken - it was calling macbinary_writefile() with a nullptr partition -#if 0 -static imgtoolerr_t macbinary_checkstream(imgtool::stream &stream, imgtool_suggestion_viability_t *viability) -{ - imgtoolerr_t err; - - err = macbinary_writefile(NULL, NULL, NULL, stream, NULL); - if (err == IMGTOOLERR_CORRUPTFILE) - { - /* the filter returned corrupt; this is not a valid file */ - *viability = SUGGESTION_END; - err = IMGTOOLERR_SUCCESS; - } - else if (err == IMGTOOLERR_SUCCESS) - { - /* success; lets recommend this filter */ - *viability = SUGGESTION_RECOMMENDED; - } - return err; -} -#endif - - - -void filter_macbinary_getinfo(uint32_t state, union filterinfo *info) -{ - switch(state) - { - case FILTINFO_STR_NAME: info->s = "macbinary"; break; - case FILTINFO_STR_HUMANNAME: info->s = "MacBinary"; break; - case FILTINFO_STR_EXTENSION: info->s = "bin"; break; - case FILTINFO_PTR_READFILE: info->read_file = macbinary_readfile; break; - case FILTINFO_PTR_WRITEFILE: info->write_file = macbinary_writefile; break; - //case FILTINFO_PTR_CHECKSTREAM: info->check_stream = macbinary_checkstream; break; - } -} diff --git a/src/tools/imgtool/modules/macutil.cpp b/src/tools/imgtool/modules/macutil.cpp deleted file mode 100644 index 08c8b84989f..00000000000 --- a/src/tools/imgtool/modules/macutil.cpp +++ /dev/null @@ -1,116 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/**************************************************************************** - - macutil.cpp - - Imgtool Utility code for manipulating certain Apple/Mac data structures - and conventions - -*****************************************************************************/ - -#include "macutil.h" -#include "timeconv.h" - - -typedef util::arbitrary_clock<std::uint32_t, 1904, 1, 1, 0, 0, 0, std::ratio<1, 1> > classic_mac_clock; - -//------------------------------------------------- -// mac_crack_time -//------------------------------------------------- - -imgtool::datetime mac_crack_time(uint32_t t) -{ - classic_mac_clock::duration d(t); - std::chrono::time_point<classic_mac_clock> tp(d); - return imgtool::datetime(imgtool::datetime::datetime_type::LOCAL, tp); -} - - -//------------------------------------------------- -// mac_setup_time -//------------------------------------------------- - -uint32_t mac_setup_time(const imgtool::datetime &t) -{ - auto mac_time_point = classic_mac_clock::from_arbitrary_time_point(t.time_point()); - return mac_time_point.time_since_epoch().count(); -} - - -//------------------------------------------------- -// mac_setup_time -//------------------------------------------------- - -uint32_t mac_setup_time(time_t t) -{ - imgtool::datetime dt(imgtool::datetime::datetime_type::LOCAL, t); - return mac_setup_time(dt); -} - - -//------------------------------------------------- -// mac_time_now -//------------------------------------------------- - -uint32_t mac_time_now(void) -{ - imgtool::datetime dt = imgtool::datetime::now(imgtool::datetime::datetime_type::LOCAL); - return mac_setup_time(dt); -} - - -//------------------------------------------------- -// mac_identify_fork -//------------------------------------------------- - -imgtoolerr_t mac_identify_fork(const char *fork_string, mac_fork_t *fork_num) -{ - if (!strcmp(fork_string, "")) - *fork_num = MAC_FORK_DATA; - else if (!strcmp(fork_string, "RESOURCE_FORK")) - *fork_num = MAC_FORK_RESOURCE; - else - return IMGTOOLERR_FORKNOTFOUND; - return IMGTOOLERR_SUCCESS; -} - - - -void mac_suggest_transfer(mac_filecategory_t file_category, imgtool_transfer_suggestion *suggestions, size_t suggestions_length) -{ - suggestions[0].viability = (file_category == MAC_FILECATEGORY_FORKED) ? SUGGESTION_RECOMMENDED : SUGGESTION_POSSIBLE; - suggestions[0].filter = filter_macbinary_getinfo; - suggestions[0].fork = NULL; - suggestions[0].description = NULL; - - suggestions[1].viability = (file_category == MAC_FILECATEGORY_TEXT) ? SUGGESTION_RECOMMENDED : SUGGESTION_POSSIBLE; - suggestions[1].filter = filter_eoln_getinfo; - suggestions[1].fork = NULL; - suggestions[1].description = NULL; - - suggestions[2].viability = (file_category == MAC_FILECATEGORY_DATA) ? SUGGESTION_RECOMMENDED : SUGGESTION_POSSIBLE; - suggestions[2].filter = NULL; - suggestions[2].fork = ""; - suggestions[2].description = "Raw (data fork)"; - - suggestions[3].viability = SUGGESTION_POSSIBLE; - suggestions[3].filter = NULL; - suggestions[3].fork = "RESOURCE_FORK"; - suggestions[3].description = "Raw (resource fork)"; -} - - - -void pascal_from_c_string(unsigned char *pstring, size_t pstring_len, const char *cstring) -{ - size_t cstring_len, i; - - cstring_len = strlen(cstring); - pstring[0] = std::min(cstring_len, pstring_len - 1); - - for (i = 0; i < pstring[0]; i++) - pstring[1 + i] = cstring[i]; - while(i < pstring_len - 1) - pstring[1 + i++] = '\0'; -} diff --git a/src/tools/imgtool/modules/macutil.h b/src/tools/imgtool/modules/macutil.h deleted file mode 100644 index 0ab3315874b..00000000000 --- a/src/tools/imgtool/modules/macutil.h +++ /dev/null @@ -1,43 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/**************************************************************************** - - macutil.h - - Imgtool Utility code for manipulating certain Apple/Mac data structures - and conventions - -*****************************************************************************/ - -#ifndef MACUTIL_H -#define MACUTIL_H - -#include "imgtool.h" - -enum mac_fork_t -{ - MAC_FORK_DATA, - MAC_FORK_RESOURCE -}; - -enum mac_filecategory_t -{ - MAC_FILECATEGORY_DATA, - MAC_FILECATEGORY_TEXT, - MAC_FILECATEGORY_FORKED -}; - - -/* converting Classic Mac OS time <==> Imgtool time */ -imgtool::datetime mac_crack_time(uint32_t t); -uint32_t mac_setup_time(const imgtool::datetime &t); -uint32_t mac_setup_time(time_t t); -uint32_t mac_time_now(void); - -imgtoolerr_t mac_identify_fork(const char *fork_string, mac_fork_t *fork_num); - -void mac_suggest_transfer(mac_filecategory_t file_category, imgtool_transfer_suggestion *suggestions, size_t suggestions_length); - -void pascal_from_c_string(unsigned char *pstring, size_t pstring_len, const char *cstring); - -#endif /* MACUTIL_H */ diff --git a/src/tools/imgtool/modules/os9.cpp b/src/tools/imgtool/modules/os9.cpp index cc016250c31..97fdcb9e209 100644 --- a/src/tools/imgtool/modules/os9.cpp +++ b/src/tools/imgtool/modules/os9.cpp @@ -8,13 +8,16 @@ ****************************************************************************/ -#include <time.h> - #include "imgtool.h" -#include "formats/imageutl.h" -#include "formats/coco_dsk.h" #include "iflopimg.h" +#include "formats/coco_dsk.h" +#include "multibyte.h" +#include "opresolv.h" + +#include <cstdio> +#include <ctime> + enum creation_policy_t { CREATE_NONE, @@ -44,7 +47,7 @@ struct os9_diskinfo unsigned int octal_track_density : 1; char name[33]; - uint8_t *allocation_bitmap; + uint8_t allocation_bitmap[65536]; }; @@ -96,20 +99,13 @@ static void pick_string(const void *ptr, size_t offset, size_t length, char *des -static void place_string(void *ptr, size_t offset, size_t length, const char *s) +static void place_string(uint8_t *bptr, size_t length, const char *s) { - size_t i; - uint8_t b; - uint8_t *bptr; - - bptr = (uint8_t *) ptr; - bptr += offset; - bptr[0] = 0x80; - for (i = 0; s[i] && (i < length); i++) + for (size_t i = 0; s[i] && (i < length); i++) { - b = ((uint8_t) s[i]) & 0x7F; + uint8_t b = ((uint8_t) s[i]) & 0x7F; if (s[i+1] == '\0') b |= 0x80; bptr[i] = b; @@ -228,7 +224,7 @@ static int os9_interpret_dirent(void *entry, char **filename, uint32_t *lsn, int entry_b[i] &= 0x7F; entry_b[i+1] = '\0'; - *lsn = pick_integer_be(entry, 29, 3); + *lsn = get_u24be((uint8_t *) &entry_b[29]); if (strcmp(entry_b, ".") && strcmp(entry_b, "..")) *filename = entry_b; return *filename != NULL; @@ -257,10 +253,10 @@ static imgtoolerr_t os9_decode_file_header(imgtool::image &image, return err; info->lsn = lsn; - attributes = pick_integer_be(header, 0, 1); - info->owner_id = pick_integer_be(header, 1, 2); - info->link_count = pick_integer_be(header, 8, 1); - info->file_size = pick_integer_be(header, 9, 4); + attributes = header[0]; + info->owner_id = get_u16be(&header[1]); + info->link_count = header[8]; + info->file_size = get_u32be(&header[9]); info->directory = (attributes & 0x80) ? 1 : 0; info->non_sharable = (attributes & 0x40) ? 1 : 0; info->public_execute = (attributes & 0x20) ? 1 : 0; @@ -275,11 +271,11 @@ static imgtoolerr_t os9_decode_file_header(imgtool::image &image, /* read all sector map entries */ max_entries = (disk_info->sector_size - 16) / 5; - max_entries = (std::min<std::size_t>)(max_entries, ARRAY_LENGTH(info->sector_map) - 1); + max_entries = (std::min<std::size_t>)(max_entries, std::size(info->sector_map) - 1); for (i = 0; i < max_entries; i++) { - lsn = pick_integer_be(header, 16 + (i * 5) + 0, 3); - count = pick_integer_be(header, 16 + (i * 5) + 3, 2); + lsn = get_u24be(&header[16 + (i * 5) + 0]); + count = get_u16be(&header[16 + (i * 5) + 3]); if (count <= 0) break; @@ -393,7 +389,7 @@ static imgtoolerr_t os9_set_file_size(imgtool::image &image, /* first find out the size of our sector map */ sector_map_length = 0; lsn = 0; - while((lsn < current_lsn_count) && (sector_map_length < ARRAY_LENGTH(file_info->sector_map))) + while((lsn < current_lsn_count) && (sector_map_length < std::size(file_info->sector_map))) { if (file_info->sector_map[sector_map_length].count == 0) return os9_corrupt_file_error(file_info); @@ -434,7 +430,7 @@ static imgtoolerr_t os9_set_file_size(imgtool::image &image, { file_info->sector_map[sector_map_length - 1].count++; } - else if (sector_map_length >= ARRAY_LENGTH(file_info->sector_map)) + else if (sector_map_length >= std::size(file_info->sector_map)) { return IMGTOOLERR_NOSPACE; } @@ -456,15 +452,15 @@ static imgtoolerr_t os9_set_file_size(imgtool::image &image, return err; file_info->file_size = new_size; - place_integer_be(header, 9, 4, file_info->file_size); + put_u32be(&header[9], file_info->file_size); /* do we have to write the sector map? */ if (sector_map_length >= 0) { - for (i = 0; i < (std::min<std::size_t>)(sector_map_length + 1, ARRAY_LENGTH(file_info->sector_map)); i++) + for (i = 0; i < (std::min<std::size_t>)(sector_map_length + 1, std::size(file_info->sector_map)); i++) { - place_integer_be(header, 16 + (i * 5) + 0, 3, file_info->sector_map[i].lsn); - place_integer_be(header, 16 + (i * 5) + 3, 2, file_info->sector_map[i].count); + put_u24be(&header[16 + (i * 5) + 0], file_info->sector_map[i].lsn); + put_u16be(&header[16 + (i * 5) + 3], file_info->sector_map[i].count); } } @@ -567,7 +563,7 @@ static imgtoolerr_t os9_lookup_path(imgtool::image &img, const char *path, /* write the file */ memset(block, 0, sizeof(block)); - place_integer_be(block, 0, 1, 0x1B | ((create == CREATE_DIR) ? 0x80 : 0x00)); + block[0] = 0x1B | ((create == CREATE_DIR) ? 0x80 : 0x00); err = os9_write_lsn(img, allocated_lsn, 0, block, sizeof(block)); if (err) goto done; @@ -585,8 +581,8 @@ static imgtoolerr_t os9_lookup_path(imgtool::image &img, const char *path, /* now prepare the directory entry */ memset(entry, 0, sizeof(entry)); - place_string(entry, 0, 28, path); - place_integer_be(entry, 29, 3, allocated_lsn); + place_string(&entry[0], 28, path); + put_u24be(&entry[29], allocated_lsn); /* now write the directory entry */ entry_index = dir_size; @@ -638,20 +634,19 @@ static imgtoolerr_t os9_diskimage_open(imgtool::image &image, imgtool::stream::p if (ferr) return imgtool_floppy_error(ferr); - info->total_sectors = pick_integer_be(header, 0, 3); - track_size_in_sectors = pick_integer_be(header, 3, 1); - info->allocation_bitmap_bytes = pick_integer_be(header, 4, 2); - info->cluster_size = pick_integer_be(header, 6, 2); - info->root_dir_lsn = pick_integer_be(header, 8, 3); - info->owner_id = pick_integer_be(header, 11, 2); -// attributes = - pick_integer_be(header, 13, 1); - info->disk_id = pick_integer_be(header, 14, 2); - info->format_flags = pick_integer_be(header, 16, 1); - info->sectors_per_track = pick_integer_be(header, 17, 2); - info->bootstrap_lsn = pick_integer_be(header, 21, 3); - info->bootstrap_size = pick_integer_be(header, 24, 2); - info->sector_size = pick_integer_be(header, 104, 2); + info->total_sectors = get_u24be(&header[ 0]); + track_size_in_sectors = header[ 3]; + info->allocation_bitmap_bytes = get_u16be(&header[ 4]); + info->cluster_size = get_u16be(&header[ 6]); + info->root_dir_lsn = get_u24be(&header[ 8]); + info->owner_id = get_u16be(&header[ 11]); +// attributes = header[ 13]; + info->disk_id = get_u16be(&header[ 14]); + info->format_flags = header[ 16]; + info->sectors_per_track = get_u16be(&header[ 17]); + info->bootstrap_lsn = get_u24be(&header[ 21]); + info->bootstrap_size = get_u16be(&header[ 24]); + info->sector_size = get_u16be(&header[104]); info->sides = (info->format_flags & 0x01) ? 2 : 1; info->double_density = (info->format_flags & 0x02) ? 1 : 0; @@ -670,10 +665,7 @@ static imgtoolerr_t os9_diskimage_open(imgtool::image &image, imgtool::stream::p return IMGTOOLERR_CORRUPTIMAGE; /* is the allocation bitmap too big? */ - info->allocation_bitmap = (uint8_t*)image.malloc(info->allocation_bitmap_bytes); - if (!info->allocation_bitmap) - return IMGTOOLERR_OUTOFMEMORY; - memset(info->allocation_bitmap, 0, info->allocation_bitmap_bytes); + memset(&info->allocation_bitmap[0], 0, info->allocation_bitmap_bytes); /* sectors per track and track size don't jive? */ if (info->sectors_per_track != track_size_in_sectors) @@ -747,30 +739,30 @@ static imgtoolerr_t os9_diskimage_create(imgtool::image &img, imgtool::stream::p format_flags = ((heads > 1) ? 0x01 : 0x00) | ((tracks > 40) ? 0x02 : 0x00); memset(&header[0], 0, sector_bytes); - place_integer_be(&header[0], 0, 3, heads * tracks * sectors); - place_integer_be(&header[0], 3, 1, sectors); - place_integer_be(&header[0], 4, 2, (allocation_bitmap_bits + 7) / 8); - place_integer_be(&header[0], 6, 2, cluster_size); - place_integer_be(&header[0], 8, 3, 1 + allocation_bitmap_lsns); - place_integer_be(&header[0], 11, 2, owner_id); - place_integer_be(&header[0], 13, 1, attributes); - place_integer_be(&header[0], 14, 2, disk_id); - place_integer_be(&header[0], 16, 1, format_flags); - place_integer_be(&header[0], 17, 2, sectors); - place_string(&header[0], 31, 32, title); - place_integer_be(&header[0], 103, 2, sector_bytes / 256); + put_u24be(&header[ 0], heads * tracks * sectors); + header[ 3] = sectors; + put_u16be(&header[ 4], (allocation_bitmap_bits + 7) / 8); + put_u16be(&header[ 6], cluster_size); + put_u24be(&header[ 8], 1 + allocation_bitmap_lsns); + put_u16be(&header[ 11], owner_id); + header[ 13] = attributes; + put_u16be(&header[ 14], disk_id); + header[ 16] = format_flags; + put_u16be(&header[ 17], sectors); + place_string(&header[ 31], 32, title); + put_u16be(&header[103], sector_bytes / 256); /* path descriptor options */ - place_integer_be(&header[0], 0x3f+0x00, 1, 1); /* device class */ - place_integer_be(&header[0], 0x3f+0x01, 1, 1); /* drive number */ - place_integer_be(&header[0], 0x3f+0x03, 1, 0x20); /* device type */ - place_integer_be(&header[0], 0x3f+0x04, 1, 1); /* density capability */ - place_integer_be(&header[0], 0x3f+0x05, 2, tracks); /* number of tracks */ - place_integer_be(&header[0], 0x3f+0x07, 1, heads); /* number of sides */ - place_integer_be(&header[0], 0x3f+0x09, 2, sectors); /* sectors per track */ - place_integer_be(&header[0], 0x3f+0x0b, 2, sectors); /* sectors on track zero */ - place_integer_be(&header[0], 0x3f+0x0d, 1, 3); /* sector interleave factor */ - place_integer_be(&header[0], 0x3f+0x0e, 1, 8); /* default sectors per allocation */ + header[0x3f+0x00] = 1; /* device class */ + header[0x3f+0x01] = 1; /* drive number */ + header[0x3f+0x03] = 0x20; /* device type */ + header[0x3f+0x04] = 1; /* density capability */ + put_u16be(&header[0x3f+0x05], tracks); /* number of tracks */ + header[0x3f+0x07] = heads; /* number of sides */ + put_u16be(&header[0x3f+0x09], sectors); /* sectors per track */ + put_u16be(&header[0x3f+0x0b], sectors); /* sectors on track zero */ + header[0x3f+0x0d] = 3; /* sector interleave factor */ + header[0x3f+0x0e] = 8; /* default sectors per allocation */ err = (imgtoolerr_t)floppy_write_sector(imgtool_floppy(img), 0, 0, first_sector_id, 0, &header[0], sector_bytes, 0); /* TODO: pass ddam argument from imgtool */ if (err) @@ -824,8 +816,8 @@ static imgtoolerr_t os9_diskimage_create(imgtool::image &img, imgtool::stream::p header[0x0D] = (uint8_t) (ltime->tm_year % 100); header[0x0E] = (uint8_t) ltime->tm_mon; header[0x0F] = (uint8_t) ltime->tm_mday; - place_integer_be(&header[0], 0x10, 3, 1 + allocation_bitmap_lsns + 1); - place_integer_be(&header[0], 0x13, 2, 8); + put_u24be(&header[0x10], 1 + allocation_bitmap_lsns + 1); + put_u16be(&header[0x13], 8); err = (imgtoolerr_t)floppy_write_sector(imgtool_floppy(img), 0, 0, first_sector_id + 1 + allocation_bitmap_lsns, 0, &header[0], sector_bytes, 0); /* TODO: pass ddam argument from imgtool */ if (err) @@ -929,7 +921,7 @@ static imgtoolerr_t os9_diskimage_nextenum(imgtool::directory &enumeration, imgt } /* if the filename is ".", the file should point to the current directory */ - if (!strcmp(filename, ".") && (pick_integer_be(dir_entry, 29, 3) != os9enum->dir_info.lsn)) + if (!strcmp(filename, ".") && (get_u24be(&dir_entry[29]) != os9enum->dir_info.lsn)) { imgtool_warn("Directory \".\" does not point back to same directory"); } @@ -946,14 +938,14 @@ static imgtoolerr_t os9_diskimage_nextenum(imgtool::directory &enumeration, imgt while(!filename[0] || !strcmp(filename, ".") || !strcmp(filename, "..")); /* read file attributes */ - lsn = pick_integer_be(dir_entry, 29, 3); + lsn = get_u24be(&dir_entry[29]); err = os9_decode_file_header(enumeration.image(), lsn, &file_info); if (err) return err; /* fill out imgtool_dirent structure */ - snprintf(ent.filename, ARRAY_LENGTH(ent.filename), "%s", filename); - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "%c%c%c%c%c%c%c%c", + snprintf(ent.filename, std::size(ent.filename), "%s", filename); + snprintf(ent.attr, std::size(ent.attr), "%c%c%c%c%c%c%c%c", file_info.directory ? 'd' : '-', file_info.non_sharable ? 's' : '-', file_info.public_execute ? 'x' : '-', @@ -1143,7 +1135,7 @@ static imgtoolerr_t os9_diskimage_delete(imgtool::partition &partition, const ch if (err) return err; - for (i = 0; (i < ARRAY_LENGTH(file_info.sector_map)) && file_info.sector_map[i].count; i++) + for (i = 0; (i < std::size(file_info.sector_map)) && file_info.sector_map[i].count; i++) { lsn = file_info.sector_map[i].lsn; for (j = 0; j < file_info.sector_map[i].count; j++) @@ -1185,10 +1177,10 @@ static imgtoolerr_t os9_diskimage_createdir(imgtool::partition &partition, const /* create intial directories */ memset(dir_data, 0, sizeof(dir_data)); - place_string(dir_data, 0, 32, ".."); - place_integer_be(dir_data, 29, 3, parent_lsn); - place_string(dir_data, 32, 32, "."); - place_integer_be(dir_data, 61, 3, file_info.lsn); + place_string(&dir_data[ 0], 32, ".."); + put_u24be(&dir_data[29], parent_lsn); + place_string(&dir_data[32], 32, "."); + put_u24be(&dir_data[61], file_info.lsn); err = os9_write_lsn(image, file_info.sector_map[0].lsn, 0, dir_data, sizeof(dir_data)); if (err) diff --git a/src/tools/imgtool/modules/pc_flop.cpp b/src/tools/imgtool/modules/pc_flop.cpp index 211b7f7b938..6a242d16abf 100644 --- a/src/tools/imgtool/modules/pc_flop.cpp +++ b/src/tools/imgtool/modules/pc_flop.cpp @@ -9,11 +9,14 @@ ****************************************************************************/ #include "imgtool.h" -#include "formats/imageutl.h" -#include "formats/pc_dsk.h" #include "fat.h" #include "iflopimg.h" +#include "formats/pc_dsk_legacy.h" + +#include "multibyte.h" +#include "opresolv.h" + #define FAT_SECLEN 512 @@ -31,10 +34,10 @@ static imgtoolerr_t fat_image_create(imgtool::image &image, imgtool::stream::ptr /* set up just enough of a boot sector to specify geometry */ memset(buffer, 0, sizeof(buffer)); - place_integer_le(buffer, 24, 2, sectors); - place_integer_le(buffer, 26, 2, heads); - place_integer_le(buffer, 19, 2, (uint16_t) (((uint64_t) tracks * heads * sectors) >> 0)); - place_integer_le(buffer, 32, 4, (uint16_t) (((uint64_t) tracks * heads * sectors) >> 16)); + put_u16le(&buffer[24], sectors); + put_u16le(&buffer[26], heads); + put_u16le(&buffer[19], uint16_t((uint64_t(tracks) * heads * sectors) >> 0)); + put_u32le(&buffer[32], uint16_t((uint64_t(tracks) * heads * sectors) >> 16)); err = image.write_block(0, buffer); if (err) goto done; @@ -44,7 +47,7 @@ static imgtoolerr_t fat_image_create(imgtool::image &image, imgtool::stream::ptr imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_CREATE_PARTITION); /* actually create the partition */ - err = fat_partition_create(image, 0, ((uint64_t) tracks) * heads * sectors); + err = fat_partition_create(image, 0, uint64_t(tracks) * heads * sectors); if (err) goto done; @@ -64,11 +67,11 @@ static imgtoolerr_t fat_image_get_geometry(imgtool::image &image, uint32_t *trac if (err) return err; - total_sectors = pick_integer_le(buffer, 19, 2) - | (pick_integer_le(buffer, 32, 4) << 16); + total_sectors = get_u16le(&buffer[19]) + | uint64_t(get_u32le(&buffer[32]) << 16); - *sectors = pick_integer_le(buffer, 24, 2); - *heads = pick_integer_le(buffer, 26, 2); + *sectors = get_u16le(&buffer[24]); + *heads = get_u16le(&buffer[26]); *tracks = total_sectors / *heads / *sectors; return IMGTOOLERR_SUCCESS; } diff --git a/src/tools/imgtool/modules/pc_hard.cpp b/src/tools/imgtool/modules/pc_hard.cpp index c04ad33cce6..353a6b5dac5 100644 --- a/src/tools/imgtool/modules/pc_hard.cpp +++ b/src/tools/imgtool/modules/pc_hard.cpp @@ -50,9 +50,11 @@ ****************************************************************************/ #include "imgtool.h" -#include "formats/imageutl.h" #include "imghd.h" +#include "multibyte.h" +#include "opresolv.h" + #define FAT_SECLEN 512 OPTION_GUIDE_START( pc_chd_create_optionguide ) @@ -103,15 +105,12 @@ static pc_chd_image_info *pc_chd_get_image_info(imgtool::image &image) static void pc_chd_locate_block(imgtool::image &image, uint64_t block, uint32_t *cylinder, uint32_t *head, uint32_t *sector) { - pc_chd_image_info *info; - const hard_disk_info *hd_info; - - info = pc_chd_get_image_info(image); - hd_info = imghd_get_header(&info->hard_disk); + pc_chd_image_info *info = pc_chd_get_image_info(image); + const auto &hd_info = imghd_get_header(&info->hard_disk); - *sector = block % hd_info->sectors; - *head = (block / hd_info->sectors) % hd_info->heads; - *cylinder = block / hd_info->sectors / hd_info->heads; + *sector = block % hd_info.sectors; + *head = (block / hd_info.sectors) % hd_info.heads; + *cylinder = block / hd_info.sectors / hd_info.heads; } @@ -168,16 +167,16 @@ static imgtoolerr_t pc_chd_partition_create(imgtool::image &image, int partition /* fill out the partition entry */ partition_entry = &header_block[446 + (partition_index * 16)]; - place_integer_le(partition_entry, 0, 1, 0x80); - place_integer_le(partition_entry, 1, 1, first_head); - place_integer_le(partition_entry, 2, 1, ((first_sector & 0x3F) | (first_cylinder >> 8 << 2))); - place_integer_le(partition_entry, 3, 1, first_cylinder); - place_integer_le(partition_entry, 4, 1, partition_type); - place_integer_le(partition_entry, 5, 1, last_head); - place_integer_le(partition_entry, 6, 1, ((last_sector & 0x3F) | (last_cylinder >> 8 << 2))); - place_integer_le(partition_entry, 7, 1, last_cylinder); - place_integer_le(partition_entry, 8, 4, first_block); - place_integer_le(partition_entry, 12, 4, block_count); + partition_entry[0] = 0x80; + partition_entry[1] = first_head; + partition_entry[2] = ((first_sector & 0x3F) | (first_cylinder >> 8 << 2)); + partition_entry[3] = first_cylinder; + partition_entry[4] = partition_type; + partition_entry[5] = last_head; + partition_entry[6] = ((last_sector & 0x3F) | (last_cylinder >> 8 << 2)); + partition_entry[7] = last_cylinder; + put_u32le(&partition_entry[ 8], first_block); + put_u32le(&partition_entry[12], block_count); /* write the partition header */ err = image.write_block(0, header_block); @@ -193,7 +192,6 @@ done: static imgtoolerr_t pc_chd_read_partition_header(imgtool::image &image) { imgtoolerr_t err; - int i; const uint8_t *partition_info; pc_chd_image_info *info; uint8_t buffer[FAT_SECLEN]; @@ -209,7 +207,7 @@ static imgtoolerr_t pc_chd_read_partition_header(imgtool::image &image) if ((buffer[510] != 0x55) || (buffer[511] != 0xAA)) return IMGTOOLERR_CORRUPTIMAGE; - for (i = 0; i < ARRAY_LENGTH(info->partitions); i++) + for (int i = 0; i < std::size(info->partitions); i++) { partition_info = &buffer[446 + i * 16]; @@ -221,8 +219,8 @@ static imgtoolerr_t pc_chd_read_partition_header(imgtool::image &image) info->partitions[i].ending_track = ((partition_info[6] << 2) & 0xFF00) | partition_info[7]; info->partitions[i].ending_sector = partition_info[6] & 0x3F; - info->partitions[i].sector_index = pick_integer_le(partition_info, 8, 4); - info->partitions[i].total_sectors = pick_integer_le(partition_info, 12, 4); + info->partitions[i].sector_index = get_u32le(&partition_info[ 8]); + info->partitions[i].total_sectors = get_u32le(&partition_info[12]); if (info->partitions[i].starting_track > info->partitions[i].ending_track) return IMGTOOLERR_CORRUPTIMAGE; @@ -310,15 +308,12 @@ static void pc_chd_image_close(imgtool::image &image) static imgtoolerr_t pc_chd_image_get_geometry(imgtool::image &image, uint32_t *tracks, uint32_t *heads, uint32_t *sectors) { - pc_chd_image_info *info; - const hard_disk_info *hd_info; - - info = pc_chd_get_image_info(image); - hd_info = imghd_get_header(&info->hard_disk); + pc_chd_image_info *info = pc_chd_get_image_info(image); + const auto &hd_info = imghd_get_header(&info->hard_disk); - *tracks = hd_info->cylinders; - *heads = hd_info->heads; - *sectors = hd_info->sectors; + *tracks = hd_info.cylinders; + *heads = hd_info.heads; + *sectors = hd_info.sectors; return IMGTOOLERR_SUCCESS; } @@ -327,13 +322,11 @@ static imgtoolerr_t pc_chd_image_get_geometry(imgtool::image &image, uint32_t *t static uint32_t pc_chd_calc_lbasector(pc_chd_image_info &info, uint32_t track, uint32_t head, uint32_t sector) { uint32_t lbasector; - const hard_disk_info *hd_info; - - hd_info = imghd_get_header(&info.hard_disk); + const auto &hd_info = imghd_get_header(&info.hard_disk); lbasector = track; - lbasector *= hd_info->heads; + lbasector *= hd_info.heads; lbasector += head; - lbasector *= hd_info->sectors; + lbasector *= hd_info.sectors; lbasector += sector; return lbasector; } @@ -345,7 +338,7 @@ static imgtoolerr_t pc_chd_image_readsector(imgtool::image &image, uint32_t trac pc_chd_image_info *info = pc_chd_get_image_info(image); // get the sector size and resize the buffer - uint32_t sector_size = imghd_get_header(&info->hard_disk)->sectorbytes; + uint32_t sector_size = imghd_get_header(&info->hard_disk).sectorbytes; try { buffer.resize(sector_size); } catch (std::bad_alloc const &) { return IMGTOOLERR_OUTOFMEMORY; } diff --git a/src/tools/imgtool/modules/prodos.cpp b/src/tools/imgtool/modules/prodos.cpp deleted file mode 100644 index 6db41ae529b..00000000000 --- a/src/tools/imgtool/modules/prodos.cpp +++ /dev/null @@ -1,2267 +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" - -#define ROOTDIR_BLOCK 2 -#define BLOCK_SIZE 512 - -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, §or1, §or2); - - /* 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, §or1, §or2); - - /* 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, §or); - 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, §or); - 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, ARRAY_LENGTH(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; - } -} diff --git a/src/tools/imgtool/modules/psion.cpp b/src/tools/imgtool/modules/psion.cpp index 5759673349e..dba1130ddab 100644 --- a/src/tools/imgtool/modules/psion.cpp +++ b/src/tools/imgtool/modules/psion.cpp @@ -24,6 +24,11 @@ #include "imgtool.h" +#include "multibyte.h" +#include "opresolv.h" + +#include <cstdio> + #define MAXFILES 256 struct psion_file @@ -54,24 +59,23 @@ static psion_pack *get_psion_pack(imgtool::image &image) return (psion_pack*)image.extra_bytes(); } -uint16_t head_checksum(uint8_t* data) +uint16_t head_checksum(const uint8_t* data) { uint16_t checksum = 0; for (int i=0; i<6; i+=2) - checksum += (data[i]<<8 | data[i+1]); + checksum += get_u16be(&data[i]); return checksum; } uint16_t get_long_rec_size(imgtool::stream &stream) { - uint8_t size_h, size_l; + uint8_t size[2]; - stream.read(&size_h, 1); - stream.read(&size_l, 1); + stream.read(size, 2); - return (size_h<<8) | size_l; + return get_u16be(size); } uint32_t update_pack_index(psion_pack *pack) @@ -245,6 +249,7 @@ char *stream_getline(imgtool::stream &source, uint16_t max_len) source.read(&data, 1); if (data != '\n') source.seek(-1, SEEK_CUR); + [[fallthrough]]; case '\n': return line; default: @@ -483,7 +488,7 @@ static imgtoolerr_t datapack_next_enum(imgtool::directory &enumeration, imgtool_ return IMGTOOLERR_SUCCESS; } memcpy(ent.filename, pack->pack_index[iter->index].filename, 8); - sprintf(ent.attr, "Type: %02x ID: %02x", pack->pack_index[iter->index].type, pack->pack_index[iter->index].id); + snprintf(ent.attr, std::size(ent.attr), "Type: %02x ID: %02x", pack->pack_index[iter->index].type, pack->pack_index[iter->index].id); if (pack->pack_index[iter->index].data_rec) { diff --git a/src/tools/imgtool/modules/rsdos.cpp b/src/tools/imgtool/modules/rsdos.cpp index 4bcde9444ab..b4924338309 100644 --- a/src/tools/imgtool/modules/rsdos.cpp +++ b/src/tools/imgtool/modules/rsdos.cpp @@ -8,13 +8,18 @@ ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> #include "imgtool.h" -#include "formats/coco_dsk.h" +#include "filter.h" #include "iflopimg.h" +#include "formats/coco_dsk.h" +#include "corestr.h" +#include "opresolv.h" + +#include <cstdio> +#include <cstdlib> +#include <cstring> + /* this structure mirrors the structure of an RS-DOS directory entry on disk */ struct rsdos_dirent { @@ -103,7 +108,7 @@ static imgtoolerr_t lookup_rsdos_file(imgtool::image &f, const char *fname, rsdo if (ent.filename[0] != -1) fnamebuf = get_dirent_fname(ent); } - while((ent.filename[0] != -1) && core_stricmp(fnamebuf.c_str(), fname)); + while((ent.filename[0] != -1) && core_stricmp(fnamebuf, fname)); if (ent.filename[0] == -1) return IMGTOOLERR_FILENOTFOUND; @@ -320,7 +325,7 @@ eof: } else { - /* Not the end of file */ + /* Note the end of file */ err = process_rsdos_file(&rsent, image, nullptr, filesize); if (err) return err; @@ -340,8 +345,8 @@ eof: std::string fname = get_dirent_fname(rsent); - snprintf(ent.filename, ARRAY_LENGTH(ent.filename), "%s", fname.c_str()); - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "%d %c", (int) rsent.ftype, (char) (rsent.asciiflag + 'B')); + snprintf(ent.filename, std::size(ent.filename), "%s", fname.c_str()); + snprintf(ent.attr, std::size(ent.attr), "%d %c", (int) rsent.ftype, (char) (rsent.asciiflag + 'B')); } return IMGTOOLERR_SUCCESS; } @@ -568,7 +573,7 @@ static imgtoolerr_t rsdos_diskimage_deletefile(imgtool::partition &partition, co // rsdos_diskimage_suggesttransfer //------------------------------------------------- -static imgtoolerr_t rsdos_diskimage_suggesttransfer(imgtool::partition &partition, const char *fname, imgtool_transfer_suggestion *suggestions, size_t suggestions_length) +static imgtoolerr_t rsdos_diskimage_suggesttransfer(imgtool::partition &partition, const char *fname, imgtool::transfer_suggestion *suggestions, size_t suggestions_length) { imgtoolerr_t err; imgtool::image &image(partition.image()); @@ -584,27 +589,27 @@ static imgtoolerr_t rsdos_diskimage_suggesttransfer(imgtool::partition &partitio if (ent.asciiflag == (char) 0xFF) { /* ASCII file */ - suggestions[0].viability = SUGGESTION_RECOMMENDED; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; suggestions[0].filter = filter_eoln_getinfo; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = NULL; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; + suggestions[1].filter = nullptr; } else if (ent.ftype == 0) { /* tokenized BASIC file */ - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[1].viability = SUGGESTION_POSSIBLE; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = nullptr; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; suggestions[1].filter = filter_cocobas_getinfo; } } else { - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[1].viability = SUGGESTION_POSSIBLE; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = nullptr; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; suggestions[1].filter = filter_eoln_getinfo; - suggestions[2].viability = SUGGESTION_POSSIBLE; + suggestions[2].viability = imgtool::SUGGESTION_POSSIBLE; suggestions[2].filter = filter_cocobas_getinfo; } @@ -640,7 +645,7 @@ void rsdos_get_info(const imgtool_class *imgclass, uint32_t state, union imgtool case IMGTOOLINFO_INT_PREFER_UCASE: info->i = 1; break; case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(struct rsdos_direnum); break; - /* --- the following bits of info are returned as NULL-terminated strings --- */ + /* --- the following bits of info are returned as NUL-terminated strings --- */ case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "rsdos"); break; case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "RS-DOS format"); break; case IMGTOOLINFO_STR_FILE: strcpy(info->s = imgtool_temp_str(), __FILE__); break; diff --git a/src/tools/imgtool/modules/rt11.cpp b/src/tools/imgtool/modules/rt11.cpp index 01ab8741dd6..cc425adbdb6 100644 --- a/src/tools/imgtool/modules/rt11.cpp +++ b/src/tools/imgtool/modules/rt11.cpp @@ -72,12 +72,13 @@ ****************************************************************************/ #include "imgtool.h" -#include "formats/imageutl.h" #include "iflopimg.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> +#include "multibyte.h" + +#include <cstdio> +#include <cstdlib> +#include <cstring> namespace @@ -384,17 +385,17 @@ static imgtoolerr_t rt11_image_open(imgtool::image &image, imgtool::stream::ptr if (err) return err; - di->directory_start = pick_integer_le(buffer, 0724, 2); + di->directory_start = get_u16le(&buffer[0724]); // real-world images seem to never have a valid checksum, but directory_start is always 6 #if 0 uint16_t tmp, cksum; tmp = 0; - cksum = pick_integer_le(buffer, 0776, 2); + cksum = get_u16le(&buffer[0776]); for (int i = 0; i < 510; i+=2) { - tmp += pick_integer_le(buffer, i, 2); + tmp += get_u16le(&buffer[i]); } /* sanity check these values */ @@ -414,9 +415,9 @@ static imgtoolerr_t rt11_image_open(imgtool::image &image, imgtool::stream::ptr if (err) return err; - di->total_segments = pick_integer_le(buffer, 0, 2); - di->last_segment = pick_integer_le(buffer, 4, 2); - di->dirent_size = (pick_integer_le(buffer, 6, 2) + 7) * 2; + di->total_segments = get_u16le(&buffer[0]); + di->last_segment = get_u16le(&buffer[4]); + di->dirent_size = (get_u16le(&buffer[6]) + 7) * 2; di->dirents_per_block = (2 * BLOCK_SIZE - 10) / di->dirent_size; return IMGTOOLERR_SUCCESS; @@ -465,7 +466,7 @@ static imgtoolerr_t rt11_enum_seek(imgtool::image &image, return err; memcpy(&rt11enum->segment_data[BLOCK_SIZE], buffer, sizeof(buffer)); - rt11enum->data = pick_integer_le(rt11enum->segment_data, 8, 2); + rt11enum->data = get_u16le(&rt11enum->segment_data[8]); } rt11enum->segment = segment; } @@ -490,19 +491,19 @@ static imgtoolerr_t rt11_get_next_dirent(imgtool::image &image, /* populate the resulting dirent */ offset = (rt11enum->index * di->dirent_size) + 10; - rt_ent.status = pick_integer_le(rt11enum->segment_data, offset, 2); + rt_ent.status = get_u16le(&rt11enum->segment_data[offset]); memcpy(rt_ent.filename, &rt11enum->segment_data[offset + 2], 6); - rt_ent.filesize = pick_integer_le(rt11enum->segment_data, offset + 8, 2) * BLOCK_SIZE; + rt_ent.filesize = get_u16le(&rt11enum->segment_data[offset + 8]) * BLOCK_SIZE; rt_ent.data = rt11enum->data; - rt_ent.time = pick_integer_le(rt11enum->segment_data, offset + 12, 2); - rt11enum->data += pick_integer_le(rt11enum->segment_data, offset + 8, 2); + rt_ent.time = get_u16le(&rt11enum->segment_data[offset + 12]); + rt11enum->data += get_u16le(&rt11enum->segment_data[offset + 8]); /* identify next entry */ next_segment = rt11enum->segment; next_index = rt11enum->index + 1; if (next_index >= di->dirents_per_block || (rt_ent.status & E_EOS)) { - next_segment = pick_integer_le(rt11enum->segment_data, 2, 2); + next_segment = get_u16le(&rt11enum->segment_data[2]); next_index = 0; } diff --git a/src/tools/imgtool/modules/thomson.cpp b/src/tools/imgtool/modules/thomson.cpp index f122bc00520..1978e3720ba 100644 --- a/src/tools/imgtool/modules/thomson.cpp +++ b/src/tools/imgtool/modules/thomson.cpp @@ -112,10 +112,15 @@ */ #include "imgtool.h" +#include "filter.h" #include "iflopimg.h" -#include "formats/imageutl.h" -#include <time.h> +#include "corestr.h" +#include "multibyte.h" +#include "opresolv.h" + +#include <cstdio> +#include <ctime> #define MAXSIZE 80*16*256*2 /* room for two faces, double-density, 80 tracks */ @@ -590,14 +595,14 @@ static int thom_find_dirent(thom_floppy* f, unsigned head, { int n = 0; while ( 1 ) { - thom_get_dirent( f, head, n, d ); - if ( d->type == THOM_DIRENT_END ) return 0; - if ( d->type == THOM_DIRENT_FILE ) { - char buf[13]; - sprintf( buf, "%s.%s", d->name, d->ext ); - if ( ! strcmp( buf, name ) ) return 1; - } - n++; + thom_get_dirent( f, head, n, d ); + if ( d->type == THOM_DIRENT_END ) return 0; + if ( d->type == THOM_DIRENT_FILE ) { + char buf[13]; + snprintf( buf, std::size(buf), "%s.%s", d->name, d->ext ); + if ( ! strcmp( buf, name ) ) return 1; + } + n++; } } @@ -952,7 +957,7 @@ static imgtoolerr_t thom_read_file(imgtool::partition &part, /* convert filename */ thom_conv_filename( filename, name, ext ); - sprintf( fname, "%s.%s", name, ext ); + snprintf( fname, std::size(fname), "%s.%s", name, ext ); if ( ! thom_find_dirent( f, head, fname, &d ) ) return IMGTOOLERR_FILENOTFOUND; @@ -973,7 +978,7 @@ static imgtoolerr_t thom_delete_file(imgtool::partition &part, /* convert filename */ thom_conv_filename( filename, name, ext ); - sprintf( fname, "%s.%s", name, ext ); + snprintf( fname, std::size(fname), "%s.%s", name, ext ); if ( ! thom_find_dirent( f, head, fname, &d ) ) return IMGTOOLERR_FILENOTFOUND; @@ -1002,7 +1007,7 @@ static imgtoolerr_t thom_write_file(imgtool::partition &part, /* convert filename */ thom_conv_filename( filename, name, ext ); - sprintf( fname, "%s.%s", name, ext ); + snprintf( fname, std::size(fname), "%s.%s", name, ext ); /* check available space & find dir entry */ if ( thom_find_dirent( f, head, fname, &d ) ) { @@ -1067,10 +1072,11 @@ static imgtoolerr_t thom_write_file(imgtool::partition &part, return IMGTOOLERR_SUCCESS; } -static imgtoolerr_t thom_suggest_transfer(imgtool::partition &part, - const char *fname, - imgtool_transfer_suggestion *suggestions, - size_t suggestions_length) +static imgtoolerr_t thom_suggest_transfer( + imgtool::partition &part, + const char *fname, + imgtool::transfer_suggestion *suggestions, + size_t suggestions_length) { int head = *( (int*) part.extra_bytes() ); imgtool::image &img(part.image()); @@ -1081,30 +1087,30 @@ static imgtoolerr_t thom_suggest_transfer(imgtool::partition &part, if ( suggestions_length < 1 ) return IMGTOOLERR_SUCCESS; if ( fname ) { - if ( ! thom_find_dirent( f, head, fname, &d ) ) - return IMGTOOLERR_FILENOTFOUND; - if ( d.ftype == 0 && d.format == 0 ) is_basic = 1; + if ( ! thom_find_dirent( f, head, fname, &d ) ) + return IMGTOOLERR_FILENOTFOUND; + if ( d.ftype == 0 && d.format == 0 ) is_basic = 1; } if ( is_basic ) { - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = filter_thombas128_getinfo; - if ( suggestions_length >= 2 ) { - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = filter_thombas7_getinfo; - } - if ( suggestions_length >= 3 ) { - suggestions[2].viability = SUGGESTION_POSSIBLE; - suggestions[2].filter = filter_thombas5_getinfo; - } - if ( suggestions_length >= 4 ) { - suggestions[3].viability = SUGGESTION_POSSIBLE; - suggestions[3].filter = NULL; - } + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = filter_thombas128_getinfo; + if ( suggestions_length >= 2 ) { + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; + suggestions[1].filter = filter_thombas7_getinfo; + } + if ( suggestions_length >= 3 ) { + suggestions[2].viability = imgtool::SUGGESTION_POSSIBLE; + suggestions[2].filter = filter_thombas5_getinfo; + } + if ( suggestions_length >= 4 ) { + suggestions[3].viability = imgtool::SUGGESTION_POSSIBLE; + suggestions[3].filter = nullptr; + } } else { - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = nullptr; } return IMGTOOLERR_SUCCESS; @@ -1206,12 +1212,12 @@ static const char *const thombas7[2][128] = { /* MO5: some keywords ar missing; DOS and TUNE are added */ static const char *const thombas5[2][128] = { { /* statements */ - "END", "FOR", "NEXT", "DATA", "DIM", "READ", NULL, "GO", "RUN", "IF", + "END", "FOR", "NEXT", "DATA", "DIM", "READ", nullptr, "GO", "RUN", "IF", "RESTORE", "RETURN", "REM", "'", "STOP", "ELSE", "TRON", "TROFF", "DEFSTR", - "DEFINT", "DEFSNG", NULL, "ON", "TUNE", "ERROR", "RESUME", "AUTO", + "DEFINT", "DEFSNG", nullptr, "ON", "TUNE", "ERROR", "RESUME", "AUTO", "DELETE", "LOCATE", "CLS", "CONSOLE", "PSET", "MOTOR", "SKIP", "EXEC", - "BEEP", "COLOR", "LINE", "BOX", NULL, "ATTRB", "DEF", "POKE", "PRINT", - "CONT", "LIST", "CLEAR", "DOS", NULL, "NEW", "SAVE", "LOAD", "MERGE", + "BEEP", "COLOR", "LINE", "BOX", nullptr, "ATTRB", "DEF", "POKE", "PRINT", + "CONT", "LIST", "CLEAR", "DOS", nullptr, "NEW", "SAVE", "LOAD", "MERGE", "OPEN", "CLOSE", "INPEN", "PEN", "PLAY", "TAB(", "TO", "SUB", "FN", "SPC(", "USING", "USR", "ERL", "ERR", "OFF", "THEN", "NOT", "STEP", "+", "-", "*", "/", "^", "AND", "OR", "XOR", "EQV", "IMP", "MOD", "@", @@ -1224,8 +1230,8 @@ static const char *const thombas5[2][128] = { }, { /* functions: 0xff prefix */ "SGN", "INT", "ABS", "FRE", "SQR", "LOG", "EXP", "COS", "SIN", - "TAN", "PEEK", "LEN", "STR$", "VAL", "ASC", "CHR$", "EOF", "CINT", NULL, - NULL, "FIX", "HEX$", NULL, "STICK", "STRIG", "GR$", "LEFT$", "RIGHT$", + "TAN", "PEEK", "LEN", "STR$", "VAL", "ASC", "CHR$", "EOF", "CINT", nullptr, + nullptr, "FIX", "HEX$", nullptr, "STICK", "STRIG", "GR$", "LEFT$", "RIGHT$", "MID$", "INSTR", "VARPTR", "RND", "INKEY$", "INPUT", "CSRLIN", "POINT", "SCREEN", "POS", "PTRIG", /* DOS specific */ @@ -1368,7 +1374,7 @@ static imgtoolerr_t thomcrypt_write_file(imgtool::partition &part, } } -void filter_thomcrypt_getinfo(uint32_t state, union filterinfo *info) +void filter_thomcrypt_getinfo(uint32_t state, imgtool::filterinfo *info) { switch(state) { case FILTINFO_STR_NAME: @@ -1596,16 +1602,14 @@ struct { { "\xc3\xa7", "\x16" "Kc" }, { "\xc3\x87", "\x16" "KC" }, - { NULL, NULL } + { nullptr, nullptr } }; static bool thom_basic_is_specialchar(const char *buf, int *pos, const char **thom) { - int i; - - for (i = 0; special_chars[i].utf8 != NULL; i++) + for (int i = 0; special_chars[i].utf8 != nullptr; i++) { if (!strncmp(&buf[*pos], special_chars[i].utf8, strlen(special_chars[i].utf8))) { @@ -1740,7 +1744,7 @@ static imgtoolerr_t thom_basic_write_file(imgtool::partition &partition, if ((c == '\r') || (c == '\n')) break; - if (pos <= ARRAY_LENGTH(buf) - 1) + if (pos <= std::size(buf) - 1) { buf[pos++] = c; } @@ -1765,8 +1769,8 @@ static imgtoolerr_t thom_basic_write_file(imgtool::partition &partition, /* set up line header */ memset(&line_header, 0, sizeof(line_header)); /* linelength or offset (2-bytes) will be rewritten */ - place_integer_be(line_header, 0, 2, 0xffff); - place_integer_be(line_header, 2, 2, line_number); + put_u16be(&line_header[0], 0xffff); + put_u16be(&line_header[2], line_number); /* emit line header */ line_header_loc = mem_stream->tell(); @@ -1841,7 +1845,7 @@ static imgtoolerr_t thom_basic_write_file(imgtool::partition &partition, /* rewrite the line length */ end_line_loc = mem_stream->tell(); mem_stream->seek(line_header_loc, SEEK_SET); - place_integer_be(line_header, 0, 2, end_line_loc - line_header_loc); + put_u16be(&line_header[0], end_line_loc - line_header_loc); mem_stream->write(line_header, sizeof(line_header)); mem_stream->seek(end_line_loc, SEEK_SET); } @@ -1854,8 +1858,8 @@ static imgtoolerr_t thom_basic_write_file(imgtool::partition &partition, mem_stream->seek(0, SEEK_SET); /* Write file header */ - place_integer_be(file_header, 0, 1, 0xFF); - place_integer_be(file_header, 1, 2, mem_stream->size()); + file_header[0] = 0xFF; + put_u16be(&file_header[1], mem_stream->size()); mem_stream->write(file_header, 3); mem_stream->seek(0, SEEK_SET); @@ -1870,32 +1874,33 @@ static imgtoolerr_t thom_basic_write_file(imgtool::partition &partition, const char *fork, \ imgtool::stream &dst) \ { \ - return thom_basic_read_file( part, name, fork, dst, short ); \ + return thom_basic_read_file( part, name, fork, dst, short ); \ } \ - static imgtoolerr_t short##_write_file(imgtool::partition &part, \ - const char *name, \ - const char *fork, \ - imgtool::stream &src, \ - util::option_resolution *opts) \ + static imgtoolerr_t short##_write_file( \ + imgtool::partition &part, \ + const char *name, \ + const char *fork, \ + imgtool::stream &src, \ + util::option_resolution *opts) \ { \ - return thom_basic_write_file( part, name, fork, src, opts, short ); \ + return thom_basic_write_file( part, name, fork, src, opts, short ); \ } \ - void filter_##short##_getinfo(uint32_t state, union filterinfo *info) \ + void filter_##short##_getinfo(uint32_t state, imgtool::filterinfo *info) \ { \ switch(state) \ { \ case FILTINFO_STR_NAME: \ - info->s = #short; \ - break; \ + info->s = #short; \ + break; \ case FILTINFO_STR_HUMANNAME: \ - info->s = long; \ - break; \ + info->s = long; \ + break; \ case FILTINFO_PTR_READFILE: \ - info->read_file = short##_read_file; \ - break; \ + info->read_file = short##_read_file; \ + break; \ case FILTINFO_PTR_WRITEFILE: \ - info->write_file = short##_write_file; \ - break; \ + info->write_file = short##_write_file; \ + break; \ } \ } @@ -1941,57 +1946,57 @@ static void thom_basic_get_info(const imgtool_class *clas, { switch ( param ) { case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: - info->i = sizeof(thom_floppy); break; + info->i = sizeof(thom_floppy); break; case IMGTOOLINFO_INT_PARTITION_EXTRA_BYTES: - info->i = sizeof(int); break; + info->i = sizeof(int); break; case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: - info->i = sizeof(int); break; + info->i = sizeof(int); break; case IMGTOOLINFO_INT_SUPPORTS_CREATION_TIME: case IMGTOOLINFO_INT_PREFER_UCASE: - info->i = 1; break; + info->i = 1; break; case IMGTOOLINFO_INT_PATH_SEPARATOR: - info->i = 0; break; + info->i = 0; break; case IMGTOOLINFO_STR_FILE: - strcpy( info->s = imgtool_temp_str(), __FILE__ ); break; + strcpy( info->s = imgtool_temp_str(), __FILE__ ); break; case IMGTOOLINFO_STR_NAME: - strcpy( info->s = imgtool_temp_str(), "thom" ); break; + strcpy( info->s = imgtool_temp_str(), "thom" ); break; case IMGTOOLINFO_STR_DESCRIPTION: - strcpy( info->s = imgtool_temp_str(), "Thomson BASIC filesystem" ); - break; + strcpy( info->s = imgtool_temp_str(), "Thomson BASIC filesystem" ); + break; case IMGTOOLINFO_PTR_CREATE: - info->create = thom_create; break; + info->create = thom_create; break; case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: - info->createimage_optguide = &thom_createimage_optguide; break; + info->createimage_optguide = &thom_createimage_optguide; break; case IMGTOOLINFO_PTR_BEGIN_ENUM: - info->begin_enum = thom_begin_enum; break; + info->begin_enum = thom_begin_enum; break; case IMGTOOLINFO_PTR_NEXT_ENUM: - info->next_enum = thom_next_enum; break; + info->next_enum = thom_next_enum; break; case IMGTOOLINFO_PTR_READ_FILE: - info->read_file = thom_read_file; break; + info->read_file = thom_read_file; break; case IMGTOOLINFO_PTR_WRITE_FILE: - info->write_file = thom_write_file; break; + info->write_file = thom_write_file; break; case IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE: - info->writefile_optguide = &thom_writefile_optguide; break; + info->writefile_optguide = &thom_writefile_optguide; break; case IMGTOOLINFO_STR_WRITEFILE_OPTSPEC: - strcpy( info->s = imgtool_temp_str(), "T[0]-4;F[0]-2;C" ); break; + strcpy( info->s = imgtool_temp_str(), "T[0]-4;F[0]-2;C" ); break; case IMGTOOLINFO_PTR_SUGGEST_TRANSFER: - info->suggest_transfer = thom_suggest_transfer; break; + info->suggest_transfer = thom_suggest_transfer; break; case IMGTOOLINFO_PTR_DELETE_FILE: - info->delete_file = thom_delete_file; break; + info->delete_file = thom_delete_file; break; case IMGTOOLINFO_PTR_FREE_SPACE: - info->free_space = thom_free_space; break; + info->free_space = thom_free_space; break; case IMGTOOLINFO_PTR_GET_GEOMETRY: - info->get_geometry = thom_get_geometry; break; + info->get_geometry = thom_get_geometry; break; case IMGTOOLINFO_PTR_INFO: - info->info = thom_info; break; + info->info = thom_info; break; case IMGTOOLINFO_PTR_READ_SECTOR: - info->read_sector = thom_read_sector; break; + info->read_sector = thom_read_sector; break; case IMGTOOLINFO_PTR_WRITE_SECTOR: - info->write_sector = thom_write_sector; break; + info->write_sector = thom_write_sector; break; case IMGTOOLINFO_PTR_LIST_PARTITIONS: - info->list_partitions = thom_list_partitions; break; + info->list_partitions = thom_list_partitions; break; case IMGTOOLINFO_PTR_OPEN_PARTITION: - info->open_partition = thom_open_partition; break; + info->open_partition = thom_open_partition; break; } } @@ -2001,21 +2006,21 @@ void thom_fd_basic_get_info(const imgtool_class *clas, { switch ( param ) { case IMGTOOLINFO_STR_NAME: - strcpy( info->s = imgtool_temp_str(), "thom_fd" ); break; + strcpy( info->s = imgtool_temp_str(), "thom_fd" ); break; case IMGTOOLINFO_STR_DESCRIPTION: - strcpy( info->s = imgtool_temp_str(), - "Thomson .fd disk image, BASIC format" ); - break; + strcpy( info->s = imgtool_temp_str(), + "Thomson .fd disk image, BASIC format" ); + break; case IMGTOOLINFO_STR_FILE_EXTENSIONS: - strcpy( info->s = imgtool_temp_str(), "fd" ); break; + strcpy( info->s = imgtool_temp_str(), "fd" ); break; case IMGTOOLINFO_PTR_OPEN: - info->open = thom_open_fd_qd; break; + info->open = thom_open_fd_qd; break; case IMGTOOLINFO_PTR_CLOSE: - info->close = thom_close_fd_qd; break; + info->close = thom_close_fd_qd; break; case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: - strcpy( info->s = imgtool_temp_str(), "H[1]-2;T40/[80];D0-[1];N" ); break; + strcpy( info->s = imgtool_temp_str(), "H[1]-2;T40/[80];D0-[1];N" ); break; default: - thom_basic_get_info( clas, param, info ); + thom_basic_get_info( clas, param, info ); } } @@ -2025,21 +2030,21 @@ void thom_qd_basic_get_info(const imgtool_class *clas, { switch ( param ) { case IMGTOOLINFO_STR_NAME: - strcpy( info->s = imgtool_temp_str(), "thom_qd" ); break; + strcpy( info->s = imgtool_temp_str(), "thom_qd" ); break; case IMGTOOLINFO_STR_DESCRIPTION: - strcpy( info->s = imgtool_temp_str(), - "Thomson .qd disk image, BASIC format" ); - break; + strcpy( info->s = imgtool_temp_str(), + "Thomson .qd disk image, BASIC format" ); + break; case IMGTOOLINFO_STR_FILE_EXTENSIONS: - strcpy( info->s = imgtool_temp_str(), "qd" ); break; + strcpy( info->s = imgtool_temp_str(), "qd" ); break; case IMGTOOLINFO_PTR_OPEN: - info->open = thom_open_fd_qd; break; + info->open = thom_open_fd_qd; break; case IMGTOOLINFO_PTR_CLOSE: - info->close = thom_close_fd_qd; break; + info->close = thom_close_fd_qd; break; case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: - strcpy( info->s = imgtool_temp_str(), "H[1]-2;T[25];D[0];N" ); break; + strcpy( info->s = imgtool_temp_str(), "H[1]-2;T[25];D[0];N" ); break; default: - thom_basic_get_info( clas, param, info ); + thom_basic_get_info( clas, param, info ); } } @@ -2049,20 +2054,20 @@ void thom_sap_basic_get_info(const imgtool_class *clas, { switch ( param ) { case IMGTOOLINFO_STR_NAME: - strcpy( info->s = imgtool_temp_str(), "thom_sap" ); break; + strcpy( info->s = imgtool_temp_str(), "thom_sap" ); break; case IMGTOOLINFO_STR_DESCRIPTION: - strcpy( info->s = imgtool_temp_str(), - "Thomson .sap disk image, BASIC format" ); - break; + strcpy( info->s = imgtool_temp_str(), + "Thomson .sap disk image, BASIC format" ); + break; case IMGTOOLINFO_STR_FILE_EXTENSIONS: - strcpy( info->s = imgtool_temp_str(), "sap" ); break; + strcpy( info->s = imgtool_temp_str(), "sap" ); break; case IMGTOOLINFO_PTR_OPEN: - info->open = thom_open_sap; break; + info->open = thom_open_sap; break; case IMGTOOLINFO_PTR_CLOSE: - info->close = thom_close_sap; break; + info->close = thom_close_sap; break; case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: - strcpy( info->s = imgtool_temp_str(), "H[1];T40/[80];D0-[1];N" ); break; + strcpy( info->s = imgtool_temp_str(), "H[1];T40/[80];D0-[1];N" ); break; default: - thom_basic_get_info( clas, param, info ); + thom_basic_get_info( clas, param, info ); } } diff --git a/src/tools/imgtool/modules/ti99.cpp b/src/tools/imgtool/modules/ti99.cpp index 04881c7b5ef..3f57f91db7c 100644 --- a/src/tools/imgtool/modules/ti99.cpp +++ b/src/tools/imgtool/modules/ti99.cpp @@ -18,15 +18,18 @@ - 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" +#include "opresolv.h" + +#include <climits> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <ctime> + /* Concepts shared by both disk structures: ---------------------------------------- @@ -166,7 +169,7 @@ 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). + theoretical 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 @@ -524,7 +527,7 @@ struct dsk_vib /* 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. */ + /* non-existent 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.) */ @@ -976,17 +979,15 @@ static imgtoolerr_t open_image_lvl1(imgtool::stream::ptr &&file_handle, ti99_img 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) + const auto &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 */ @@ -1300,15 +1301,13 @@ static void dsk_aphysrec_to_sector_address(int aphysrec, const ti99_geometry *ge 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) +[[maybe_unused]] 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; + address.sector = aphysrec % geometry.secspertrack; + aphysrec /= geometry.secspertrack; + address.side = aphysrec % geometry.heads; + address.cylinder = aphysrec / geometry.heads; } -#endif /* Read one 256-byte physical record from a disk image @@ -1327,7 +1326,7 @@ static int read_absolute_physrec(ti99_lvl1_imgref *l1_img, unsigned aphysrec, vo if (l1_img->img_format == if_harddisk) { #if 0 - win_aphysrec_to_sector_address(aphysrec, & l1_img->geometry, & address); + win_aphysrec_to_sector_address(aphysrec, l1_img->geometry, address); return read_sector(l1_img, & address, dest); #endif @@ -1563,7 +1562,7 @@ struct dsk_fdr 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, */ + /* this field for data chain pointer extension, */ /* but this was never implemented. */ uint8_t flags; /* file status flags (see enum above) */ uint8_t recsperphysrec; /* logical records per physrec */ @@ -1579,9 +1578,9 @@ struct dsk_fdr /* 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. */ + /* DSR may be larger than they should. */ uint8_t eof; /* EOF offset in last physrec for variable length */ - /* record files and program files (0->256)*/ + /* record files and program files (0->256) */ uint8_t reclen; /* logical record size in bytes ([1,255] 0->256) */ /* Maximum allowable record size for variable */ /* length record files. Reserved for program */ @@ -1625,7 +1624,7 @@ struct win_fdr /* 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. */ + /* DSR may be larger than they should. */ /* other sibling FDRs: index of the first file */ /* physrec in this particular sibling FDR */ uint8_t eof; /* EOF offset in last physrec for variable length */ @@ -1837,7 +1836,7 @@ static int dsk_read_catalog(struct ti99_lvl2_imgref *l2_img, int aphysrec, ti99_ || ((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]), + qsort(dest->files, std::size(dest->files), sizeof(dest->files[0]), cat_file_compare_qsort); break; } @@ -3304,8 +3303,7 @@ static int write_file_physrec(struct ti99_lvl2_fileref *l2_file, unsigned fphysr /* 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) +[[maybe_unused]] 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; @@ -3313,7 +3311,7 @@ static int set_win_fdr_field(struct ti99_lvl2_fileref *l2_file, size_t offset, s 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)) + fdr_aphysrec = get_win_fdr_nextsibFDR_aphysrec(l2_file->win.l2_img, &fdr_buf)) { memcpy(((uint8_t *) &fdr_buf) + offset, data, size); if (write_absolute_physrec(&l2_file->win.l2_img->l1_img, fdr_aphysrec, &fdr_buf)) @@ -3325,7 +3323,6 @@ static int set_win_fdr_field(struct ti99_lvl2_fileref *l2_file, size_t offset, s return errorcode; } -#endif static uint8_t get_file_flags(struct ti99_lvl2_fileref *l2_file) { @@ -3675,11 +3672,10 @@ static void set_file_update_date(struct ti99_lvl2_fileref *l2_file, ti99_date_ti } } -#ifdef UNUSED_FUNCTION -static void current_date_time(ti99_date_time *reply) +[[maybe_unused]] static void current_date_time(ti99_date_time *reply) { /* All these functions should be ANSI */ - time_t cur_time = time(NULL); + time_t cur_time = time(nullptr); struct tm expanded_time = *localtime(& cur_time); reply->time_MSB = (expanded_time.tm_hour << 3) | (expanded_time.tm_min >> 3); @@ -3687,7 +3683,6 @@ static void current_date_time(ti99_date_time *reply) 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 - @@ -3712,14 +3707,13 @@ struct ti99_lvl3_fileref 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) +[[maybe_unused]] static int open_file_lvl3(ti99_lvl3_fileref *l3_file) { l3_file->cur_log_rec = 0; l3_file->cur_phys_rec = 0; @@ -3754,7 +3748,7 @@ static int is_eof(ti99_lvl3_fileref *l3_file) /* Read next record from a file */ -static int read_next_record(ti99_lvl3_fileref *l3_file, void *dest, int *out_reclen) +[[maybe_unused]] static int read_next_record(ti99_lvl3_fileref *l3_file, void *dest, int *out_reclen) { int errorcode; uint8_t physrec_buf[256]; @@ -3824,7 +3818,6 @@ static int read_next_record(ti99_lvl3_fileref *l3_file, void *dest, int *out_rec return 0; } -#endif #if 0 #pragma mark - @@ -4275,10 +4268,10 @@ static imgtoolerr_t dsk_image_nextenum(imgtool::directory &enumeration, imgtool_ { if (iter->listing_subdirs) { - fname_to_str(ent.filename, iter->image->dsk.catalogs[0].subdirs[iter->index[iter->level]].name, ARRAY_LENGTH(ent.filename)); + fname_to_str(ent.filename, iter->image->dsk.catalogs[0].subdirs[iter->index[iter->level]].name, std::size(ent.filename)); /* set type of DIR */ - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "DIR"); + snprintf(ent.attr, std::size(ent.attr), "DIR"); /* len in physrecs */ /* @BN@ return length in bytes */ @@ -4299,7 +4292,7 @@ static imgtoolerr_t dsk_image_nextenum(imgtool::directory &enumeration, imgtool_ if (reply) return IMGTOOLERR_READERROR; #if 0 - fname_to_str(ent.filename, fdr.name, ARRAY_LENGTH(ent.filename)); + fname_to_str(ent.filename, fdr.name, std::size(ent.filename)); #else { char buf[11]; @@ -4307,19 +4300,19 @@ static imgtoolerr_t dsk_image_nextenum(imgtool::directory &enumeration, imgtool_ 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(ent.filename, iter->image->dsk.catalogs[0].subdirs[iter->index[0]].name, std::size(ent.filename)); + strncat(ent.filename, ".", std::size(ent.filename) - 1); } fname_to_str(buf, fdr.name, 11); - strncat(ent.filename, buf, ARRAY_LENGTH(ent.filename) - 1); + strncat(ent.filename, buf, std::size(ent.filename) - 1); } #endif /* parse flags */ if (fdr.flags & fdr99_f_program) - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "PGM%s", + snprintf(ent.attr, std::size(ent.attr), "PGM%s", (fdr.flags & fdr99_f_wp) ? " R/O" : ""); else - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "%c/%c %d%s", + snprintf(ent.attr, std::size(ent.attr), "%c/%c %d%s", (fdr.flags & fdr99_f_int) ? 'I' : 'D', (fdr.flags & fdr99_f_var) ? 'V' : 'F', fdr.reclen, @@ -4399,7 +4392,7 @@ static imgtoolerr_t win_image_nextenum(imgtool::directory &enumeration, imgtool_ 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)); + fname_to_str(ent.filename, iter->catalog[iter->level].subdirs[iter->index[iter->level]].name, std::size(ent.filename)); #else { char buf[11]; @@ -4408,16 +4401,16 @@ static imgtoolerr_t win_image_nextenum(imgtool::directory &enumeration, imgtool_ 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); + strncat(ent.filename, buf, std::size(ent.filename) - 1); + strncat(ent.filename, ".", std::size(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); + strncat(ent.filename, buf, std::size(ent.filename) - 1); } #endif /* set type of DIR */ - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "DIR"); + snprintf(ent.attr, std::size(ent.attr), "DIR"); /* len in physrecs */ /* @BN@ return length in bytes */ @@ -4442,7 +4435,7 @@ static imgtoolerr_t win_image_nextenum(imgtool::directory &enumeration, imgtool_ 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)); + fname_to_str(ent.filename, iter->catalog[iter->level].files[iter->index[iter->level]].name, std::size(ent.filename)); #else { char buf[11]; @@ -4451,19 +4444,19 @@ static imgtoolerr_t win_image_nextenum(imgtool::directory &enumeration, imgtool_ 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); + strncat(ent.filename, buf, std::size(ent.filename) - 1); + strncat(ent.filename, ".", std::size(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); + strncat(ent.filename, buf, std::size(ent.filename) - 1); } #endif /* parse flags */ if (fdr.flags & fdr99_f_program) - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "PGM%s", + snprintf(ent.attr, std::size(ent.attr), "PGM%s", (fdr.flags & fdr99_f_wp) ? " R/O" : ""); else - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "%c/%c %d%s", + snprintf(ent.attr, std::size(ent.attr), "%c/%c %d%s", (fdr.flags & fdr99_f_int) ? 'I' : 'D', (fdr.flags & fdr99_f_var) ? 'V' : 'F', fdr.reclen, @@ -4948,7 +4941,7 @@ static imgtoolerr_t dsk_image_deletefile(imgtool::partition &partition, const ch /* free data AUs */ // fphysrecs = - get_UINT16BE(fdr.fphysrecs); + get_UINT16BE(fdr.fphysrecs); i = 0; cluster_index = 0; @@ -5090,7 +5083,7 @@ static imgtoolerr_t win_image_deletefile(imgtool::partition &partition, const ch /* 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 */ + need to check against them explicitly */ { int pastendoflist_flag; unsigned prevfdr_aphysrec; diff --git a/src/tools/imgtool/modules/ti990hd.cpp b/src/tools/imgtool/modules/ti990hd.cpp index 8edaeaf3fb6..a78589ff5aa 100644 --- a/src/tools/imgtool/modules/ti990hd.cpp +++ b/src/tools/imgtool/modules/ti990hd.cpp @@ -8,12 +8,15 @@ Raphael Nabet, 2003 */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <limits.h> #include "imgtool.h" +#include "opresolv.h" + +#include <climits> +#include <cstdio> +#include <cstdlib> +#include <cstring> + /* Max sector length is bytes. Generally 256, except for a few older disk units which use 288-byte-long sectors, and SCSI units which generally use standard 512-byte-long sectors. */ @@ -96,7 +99,7 @@ enum Track 1 Sector 0 through N-2: optional disk program image loader Track 1 Sector N-1: copy of Track 0 Sector 0 Track 1 Sector N: copy of Track 0 Sector 1 - Last cylinder has disagnostic information (reported as .S$DIAG) + Last cylinder has diagnostic information (reported as .S$DIAG) Remaining sectors are used for fdr and data. */ @@ -214,7 +217,7 @@ struct ti990_fdr UINT16BE hkc; /* hask key count: the number of file descriptor records that are present in the directory that hashed to this record number */ UINT16BE hkv; /* hask key value: the result of the hash algorithm for the file name actually covered in this record */ char fnm[8]; /* file name */ - uint8_t rsv[2]; /* reserved */ + uint8_t rsv[2]; /* reserved */ UINT16BE fl1; /* flags word 1 */ UINT16BE flg; /* flags word 2 */ UINT16BE prs; /* physical record size */ @@ -227,31 +230,31 @@ struct ti990_fdr UINT32BE eom; /* end of medium record number */ UINT32BE bkm; /* end of medium block number */ UINT16BE ofm; /* end of medium offset / */ - /* prelog number for KIF */ + /* prelog number for KIF */ UINT32BE fbq; /* free block queue head */ UINT16BE btr; /* B-tree roots block # */ UINT32BE ebq; /* empty block queue head */ UINT16BE kdr; /* key descriptions record # */ - uint8_t ud[6]; /* last update date */ - uint8_t cd[6]; /* creation date */ - uint8_t apb; /* ADU's per block */ - uint8_t bpa; /* blocks per ADU */ - UINT16BE mrs; /* minimumu KIF record size */ - uint8_t sat[64]; /* secondary allocation table: 16 2-word entries. The first word of an entry contains the size, in ADUs, of the secondary allocation. The second word contains the starting ADU of the allocation. */ + uint8_t ud[6]; /* last update date */ + uint8_t cd[6]; /* creation date */ + uint8_t apb; /* ADU's per block */ + uint8_t bpa; /* blocks per ADU */ + UINT16BE mrs; /* minimum KIF record size */ + uint8_t sat[64]; /* secondary allocation table: 16 2-word entries. The first word of an entry contains the size, in ADUs, of the secondary allocation. The second word contains the starting ADU of the allocation. */ /* bytes >86 to >100 are optional */ - uint8_t res[10]; /* reserved: seem to be actually meaningful (at least under DX10 3.6.x) */ + uint8_t res[10]; /* reserved: seem to be actually meaningful (at least under DX10 3.6.x) */ char uid[8]; /* user id of file creator */ UINT16BE psa; /* public security attribute */ ti990_ace ace[9]; /* 9 access control entries */ - uint8_t fil[2]; /* not used */ + uint8_t fil[2]; /* not used */ }; /* ADR record: variant of FDR for Aliases The fields marked here with *** are in the ADR template to maintain - compatability with the FDR template. + compatibility with the FDR template. */ struct ti990_adr { @@ -284,19 +287,19 @@ struct ti990_cdr UINT16BE fill00; /* reserved */ UINT16BE fill01; /* reserved */ UINT16BE fdf; /* flags (same as fdr.flg) */ - uint8_t flg; /* channel flzgs */ - uint8_t iid; /* owner task installed ID */ - uint8_t typ; /* default resource type */ - uint8_t tf; /* resource type flags */ + uint8_t flg; /* channel flzgs */ + uint8_t iid; /* owner task installed ID */ + uint8_t typ; /* default resource type */ + uint8_t tf; /* resource type flags */ UINT16BE mxl; /* maximum message length */ - uint8_t fill04[6]; /* reserved (and, no, I don't know where fill02 and fill03 have gone) */ + uint8_t fill04[6]; /* reserved (and, no, I don't know where fill02 and fill03 have gone) */ UINT16BE rna; /* record number of next CDR or ADR */ UINT16BE raf; /* record # of actual FDR */ - uint8_t fill05[110]; /* reserved */ + uint8_t fill05[110]; /* reserved */ char uid[8]; /* user ID of channel creator */ UINT16BE psa; /* public security attribute */ - uint8_t scg[94]; /* "SDT with 9 control groups" (whatever it means - and, no, 94 is not dividable by 9) */ - uint8_t fill06[8]; /* reserved */ + uint8_t scg[94]; /* "SDT with 9 control groups" (whatever it means - and, no, 94 is not dividable by 9) */ + uint8_t fill06[8]; /* reserved */ }; /* @@ -321,19 +324,18 @@ union directory_entry */ struct tifile_header { - char tifiles[8]; /* always '\7TIFILES' */ - uint8_t secsused_MSB; /* file length in sectors (big-endian) */ - uint8_t secsused_LSB; - uint8_t flags; /* see enum above */ - uint8_t recspersec; /* records per sector */ - uint8_t eof; /* current position of eof in last sector (0->255)*/ - uint8_t reclen; /* bytes per record ([1,255] 0->256) */ - uint8_t fixrecs_MSB; /* file length in records (big-endian) */ - uint8_t fixrecs_LSB; - uint8_t res[128-16]; /* reserved */ + char tifiles[8]; /* always '\7TIFILES' */ + uint8_t secsused_MSB; /* file length in sectors (big-endian) */ + uint8_t secsused_LSB; + uint8_t flags; /* see enum above */ + uint8_t recspersec; /* records per sector */ + uint8_t eof; /* current position of eof in last sector (0->255)*/ + uint8_t reclen; /* bytes per record ([1,255] 0->256) */ + uint8_t fixrecs_MSB; /* file length in records (big-endian) */ + uint8_t fixrecs_LSB; + uint8_t res[128-16]; /* reserved */ }; - /* catalog entry (used for in-memory catalog) */ @@ -398,11 +400,9 @@ static imgtoolerr_t ti990_image_beginenum(imgtool::directory &enumeration, const static imgtoolerr_t ti990_image_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent); static void ti990_image_closeenum(imgtool::directory &enumeration); static imgtoolerr_t ti990_image_freespace(imgtool::partition &partition, uint64_t *size); -#ifdef UNUSED_FUNCTION -static imgtoolerr_t ti990_image_readfile(imgtool::partition &partition, const char *fpath, imgtool::stream *destf); -static imgtoolerr_t ti990_image_writefile(imgtool::partition &partition, const char *fpath, imgtool::stream *sourcef, util::option_resolution *writeoptions); -static imgtoolerr_t ti990_image_deletefile(imgtool::partition &partition, const char *fpath); -#endif +[[maybe_unused]] static imgtoolerr_t ti990_image_readfile(imgtool::partition &partition, const char *fpath, imgtool::stream *destf); +[[maybe_unused]] static imgtoolerr_t ti990_image_writefile(imgtool::partition &partition, const char *fpath, imgtool::stream *sourcef, util::option_resolution *writeoptions); +[[maybe_unused]] static imgtoolerr_t ti990_image_deletefile(imgtool::partition &partition, const char *fpath); static imgtoolerr_t ti990_image_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *createoptions); enum @@ -452,11 +452,10 @@ void ti990_get_info(const imgtool_class *imgclass, uint32_t state, union imgtool } } -#ifdef UNUSED_FUNCTION /* Convert a C string to a 8-character file name (padded with spaces if necessary) */ -static void str_to_fname(char dst[8], const char *src) +[[maybe_unused]] static void str_to_fname(char dst[8], const char *src) { int i; @@ -478,7 +477,6 @@ static void str_to_fname(char dst[8], const char *src) i++; } } -#endif /* Convert a 8-character file name to a C string (removing trailing spaces if necessary) @@ -555,7 +553,6 @@ static int read_sector_physical_len(imgtool::stream &file_handle, const ti990_ph return 0; } -#ifdef UNUSED_FUNCTION /* Read one sector from a disk image @@ -564,11 +561,10 @@ static int read_sector_physical_len(imgtool::stream &file_handle, const ti990_ph geometry: disk geometry (sectors per track, tracks per side, sides) dest: pointer to a destination buffer of geometry->bytes_per_sector bytes */ -static int read_sector_physical(imgtool::stream *file_handle, const ti990_phys_sec_address *address, const ti990_geometry *geometry, void *dest) +[[maybe_unused]] static int read_sector_physical(imgtool::stream &file_handle, const ti990_phys_sec_address *address, const ti990_geometry *geometry, void *dest) { return read_sector_physical_len(file_handle, address, geometry, dest, geometry->bytes_per_sector); } -#endif /* Write one sector to a disk image @@ -606,7 +602,6 @@ static int write_sector_physical_len(imgtool::stream &file_handle, const ti990_p return 0; } -#ifdef UNUSED_FUNCTION /* Write one sector to a disk image @@ -615,11 +610,10 @@ static int write_sector_physical_len(imgtool::stream &file_handle, const ti990_p geometry: disk geometry (sectors per track, tracks per side, sides) dest: pointer to a source buffer of geometry->bytes_per_sector bytes */ -static int write_sector_physical(imgtool::stream *file_handle, const ti990_phys_sec_address *address, const ti990_geometry *geometry, const void *src) +[[maybe_unused]] static int write_sector_physical(imgtool::stream &file_handle, const ti990_phys_sec_address *address, const ti990_geometry *geometry, const void *src) { return write_sector_physical_len(file_handle, address, geometry, src, geometry->bytes_per_sector); } -#endif /* Convert logical sector address to physical sector address @@ -651,7 +645,6 @@ static int read_sector_logical_len(imgtool::stream &file_handle, int secnum, con return read_sector_physical_len(file_handle, &address, geometry, dest, len); } -#ifdef UNUSED_FUNCTION /* Read one sector from a disk image @@ -660,11 +653,10 @@ static int read_sector_logical_len(imgtool::stream &file_handle, int secnum, con geometry: disk geometry (sectors per track, tracks per side, sides) dest: pointer to a destination buffer of geometry->bytes_per_sector bytes */ -static int read_sector_logical(imgtool::stream *file_handle, int secnum, const ti990_geometry *geometry, void *dest) +[[maybe_unused]] static int read_sector_logical(imgtool::stream &file_handle, int secnum, const ti990_geometry *geometry, void *dest) { return read_sector_logical_len(file_handle, secnum, geometry, dest, geometry->bytes_per_sector); } -#endif /* Write one sector to a disk image @@ -703,7 +695,6 @@ static int write_sector_logical(imgtool::stream &file_handle, int secnum, const #pragma mark CATALOG FILE ROUTINES #endif -#ifdef UNUSED_FUNCTION /* Find the catalog entry and fdr record associated with a file name @@ -715,7 +706,7 @@ static int write_sector_logical(imgtool::stream &file_handle, int secnum, const out_parent_fdr_secnum: on output, sector offset of the fdr for the parent directory fdr (-1 if root) (may be NULL) */ -static int find_fdr(ti990_image *image, const char fpath[MAX_PATH_LEN+1], int *catalog_index, int *out_fdr_secnum, int *out_parent_fdr_secnum) +static imgtoolerr_t find_fdr(ti990_image *image, const char fpath[MAX_PATH_LEN+1], int *catalog_index, int *out_fdr_secnum, int *out_parent_fdr_secnum) { int fdr_secnum = -1, parent_fdr_secnum; int i; @@ -737,7 +728,7 @@ static int find_fdr(ti990_image *image, const char fpath[MAX_PATH_LEN+1], int *c do { /* read directory header */ - reply = read_sector_logical_len(image->file_handle, base, & image->geometry, &dor, sizeof(dor)); + reply = read_sector_logical_len(*image->file_handle, base, & image->geometry, &dor, sizeof(dor)); if (reply) return IMGTOOLERR_READERROR; @@ -765,7 +756,7 @@ static int find_fdr(ti990_image *image, const char fpath[MAX_PATH_LEN+1], int *c i = hash_key; while (1) { - reply = read_sector_logical_len(image->file_handle, base + i, & image->geometry, + reply = read_sector_logical_len(*image->file_handle, base + i, & image->geometry, & xdr, 0x86); if (reply) return IMGTOOLERR_READERROR; @@ -800,7 +791,7 @@ static int find_fdr(ti990_image *image, const char fpath[MAX_PATH_LEN+1], int *c if (flag & fdr_flg_ali) { /* read original fdr */ - reply = read_sector_logical_len(image->file_handle, base + get_UINT16BE(xdr.adr.raf), + reply = read_sector_logical_len(*image->file_handle, base + get_UINT16BE(xdr.adr.raf), & image->geometry, & xdr, 0x86); flag = get_UINT16BE(xdr.fdr.flg); @@ -835,9 +826,8 @@ static int find_fdr(ti990_image *image, const char fpath[MAX_PATH_LEN+1], int *c if (out_parent_fdr_secnum) *out_parent_fdr_secnum = parent_fdr_secnum; - return 0; + return IMGTOOLERR_SUCCESS; } -#endif #if 0 /* @@ -1251,7 +1241,7 @@ static imgtoolerr_t ti990_image_nextenum(imgtool::directory &enumeration, imgtoo else { #if 0 - fname_to_str(ent.filename, iter->xdr[iter->level].fdr.fnm, ARRAY_LENGTH(ent.filename)); + fname_to_str(ent.filename, iter->xdr[iter->level].fdr.fnm, std::size(ent.filename)); #else { int i; @@ -1261,11 +1251,11 @@ static imgtoolerr_t ti990_image_nextenum(imgtool::directory &enumeration, imgtoo for (i=0; i<iter->level; i++) { fname_to_str(buf, iter->xdr[i].fdr.fnm, 9); - strncat(ent.filename, buf, ARRAY_LENGTH(ent.filename) - 1); - strncat(ent.filename, ".", ARRAY_LENGTH(ent.filename) - 1); + strncat(ent.filename, buf, std::size(ent.filename) - 1); + strncat(ent.filename, ".", std::size(ent.filename) - 1); } fname_to_str(buf, iter->xdr[iter->level].fdr.fnm, 9); - strncat(ent.filename, buf, ARRAY_LENGTH(ent.filename) - 1); + strncat(ent.filename, buf, std::size(ent.filename) - 1); } #endif @@ -1273,7 +1263,7 @@ static imgtoolerr_t ti990_image_nextenum(imgtool::directory &enumeration, imgtoo flag = get_UINT16BE(iter->xdr[iter->level].fdr.flg); if (flag & fdr_flg_cdr) { - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "CHANNEL"); + snprintf(ent.attr, std::size(ent.attr), "CHANNEL"); ent.filesize = 0; } @@ -1291,7 +1281,7 @@ static imgtoolerr_t ti990_image_nextenum(imgtool::directory &enumeration, imgtoo fname_to_str(buf, target_fdr.fnm, 9); - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "ALIAS OF %s", buf); + snprintf(ent.attr, std::size(ent.attr), "ALIAS OF %s", buf); ent.filesize = 0; } @@ -1341,7 +1331,7 @@ static imgtoolerr_t ti990_image_nextenum(imgtool::directory &enumeration, imgtoo } break; } - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), + snprintf(ent.attr, std::size(ent.attr), "%s %c %s%s%s%s%s", fmt, (flag & fdr_flg_all) ? 'N' : 'C', type, (flag & fdr_flg_blb) ? "" : " BLK", (flag & fdr_flg_tmp) ? " TMP" : "", @@ -1455,14 +1445,12 @@ static imgtoolerr_t ti990_image_freespace(imgtool::partition &partition, uint64_ return IMGTOOLERR_SUCCESS; } -#ifdef UNUSED_FUNCTION /* Extract a file from a ti990_image. */ static imgtoolerr_t ti990_image_readfile(imgtool::partition &partition, const char *fpath, imgtool::stream *destf) { - imgtool::image *img = &partition->image(); - ti990_image *image = get_ti990_image(img); + ti990_image *image = get_ti990_image(partition.image()); int catalog_index, fdr_secnum, parent_fdr_secnum; imgtoolerr_t reply; @@ -1473,7 +1461,7 @@ static imgtoolerr_t ti990_image_readfile(imgtool::partition &partition, const ch /* ... */ - return 0; + return IMGTOOLERR_SUCCESS; #if 0 ti99_image *image = (ti99_image*) img; @@ -1549,7 +1537,7 @@ static imgtoolerr_t ti990_image_readfile(imgtool::partition &partition, const ch lnks_index++; } - return 0; + return IMGTOOLERR_SUCCESS; #endif } @@ -1558,8 +1546,7 @@ static imgtoolerr_t ti990_image_readfile(imgtool::partition &partition, const ch */ static imgtoolerr_t ti990_image_writefile(imgtool::partition &partition, const char *fpath, imgtool::stream *sourcef, util::option_resolution *writeoptions) { - imgtool::image *img = &partition->image(); - ti990_image *image = get_ti990_image(img); + ti990_image *image = get_ti990_image(partition.image()); int catalog_index, fdr_secnum, parent_fdr_secnum; imgtoolerr_t reply; @@ -1571,7 +1558,7 @@ static imgtoolerr_t ti990_image_writefile(imgtool::partition &partition, const c /* ... */ - return 0; + return IMGTOOLERR_SUCCESS; #if 0 ti99_image *image = (ti99_image*) img; @@ -1673,7 +1660,7 @@ static imgtoolerr_t ti990_image_writefile(imgtool::partition &partition, const c if (write_sector_logical(image->file_handle, 0, & image->geometry, &image->sec0)) return IMGTOOLERR_WRITEERROR; - return 0; + return IMGTOOLERR_SUCCESS; #endif } @@ -1682,8 +1669,7 @@ static imgtoolerr_t ti990_image_writefile(imgtool::partition &partition, const c */ static imgtoolerr_t ti990_image_deletefile(imgtool::partition &partition, const char *fpath) { - imgtool::image *img = &partition->image(); - ti990_image *image = get_ti990_image(img); + ti990_image *image = get_ti990_image(partition.image()); int catalog_index, fdr_secnum, parent_fdr_secnum; imgtoolerr_t reply; @@ -1694,7 +1680,7 @@ static imgtoolerr_t ti990_image_deletefile(imgtool::partition &partition, const /* ... */ - return 0; + return IMGTOOLERR_SUCCESS; #if 0 ti99_image *image = (ti99_image*) img; @@ -1762,10 +1748,9 @@ static imgtoolerr_t ti990_image_deletefile(imgtool::partition &partition, const if (write_sector_logical(image->file_handle, 0, & image->geometry, &image->sec0)) return IMGTOOLERR_WRITEERROR; - return 0; + return IMGTOOLERR_SUCCESS; #endif } -#endif /* Create a blank ti990_image. diff --git a/src/tools/imgtool/modules/vzdos.cpp b/src/tools/imgtool/modules/vzdos.cpp index bf46863bb28..b7dee751434 100644 --- a/src/tools/imgtool/modules/vzdos.cpp +++ b/src/tools/imgtool/modules/vzdos.cpp @@ -1,4 +1,4 @@ -// license:GPL-2.0+ +// license:BSD-3-Clause // copyright-holders:Dirk Best /**************************************************************************** @@ -8,15 +8,23 @@ ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <math.h> #include "imgtool.h" -#include "formats/imageutl.h" -#include "formats/vt_dsk.h" +#include "filter.h" #include "iflopimg.h" +#include "formats/vt_dsk_legacy.h" + +#include "corestr.h" +#include "hashing.h" +#include "multibyte.h" +#include "opresolv.h" + +#include <algorithm> +#include <cmath> +#include <cstdio> +#include <cstdlib> +#include <cstring> + /* sector format @@ -44,13 +52,22 @@ as track map, with one bit for each sector used. /* vzdos directry entry */ struct vzdos_dirent { - char ftype; - char delimitor; - char fname[8]; + struct { + char ftype; + char delimitor; + char fname[8]; + } node; uint8_t start_track; uint8_t start_sector; uint16_t start_address; uint16_t end_address; + + vzdos_dirent() : + start_track(0), start_sector(0), + start_address(0), end_address(0) + { + memset(&node, 0, sizeof(node)); + } }; struct vz_iterator @@ -80,18 +97,6 @@ static int vzdos_get_fname_len(const char *fname) return len; } -/* calculate checksum-16 of buffer */ -static uint16_t chksum16(uint8_t *buffer, int len) -{ - int i; - uint16_t sum = 0; - - for (i = 0; i < len; i++) - sum += buffer[i]; - - return sum; -} - /* returns the offset where the actual sector data starts */ static imgtoolerr_t vzdos_get_data_start(imgtool::image &img, int track, int sector, int *start) { @@ -127,7 +132,7 @@ static imgtoolerr_t vzdos_read_sector_data(imgtool::image &img, int track, int s if (ret) return (imgtoolerr_t)ret; /* verify sector checksums */ - if (pick_integer_le(buffer, DATA_SIZE + 2, 2) != chksum16(buffer, DATA_SIZE + 2)) + if (get_u16le(&buffer[DATA_SIZE + 2]) != util::sum16_creator::simple(buffer, DATA_SIZE + 2)) return IMGTOOLERR_CORRUPTFILE; memcpy(data, &buffer, DATA_SIZE + 2); @@ -145,7 +150,7 @@ static imgtoolerr_t vzdos_write_sector_data(imgtool::image &img, int track, int if (ret) return (imgtoolerr_t)ret; memcpy(buffer, data, DATA_SIZE + 2); - place_integer_le(buffer, DATA_SIZE + 2, 2, chksum16(data, DATA_SIZE + 2)); + put_u16le(&buffer[DATA_SIZE + 2], util::sum16_creator::simple(data, DATA_SIZE + 2)); ret = floppy_write_sector(imgtool_floppy(img), 0, track, sector_order[sector], data_start, buffer, sizeof(buffer), 0); /* TODO: pass ddam argument from imgtool */ if (ret) return (imgtoolerr_t)ret; @@ -157,8 +162,7 @@ static imgtoolerr_t vzdos_write_sector_data(imgtool::image &img, int track, int static imgtoolerr_t vzdos_clear_sector(imgtool::image &img, int track, int sector) { uint8_t data[DATA_SIZE + 2]; - - memset(data, 0x00, sizeof(data)); + std::fill(std::begin(data), std::end(data), 0x00); return vzdos_write_sector_data(img, track, sector, data); } @@ -166,21 +170,21 @@ static imgtoolerr_t vzdos_clear_sector(imgtool::image &img, int track, int secto /* return a directory entry for an index */ static imgtoolerr_t vzdos_get_dirent(imgtool::image &img, int index, vzdos_dirent *ent) { - int ret, entry; uint8_t buffer[DATA_SIZE + 2]; - ret = vzdos_read_sector_data(img, 0, (int) index / 8, buffer); - if (ret) return (imgtoolerr_t)ret; + imgtoolerr_t const ret = vzdos_read_sector_data(img, 0, int(index) / 8, buffer); + if (IMGTOOLERR_SUCCESS != ret) + return ret; - entry = ((index % 8) * sizeof(vzdos_dirent)); + int const entry = ((index % 8) * sizeof(vzdos_dirent)); - memcpy(ent, &buffer[entry], 10); - ent->start_track = pick_integer_le(&buffer[entry], 10, 1); - ent->start_sector = pick_integer_le(&buffer[entry], 11, 1); - ent->start_address = pick_integer_le(&buffer[entry], 12, 2); - ent->end_address = pick_integer_le(&buffer[entry], 14, 2); + memcpy(&ent->node, &buffer[entry], 10); + ent->start_track = buffer[entry + 10]; + ent->start_sector = buffer[entry + 11]; + ent->start_address = get_u16le(&buffer[entry + 12]); + ent->end_address = get_u16le(&buffer[entry + 14]); - if (ent->ftype == 0x00) + if (ent->node.ftype == 0x00) return IMGTOOLERR_FILENOTFOUND; /* check values */ @@ -206,10 +210,10 @@ static imgtoolerr_t vzdos_set_dirent(imgtool::image &img, int index, vzdos_diren entry = ((index % 8) * sizeof(vzdos_dirent)); memcpy(&buffer[entry], &ent, 10); - place_integer_le(buffer, entry + 10, 1, ent.start_track); - place_integer_le(buffer, entry + 11, 1, ent.start_sector); - place_integer_le(buffer, entry + 12, 2, ent.start_address); - place_integer_le(buffer, entry + 14, 2, ent.end_address); + buffer[entry + 10] = ent.start_track; + buffer[entry + 11] = ent.start_sector; + put_u16le(&buffer[entry + 12], ent.start_address); + put_u16le(&buffer[entry + 14], ent.end_address); /* save new sector */ ret = vzdos_write_sector_data(img, 0, (int) index / 8, buffer); @@ -221,20 +225,12 @@ static imgtoolerr_t vzdos_set_dirent(imgtool::image &img, int index, vzdos_diren /* clear a directory entry */ static imgtoolerr_t vzdos_clear_dirent(imgtool::image &img, int index) { - int ret; vzdos_dirent entry; - - memset(&entry, 0x00, sizeof(vzdos_dirent)); - - ret = vzdos_set_dirent(img, index, entry); - if (ret) return (imgtoolerr_t)ret; - - return IMGTOOLERR_SUCCESS; + return vzdos_set_dirent(img, index, entry); } /* search the index for a directory entry */ static imgtoolerr_t vzdos_searchentry(imgtool::image &image, const char *fname, int *entry) { - int i, len, ret; vzdos_dirent ent; char filename[9]; @@ -246,23 +242,23 @@ static imgtoolerr_t vzdos_searchentry(imgtool::image &image, const char *fname, *entry = -1; - for (i = 0; i < MAX_DIRENTS; i++) { - ret = vzdos_get_dirent(image, i, &ent); - if (ret) return (imgtoolerr_t)ret; + for (int i = 0; i < MAX_DIRENTS; i++) { + imgtoolerr_t const ret = vzdos_get_dirent(image, i, &ent); + if (IMGTOOLERR_SUCCESS != ret) + return ret; - len = vzdos_get_fname_len(ent.fname) + 1; + int const len = vzdos_get_fname_len(ent.node.fname) + 1; if (strlen(fname) != len) continue; - memset(filename, 0x00, sizeof(filename)); - memcpy(filename, ent.fname, len); + std::fill(std::begin(filename), std::end(filename), 0x00); + memcpy(filename, ent.node.fname, len); if (!core_stricmp(fname, filename)) { *entry = i; break; } - } if (*entry == -1) @@ -359,7 +355,6 @@ static imgtoolerr_t vzdos_free_trackmap(imgtool::image &img, int *track, int *se static imgtoolerr_t vzdos_write_formatted_sector(imgtool::image &img, int track, int sector) { - int ret; uint8_t sector_data[DATA_SIZE + 4 + 24]; static const uint8_t sector_header[24] = { @@ -368,15 +363,16 @@ static imgtoolerr_t vzdos_write_formatted_sector(imgtool::image &img, int track, 0x80, 0x80, 0x80, 0x00, 0xC3, 0x18, 0xE7, 0xFE }; - memset(sector_data, 0x00, sizeof(sector_data)); + std::fill(std::begin(sector_data), std::end(sector_data), 0x00); memcpy(sector_data, sector_header, sizeof(sector_header)); sector_data[10] = (uint8_t) track; /* current track */ sector_data[11] = (uint8_t) sector; /* current sector */ sector_data[12] = (uint8_t) track + sector; /* checksum-8 */ - ret = floppy_write_sector(imgtool_floppy(img), 0, track, sector_order[sector], 0, sector_data, sizeof(sector_data), 0); /* TODO: pass ddam argument from imgtool */ - if (ret) return (imgtoolerr_t)ret; + floperr_t const ret = floppy_write_sector(imgtool_floppy(img), 0, track, sector_order[sector], 0, sector_data, sizeof(sector_data), 0); /* TODO: pass ddam argument from imgtool */ + if (FLOPPY_ERROR_SUCCESS != ret) + return IMGTOOLERR_WRITEERROR; return IMGTOOLERR_SUCCESS; } @@ -424,15 +420,15 @@ static imgtoolerr_t vzdos_diskimage_nextenum(imgtool::directory &enumeration, im /* kill trailing spaces */ for (len = 7; len > 0; len--) { - if (dirent.fname[len] != 0x20) { + if (dirent.node.fname[len] != 0x20) { break; } } - memcpy(ent.filename, &dirent.fname, len + 1); + memcpy(ent.filename, &dirent.node.fname, len + 1); ent.filesize = dirent.end_address - dirent.start_address; - switch (dirent.ftype) + switch (dirent.node.ftype) { case 0x01: type = "Deleted"; break; case 'T': type = "Basic"; break; @@ -445,7 +441,7 @@ static imgtoolerr_t vzdos_diskimage_nextenum(imgtool::directory &enumeration, im default: type = "Unknown"; } - snprintf(ent.attr, ARRAY_LENGTH(ent.attr), "%s", type); + snprintf(ent.attr, std::size(ent.attr), "%s", type); iter->index++; } @@ -500,12 +496,12 @@ static imgtoolerr_t vzdos_diskimage_readfile(imgtool::partition &partition, cons if (ret) return ret; /* detect sectors pointing to themselfs */ - if ((track == (int)pick_integer_le(buffer, DATA_SIZE, 1)) && (sector == (int)pick_integer_le(buffer, DATA_SIZE + 1, 1))) + if ((track == (int)buffer[DATA_SIZE]) && (sector == (int)buffer[DATA_SIZE + 1])) return IMGTOOLERR_CORRUPTIMAGE; /* load next track and sector values */ - track = pick_integer_le(buffer, DATA_SIZE, 1); - sector = pick_integer_le(buffer, DATA_SIZE + 1, 1); + track = buffer[DATA_SIZE]; + sector = buffer[DATA_SIZE + 1]; /* track 0 is invalid */ if ((track == 0) && (filesize > DATA_SIZE)) @@ -581,8 +577,8 @@ static imgtoolerr_t vzdos_diskimage_deletefile(imgtool::partition &partition, co if (ret) return ret; /* load next track and sector values */ - next_track = pick_integer_le(buffer, DATA_SIZE, 1); - next_sector = pick_integer_le(buffer, DATA_SIZE + 1, 1); + next_track = buffer[DATA_SIZE]; + next_sector = buffer[DATA_SIZE + 1]; /* overwrite sector with default values */ ret = vzdos_clear_sector(img, track, sector); @@ -617,8 +613,8 @@ static imgtoolerr_t vzdos_writefile(imgtool::partition &partition, int offset, i return IMGTOOLERR_READONLY; /* check for already existing filename -> overwrite */ - strcpy(filename, entry->fname); - filename[vzdos_get_fname_len(entry->fname) + 1] = 0x00; + strcpy(filename, entry->node.fname); + filename[vzdos_get_fname_len(entry->node.fname) + 1] = 0x00; ret = vzdos_get_dirent_fname(img, filename, &temp_entry); if (!ret) { /* file already exists, delete it */ @@ -702,8 +698,6 @@ static imgtoolerr_t vzdos_writefile(imgtool::partition &partition, int offset, i /* create a new file or overwrite a file */ static imgtoolerr_t vzdos_diskimage_writefile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) { - imgtoolerr_t ret; - int ftype; vzdos_dirent entry; /* TODO: check for leading spaces and strip */ @@ -711,37 +705,34 @@ static imgtoolerr_t vzdos_diskimage_writefile(imgtool::partition &partition, con return IMGTOOLERR_BADFILENAME; /* prepare directory entry */ - ftype = opts->lookup_int('T'); + int const ftype = opts->lookup_int('T'); switch (ftype) { case 0: - entry.ftype = 'T'; + entry.node.ftype = 'T'; entry.start_address = 31465; break; case 1: - entry.ftype = 'B'; + entry.node.ftype = 'B'; entry.start_address = 31465; /* ??? */ break; case 2: - entry.ftype = 'D'; + entry.node.ftype = 'D'; entry.start_address = 31465; /* ??? */ break; default: break; } - entry.delimitor = ':'; - memset(&entry.fname, 0x20, 8); /* pad with spaces */ - memcpy(&entry.fname, filename, strlen(filename)); + entry.node.delimitor = ':'; + memset(&entry.node.fname, 0x20, 8); /* pad with spaces */ + memcpy(&entry.node.fname, filename, strlen(filename)); /* write file to disk */ - ret = vzdos_writefile(partition, 0, sourcef, &entry); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; + return vzdos_writefile(partition, 0, sourcef, &entry); } -static imgtoolerr_t vzdos_diskimage_suggesttransfer(imgtool::partition &partition, const char *fname, imgtool_transfer_suggestion *suggestions, size_t suggestions_length) +static imgtoolerr_t vzdos_diskimage_suggesttransfer(imgtool::partition &partition, const char *fname, imgtool::transfer_suggestion *suggestions, size_t suggestions_length) { imgtoolerr_t ret; imgtool::image &image(partition.image()); @@ -751,37 +742,37 @@ static imgtoolerr_t vzdos_diskimage_suggesttransfer(imgtool::partition &partitio ret = vzdos_get_dirent_fname(image, fname, &entry); if (ret) return ret; - switch (entry.ftype) { + switch (entry.node.ftype) { case 'B': - suggestions[0].viability = SUGGESTION_RECOMMENDED; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; suggestions[0].filter = filter_vzsnapshot_getinfo; suggestions[0].description = "VZ Snapshot"; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = NULL; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; + suggestions[1].filter = nullptr; suggestions[1].description = "Raw"; break; case 'T': - suggestions[0].viability = SUGGESTION_RECOMMENDED; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; suggestions[0].filter = filter_vzsnapshot_getinfo; suggestions[0].description = "VZ Snapshot"; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = NULL; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; + suggestions[1].filter = nullptr; suggestions[1].description = "Raw"; - suggestions[2].viability = SUGGESTION_POSSIBLE; + suggestions[2].viability = imgtool::SUGGESTION_POSSIBLE; suggestions[2].filter = filter_vzbas_getinfo; suggestions[2].description = "Tokenized Basic"; break; default: - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = nullptr; suggestions[0].description = "Raw"; } } else { - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; + suggestions[0].viability = imgtool::SUGGESTION_RECOMMENDED; + suggestions[0].filter = nullptr; suggestions[0].description = "Raw"; - suggestions[1].viability = SUGGESTION_POSSIBLE; + suggestions[1].viability = imgtool::SUGGESTION_POSSIBLE; suggestions[1].filter = filter_vzsnapshot_getinfo; suggestions[1].description = "VZ Snapshot"; } @@ -824,7 +815,7 @@ static imgtoolerr_t vzsnapshot_readfile(imgtool::partition &partition, const cha header[1] = 'Z'; header[2] = 'F'; - switch (entry.ftype) { + switch (entry.node.ftype) { case 'B': header[3] = '1'; header[21] = 0xF1; @@ -839,8 +830,8 @@ static imgtoolerr_t vzsnapshot_readfile(imgtool::partition &partition, const cha } memset(header + 4, 0x00, 17); - memcpy(header + 4, entry.fname, vzdos_get_fname_len(entry.fname) + 1); - place_integer_le(header, 22, 2, entry.start_address); + memcpy(header + 4, entry.node.fname, vzdos_get_fname_len(entry.node.fname) + 1); + put_u16le(&header[22], entry.start_address); /* write header to file */ destf.write(header, sizeof(header)); @@ -863,21 +854,21 @@ static imgtoolerr_t vzsnapshot_writefile(imgtool::partition &partition, const ch sourcef.read(header, sizeof(header)); /* prepare directory entry */ - entry.ftype = header[21] == 0xF1 ? 'B' : 'T'; - entry.delimitor = ':'; - entry.start_address = pick_integer_le(header, 22, 2); + entry.node.ftype = (header[21] == 0xF1) ? 'B' : 'T'; + entry.node.delimitor = ':'; + entry.start_address = get_u16le(&header[22]); /* filename from header or directly? */ fnameopt = opts->lookup_int('F'); if (fnameopt == 0) { - memcpy(&entry.fname, &header[4], 8); + memcpy(&entry.node.fname, &header[4], 8); } else { /* TODO: check for leading spaces and strip */ if (strlen(filename) > 8 || strlen(filename) < 1) return IMGTOOLERR_BADFILENAME; - memcpy(&entry.fname, filename, strlen(filename) - 3); + memcpy(&entry.node.fname, filename, strlen(filename) - 3); } /* write file to disk */ @@ -887,7 +878,7 @@ static imgtoolerr_t vzsnapshot_writefile(imgtool::partition &partition, const ch return IMGTOOLERR_SUCCESS; } -void filter_vzsnapshot_getinfo(uint32_t state, union filterinfo *info) +void filter_vzsnapshot_getinfo(uint32_t state, imgtool::filterinfo *info) { switch(state) { @@ -936,16 +927,16 @@ void vzdos_get_info(const imgtool_class *imgclass, uint32_t state, union imgtool case IMGTOOLINFO_INT_PREFER_UCASE: info->i = 1; break; case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(vz_iterator); break; - /* --- the following bits of info are returned as NULL-terminated strings --- */ + /* --- the following bits of info are returned as NUL-terminated strings --- */ case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "vzdos"); break; case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "VZ-DOS format"); break; case IMGTOOLINFO_STR_FILE: strcpy(info->s = imgtool_temp_str(), __FILE__); break; case IMGTOOLINFO_STR_WRITEFILE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), "T[0]-2;F[0]-1"); break; - case IMGTOOLINFO_STR_EOLN: info->s = NULL; break; + case IMGTOOLINFO_STR_EOLN: info->s = nullptr; 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_OPEN: info->open = NULL; break; + case IMGTOOLINFO_PTR_OPEN: info->open = nullptr; break; case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = vzdos_diskimage_beginenum; break; case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = vzdos_diskimage_nextenum; break; case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = vzdos_diskimage_freespace; break; |