diff options
author | 2015-09-30 17:21:14 +0200 | |
---|---|---|
committer | 2015-09-30 17:21:14 +0200 | |
commit | 1fc48ce120a376c288daeeed98daccecf1b60d7b (patch) | |
tree | 72cefcede17f3a27fa8256b43bfac9756db82312 /src/mess/tools | |
parent | 87a576c55501bd7125b51ca786a010229669df0e (diff) |
move mess into mame (nw)
Diffstat (limited to 'src/mess/tools')
50 files changed, 0 insertions, 41619 deletions
diff --git a/src/mess/tools/castool/main.c b/src/mess/tools/castool/main.c deleted file mode 100644 index 22564dcdf78..00000000000 --- a/src/mess/tools/castool/main.c +++ /dev/null @@ -1,217 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Miodrag Milanovic -/*************************************************************************** - - main.c - - Castool command line front end - - 27/03/2009 Initial version by Miodrag Milanovic - -***************************************************************************/ - -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <stdlib.h> -#include <time.h> -#include <assert.h> - -#include "corestr.h" - -#include "formats/a26_cas.h" -#include "formats/ace_tap.h" -#include "formats/adam_cas.h" -#include "formats/apf_apt.h" -#include "formats/cbm_tap.h" -#include "formats/cgen_cas.h" -#include "formats/coco_cas.h" -#include "formats/csw_cas.h" -#include "formats/fm7_cas.h" -#include "formats/fmsx_cas.h" -#include "formats/gtp_cas.h" -#include "formats/hect_tap.h" -#include "formats/kc_cas.h" -#include "formats/kim1_cas.h" -#include "formats/lviv_lvt.h" -#include "formats/mz_cas.h" -#include "formats/orao_cas.h" -#include "formats/oric_tap.h" -#include "formats/p6001_cas.h" -#include "formats/phc25_cas.h" -#include "formats/pmd_cas.h" -#include "formats/primoptp.h" -#include "formats/rk_cas.h" -#include "formats/sc3000_bit.h" -#include "formats/sol_cas.h" -#include "formats/sorc_cas.h" -#include "formats/sord_cas.h" -#include "formats/spc1000_cas.h" -#include "formats/svi_cas.h" -#include "formats/thom_cas.h" -#include "formats/trs_cas.h" -#include "formats/tvc_cas.h" -#include "formats/tzx_cas.h" -#include "formats/uef_cas.h" -#include "formats/vg5k_cas.h" -#include "formats/vt_cas.h" -#include "formats/x07_cas.h" -#include "formats/x1_tap.h" -#include "formats/zx81_p.h" - -struct SupportedCassetteFormats -{ - const char *name; - const struct CassetteFormat * const *formats; - const char *desc; -}; - -const struct SupportedCassetteFormats formats[] = { - {"a26", a26_cassette_formats ,"Atari 2600 SuperCharger"}, - {"apf", apf_cassette_formats ,"APF Imagination Machine"}, - {"bbc", bbc_cassette_formats ,"Acorn BBC & Electron"}, - {"cbm", cbm_cassette_formats ,"Commodore 8-bit series"}, - {"cdt", cdt_cassette_formats ,"Amstrad CPC"}, - {"cgenie", cgenie_cassette_formats ,"EACA Colour Genie"}, - {"coco", coco_cassette_formats ,"Tandy Radio Shack Color Computer"}, - {"csw", csw_cassette_formats ,"Compressed Square Wave"}, - {"ddp", coleco_adam_cassette_formats ,"Coleco ADAM"}, - {"fm7", fm7_cassette_formats ,"Fujitsu FM-7"}, - {"fmsx", fmsx_cassette_formats ,"MSX"}, - {"gtp", gtp_cassette_formats ,"Elektronika inzenjering Galaksija"}, - {"hector", hector_cassette_formats ,"Micronique Hector & Interact Family Computer"}, - {"jupiter", ace_cassette_formats ,"Jupiter Cantab Jupiter Ace"}, - {"kc85", kc_cassette_formats ,"VEB Mikroelektronik KC 85"}, - {"kim1", kim1_cassette_formats ,"MOS KIM-1"}, - {"lviv", lviv_lvt_format ,"PK-01 Lviv"}, - {"mo5", mo5_cassette_formats ,"Thomson MO-series"}, - {"mz", mz700_cassette_formats ,"Sharp MZ-700"}, - {"orao", orao_cassette_formats ,"PEL Varazdin Orao"}, - {"oric", oric_cassette_formats ,"Tangerine Oric"}, - {"pc6001", pc6001_cassette_formats ,"NEC PC-6001"}, - {"phc25", phc25_cassette_formats ,"Sanyo PHC-25"}, - {"pmd85", pmd85_cassette_formats ,"Tesla PMD-85"}, - {"primo", primo_ptp_format ,"Microkey Primo"}, - {"rku", rku_cassette_formats ,"UT-88"}, - {"rk8", rk8_cassette_formats ,"Mikro-80"}, - {"rks", rks_cassette_formats ,"Specialist"}, - {"rko", rko_cassette_formats ,"Orion"}, - {"rkr", rkr_cassette_formats ,"Radio-86RK"}, - {"rka", rka_cassette_formats ,"Zavod BRA Apogee BK-01"}, - {"rkm", rkm_cassette_formats ,"Mikrosha"}, - {"rkp", rkp_cassette_formats ,"SAM SKB VM Partner-01.01"}, - {"sc3000", sc3000_cassette_formats ,"Sega SC-3000"}, - {"sol20", sol20_cassette_formats ,"PTC SOL-20"}, - {"sorcerer", sorcerer_cassette_formats ,"Exidy Sorcerer"}, - {"sordm5", sordm5_cassette_formats ,"Sord M5"}, - {"spc1000", spc1000_cassette_formats ,"Samsung SPC-1000"}, - {"svi", svi_cassette_formats ,"Spectravideo SVI-318 & SVI-328"}, - {"to7", to7_cassette_formats ,"Thomson TO-series"}, - {"trs80l2", trs80l2_cassette_formats ,"TRS-80 Level 2"}, - {"tvc64", tvc64_cassette_formats ,"Videoton TVC 64"}, - {"tzx", tzx_cassette_formats ,"Sinclair ZX Spectrum"}, - {"uef", uef_cassette_formats ,"Acorn Electron"}, - {"vg5k", vg5k_cassette_formats ,"Philips VG 5000"}, - {"vtech1", vtech1_cassette_formats ,"Video Technology Laser 110-310"}, - {"vtech2", vtech2_cassette_formats ,"Video Technology Laser 350-700"}, - {"x07", x07_cassette_formats ,"Canon X-07"}, - {"x1", x1_cassette_formats ,"Sharp X1"}, - {"zx80_o", zx80_o_format ,"Sinclair ZX80"}, - {"zx81_p", zx81_p_format ,"Sinclair ZX81"}, - - - - {NULL,NULL,NULL} -}; - - -static const char *get_extension(const char *name) -{ - const char *s; - s = name; - if (s != NULL) - s = strrchr(s, '.'); - return s ? s+1 : NULL; -} - -static void display_usage(void) -{ - fprintf(stderr, "Usage: \n"); - fprintf(stderr, " castool.exe convert <format> <inputfile> <outputfile.wav>\n"); -} - -static void display_formats(void) -{ - int i,j; - fprintf(stderr, "Supported formats:\n\n"); - for (i = 0; formats[i].name; i++) { - fprintf(stderr, "%10s - %s\n",formats[i].name,formats[i].desc); - for (j = 1; formats[i].formats[j]; j++) { - fprintf(stderr, "%15s %s\n","",formats[i].formats[j]->extensions); - } - } -} - -int CLIB_DECL main(int argc, char *argv[]) -{ - int i; - int found =0; - const struct CassetteFormat * const *selected_formats = NULL; - cassette_image *cassette; - FILE *f; - - if (argc > 1) - { - if (!core_stricmp("convert", argv[1])) - { - // convert command - if (argc!=5) { - fprintf(stderr, "Wrong parameter number.\n\n"); - display_usage(); - return -1; - } else { - for (i = 0; formats[i].name; i++) { - if (core_stricmp(formats[i].name,argv[2])==0) { - selected_formats = formats[i].formats; - found = 1; - } - } - if (found==0) { - fprintf(stderr, "Wrong format name.\n\n"); - display_usage(); - fprintf(stderr, "\n"); - display_formats(); - return -1; - } - - f = fopen(argv[3], "rb"); - if (!f) { - fprintf(stderr, "File %s not found.\n",argv[3]); - return -1; - } - - if (cassette_open_choices(f, &stdio_ioprocs, get_extension(argv[3]), selected_formats, CASSETTE_FLAG_READONLY, &cassette)) { - fprintf(stderr, "Invalid format of input file.\n"); - fclose(f); - return -1; - } - - cassette_dump(cassette,argv[4]); - cassette_close(cassette); - fclose(f); - goto theend; - } - } - } - - /* Usage */ - fprintf(stderr, "castool - Generic cassette manipulation tool for use with MESS\n\n"); - display_usage(); - fprintf(stderr, "\n"); - display_formats(); - fprintf(stderr, "\nExample usage:\n"); - fprintf(stderr, " castool.exe convert tzx game.tzx game.wav\n\n"); - -theend : - return 0; -} diff --git a/src/mess/tools/floptool/main.c b/src/mess/tools/floptool/main.c deleted file mode 100644 index 2cb36f3a873..00000000000 --- a/src/mess/tools/floptool/main.c +++ /dev/null @@ -1,275 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Miodrag Milanovic -/*************************************************************************** - - main.c - - Floptool command line front end - - 20/07/2011 Initial version by Miodrag Milanovic - -***************************************************************************/ - -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <stdlib.h> -#include <time.h> -#include <stdarg.h> -#include <assert.h> - -#include "corestr.h" - -#include "formats/mfi_dsk.h" -#include "formats/dfi_dsk.h" -#include "formats/ipf_dsk.h" - -#include "formats/hxcmfm_dsk.h" -#include "formats/ami_dsk.h" - -#include "formats/st_dsk.h" -#include "formats/pasti_dsk.h" - -#include "formats/dsk_dsk.h" - -#include "formats/d88_dsk.h" -#include "formats/imd_dsk.h" -#include "formats/td0_dsk.h" -#include "formats/cqm_dsk.h" -#include "formats/pc_dsk.h" -#include "formats/naslite_dsk.h" - -#include "formats/ap_dsk35.h" -#include "formats/ap2_dsk.h" - -#include "formats/oric_dsk.h" - -#include "formats/applix_dsk.h" - -static floppy_format_type floppy_formats[] = { - FLOPPY_MFI_FORMAT, - FLOPPY_DFI_FORMAT, - FLOPPY_IPF_FORMAT, - - FLOPPY_MFM_FORMAT, - FLOPPY_ADF_FORMAT, - - FLOPPY_ST_FORMAT, - FLOPPY_MSA_FORMAT, - FLOPPY_PASTI_FORMAT, - - FLOPPY_DSK_FORMAT, - - FLOPPY_D88_FORMAT, - FLOPPY_IMD_FORMAT, - FLOPPY_TD0_FORMAT, - FLOPPY_CQM_FORMAT, - FLOPPY_PC_FORMAT, - FLOPPY_NASLITE_FORMAT, - - FLOPPY_DC42_FORMAT, - FLOPPY_A216S_FORMAT, - FLOPPY_RWTS18_FORMAT, - FLOPPY_EDD_FORMAT, - - FLOPPY_ORIC_DSK_FORMAT, - - FLOPPY_APPLIX_FORMAT, -}; - -void CLIB_DECL ATTR_PRINTF(1,2) logerror(const char *format, ...) -{ - va_list arg; - va_start(arg, format); - vprintf(format, arg); - va_end(arg); -} - -enum { FORMAT_COUNT = ARRAY_LENGTH(floppy_formats) }; - -static floppy_image_format_t *formats[FORMAT_COUNT]; - -static void init_formats() -{ - for(int i=0; i != FORMAT_COUNT; i++) - formats[i] = floppy_formats[i](); -} - -static floppy_image_format_t *find_format_by_name(const char *name) -{ - for(int i=0; i != FORMAT_COUNT; i++) - if(!core_stricmp(name, formats[i]->name())) - return formats[i]; - return 0; -} - -static floppy_image_format_t *find_format_by_identify(io_generic *image) -{ - int best = 0; - floppy_image_format_t *best_fif = 0; - - for(int i = 0; i != FORMAT_COUNT; i++) { - floppy_image_format_t *fif = formats[i]; - int score = fif->identify(image, floppy_image::FF_UNKNOWN); - if(score > best) { - best = score; - best_fif = fif; - } - } - return best_fif; -} - -static void display_usage() -{ - fprintf(stderr, "Usage: \n"); - fprintf(stderr, " floptool.exe identify <inputfile> [<inputfile> ...]\n"); - fprintf(stderr, " floptool.exe convert [input_format|auto] output_format <inputfile> <outputfile>\n"); -} - -static void display_formats() -{ - fprintf(stderr, "Supported formats:\n\n"); - for(int i = 0; i != FORMAT_COUNT; i++) - { - floppy_image_format_t *fif = formats[i]; - fprintf(stderr, "%15s - %s [%s]\n", fif->name(), fif->description(), fif->extensions()); - } -} - -static void display_full_usage() -{ - /* Usage */ - fprintf(stderr, "floptool - Generic floppy image manipulation tool for use with MESS\n\n"); - display_usage(); - fprintf(stderr, "\n"); - display_formats(); - fprintf(stderr, "\nExample usage:\n"); - fprintf(stderr, " floptool.exe identify image.dsk\n\n"); - -} - -static int identify(int argc, char *argv[]) -{ - if (argc<3) { - fprintf(stderr, "Missing name of file to identify.\n\n"); - display_usage(); - return 1; - } - - for(int i=2; i<argc; i++) { - char msg[4096]; - sprintf(msg, "Error opening %s for reading", argv[i]); - FILE *f = fopen(argv[i], "rb"); - if (!f) { - perror(msg); - return 1; - } - io_generic io; - io.file = f; - io.procs = &stdio_ioprocs_noclose; - io.filler = 0xff; - - floppy_image_format_t *best_fif = find_format_by_identify(&io); - if (best_fif) - printf("%s : %s\n", argv[i], best_fif->description()); - else - printf("%s : Unknown format\n", argv[i]); - fclose(f); - } - return 0; -} - -static int convert(int argc, char *argv[]) -{ - if (argc!=6) { - fprintf(stderr, "Incorrect number of arguments.\n\n"); - display_usage(); - return 1; - } - - floppy_image_format_t *source_format, *dest_format; - - char msg[4096]; - sprintf(msg, "Error opening %s for reading", argv[4]); - FILE *f = fopen(argv[4], "rb"); - if (!f) { - perror(msg); - return 1; - } - io_generic source_io; - source_io.file = f; - source_io.procs = &stdio_ioprocs_noclose; - source_io.filler = 0xff; - - if(!core_stricmp(argv[2], "auto")) { - source_format = find_format_by_identify(&source_io); - if(!source_format) { - fprintf(stderr, "Error: Could not identify the format of file %s\n", argv[4]); - return 1; - } - - } else { - source_format = find_format_by_name(argv[2]); - if(!source_format) { - fprintf(stderr, "Error: Format '%s' unknown\n", argv[2]); - return 1; - } - } - - dest_format = find_format_by_name(argv[3]); - if(!dest_format) { - fprintf(stderr, "Error: Format '%s' unknown\n", argv[3]); - return 1; - } - if(!dest_format->supports_save()) { - fprintf(stderr, "Error: saving to format '%s' unsupported\n", argv[3]); - return 1; - } - - sprintf(msg, "Error opening %s for writing", argv[5]); - f = fopen(argv[5], "wb"); - if (!f) { - perror(msg); - return 1; - } - io_generic dest_io; - dest_io.file = f; - dest_io.procs = &stdio_ioprocs_noclose; - dest_io.filler = 0xff; - - floppy_image image(84, 2, floppy_image::FF_UNKNOWN); - if(!source_format->load(&source_io, floppy_image::FF_UNKNOWN, &image)) { - fprintf(stderr, "Error: parsing input file as '%s' failed\n", source_format->name()); - return 1; - } - - if(!dest_format->save(&dest_io, &image)) { - fprintf(stderr, "Error: writing output file as '%s' failed\n", dest_format->name()); - return 1; - } - - fclose((FILE *)source_io.file); - fclose((FILE *)dest_io.file); - - return 0; -} - -int CLIB_DECL main(int argc, char *argv[]) -{ - init_formats(); - - if (argc == 1) { - display_full_usage(); - return 0; - } - - if (!core_stricmp("identify", argv[1])) - return identify(argc, argv); - else if (!core_stricmp("convert", argv[1])) - return convert(argc, argv); - else { - fprintf(stderr, "Unknown command '%s'\n\n", argv[1]); - display_usage(); - return 1; - } -} diff --git a/src/mess/tools/imgtool/charconv.c b/src/mess/tools/imgtool/charconv.c deleted file mode 100644 index 39b5953d799..00000000000 --- a/src/mess/tools/imgtool/charconv.c +++ /dev/null @@ -1,162 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - charconv.c - - Imgtool character set conversion routines. - -***************************************************************************/ - -#include "corestr.h" -#include "charconv.h" - - -/*------------------------------------------------- - utf8_from_latin1 - convert an ISO-8859-1 - character sequence to an UTF-8 string --------------------------------------------------*/ - -static char *utf8_from_latin1(const char *src) -{ - char *buffer, *bufptr; - - /* validate input */ - if (!src) - { - return NULL; - } - - /* allocate space for result, twice the source len to be safe */ - buffer = (char *) osd_malloc(strlen(src) * 2 + 1); - - /* point to the start */ - bufptr = buffer; - - do - { - unsigned char c = *src; - - if (c < 0x80) - { - *bufptr++ = c; - } - else if (c < 0xc0) - { - *bufptr++ = '\xc2'; - *bufptr++ = c; - } - else - { - *bufptr++ = '\xc3'; - *bufptr++ = c - 0x40; - } - } while (*src++); - - return buffer; -} - - -/*------------------------------------------------- - latin1_from_utf8 - convert an UTF-8 - character sequence to an ISO-8859-1 string --------------------------------------------------*/ - -static char *latin1_from_utf8(const char *src) -{ - char *buffer, *bufptr; - - /* validate input */ - if (!src) - { - return NULL; - } - - /* allocate space for result */ - buffer = (char *) osd_malloc(strlen(src) + 1); - - /* point to the start */ - bufptr = buffer; - - do - { - unsigned char c = *src; - - if (c < 0x80) - { - *bufptr++ = c; - } - else if (c == 0xc2) - { - c = *++src; - *bufptr++ = c; - } - else if (c == 0xc3) - { - c = *++src; - *bufptr++ = c + 0x40; - } - else - { - /* conversion failed */ - *bufptr++ = '\0'; - break; - } - } while(*src++); - - return buffer; -} - - -/*------------------------------------------------- - utf8_from_native - convert specified character - sequence to an UTF-8 string --------------------------------------------------*/ - -char *utf8_from_native(imgtool_charset charset, const char *src) -{ - char *result; - - switch (charset) - { - case IMGTOOL_CHARSET_UTF8: - result = core_strdup(src); - break; - - case IMGTOOL_CHARSET_ISO_8859_1: - result = utf8_from_latin1(src); - break; - - default: - result = NULL; - break; - } - return result; -} - - -/*------------------------------------------------- - native_from_utf8 - convert an UTF-8 string - to specified character set --------------------------------------------------*/ - -char *native_from_utf8(imgtool_charset charset, const char *src) -{ - char *result; - - switch (charset) - { - case IMGTOOL_CHARSET_UTF8: - result = core_strdup(src); - break; - - case IMGTOOL_CHARSET_ISO_8859_1: - result = latin1_from_utf8(src); - break; - - default: - result = NULL; - break; - } - return result; -} diff --git a/src/mess/tools/imgtool/charconv.h b/src/mess/tools/imgtool/charconv.h deleted file mode 100644 index 1544e9df402..00000000000 --- a/src/mess/tools/imgtool/charconv.h +++ /dev/null @@ -1,31 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - charconv.h - - Imgtool character set conversion routines. - -***************************************************************************/ - - -#ifndef __CHARCONV_H__ -#define __CHARCONV_H__ - - -/* Supported character sets */ -enum imgtool_charset -{ - IMGTOOL_CHARSET_UTF8, - IMGTOOL_CHARSET_ISO_8859_1, -}; - - -/* Convert specified charset to UTF-8 */ -char *utf8_from_native(imgtool_charset charset, const char *src); - -/* Convert UTF-8 string to specified charset */ -char *native_from_utf8(imgtool_charset charset, const char *src); - - -#endif /* __CHARCONV_H__ */ diff --git a/src/mess/tools/imgtool/filtbas.c b/src/mess/tools/imgtool/filtbas.c deleted file mode 100644 index bff1bda121e..00000000000 --- a/src/mess/tools/imgtool/filtbas.c +++ /dev/null @@ -1,3115 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/**************************************************************************** - - filtbas.c - - Filter for Microsoft-style tokenized BASIC files - - BASIC files typically follow the following format: - - int8 $ff - int16 <TOTAL LENGTH> - ... - int16 <PTR_NEXT_LINE> - int16 <LINE_NUM> - int8[] <TOKENISED_DATA> - int8 $00 End of line delimiter - -*****************************************************************************/ - -#include <string.h> -#include <stdarg.h> -#include <ctype.h> - -#include "imgtool.h" -#include "formats/imageutl.h" - - -/*************************************************************************** - CONSTANTS -***************************************************************************/ - -#define EOLN (CRLF == 1 ? "\r" : (CRLF == 2 ? "\n" : (CRLF == 3 ? "\r\n" : NULL))) - - - -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -struct basictoken_tableent -{ - UINT8 shift; - UINT8 base; - const char *const *tokens; - int num_tokens; -}; - - - -struct basictokens -{ - UINT16 baseaddress; - unsigned int skip_bytes : 15; - unsigned int be : 1; - const basictoken_tableent *entries; - int num_entries; -}; - - - -/*************************************************************************** - IMPLEMENTATION -***************************************************************************/ - -/*------------------------------------------------- - basic_readfile - reads a file and decodes - BASIC tokens into ASCII text --------------------------------------------------*/ - -static imgtoolerr_t basic_readfile(const basictokens *tokens, - imgtool_partition *partition, const char *filename, - const char *fork, imgtool_stream *destf) -{ - imgtoolerr_t err; - imgtool_stream *mem_stream; - UINT8 line_header[4]; - UINT16 line_number; //, address; - UINT8 b, shift; - int i; - int in_string = FALSE; - const basictoken_tableent *token_table; - const char *token; - - /* open a memory stream */ - mem_stream = stream_open_mem(NULL, 0); - if (mem_stream == NULL) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto done; - } - - /* read actual file */ - err = imgtool_partition_read_file(partition, filename, fork, mem_stream, NULL); - if (err) - goto done; - - /* skip first few bytes */ - stream_seek(mem_stream, tokens->skip_bytes, SEEK_SET); - - /* keep reading line headers */ - while(stream_read(mem_stream, line_header, sizeof(line_header)) == sizeof(line_header)) - { - /* pluck the address and line number out */ - if (tokens->be) - { - //address = (UINT16) - pick_integer_be(line_header, 0, 2); - line_number = (UINT16) pick_integer_be(line_header, 2, 2); - } - else - { - //address = (UINT16) - pick_integer_le(line_header, 0, 2); - line_number = (UINT16) pick_integer_le(line_header, 2, 2); - } - - /* write the line number */ - stream_printf(destf, "%u ", (unsigned) line_number); - shift = 0x00; - - while((stream_read(mem_stream, &b, 1) > 0) && (b != 0x00)) - { - if (b == 0x22) - in_string = in_string ? FALSE : TRUE; - - if ((b & 0x80) && (!in_string)) - { - token = NULL; - - for (i = 0; i < tokens->num_entries; i++) - { - token_table = &tokens->entries[i]; - if (token_table->shift == shift) - { - if ((b - 0x80) < token_table->num_tokens) - { - token = token_table->tokens[b - 0x80]; - if (token) - shift = 0x00; - } - } - - if (token_table->shift == b) - { - shift = token_table->shift; - break; - } - } - - if (shift == 0x00) - stream_puts(destf, token ? token : "!"); - } - else - { - stream_putc(destf, (char) b); - } - } - - stream_puts(destf, EOLN); - } - -done: - if (mem_stream != NULL) - stream_close(mem_stream); - return err; -} - - - -/*------------------------------------------------- - basic_writefile - translates ASCII text to - BASIC tokens and writes it to a file --------------------------------------------------*/ - -static imgtoolerr_t basic_writefile(const basictokens *tokens, - imgtool_partition *partition, const char *filename, - const char *fork, imgtool_stream *sourcef, option_resolution *opts) -{ - imgtoolerr_t err; - imgtool_stream *mem_stream; - char buf[1024]; - int eof = FALSE; - UINT32 len; - char c; - int i, j, pos, in_quotes; - UINT16 line_number; - UINT8 line_header[4]; - UINT8 file_header[3]; - const basictoken_tableent *token_table; - const char *token; - UINT8 token_shift, token_value; - UINT16 address; - - /* open a memory stream */ - mem_stream = stream_open_mem(NULL, 0); - if (mem_stream == NULL) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto done; - } - - /* skip first few bytes */ - stream_fill(mem_stream, 0x00, tokens->skip_bytes); - - /* loop until the file is complete */ - while(!eof) - { - /* read a line */ - pos = 0; - while((len = stream_read(sourcef, &c, 1)) > 0) - { - /* break if at end of line */ - if ((c == '\r') || (c == '\n')) - break; - - if (pos <= ARRAY_LENGTH(buf) - 1) - { - buf[pos++] = c; - } - } - eof = (len == 0); - buf[pos] = '\0'; - - /* ignore lines that don't start with digits */ - if (isdigit(buf[0])) - { - /* start at beginning of line */ - pos = 0; - - /* read line number */ - line_number = 0; - while(isdigit(buf[pos])) - { - line_number *= 10; - line_number += (buf[pos++] - '0'); - } - - /* determine address */ - if (tokens->baseaddress != 0) - { - address = tokens->baseaddress + (UINT16)stream_size(mem_stream) + 4; - } - else - { - address = 0x0000; - } - - /* set up line header */ - memset(&line_header, 0, sizeof(line_header)); - if (tokens->be) - { - place_integer_be(line_header, 0, 2, address); - place_integer_be(line_header, 2, 2, line_number); - } - else - { - place_integer_be(line_header, 0, 2, address); - place_integer_be(line_header, 2, 2, line_number); - } - - /* emit line header */ - stream_write(mem_stream, line_header, sizeof(line_header)); - - /* skip spaces */ - while(isspace(buf[pos])) - pos++; - - /* when we start out, we are not within quotation marks */ - in_quotes = FALSE; - - /* read until end of line */ - while(buf[pos] != '\0') - { - token = NULL; - token_shift = 0; - token_value = 0; - - if (buf[pos] == '\"') - { - /* flip quotation status */ - in_quotes = !in_quotes; - } - else if (!in_quotes) - { - for (i = 0; (token == NULL) && (i < tokens->num_entries); i++) - { - token_table = &tokens->entries[i]; - for (j = 0; (token == NULL) && (j < token_table->num_tokens); j++) - { - if (!strncmp(&buf[pos], token_table->tokens[j], strlen(token_table->tokens[j]))) - { - token = token_table->tokens[j]; - token_shift = token_table->shift; - token_value = token_table->base + j; - pos += strlen(token); - } - } - } - } - - /* did we find a token? */ - if (token != NULL) - { - /* emit the token */ - if (token_shift != 0) - stream_write(mem_stream, &token_shift, 1); - stream_write(mem_stream, &token_value, 1); - } - else - { - /* no token; emit the byte */ - stream_write(mem_stream, &buf[pos++], 1); - } - } - - /* emit line terminator */ - stream_fill(mem_stream, 0x00, 1); - } - } - - /* emit program terminator */ - stream_fill(mem_stream, 0x00, 2); - - /* reset stream */ - stream_seek(mem_stream, 0, SEEK_SET); - - /* this is somewhat gross */ - if (tokens->skip_bytes >= 3) - { - if (tokens->be) - { - place_integer_be(file_header, 0, 1, 0xFF); - place_integer_be(file_header, 1, 2, stream_size(mem_stream)); - } - else - { - place_integer_le(file_header, 0, 1, 0xFF); - place_integer_le(file_header, 1, 2, stream_size(mem_stream)); - } - stream_write(mem_stream, file_header, 3); - stream_seek(mem_stream, 0, SEEK_SET); - } - - /* write actual file */ - err = imgtool_partition_write_file(partition, filename, fork, mem_stream, opts, NULL); - if (err) - goto done; - -done: - if (mem_stream != NULL) - stream_close(mem_stream); - return err; -} - - - -/*************************************************************************** - TOKEN DEFINITIONS -***************************************************************************/ - -static const char *const cocobas_statements[] = -{ - "FOR", /* 0x80 */ - "GO", /* 0x81 */ - "REM", /* 0x82 */ - "'", /* 0x83 */ - "ELSE", /* 0x84 */ - "IF", /* 0x85 */ - "DATA", /* 0x86 */ - "PRINT", /* 0x87 */ - "ON", /* 0x88 */ - "INPUT", /* 0x89 */ - "END", /* 0x8a */ - "NEXT", /* 0x8b */ - "DIM", /* 0x8c */ - "READ", /* 0x8d */ - "RUN", /* 0x8e */ - "RESTORE", /* 0x8f */ - "RETURN", /* 0x90 */ - "STOP", /* 0x91 */ - "POKE", /* 0x92 */ - "CONT", /* 0x93 */ - "LIST", /* 0x94 */ - "CLEAR", /* 0x95 */ - "NEW", /* 0x96 */ - "CLOAD", /* 0x97 */ - "CSAVE", /* 0x98 */ - "OPEN", /* 0x99 */ - "CLOSE", /* 0x9a */ - "LLIST", /* 0x9b */ - "SET", /* 0x9c */ - "RESET", /* 0x9d */ - "CLS", /* 0x9e */ - "MOTOR", /* 0x9f */ - "SOUND", /* 0xa0 */ - "AUDIO", /* 0xa1 */ - "EXEC", /* 0xa2 */ - "SKIPF", /* 0xa3 */ - "TAB(", /* 0xa4 */ - "TO", /* 0xa5 */ - "SUB", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "OFF", /* 0xaa */ - "+", /* 0xab */ - "-", /* 0xac */ - "*", /* 0xad */ - "/", /* 0xae */ - "^", /* 0xaf */ - "AND", /* 0xb0 */ - "OR", /* 0xb1 */ - ">", /* 0xb2 */ - "=", /* 0xb3 */ - "<", /* 0xb4 */ - "DEL", /* 0xb5 */ - "EDIT", /* 0xb6 */ - "TRON", /* 0xb7 */ - "TROFF", /* 0xb8 */ - "DEF", /* 0xb9 */ - "LET", /* 0xba */ - "LINE", /* 0xbb */ - "PCLS", /* 0xbc */ - "PSET", /* 0xbd */ - "PRESET", /* 0xbe */ - "SCREEN", /* 0xbf */ - "PCLEAR", /* 0xc0 */ - "COLOR", /* 0xc1 */ - "CIRCLE", /* 0xc2 */ - "PAINT", /* 0xc3 */ - "GET", /* 0xc4 */ - "PUT", /* 0xc5 */ - "DRAW", /* 0xc6 */ - "PCOPY", /* 0xc7 */ - "PMODE", /* 0xc8 */ - "PLAY", /* 0xc9 */ - "DLOAD", /* 0xca */ - "RENUM", /* 0xcb */ - "FN", /* 0xcc */ - "USING", /* 0xcd */ - "DIR", /* 0xce */ - "DRIVE", /* 0xcf */ - "FIELD", /* 0xd0 */ - "FILES", /* 0xd1 */ - "KILL", /* 0xd2 */ - "LOAD", /* 0xd3 */ - "LSET", /* 0xd4 */ - "MERGE", /* 0xd5 */ - "RENAME", /* 0xd6 */ - "RSET", /* 0xd7 */ - "SAVE", /* 0xd8 */ - "WRITE", /* 0xd9 */ - "VERIFY", /* 0xda */ - "UNLOAD", /* 0xdb */ - "DSKINI", /* 0xdc */ - "BACKUP", /* 0xdd */ - "COPY", /* 0xde */ - "DSKI$", /* 0xdf */ - "DSKO$", /* 0xe0 */ - "DOS", /* 0xe1 */ - "WIDTH", /* 0xe2 */ - "PALETTE", /* 0xe3 */ - "HSCREEN", /* 0xe4 */ - "LPOKE", /* 0xe5 */ - "HCLS", /* 0xe6 */ - "HCOLOR", /* 0xe7 */ - "HPAINT", /* 0xe8 */ - "HCIRCLE", /* 0xe9 */ - "HLINE", /* 0xea */ - "HGET", /* 0xeb */ - "HPUT", /* 0xec */ - "HBUFF", /* 0xed */ - "HPRINT", /* 0xee */ - "ERR", /* 0xef */ - "BRK", /* 0xf0 */ - "LOCATE", /* 0xf1 */ - "HSTAT", /* 0xf2 */ - "HSET", /* 0xf3 */ - "HRESET", /* 0xf4 */ - "HDRAW", /* 0xf5 */ - "CMP", /* 0xf6 */ - "RGB", /* 0xf7 */ - "ATTR" /* 0xf8 */ -}; - -static const char *const cocobas_functions[] = -{ - "SGN", /* 0xff80 */ - "INT", /* 0xff81 */ - "ABS", /* 0xff82 */ - "USR", /* 0xff83 */ - "RND", /* 0xff84 */ - "SIN", /* 0xff85 */ - "PEEK", /* 0xff86 */ - "LEN", /* 0xff87 */ - "STR$", /* 0xff88 */ - "VAL", /* 0xff89 */ - "ASC", /* 0xff8a */ - "CHR$", /* 0xff8b */ - "EOF", /* 0xff8c */ - "JOYSTK", /* 0xff8d */ - "LEFT$", /* 0xff8e */ - "RIGHT$", /* 0xff8f */ - "MID$", /* 0xff90 */ - "POINT", /* 0xff91 */ - "INKEY$", /* 0xff92 */ - "MEM", /* 0xff93 */ - "ATN", /* 0xff94 */ - "COS", /* 0xff95 */ - "TAN", /* 0xff96 */ - "EXP", /* 0xff97 */ - "FIX", /* 0xff98 */ - "LOG", /* 0xff99 */ - "POS", /* 0xff9a */ - "SQR", /* 0xff9b */ - "HEX$", /* 0xff9c */ - "VARPTR", /* 0xff9d */ - "INSTR", /* 0xff9e */ - "TIMER", /* 0xff9f */ - "PPOINT", /* 0xffa0 */ - "STRING$", /* 0xffa1 */ - "CVN", /* 0xffa2 */ - "FREE", /* 0xffa3 */ - "LOC", /* 0xffa4 */ - "LOF", /* 0xffa5 */ - "MKN$", /* 0xffa6 */ - "AS", /* 0xffa7 */ - "LPEEK", /* 0xffa8 */ - "BUTTON", /* 0xffa9 */ - "HPOINT", /* 0xffaa */ - "ERNO", /* 0xffab */ - "ERLIN" /* 0xffac */ -}; - -static const char *const dragonbas_statements[] = -{ - "FOR", /* 0x80 */ - "GO", /* 0x81 */ - "REM", /* 0x82 */ - "'", /* 0x83 */ - "ELSE", /* 0x84 */ - "IF", /* 0x85 */ - "DATA", /* 0x86 */ - "PRINT", /* 0x87 */ - "ON", /* 0x88 */ - "INPUT", /* 0x89 */ - "END", /* 0x8a */ - "NEXT", /* 0x8b */ - "DIM", /* 0x8c */ - "READ", /* 0x8d */ - "LET", /* 0x8e */ - "RUN", /* 0x8f */ - "RESTORE", /* 0x90 */ - "RETURN", /* 0x91 */ - "STOP", /* 0x92 */ - "POKE", /* 0x93 */ - "CONT", /* 0x94 */ - "LIST", /* 0x95 */ - "CLEAR", /* 0x96 */ - "NEW", /* 0x97 */ - "DEF", /* 0x98 */ - "CLOAD", /* 0x99 */ - "CSAVE", /* 0x9a */ - "OPEN", /* 0x9b */ - "CLOSE", /* 0x9c */ - "LLIST", /* 0x9d */ - "SET", /* 0x9e */ - "RESET", /* 0x9f */ - "CLS", /* 0xa0 */ - "MOTOR", /* 0xa1 */ - "SOUND", /* 0xa2 */ - "AUDIO", /* 0xa3 */ - "EXEC", /* 0xa4 */ - "SKIPF", /* 0xa5 */ - "DEL", /* 0xa6 */ - "EDIT", /* 0xa7 */ - "TRON", /* 0xa8 */ - "TROFF", /* 0xa9 */ - "LINE", /* 0xaa */ - "PCLS", /* 0xab */ - "PSET", /* 0xac */ - "PRESET", /* 0xad */ - "SCREEN", /* 0xae */ - "PCLEAR", /* 0xaf */ - "COLOR", /* 0xb0 */ - "CIRCLE", /* 0xb1 */ - "PAINT", /* 0xb2 */ - "GET", /* 0xb3 */ - "PUT", /* 0xb4 */ - "DRAW", /* 0xb5 */ - "PCOPY", /* 0xb6 */ - "PMODE", /* 0xb7 */ - "PLAY", /* 0xb8 */ - "DLOAD", /* 0xb9 */ - "RENUM", /* 0xba */ - "TAB(", /* 0xbb */ - "TO", /* 0xbc */ - "SUB", /* 0xbd */ - "FN", /* 0xbe */ - "THEN", /* 0xbf */ - "NOT", /* 0xc0 */ - "STEP", /* 0xc1 */ - "OFF", /* 0xc2 */ - "+", /* 0xc3 */ - "-", /* 0xc4 */ - "*", /* 0xc5 */ - "/", /* 0xc6 */ - "^", /* 0xc7 */ - "AND", /* 0xc8 */ - "OR", /* 0xc9 */ - ">", /* 0xca */ - "=", /* 0xcb */ - "<", /* 0xcc */ - "USING", /* 0xcd */ - "DIR", /* 0xce */ - "DRIVE", /* 0xcf */ - "FIELD", /* 0xd0 */ - "FILES", /* 0xd1 */ - "KILL", /* 0xd2 */ - "LOAD", /* 0xd3 */ - "LSET", /* 0xd4 */ - "MERGE", /* 0xd5 */ - "RENAME", /* 0xd6 */ - "RSET", /* 0xd7 */ - "SAVE", /* 0xd8 */ - "WRITE", /* 0xd9 */ - "VERIFY", /* 0xda */ - "UNLOAD", /* 0xdb */ - "DSKINI", /* 0xdc */ - "BACKUP", /* 0xdd */ - "COPY", /* 0xde */ - "DSKI$", /* 0xdf */ - "DSKO$" /* 0xe0 */ -}; - -static const char *const dragonbas_functions[] = -{ - "SGN", /* 0xff80 */ - "INT", /* 0xff81 */ - "ABS", /* 0xff82 */ - "POS", /* 0xff83 */ - "RND", /* 0xff84 */ - "SQR", /* 0xff85 */ - "LOG", /* 0xff86 */ - "EXP", /* 0xff87 */ - "SIN", /* 0xff88 */ - "COS", /* 0xff89 */ - "TAN", /* 0xff8a */ - "ATN", /* 0xff8b */ - "PEEK", /* 0xff8c */ - "LEN", /* 0xff8d */ - "STR$", /* 0xff8e */ - "VAL", /* 0xff8f */ - "ASC", /* 0xff90 */ - "CHR$", /* 0xff91 */ - "EOF", /* 0xff92 */ - "JOYSTK", /* 0xff93 */ - "FIX", /* 0xff94 */ - "HEX$", /* 0xff95 */ - "LEFT$", /* 0xff96 */ - "RIGHT$", /* 0xff97 */ - "MID$", /* 0xff98 */ - "POINT", /* 0xff99 */ - "INKEY$", /* 0xff9a */ - "MEM", /* 0xff9b */ - "VARPTR", /* 0xff9c */ - "INSTR", /* 0xff9d */ - "TIMER", /* 0xff9e */ - "PPOINT", /* 0xff9f */ - "STRING$", /* 0xffa0 */ - "USR" /* 0xffa1 */ - "CVN", /* 0xffa2 */ - "FREE", /* 0xffa3 */ - "LOC", /* 0xffa4 */ - "LOF", /* 0xffa5 */ - "MKN$" /* 0xffa6 */ -}; - -static const char *const vzbas[] = -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "RESET", /* 0x82 */ - "SET", /* 0x83 */ - "CLS", /* 0x84 */ - NULL, /* 0x85 */ - "RANDOM", /* 0x86 */ - "NEXT", /* 0x87 */ - "DATA", /* 0x88 */ - "INPUT", /* 0x89 */ - "DIM", /* 0x8a */ - "READ", /* 0x8b */ - "LET", /* 0x8c */ - "GOTO", /* 0x8d */ - "RUN", /* 0x8e */ - "IF", /* 0x8f */ - "RESTORE", /* 0x90 */ - "GOSUB", /* 0x91 */ - "RETURN", /* 0x92 */ - "'", /* 0x93 */ - "STOP", /* 0x94 */ - "ELSE", /* 0x95 */ - "COPY", /* 0x96 */ - "COLOR", /* 0x97 */ - "VERIFY", /* 0x98 */ - "DEFINT", /* 0x99 */ - "DEFSNG", /* 0x9a */ - "DEFDBL", /* 0x9b */ - "CRUN", /* 0x9c */ - "MODE", /* 0x9d */ - "ERROR", /* 0x9e */ - "RESUME", /* 0x9f */ - "OUT", /* 0xa0 */ - "IN", /* 0xa1 */ - NULL, /* 0xa2 */ - NULL, /* 0xa3 */ - NULL, /* 0xa4 */ - NULL, /* 0xa5 */ - NULL, /* 0xa6 */ - NULL, /* 0xa7 */ - NULL, /* 0xa8 */ - NULL, /* 0xa9 */ - NULL, /* 0xaa */ - NULL, /* 0xab */ - NULL, /* 0xac */ - NULL, /* 0xad */ - "(RESET)", /* 0xae */ - "LPRINT", /* 0xaf */ - NULL, /* 0xb0 */ - "POKE", /* 0xb1 */ - "PRINT", /* 0xb2 */ - "CONT", /* 0xb3 */ - "LIST", /* 0xb4 */ - "LLIST", /* 0xb5 */ - "DELETE", /* 0xb6 */ - "AUTO", /* 0xb7 */ - "CLEAR", /* 0xb8 */ - "CLOAD", /* 0xb9 */ - "CSAVE", /* 0xba */ - "NEW", /* 0xbb */ - "TAB(", /* 0xbc */ - "TO", /* 0xbd */ - NULL, /* 0xbe */ - "USING", /* 0xbf */ - "VARPTR", /* 0xc0 */ - "USR", /* 0xc1 */ - "ERL", /* 0xc2 */ - "ERR", /* 0xc3 */ - "STRING$", /* 0xc4 */ - NULL, /* 0xc5 */ - "POINT", /* 0xc6 */ - NULL, /* 0xc7 */ - "MEM", /* 0xc8 */ - "INKEY$", /* 0xc9 */ - "THEN", /* 0xca */ - "NOT", /* 0xcb */ - "STEP", /* 0xcc */ - "+", /* 0xcd */ - "-", /* 0xce */ - "*", /* 0xcf */ - "/", /* 0xd0 */ - "^", /* 0xd1 */ - "AND", /* 0xd2 */ - "OR", /* 0xd3 */ - ">", /* 0xd4 */ - "=", /* 0xd5 */ - "<", /* 0xd6 */ - "SGN", /* 0xd7 */ - "INT", /* 0xd8 */ - "ABS", /* 0xd9 */ - "FRE", /* 0xda */ - "INP", /* 0xdb */ - "POS", /* 0xdc */ - "SQR", /* 0xdd */ - "AND", /* 0xde */ - "LOG", /* 0xdf */ - "EXP", /* 0xe0 */ - "COS", /* 0xe1 */ - "SIN", /* 0xe2 */ - "TAN", /* 0xe3 */ - "ATN", /* 0xe4 */ - "PEEK", /* 0xe5 */ - NULL, /* 0xe6 */ - NULL, /* 0xe7 */ - NULL, /* 0xe8 */ - NULL, /* 0xe9 */ - NULL, /* 0xea */ - NULL, /* 0xeb */ - NULL, /* 0xec */ - NULL, /* 0xed */ - NULL, /* 0xee */ - "CINT", /* 0xef */ - "CSNG", /* 0xf0 */ - "CDBL", /* 0xf1 */ - "FIX", /* 0xf2 */ - "LEN", /* 0xf3 */ - "STR$", /* 0xf4 */ - "VAL", /* 0xf5 */ - "ASC", /* 0xf6 */ - "CHR$", /* 0xf7 */ - "LEFT$", /* 0xf8 */ - "RIGHT$", /* 0xf9 */ - "MID$", /* 0xfa */ - NULL, /* 0xfb */ - NULL, /* 0xfc */ - NULL, /* 0xfd */ - NULL, /* 0xfe */ - NULL /* 0xff */ -}; - -static const char *const bml3bas_statements[] = -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "DIM", /* 0x84 */ - "READ", /* 0x85 */ - "LET", /* 0x86 */ - "GO", /* 0x87 */ - "RUN", /* 0x88 */ - "IF", /* 0x89 */ - "RESTORE", /* 0x8a */ - "RETURN", /* 0x8b */ - "REM", /* 0x8c */ - "'", /* 0x8d */ - "STOP", /* 0x8e */ - "ELSE", /* 0x8f */ - "TRON", /* 0x90 */ - "TROFF", /* 0x91 */ - "SWAP", /* 0x92 */ - "DEFSTR", /* 0x93 */ - "DEFINT", /* 0x94 */ - "DEFSNG", /* 0x95 */ - "DEFDBL", /* 0x96 */ - "ON", /* 0x97 */ - "WAIT", /* 0x98 */ - "RENUM", /* 0x99 */ - "EDIT", /* 0x9a */ - "ERROR", /* 0x9b */ - "RESUME", /* 0x9c */ - "AUTO", /* 0x9d */ - "DELETE", /* 0x9e */ - "TERM", /* 0x9f */ - "WIDTH", /* 0xa0 */ - "UNLIST", /* 0xa1 */ - "MON", /* 0xa2 */ - "LOCATE", /* 0xa3 */ - "CLS", /* 0xa4 */ - "CONSOLE", /* 0xa5 */ - "PSET", /* 0xa6 */ - "PRESET", /* 0xa7 */ - "MOTOR", /* 0xa8 */ - "SKIPF", /* 0xa9 */ - "SAVE", /* 0xaa */ - "LOAD", /* 0xab */ - "MERGE", /* 0xac */ - "EXEC", /* 0xad */ - "OPEN", /* 0xae */ - "CLOSE", /* 0xaf */ - "FILES", /* 0xb0 */ - "COM", /* 0xb1 */ - "KEY", /* 0xb2 */ - "PAINT", /* 0xb3 */ - "BEEP", /* 0xb4 */ - "COLOR", /* 0xb5 */ - "LINE", /* 0xb6 */ - "DEF", /* 0xb7 */ - "POKE", /* 0xb8 */ - "PRINT", /* 0xb9 */ - "CONT", /* 0xba */ - "LIST", /* 0xbb */ - "CLEAR", /* 0xbc */ - "RANDOMIZE",/* 0xbd */ - "WHILE", /* 0xbe */ - "WEND", /* 0xbf */ - "NEW", /* 0xc0 */ - "TAB(", /* 0xc1 */ - "TO", /* 0xc2 */ - "SUB", /* 0xc3 */ - "FN", /* 0xc4 */ - "SPC(", /* 0xc5 */ - "USING", /* 0xc6 */ - "USR", /* 0xc7 */ - "ERL", /* 0xc8 */ - "ERR", /* 0xc9 */ - "OFF", /* 0xca */ - "THEN", /* 0xcb */ - "NOT", /* 0xcc */ - "STEP", /* 0xcd */ - "+", /* 0xce */ - "-", /* 0xcf */ - "*", /* 0xd0 */ - "/", /* 0xd1 */ - "^", /* 0xd2 */ - "AND", /* 0xd3 */ - "OR", /* 0xd4 */ - "XOR", /* 0xd5 */ - "EQV", /* 0xd6 */ - "IMP", /* 0xd7 */ - "MOD", /* 0xd8 */ - "\\", /* 0xd9 */ - ">", /* 0xda */ - "=", /* 0xdb */ - "<" /* 0xdc */ -}; - -static const char *const bml3bas_functions[] = -{ - "SGN", /* 0xff80 */ - "INT", /* 0xff81 */ - "ABS", /* 0xff82 */ - "FRE", /* 0xff83 */ - "POS", /* 0xff84 */ - "SQR", /* 0xff85 */ - "LOG", /* 0xff86 */ - "EXP", /* 0xff87 */ - "COS", /* 0xff88 */ - "SIN", /* 0xff89 */ - "TAN", /* 0xff8a */ - "ATN", /* 0xff8b */ - "PEEK", /* 0xff8c */ - "LEN", /* 0xff8d */ - "STR$", /* 0xff8e */ - "VAL", /* 0xff8f */ - "ASC", /* 0xff90 */ - "CHR$", /* 0xff91 */ - "CINT", /* 0xff92 */ - "CSNG", /* 0xff93 */ - "CDBL", /* 0xff94 */ - "FIX", /* 0xff95 */ - "SPACE$", /* 0xff96 */ - "HEX$", /* 0xff97 */ - "OCT$", /* 0xff98 */ - "LOF", /* 0xff99 */ - "EOF", /* 0xff9a */ - "PEN", /* 0xff9b */ - "LEFT$", /* 0xff9c */ - "RIGHT$", /* 0xff9d */ - "MID$", /* 0xff9e */ - "INSTR", /* 0xff9f */ - "SCREEN", /* 0xffa0 */ - "VARPTR", /* 0xffa1 */ - "STRING$", /* 0xffa2 */ - "RND", /* 0xffa3 */ - "INKEY$", /* 0xffa4 */ - "INPUT", /* 0xffa5 */ - "CSRLIN", /* 0xffa6 */ - "POINT", /* 0xffa7 */ - "TIME", /* 0xffa8 */ - "DATE" /* 0xffa9 */ -}; - - -#ifdef BASIC_ -/* ----------------------------------------------------------------------- * - * CBM machines * - * ----------------------------------------------------------------------- */ -static const char *const basic_10[] = /* "BASIC 1.0" - supported by pet */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - NULL, /* 0xcb */ - NULL, /* 0xcc */ - NULL, /* 0xcd */ - NULL, /* 0xce */ - NULL, /* 0xcf */ - NULL, /* 0xd0 */ - NULL, /* 0xd1 */ - NULL, /* 0xd2 */ - NULL, /* 0xd3 */ - NULL, /* 0xd4 */ - NULL, /* 0xd5 */ - NULL, /* 0xd6 */ - NULL, /* 0xd7 */ - NULL, /* 0xd8 */ - NULL, /* 0xd9 */ - NULL, /* 0xda */ - NULL, /* 0xdb */ - NULL, /* 0xdc */ - NULL, /* 0xdd */ - NULL, /* 0xde */ - NULL, /* 0xdf */ - NULL, /* 0xe0 */ - NULL, /* 0xe1 */ - NULL, /* 0xe2 */ - NULL, /* 0xe3 */ - NULL, /* 0xe4 */ - NULL, /* 0xe5 */ - NULL, /* 0xe6 */ - NULL, /* 0xe7 */ - NULL, /* 0xe8 */ - NULL, /* 0xe9 */ - NULL, /* 0xea */ - NULL, /* 0xeb */ - NULL, /* 0xec */ - NULL, /* 0xed */ - NULL, /* 0xee */ - NULL, /* 0xef */ - NULL, /* 0xf0 */ - NULL, /* 0xf1 */ - NULL, /* 0xf2 */ - NULL, /* 0xf3 */ - NULL, /* 0xf4 */ - NULL, /* 0xf5 */ - NULL, /* 0xf6 */ - NULL, /* 0xf7 */ - NULL, /* 0xf8 */ - NULL, /* 0xf9 */ - NULL, /* 0xfa */ - NULL, /* 0xfb */ - NULL, /* 0xfc */ - NULL, /* 0xfd */ - NULL, /* 0xfe */ - "{PI}" /* 0xff - A single character shaped as greek lowercase 'PI' */ -}; - -static const char *const basic_20[] = /* "BASIC 2.0" - supported by vic20 & clones, c64 & clones, cbm30xx series */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - NULL, /* 0xcc */ - NULL, /* 0xcd */ - NULL, /* 0xce */ - NULL, /* 0xcf */ - NULL, /* 0xd0 */ - NULL, /* 0xd1 */ - NULL, /* 0xd2 */ - NULL, /* 0xd3 */ - NULL, /* 0xd4 */ - NULL, /* 0xd5 */ - NULL, /* 0xd6 */ - NULL, /* 0xd7 */ - NULL, /* 0xd8 */ - NULL, /* 0xd9 */ - NULL, /* 0xda */ - NULL, /* 0xdb */ - NULL, /* 0xdc */ - NULL, /* 0xdd */ - NULL, /* 0xde */ - NULL, /* 0xdf */ - NULL, /* 0xe0 */ - NULL, /* 0xe1 */ - NULL, /* 0xe2 */ - NULL, /* 0xe3 */ - NULL, /* 0xe4 */ - NULL, /* 0xe5 */ - NULL, /* 0xe6 */ - NULL, /* 0xe7 */ - NULL, /* 0xe8 */ - NULL, /* 0xe9 */ - NULL, /* 0xea */ - NULL, /* 0xeb */ - NULL, /* 0xec */ - NULL, /* 0xed */ - NULL, /* 0xee */ - NULL, /* 0xef */ - NULL, /* 0xf0 */ - NULL, /* 0xf1 */ - NULL, /* 0xf2 */ - NULL, /* 0xf3 */ - NULL, /* 0xf4 */ - NULL, /* 0xf5 */ - NULL, /* 0xf6 */ - NULL, /* 0xf7 */ - NULL, /* 0xf8 */ - NULL, /* 0xf9 */ - NULL, /* 0xfa */ - NULL, /* 0xfb */ - NULL, /* 0xfc */ - NULL, /* 0xfd */ - NULL, /* 0xfe */ - "{PI}" /* 0xff - A single character shaped as greek lowercase 'PI' */ -}; - -static const char *const basic_20_super_expander_vic[] = /* "BASIC 2.0 with Super Expander" - supported by vic20 & clones */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - "KEY", /* 0xcc */ - "GRAPHIC", /* 0xcd */ - "SCNCLR", /* 0xce */ - "CIRCLE", /* 0xcf */ - "DRAW", /* 0xd0 */ - "REGION", /* 0xd1 */ - "COLOR", /* 0xd2 */ - "POINT", /* 0xd3 */ - "SOUND", /* 0xd4 */ - "CHAR", /* 0xd5 */ - "PAINT", /* 0xd6 */ - "RPOT", /* 0xd7 */ - "RPEN", /* 0xd8 */ - "RSND", /* 0xd9 */ - "RCOLR", /* 0xda */ - "RGR", /* 0xdb */ - "RJOY", /* 0xdc */ - "RDOT", /* 0xdd */ - NULL, /* 0xde */ - NULL, /* 0xdf */ - NULL, /* 0xe0 */ - NULL, /* 0xe1 */ - NULL, /* 0xe2 */ - NULL, /* 0xe3 */ - NULL, /* 0xe4 */ - NULL, /* 0xe5 */ - NULL, /* 0xe6 */ - NULL, /* 0xe7 */ - NULL, /* 0xe8 */ - NULL, /* 0xe9 */ - NULL, /* 0xea */ - NULL, /* 0xeb */ - NULL, /* 0xec */ - NULL, /* 0xed */ - NULL, /* 0xee */ - NULL, /* 0xef */ - NULL, /* 0xf0 */ - NULL, /* 0xf1 */ - NULL, /* 0xf2 */ - NULL, /* 0xf3 */ - NULL, /* 0xf4 */ - NULL, /* 0xf5 */ - NULL, /* 0xf6 */ - NULL, /* 0xf7 */ - NULL, /* 0xf8 */ - NULL, /* 0xf9 */ - NULL, /* 0xfa */ - NULL, /* 0xfb */ - NULL, /* 0xfc */ - NULL, /* 0xfd */ - NULL, /* 0xfe */ - "{PI}" /* 0xff - A single character shaped as greek lowercase 'PI' */ -}; - -static const char *const basic_20_turtle_basic_10[] = /* "BASIC 2.0 with Turtle BASIC 1.0" - supported by vic20 & clones */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - "GRAPHIC", /* 0xcc */ - "OLD", /* 0xcd */ - "TURN", /* 0xce */ - "PEN", /* 0xcf */ - "DRAW", /* 0xd0 */ - "MOVE", /* 0xd1 */ - "POINT", /* 0xd2 */ - "KILL", /* 0xd3 */ - "WRITE", /* 0xd4 */ - "REPEAT", /* 0xd5 */ - "SCREEN", /* 0xd6 */ - "DOKE", /* 0xd7 */ - "RELOC", /* 0xd8 */ - "FILL", /* 0xd9 */ - "RTIME", /* 0xda */ - "BASE", /* 0xdb */ - "PAUSE", /* 0xdc */ - "POP", /* 0xdd */ - "COLOR", /* 0xde */ - "MERGE", /* 0xdf */ - "CHAR", /* 0xe0 */ - "TAKE", /* 0xe1 */ - "SOUND", /* 0xe2 */ - "VOL", /* 0xe3 */ - "PUT", /* 0xe4 */ - "PLACE", /* 0xe5 */ - "CLS", /* 0xe6 */ - "ACCEPT", /* 0xe7 */ - "RESET", /* 0xe8 */ - "GRAB", /* 0xe9 */ - "RDOT", /* 0xea */ - "PLR$", /* 0xeb */ - "DEEK", /* 0xec */ - "JOY", /* 0xed */ - NULL, /* 0xee */ - NULL, /* 0xef */ - NULL, /* 0xf0 */ - NULL, /* 0xf1 */ - NULL, /* 0xf2 */ - NULL, /* 0xf3 */ - NULL, /* 0xf4 */ - NULL, /* 0xf5 */ - NULL, /* 0xf6 */ - NULL, /* 0xf7 */ - NULL, /* 0xf8 */ - NULL, /* 0xf9 */ - NULL, /* 0xfa */ - NULL, /* 0xfb */ - NULL, /* 0xfc */ - NULL, /* 0xfd */ - NULL, /* 0xfe */ - "{PI}" /* 0xff - A single character shaped as greek lowercase 'PI' */ -}; - -static const char *const basic_20_speech_basic_27[] = /* "BASIC 2.0 with Speech BASIC 2.7" - supported by c64 & clones */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - "RESET", /* 0xcc */ - "BASIC", /* 0xcd */ - "HELP", /* 0xce */ - "KEY", /* 0xcf */ - "HIMEM", /* 0xd0 */ - "DISK", /* 0xd1 */ - "DIR", /* 0xd2 */ - "BLOAD", /* 0xd3 */ - "BSAVE", /* 0xd4 */ - "MAP", /* 0xd5 */ - "MEM", /* 0xd6 */ - "PAUSE", /* 0xd7 */ - "BLOCK", /* 0xd8 */ - "HEAR", /* 0xd9 */ - "RECORD", /* 0xda */ - "PLAY", /* 0xdb */ - "VOLDEF", /* 0xdc */ - "COLDEF", /* 0xdd */ - "HEX", /* 0xde */ - "DEZ", /* 0xdf */ - "SCREEN", /* 0xe0 */ - "EXEC", /* 0xe1 */ - "MON", /* 0xe2 */ - "{LEFT ARROW}", /* 0xe3 - A single character shaped as a left pointing arrow */ - "FROM", /* 0xe4 */ - "SPEED", /* 0xe5 */ - "OFF", /* 0xe6 */ - NULL, /* 0xe7 */ - NULL, /* 0xe8 */ - NULL, /* 0xe9 */ - NULL, /* 0xea */ - NULL, /* 0xeb */ - NULL, /* 0xec */ - NULL, /* 0xed */ - NULL, /* 0xee */ - NULL, /* 0xef */ - NULL, /* 0xf0 */ - NULL, /* 0xf1 */ - NULL, /* 0xf2 */ - NULL, /* 0xf3 */ - NULL, /* 0xf4 */ - NULL, /* 0xf5 */ - NULL, /* 0xf6 */ - NULL, /* 0xf7 */ - NULL, /* 0xf8 */ - NULL, /* 0xf9 */ - NULL, /* 0xfa */ - NULL, /* 0xfb */ - NULL, /* 0xfc */ - NULL, /* 0xfd */ - NULL, /* 0xfe */ - "{PI}" /* 0xff - A single character shaped as greek lowercase 'PI' */ -}; - -static const char *const basic_20_at_basic[] = /* "BASIC 2.0 with @BASIC" - supported by c64 & clones */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - "TRACE", /* 0xcc */ - "DELETE", /* 0xcd */ - "AUTO", /* 0xce */ - "OLD", /* 0xcf */ - "DUMP", /* 0xd0 */ - "FIND", /* 0xd1 */ - "RENUMBER", /* 0xd2 */ - "DLOAD", /* 0xd3 */ - "DSAVE", /* 0xd4 */ - "DVERIFY", /* 0xd5 */ - "DIRECTORY" /* 0xd6 */ - "CATALOG", /* 0xd7 */ - "SCRATCH", /* 0xd8 */ - "COLLECT", /* 0xd9 */ - "RENAME", /* 0xda */ - "COPY", /* 0xdb */ - "BACKUP", /* 0xdc */ - "DISK", /* 0xdd */ - "HEADER", /* 0xde */ - "APPEND", /* 0xdf */ - "MERGE", /* 0xe0 */ - "MLOAD", /* 0xe1 */ - "MVERIFY", /* 0xe2 */ - "MSAVE", /* 0xe3 */ - "KEY", /* 0xe4 */ - "BASIC", /* 0xe5 */ - "RESET", /* 0xe6 */ - "EXIT", /* 0xe7 */ - "ENTER", /* 0xe8 */ - "DOKE", /* 0xe9 */ - "SET", /* 0xea */ - "HELP", /* 0xeb */ - "SCREEN", /* 0xec */ - "LOMEM", /* 0xed */ - "HIMEM", /* 0xee */ - "COLOUR", /* 0xef */ - "TYPE", /* 0xf0 */ - "TIME", /* 0xf1 */ - "DEEK", /* 0xf2 */ - "HEX$", /* 0xf3 */ - "BIN$", /* 0xf4 */ - "OFF", /* 0xf5 */ - "ALARM", /* 0xf6 */ - NULL, /* 0xf7 */ - NULL, /* 0xf8 */ - NULL, /* 0xf9 */ - NULL, /* 0xfa */ - NULL, /* 0xfb */ - NULL, /* 0xfc */ - NULL, /* 0xfd */ - NULL, /* 0xfe */ - "{PI}" /* 0xff - A single character shaped as greek lowercase 'PI' */ -}; - -static const char *const basic_20_simon_s_basic[] = /* "BASIC 2.0 with Simon's BASIC" - supported by c64 & clones */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - NULL, /* 0xcc */ - NULL, /* 0xcd */ - NULL, /* 0xce */ - NULL, /* 0xcf */ - NULL, /* 0xd0 */ - NULL, /* 0xd1 */ - NULL, /* 0xd2 */ - NULL, /* 0xd3 */ - NULL, /* 0xd4 */ - NULL, /* 0xd5 */ - NULL, /* 0xd6 */ - NULL, /* 0xd7 */ - NULL, /* 0xd8 */ - NULL, /* 0xd9 */ - NULL, /* 0xda */ - NULL, /* 0xdb */ - NULL, /* 0xdc */ - NULL, /* 0xdd */ - NULL, /* 0xde */ - NULL, /* 0xdf */ - NULL, /* 0xe0 */ - NULL, /* 0xe1 */ - NULL, /* 0xe2 */ - NULL, /* 0xe3 */ - NULL, /* 0xe4 */ - NULL, /* 0xe5 */ - NULL, /* 0xe6 */ - NULL, /* 0xe7 */ - NULL, /* 0xe8 */ - NULL, /* 0xe9 */ - NULL, /* 0xea */ - NULL, /* 0xeb */ - NULL, /* 0xec */ - NULL, /* 0xed */ - NULL, /* 0xee */ - NULL, /* 0xef */ - NULL, /* 0xf0 */ - NULL, /* 0xf1 */ - NULL, /* 0xf2 */ - NULL, /* 0xf3 */ - NULL, /* 0xf4 */ - NULL, /* 0xf5 */ - NULL, /* 0xf6 */ - NULL, /* 0xf7 */ - NULL, /* 0xf8 */ - NULL, /* 0xf9 */ - NULL, /* 0xfa */ - NULL, /* 0xfb */ - NULL, /* 0xfc */ - NULL, /* 0xfd */ - NULL, /* 0xfe */ - "{PI}", /* 0xff - A single character shaped as greek lowercase 'PI' */ - NULL, /* 0x6400 */ - "HIRES", /* 0x6401 */ - "PLOT", /* 0x6402 */ - "LINE", /* 0x6403 */ - "BLOCK", /* 0x6404 */ - "FCHR", /* 0x6405 */ - "FCOL", /* 0x6406 */ - "FILL", /* 0x6407 */ - "REC", /* 0x6408 */ - "ROT", /* 0x6409 */ - "DRAW", /* 0x640a */ - "CHAR", /* 0x640b */ - "HI COL", /* 0x640c */ - "INV", /* 0x640d */ - "FRAC", /* 0x640e */ - "MOVE", /* 0x640f */ - "PLACE", /* 0x6410 */ - "UPB", /* 0x6411 */ - "UPW", /* 0x6412 */ - "LEFTW", /* 0x6413 */ - "LEFTB", /* 0x6414 */ - "DOWNB", /* 0x6415 */ - "DOWNW", /* 0x6416 */ - "RIGHTB", /* 0x6417 */ - "RIGHTW", /* 0x6418 */ - "MULTI", /* 0x6419 */ - "COLOUR", /* 0x641a */ - "MMOB", /* 0x641b */ - "BFLASH", /* 0x641c */ - "MOB SET", /* 0x641d */ - "MUSIC", /* 0x641e */ - "FLASH", /* 0x641f */ - "REPEAT", /* 0x6420 */ - "PLAY", /* 0x6421 */ - ">>", /* 0x6422 */ - "CENTRE", /* 0x6423 */ - "ENVELOPE", /* 0x6424 */ - "CGOTO", /* 0x6425 */ - "WAVE", /* 0x6426 */ - "FETCH", /* 0x6427 */ - "AT(", /* 0x6428 */ - "UNTIL", /* 0x6429 */ - ">>", /* 0x642a */ - ">>", /* 0x642b */ - "USE", /* 0x642c */ - ">>", /* 0x642d */ - "GLOBAL", /* 0x642e */ - ">>", /* 0x642f */ - "RESET", /* 0x6430 */ - "PROC", /* 0x6431 */ - "CALL", /* 0x6432 */ - "EXEC", /* 0x6433 */ - "END PROC", /* 0x6434 */ - "EXIT", /* 0x6435 */ - "END LOOP", /* 0x6436 */ - "ON KEY", /* 0x6437 */ - "DISABLE", /* 0x6438 */ - "RESUME", /* 0x6439 */ - "LOOP", /* 0x643a */ - "DELAY", /* 0x643b */ - ">>", /* 0x643c */ - ">>", /* 0x643d */ - ">>", /* 0x643e */ - ">>", /* 0x643f */ - "SECURE", /* 0x6440 */ - "DISAPA", /* 0x6441 */ - "CIRCLE", /* 0x6442 */ - "ON ERROR", /* 0x6443 */ - "NO ERROR", /* 0x6444 */ - "LOCAL", /* 0x6445 */ - "RCOMP", /* 0x6446 */ - "ELSE", /* 0x6447 */ - "RETRACE", /* 0x6448 */ - "TRACE", /* 0x6449 */ - "DIR", /* 0x644a */ - "PAGE", /* 0x644b */ - "DUMP", /* 0x644c */ - "FIND", /* 0x644d */ - "OPTION", /* 0x644e */ - "AUTO", /* 0x644f */ - "OLD", /* 0x6450 */ - "JOY", /* 0x6451 */ - "MOD", /* 0x6452 */ - "DIV", /* 0x6453 */ - ">>", /* 0x6454 */ - "DUP", /* 0x6455 */ - "INKEY", /* 0x6456 */ - "INST", /* 0x6457 */ - "TEST", /* 0x6458 */ - "LIN", /* 0x6459 */ - "EXOR", /* 0x645a */ - "INSERT", /* 0x645b */ - "POT", /* 0x645c */ - "PENX", /* 0x645d */ - ">>", /* 0x645e */ - "PENY", /* 0x645f */ - "SOUND", /* 0x6460 */ - "GRAPHICS", /* 0x6461 */ - "DESIGN", /* 0x6462 */ - "RLOCMOB", /* 0x6463 */ - "CMOB", /* 0x6464 */ - "BCKGNDS", /* 0x6465 */ - "PAUSE", /* 0x6466 */ - "NRM", /* 0x6467 */ - "MOB OFF", /* 0x6468 */ - "OFF", /* 0x6469 */ - "ANGL", /* 0x646a */ - "ARC", /* 0x646b */ - "COLD", /* 0x646c */ - "SCRSV", /* 0x646d */ - "SCRLD", /* 0x646e */ - "TEXT", /* 0x646f */ - "CSET", /* 0x6470 */ - "VOL", /* 0x6471 */ - "DISK", /* 0x6472 */ - "HRDCPY", /* 0x6473 */ - "KEY", /* 0x6474 */ - "PAINT", /* 0x6475 */ - "LOW COL", /* 0x6476 */ - "COPY", /* 0x6477 */ - "MERGE", /* 0x6478 */ - "RENUMBER", /* 0x6479 */ - "MEM", /* 0x647a */ - "DETECT", /* 0x647b */ - "CHECK", /* 0x647c */ - "DISPLAY", /* 0x647d */ - "ERR", /* 0x647e */ - "OUT" /* 0x647f */ -}; - -static const char *const basic_20_exp_40[] = /* "BASIC 2.0 with BASIC 4.0 Expansion" - supported by c64 & clones */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - "CONCAT", /* 0xcc */ - "DOPEN", /* 0xcd */ - "DCLOSE", /* 0xce */ - "RECORD", /* 0xcf */ - "HEADER", /* 0xd0 */ - "COLLECT", /* 0xd1 */ - "BACKUP", /* 0xd2 */ - "COPY", /* 0xd3 */ - "APPEND", /* 0xd4 */ - "DSAVE", /* 0xd5 */ - "DLOAD", /* 0xd6 */ - "CATALOG", /* 0xd7 */ - "RENAME", /* 0xd8 */ - "SCRATCH", /* 0xd9 */ - "DIRECTORY", /* 0xda */ - "COLOR", /* 0xdb */ - "COLD", /* 0xdc */ - "KEY", /* 0xdd */ - "DVERIFY", /* 0xde */ - "DELETE" /* 0xdf */ - "AUTO", /* 0xe0 */ - "MERGE", /* 0xe1 */ - "OLD", /* 0xe2 */ - "MONITOR", /* 0xe3 */ - NULL, /* 0xe4 */ - NULL, /* 0xe5 */ - NULL, /* 0xe6 */ - NULL, /* 0xe7 */ - NULL, /* 0xe8 */ - NULL, /* 0xe9 */ - NULL, /* 0xea */ - NULL, /* 0xeb */ - NULL, /* 0xec */ - NULL, /* 0xed */ - NULL, /* 0xee */ - NULL, /* 0xef */ - NULL, /* 0xf0 */ - NULL, /* 0xf1 */ - NULL, /* 0xf2 */ - NULL, /* 0xf3 */ - NULL, /* 0xf4 */ - NULL, /* 0xf5 */ - NULL, /* 0xf6 */ - NULL, /* 0xf7 */ - NULL, /* 0xf8 */ - NULL, /* 0xf9 */ - NULL, /* 0xfa */ - NULL, /* 0xfb */ - NULL, /* 0xfc */ - NULL, /* 0xfd */ - NULL, /* 0xfe */ - "{PI}" /* 0xff - A single character shaped as greek lowercase 'PI' */ -}; - -static const char *const basic_35[] = /* "BASIC 3.5" - supported by c16 & clones, except c364 */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - "RGR", /* 0xcc */ - "RCLR" /* 0xcd */ - "RLUM" /* 0xce */ - "JOY", /* 0xcf */ - "RDOT" /* 0xd0 */ - "DEC", /* 0xd1 */ - "HEX$", /* 0xd2 */ - "ERR$", /* 0xd3 */ - "INSTR", /* 0xd4 */ - "ELSE", /* 0xd5 */ - "RESUME", /* 0xd6 */ - "TRAP", /* 0xd7 */ - "TRON", /* 0xd8 */ - "TROFF", /* 0xd9 */ - "SOUND", /* 0xda */ - "VOL", /* 0xdb */ - "AUTO", /* 0xdc */ - "PUDEF", /* 0xdd */ - "GRAPHIC", /* 0xde */ - "PAINT", /* 0xdf */ - "CHAR", /* 0xe0 */ - "BOX", /* 0xe1 */ - "CIRCLE", /* 0xe2 */ - "GSHAPE", /* 0xe3 */ - "SSHAPE", /* 0xe4 */ - "DRAW", /* 0xe5 */ - "LOCATE", /* 0xe6 */ - "COLOR", /* 0xe7 */ - "SCNCLR", /* 0xe8 */ - "SCALE", /* 0xe9 */ - "HELP", /* 0xea */ - "DO", /* 0xeb */ - "LOOP", /* 0xec */ - "EXIT", /* 0xed */ - "DIRECTORY", /* 0xee */ - "DSAVE", /* 0xef */ - "DLOAD", /* 0xf0 */ - "HEADER", /* 0xf1 */ - "SCRATCH", /* 0xf2 */ - "COLLECT", /* 0xf3 */ - "COPY", /* 0xf4 */ - "RENAME", /* 0xf5 */ - "BACKUP", /* 0xf6 */ - "DELETE", /* 0xf7 */ - "RENUMBER", /* 0xf8 */ - "KEY", /* 0xf9 */ - "MONITOR", /* 0xfa */ - "USING", /* 0xfb */ - "UNTIL", /* 0xfc */ - "WHILE", /* 0xfd */ - NULL, /* 0xfe */ - "{PI}" /* 0xff - A single character shaped as greek lowercase 'PI' */ -}; - -static const char *const basic_35_magic_voice[] = /* "BASIC 3.5 with Magic Voice Speech Synthesizer" - supported by c364 */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - "RGR", /* 0xcc */ - "RCLR" /* 0xcd */ - "RLUM" /* 0xce */ - "JOY", /* 0xcf */ - "RDOT" /* 0xd0 */ - "DEC", /* 0xd1 */ - "HEX$", /* 0xd2 */ - "ERR$", /* 0xd3 */ - "INSTR", /* 0xd4 */ - "ELSE", /* 0xd5 */ - "RESUME", /* 0xd6 */ - "TRAP", /* 0xd7 */ - "TRON", /* 0xd8 */ - "TROFF", /* 0xd9 */ - "SOUND", /* 0xda */ - "VOL", /* 0xdb */ - "AUTO", /* 0xdc */ - "PUDEF", /* 0xdd */ - "GRAPHIC", /* 0xde */ - "PAINT", /* 0xdf */ - "CHAR", /* 0xe0 */ - "BOX", /* 0xe1 */ - "CIRCLE", /* 0xe2 */ - "GSHAPE", /* 0xe3 */ - "SSHAPE", /* 0xe4 */ - "DRAW", /* 0xe5 */ - "LOCATE", /* 0xe6 */ - "COLOR", /* 0xe7 */ - "SCNCLR", /* 0xe8 */ - "SCALE", /* 0xe9 */ - "HELP", /* 0xea */ - "DO", /* 0xeb */ - "LOOP", /* 0xec */ - "EXIT", /* 0xed */ - "DIRECTORY", /* 0xee */ - "DSAVE", /* 0xef */ - "DLOAD", /* 0xf0 */ - "HEADER", /* 0xf1 */ - "SCRATCH", /* 0xf2 */ - "COLLECT", /* 0xf3 */ - "COPY", /* 0xf4 */ - "RENAME", /* 0xf5 */ - "BACKUP", /* 0xf6 */ - "DELETE", /* 0xf7 */ - "RENUMBER", /* 0xf8 */ - "KEY", /* 0xf9 */ - "MONITOR", /* 0xfa */ - "USING", /* 0xfb */ - "UNTIL", /* 0xfc */ - "WHILE", /* 0xfd */ - NULL, /* 0xfe - Prefix for additional tokens */ - "{PI}", /* 0xff - A single character shaped as greek lowercase 'PI' */ - NULL, /* 0xfe00 */ - "RATE", /* 0xfe01 */ - "VOC", /* 0xfe02 */ - NULL, /* 0xfe03 */ - "RDY", /* 0xfe04 */ - NULL, /* 0xfe05 */ - NULL, /* 0xfe06 */ - NULL, /* 0xfe07 */ - NULL, /* 0xfe08 */ - NULL, /* 0xfe09 */ - "SAY" /* 0xfe0a */ -}; - -static const char *const basic_40[] = /* "BASIC 4.0" - supported by cbm40xx & cbm80xx series, p500, cbm600 & clones */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - "CONCAT", /* 0xcc */ - "DOPEN", /* 0xcd */ - "DCLOSE", /* 0xce */ - "RECORD", /* 0xcf */ - "HEADER", /* 0xd0 */ - "COLLECT", /* 0xd1 */ - "BACKUP", /* 0xd2 */ - "COPY", /* 0xd3 */ - "APPEND", /* 0xd4 */ - "DSAVE", /* 0xd5 */ - "DLOAD", /* 0xd6 */ - "CATALOG", /* 0xd7 */ - "RENAME", /* 0xd8 */ - "SCRATCH", /* 0xd9 */ - "DIRECTORY", /* 0xda */ - NULL, /* 0xdb */ - NULL, /* 0xdc */ - NULL, /* 0xdd */ - NULL, /* 0xde */ - NULL, /* 0xdf */ - NULL, /* 0xe0 */ - NULL, /* 0xe1 */ - NULL, /* 0xe2 */ - NULL, /* 0xe3 */ - NULL, /* 0xe4 */ - NULL, /* 0xe5 */ - NULL, /* 0xe6 */ - NULL, /* 0xe7 */ - NULL, /* 0xe8 */ - NULL, /* 0xe9 */ - NULL, /* 0xea */ - NULL, /* 0xeb */ - NULL, /* 0xec */ - NULL, /* 0xed */ - NULL, /* 0xee */ - NULL, /* 0xef */ - NULL, /* 0xf0 */ - NULL, /* 0xf1 */ - NULL, /* 0xf2 */ - NULL, /* 0xf3 */ - NULL, /* 0xf4 */ - NULL, /* 0xf5 */ - NULL, /* 0xf6 */ - NULL, /* 0xf7 */ - NULL, /* 0xf8 */ - NULL, /* 0xf9 */ - NULL, /* 0xfa */ - NULL, /* 0xfb */ - NULL, /* 0xfc */ - NULL, /* 0xfd */ - NULL, /* 0xfe */ - "{PI}" /* 0xff - A single character shaped as greek lowercase 'PI' */ -}; - -static const char *const basic_70[] = /* "BASIC 7.0" - supported by c128 & clones */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - "RGR", /* 0xcc */ - "RCLR", /* 0xcd */ - NULL, /* 0xce - Prefix for additional tokens */ - "JOY", /* 0xcf */ - "RDOT" /* 0xd0 */ - "DEC", /* 0xd1 */ - "HEX$", /* 0xd2 */ - "ERR$", /* 0xd3 */ - "INSTR", /* 0xd4 */ - "ELSE", /* 0xd5 */ - "RESUME", /* 0xd6 */ - "TRAP", /* 0xd7 */ - "TRON", /* 0xd8 */ - "TROFF", /* 0xd9 */ - "SOUND", /* 0xda */ - "VOL", /* 0xdb */ - "AUTO", /* 0xdc */ - "PUDEF", /* 0xdd */ - "GRAPHIC", /* 0xde */ - "PAINT", /* 0xdf */ - "CHAR", /* 0xe0 */ - "BOX", /* 0xe1 */ - "CIRCLE", /* 0xe2 */ - "GSHAPE", /* 0xe3 */ - "SSHAPE", /* 0xe4 */ - "DRAW", /* 0xe5 */ - "LOCATE", /* 0xe6 */ - "COLOR", /* 0xe7 */ - "SCNCLR", /* 0xe8 */ - "SCALE", /* 0xe9 */ - "HELP", /* 0xea */ - "DO", /* 0xeb */ - "LOOP", /* 0xec */ - "EXIT", /* 0xed */ - "DIRECTORY", /* 0xee */ - "DSAVE", /* 0xef */ - "DLOAD", /* 0xf0 */ - "HEADER", /* 0xf1 */ - "SCRATCH", /* 0xf2 */ - "COLLECT", /* 0xf3 */ - "COPY", /* 0xf4 */ - "RENAME", /* 0xf5 */ - "BACKUP", /* 0xf6 */ - "DELETE", /* 0xf7 */ - "RENUMBER", /* 0xf8 */ - "KEY", /* 0xf9 */ - "MONITOR", /* 0xfa */ - "USING", /* 0xfb */ - "UNTIL", /* 0xfc */ - "WHILE", /* 0xfd */ - NULL, /* 0xfe - Prefix for additional tokens */ - "{PI}", /* 0xff - A single character shaped as greek lowercase 'PI' */ - NULL, /* 0xce00 */ - NULL, /* 0xce01 */ - "POT", /* 0xce02 */ - "BUMP", /* 0xce03 */ - "PEN", /* 0xce04 */ - "RSPPOS", /* 0xce05 */ - "RSPRITE", /* 0xce06 */ - "RSPCOLOR", /* 0xce07 */ - "XOR", /* 0xce08 */ - "RWINDOW", /* 0xce09 */ - "POINTER", /* 0xce0a */ - NULL, /* 0xfe00 */ - NULL, /* 0xfe01 */ - "BANK", /* 0xfe02 */ - "FILTER", /* 0xfe03 */ - "PLAY", /* 0xfe04 */ - "TEMPO", /* 0xfe05 */ - "MOVSPR", /* 0xfe06 */ - "SPRITE", /* 0xfe07 */ - "SPRCOLOR", /* 0xfe08 */ - "RREG", /* 0xfe09 */ - "ENVELOPE", /* 0xfe0a */ - "SLEEP", /* 0xfe0b */ - "CATALOG", /* 0xfe0c */ - "DOPEN", /* 0xfe0d */ - "APPEND", /* 0xfe0e */ - "DCLOSE", /* 0xfe0f */ - "BSAVE", /* 0xfe10 */ - "BLOAD", /* 0xfe11 */ - "RECORD", /* 0xfe12 */ - "CONCAT", /* 0xfe13 */ - "DVERIFY", /* 0xfe14 */ - "DCLEAR", /* 0xfe15 */ - "SPRSAV", /* 0xfe16 */ - "COLLISION", /* 0xfe17 */ - "BEGIN", /* 0xfe18 */ - "BEND", /* 0xfe19 */ - "WINDOW", /* 0xfe1a */ - "BOOT", /* 0xfe1b */ - "WIDTH", /* 0xfe1c */ - "SPRDEF", /* 0xfe1d */ - "QUIT", /* 0xfe1e */ - "STASH", /* 0xfe1f */ - NULL, /* 0xfe20 */ - "FETCH", /* 0xfe21 */ - NULL, /* 0xfe22 */ - "SWAP", /* 0xfe23 */ - "OFF", /* 0xfe24 */ - "FAST", /* 0xfe25 */ - "SLOW" /* 0xfe26 */ -}; - -static const char *const basic_100[] = /* "BASIC 10.0" - supported by c65 & clones */ -{ - "END", /* 0x80 */ - "FOR", /* 0x81 */ - "NEXT", /* 0x82 */ - "DATA", /* 0x83 */ - "INPUT#", /* 0x84 */ - "INPUT", /* 0x85 */ - "DIM", /* 0x86 */ - "READ", /* 0x87 */ - "LET", /* 0x88 */ - "GOTO", /* 0x89 */ - "RUN", /* 0x8a */ - "IF", /* 0x8b */ - "RESTORE", /* 0x8c */ - "GOSUB", /* 0x8d */ - "RETURN", /* 0x8e */ - "REM", /* 0x8f */ - "STOP", /* 0x90 */ - "ON", /* 0x91 */ - "WAIT", /* 0x92 */ - "LOAD", /* 0x93 */ - "SAVE", /* 0x94 */ - "VERIFY", /* 0x95 */ - "DEF", /* 0x96 */ - "POKE", /* 0x97 */ - "PRINT#", /* 0x98 */ - "PRINT", /* 0x99 */ - "CONT", /* 0x9a */ - "LIST", /* 0x9b */ - "CLR", /* 0x9c */ - "CMD", /* 0x9d */ - "SYS", /* 0x9e */ - "OPEN", /* 0x9f */ - "CLOSE", /* 0xa0 */ - "GET", /* 0xa1 */ - "NEW", /* 0xa2 */ - "TAB(", /* 0xa3 */ - "TO", /* 0xa4 */ - "FN", /* 0xa5 */ - "SPC(", /* 0xa6 */ - "THEN", /* 0xa7 */ - "NOT", /* 0xa8 */ - "STEP", /* 0xa9 */ - "+", /* 0xaa */ - "-", /* 0xab */ - "*", /* 0xac */ - "/", /* 0xad */ - "^", /* 0xae */ - "AND", /* 0xaf */ - "OR", /* 0xb0 */ - ">", /* 0xb1 */ - "=", /* 0xb2 */ - "<", /* 0xb3 */ - "SGN", /* 0xb4 */ - "INT", /* 0xb5 */ - "ABS", /* 0xb6 */ - "USR", /* 0xb7 */ - "FRE", /* 0xb8 */ - "POS", /* 0xb9 */ - "SQR", /* 0xba */ - "RND", /* 0xbb */ - "LOG", /* 0xbc */ - "EXP", /* 0xbd */ - "COS", /* 0xbe */ - "SIN", /* 0xbf */ - "TAN", /* 0xc0 */ - "ATN", /* 0xc1 */ - "PEEK", /* 0xc2 */ - "LEN", /* 0xc3 */ - "STR$", /* 0xc4 */ - "VAL", /* 0xc5 */ - "ASC", /* 0xc6 */ - "CHR$", /* 0xc7 */ - "LEFT$", /* 0xc8 */ - "RIGHT$", /* 0xc9 */ - "MID$", /* 0xca */ - "GO", /* 0xcb */ - "RGR", /* 0xcc */ - "RCLR", /* 0xcd */ - NULL, /* 0xce - Prefix for additional tokens */ - "JOY", /* 0xcf */ - "RDOT" /* 0xd0 */ - "DEC", /* 0xd1 */ - "HEX$", /* 0xd2 */ - "ERR$", /* 0xd3 */ - "INSTR", /* 0xd4 */ - "ELSE", /* 0xd5 */ - "RESUME", /* 0xd6 */ - "TRAP", /* 0xd7 */ - "TRON", /* 0xd8 */ - "TROFF", /* 0xd9 */ - "SOUND", /* 0xda */ - "VOL", /* 0xdb */ - "AUTO", /* 0xdc */ - "PUDEF", /* 0xdd */ - "GRAPHIC", /* 0xde */ - "PAINT", /* 0xdf */ - "CHAR", /* 0xe0 */ - "BOX", /* 0xe1 */ - "CIRCLE", /* 0xe2 */ - "PASTE", /* 0xe3 */ - "CUT", /* 0xe4 */ - "LINE", /* 0xe5 */ - "LOCATE", /* 0xe6 */ - "COLOR", /* 0xe7 */ - "SCNCLR", /* 0xe8 */ - "SCALE", /* 0xe9 */ - "HELP", /* 0xea */ - "DO", /* 0xeb */ - "LOOP", /* 0xec */ - "EXIT", /* 0xed */ - "DIR", /* 0xee */ - "DSAVE", /* 0xef */ - "DLOAD", /* 0xf0 */ - "HEADER", /* 0xf1 */ - "SCRATCH", /* 0xf2 */ - "COLLECT", /* 0xf3 */ - "COPY", /* 0xf4 */ - "RENAME", /* 0xf5 */ - "BACKUP", /* 0xf6 */ - "DELETE", /* 0xf7 */ - "RENUMBER", /* 0xf8 */ - "KEY", /* 0xf9 */ - "MONITOR", /* 0xfa */ - "USING", /* 0xfb */ - "UNTIL", /* 0xfc */ - "WHILE", /* 0xfd */ - NULL, /* 0xfe - Prefix for additional tokens */ - "{PI}", /* 0xff - A single character shaped as greek lowercase 'PI' */ - NULL, /* 0xce00 */ - NULL, /* 0xce01 */ - "POT", /* 0xce02 */ - "BUMP", /* 0xce03 */ - "PEN", /* 0xce04 */ - "RSPPOS", /* 0xce05 */ - "RSPRITE", /* 0xce06 */ - "RSPCOLOR", /* 0xce07 */ - "XOR", /* 0xce08 */ - "RWINDOW", /* 0xce09 */ - "POINTER", /* 0xce0a */ - NULL, /* 0xfe00 */ - NULL, /* 0xfe01 */ - "BANK", /* 0xfe02 */ - "FILTER", /* 0xfe03 */ - "PLAY", /* 0xfe04 */ - "TEMPO", /* 0xfe05 */ - "MOVSPR", /* 0xfe06 */ - "SPRITE", /* 0xfe07 */ - "SPRCOLOR", /* 0xfe08 */ - "RREG", /* 0xfe09 */ - "ENVELOPE", /* 0xfe0a */ - "SLEEP", /* 0xfe0b */ - "CATALOG", /* 0xfe0c */ - "DOPEN", /* 0xfe0d */ - "APPEND", /* 0xfe0e */ - "DCLOSE", /* 0xfe0f */ - "BSAVE", /* 0xfe10 */ - "BLOAD", /* 0xfe11 */ - "RECORD", /* 0xfe12 */ - "CONCAT", /* 0xfe13 */ - "DVERIFY", /* 0xfe14 */ - "DCLEAR", /* 0xfe15 */ - "SPRSAV", /* 0xfe16 */ - "COLLISION", /* 0xfe17 */ - "BEGIN", /* 0xfe18 */ - "BEND", /* 0xfe19 */ - "WINDOW", /* 0xfe1a */ - "BOOT", /* 0xfe1b */ - "WIDTH", /* 0xfe1c */ - "SPRDEF", /* 0xfe1d */ - "QUIT", /* 0xfe1e */ - "DMA", /* 0xfe1f */ - NULL, /* 0xfe20 */ - "DMA", /* 0xfe21 */ - NULL, /* 0xfe22 */ - "DMA", /* 0xfe23 */ - "OFF", /* 0xfe24 */ - "FAST", /* 0xfe25 */ - "SLOW", /* 0xfe26 */ - "TYPE", /* 0xfe27 */ - "BVERIFY", /* 0xfe28 */ - "ECTORY", /* 0xfe29 */ - "ERASE", /* 0xfe2a */ - "FIND", /* 0xfe2b */ - "CHANGE", /* 0xfe2c */ - "SET", /* 0xfe2d */ - "SCREEN", /* 0xfe2e */ - "POLYGON", /* 0xfe2f */ - "ELLIPSE", /* 0xfe30 */ - "VIEWPORT", /* 0xfe31 */ - "GCOPY", /* 0xfe32 */ - "PEN", /* 0xfe33 */ - "PALETTE", /* 0xfe34 */ - "DMODE", /* 0xfe35 */ - "DPAT", /* 0xfe36 */ - "PIC", /* 0xfe37 */ - "GENLOCK", /* 0xfe38 */ - "FOREGROUND", /* 0xfe39 */ - NULL, /* 0xfe3a */ - "BACKGROUND", /* 0xfe3b */ - "BORDER", /* 0xfe3c */ - "HIGHLIGHT" /* 0xfe3d */ -}; - -#endif - - - -/*************************************************************************** - COCO BASIC -***************************************************************************/ - -static const basictoken_tableent cocobas_tokenents[] = -{ - { 0x00, 0x80, cocobas_statements, ARRAY_LENGTH(cocobas_statements) }, - { 0xff, 0x80, cocobas_functions, ARRAY_LENGTH(cocobas_functions) } -}; - -static const basictokens cocobas_tokens = -{ - 0x2600, - 3, - TRUE, - cocobas_tokenents, - ARRAY_LENGTH(cocobas_tokenents) -}; - -static imgtoolerr_t cocobas_readfile(imgtool_partition *partition, const char *filename, - const char *fork, imgtool_stream *destf) -{ - return basic_readfile(&cocobas_tokens, partition, filename, fork, destf); -} - -static imgtoolerr_t cocobas_writefile(imgtool_partition *partition, const char *filename, - const char *fork, imgtool_stream *sourcef, option_resolution *opts) -{ - return basic_writefile(&cocobas_tokens, partition, filename, fork, sourcef, opts); -} - -void filter_cocobas_getinfo(UINT32 state, union filterinfo *info) -{ - switch(state) - { - case FILTINFO_STR_NAME: info->s = "cocobas"; break; - case FILTINFO_STR_HUMANNAME: info->s = "CoCo Tokenized Basic Files"; break; - case FILTINFO_PTR_READFILE: info->read_file = cocobas_readfile; break; - case FILTINFO_PTR_WRITEFILE: info->write_file = cocobas_writefile; break; - } -} - - - -/*************************************************************************** - DRAGON BASIC -***************************************************************************/ - -static const basictoken_tableent dragonbas_tokenents[] = -{ - { 0x00, 0x80, dragonbas_statements, ARRAY_LENGTH(dragonbas_statements) }, - { 0xff, 0x80, dragonbas_functions, ARRAY_LENGTH(dragonbas_functions) } -}; - -static const basictokens dragonbas_tokens = -{ - 0x2600, - 4, - TRUE, - dragonbas_tokenents, - ARRAY_LENGTH(dragonbas_tokenents) -}; - -static imgtoolerr_t dragonbas_readfile(imgtool_partition *partition, const char *filename, - const char *fork, imgtool_stream *destf) -{ - return basic_readfile(&dragonbas_tokens, partition, filename, fork, destf); -} - -static imgtoolerr_t dragonbas_writefile(imgtool_partition *partition, const char *filename, - const char *fork, imgtool_stream *sourcef, option_resolution *opts) -{ - return basic_writefile(&dragonbas_tokens, partition, filename, fork, sourcef, opts); -} - -void filter_dragonbas_getinfo(UINT32 state, union filterinfo *info) -{ - switch(state) - { - case FILTINFO_STR_NAME: info->s = "dragonbas"; break; - case FILTINFO_STR_HUMANNAME: info->s = "Dragon Tokenized Basic Files"; break; - case FILTINFO_PTR_READFILE: info->read_file = dragonbas_readfile; break; - case FILTINFO_PTR_WRITEFILE: info->write_file = dragonbas_writefile; break; - } -} - - - -/*************************************************************************** - VZBASIC -***************************************************************************/ - -static const basictoken_tableent vzbas_tokenents[] = -{ - { 0x00, 0x80, vzbas, ARRAY_LENGTH(vzbas) } -}; - - - -static const basictokens vzbas_tokens = -{ - 0x7ae9, - 0, - FALSE, - vzbas_tokenents, - ARRAY_LENGTH(vzbas_tokenents) -}; - -static imgtoolerr_t vzbas_readfile(imgtool_partition *partition, const char *filename, - const char *fork, imgtool_stream *destf) -{ - return basic_readfile(&vzbas_tokens, partition, filename, fork, destf); -} - -static imgtoolerr_t vzbas_writefile(imgtool_partition *partition, const char *filename, - const char *fork, imgtool_stream *sourcef, option_resolution *opts) -{ - return basic_writefile(&vzbas_tokens, partition, filename, fork, sourcef, opts); -} - -void filter_vzbas_getinfo(UINT32 state, union filterinfo *info) -{ - switch(state) - { - case FILTINFO_STR_NAME: info->s = "vzbas"; break; - case FILTINFO_STR_HUMANNAME: info->s = "Laser/VZ Tokenized Basic Files"; break; - case FILTINFO_PTR_READFILE: info->read_file = vzbas_readfile; break; - case FILTINFO_PTR_WRITEFILE: info->write_file = vzbas_writefile; break; - } -} - - - -/*************************************************************************** - BML3 BASIC -***************************************************************************/ - -static const basictoken_tableent bml3bas_tokenents[] = -{ - { 0x00, 0x80, bml3bas_statements, ARRAY_LENGTH(bml3bas_statements) }, - { 0xff, 0x80, bml3bas_functions, ARRAY_LENGTH(bml3bas_functions) } -}; - -static const basictokens bml3bas_tokens = -{ - 0x2600, - 3, - TRUE, - bml3bas_tokenents, - ARRAY_LENGTH(bml3bas_tokenents) -}; - -static imgtoolerr_t bml3bas_readfile(imgtool_partition *partition, const char *filename, - const char *fork, imgtool_stream *destf) -{ - return basic_readfile(&bml3bas_tokens, partition, filename, fork, destf); -} - -static imgtoolerr_t bml3bas_writefile(imgtool_partition *partition, const char *filename, - const char *fork, imgtool_stream *sourcef, option_resolution *opts) -{ - return basic_writefile(&bml3bas_tokens, partition, filename, fork, sourcef, opts); -} - -void filter_bml3bas_getinfo(UINT32 state, union filterinfo *info) -{ - switch(state) - { - case FILTINFO_STR_NAME: info->s = "bml3bas"; break; - case FILTINFO_STR_HUMANNAME: info->s = "Basic Master Level 3 Tokenized Basic Files"; break; - case FILTINFO_PTR_READFILE: info->read_file = bml3bas_readfile; break; - case FILTINFO_PTR_WRITEFILE: info->write_file = bml3bas_writefile; break; - } -} diff --git a/src/mess/tools/imgtool/filteoln.c b/src/mess/tools/imgtool/filteoln.c deleted file mode 100644 index 30fb52ed429..00000000000 --- a/src/mess/tools/imgtool/filteoln.c +++ /dev/null @@ -1,127 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/**************************************************************************** - - filteoln.c - - Native end-of-line filter - -*****************************************************************************/ - -#include <string.h> - -#include "imgtool.h" - -#define EOLN (CRLF == 1 ? "\r" : (CRLF == 2 ? "\n" : (CRLF == 3 ? "\r\n" : NULL))) - - - -static imgtoolerr_t convert_stream_eolns(imgtool_stream *source, imgtool_stream *dest, const char *eoln) -{ - size_t len, i, pos; - char buffer[2000]; - int hit_cr = FALSE; - - while((len = stream_read(source, buffer, sizeof(buffer))) > 0) - { - pos = 0; - - for (i = 0; i < len; i++) - { - switch(buffer[i]) - { - case '\r': - case '\n': - if (!hit_cr || (buffer[i] != '\n')) - { - if (i > pos) - stream_write(dest, buffer + pos, i - pos); - stream_write(dest, eoln, strlen(eoln)); - } - pos = i + 1; - break; - } - hit_cr = (buffer[i] == '\r'); - } - - if (i > pos) - stream_write(dest, buffer + pos, i - pos); - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t ascii_readfile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf) -{ - imgtoolerr_t err; - imgtool_stream *mem_stream; - - mem_stream = stream_open_mem(NULL, 0); - if (!mem_stream) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto done; - } - - err = imgtool_partition_read_file(partition, filename, fork, mem_stream, NULL); - if (err) - goto done; - - stream_seek(mem_stream, SEEK_SET, 0); - err = convert_stream_eolns(mem_stream, destf, EOLN); - if (err) - goto done; - -done: - if (mem_stream) - stream_close(mem_stream); - return err; -} - - - -static imgtoolerr_t ascii_writefile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, option_resolution *opts) -{ - imgtoolerr_t err; - imgtool_stream *mem_stream = NULL; - const char *eoln; - - /* create a stream */ - mem_stream = stream_open_mem(NULL, 0); - if (!mem_stream) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto done; - } - - eoln = imgtool_partition_get_info_string(partition, IMGTOOLINFO_STR_EOLN); - - err = convert_stream_eolns(sourcef, mem_stream, eoln); - if (err) - goto done; - stream_seek(mem_stream, SEEK_SET, 0); - - err = imgtool_partition_write_file(partition, filename, fork, mem_stream, opts, NULL); - if (err) - goto done; - -done: - if (mem_stream) - stream_close(mem_stream); - return err; -} - - - -void filter_eoln_getinfo(UINT32 state, union filterinfo *info) -{ - switch(state) - { - case FILTINFO_STR_NAME: info->s = "ascii"; break; - case FILTINFO_STR_HUMANNAME: info->s = "Ascii"; break; - case FILTINFO_PTR_READFILE: info->read_file = ascii_readfile; break; - case FILTINFO_PTR_WRITEFILE: info->write_file = ascii_writefile; break; - } -} diff --git a/src/mess/tools/imgtool/filter.c b/src/mess/tools/imgtool/filter.c deleted file mode 100644 index 5887d6b501d..00000000000 --- a/src/mess/tools/imgtool/filter.c +++ /dev/null @@ -1,82 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - filter.c - - Imgtool filters - -***************************************************************************/ - -#include <string.h> - -#include "imgtool.h" - -/* ----------------------------------------------------------------------- */ - -INT64 filter_get_info_int(filter_getinfoproc get_info, UINT32 state) -{ - union filterinfo info; - info.i = 0; - get_info(state, &info); - return info.i; -} - -void *filter_get_info_ptr(filter_getinfoproc get_info, UINT32 state) -{ - union filterinfo info; - info.p = NULL; - get_info(state, &info); - return info.p; -} - -void *filter_get_info_fct(filter_getinfoproc get_info, UINT32 state) -{ - union filterinfo info; - info.f = NULL; - get_info(state, &info); - return info.f; -} - -const char *filter_get_info_string(filter_getinfoproc get_info, UINT32 state) -{ - union filterinfo info; - info.s = NULL; - get_info(state, &info); - return info.s; -} - -/* ----------------------------------------------------------------------- */ - -const filter_getinfoproc filters[] = -{ - filter_eoln_getinfo, - filter_cocobas_getinfo, - filter_dragonbas_getinfo, - filter_macbinary_getinfo, - filter_vzsnapshot_getinfo, - filter_vzbas_getinfo, - filter_thombas5_getinfo, - filter_thombas7_getinfo, - filter_thombas128_getinfo, - filter_thomcrypt_getinfo, - filter_bml3bas_getinfo, - NULL -}; - - - -filter_getinfoproc filter_lookup(const char *name) -{ - int i; - const char *filter_name; - - for (i = 0; filters[i]; i++) - { - filter_name = filter_get_info_string(filters[i], FILTINFO_STR_NAME); - if (!strcmp(name, filter_name)) - return filters[i]; - } - - return NULL; -} diff --git a/src/mess/tools/imgtool/filter.h b/src/mess/tools/imgtool/filter.h deleted file mode 100644 index 814d813d598..00000000000 --- a/src/mess/tools/imgtool/filter.h +++ /dev/null @@ -1,66 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - filter.h - - Imgtool filters - -***************************************************************************/ - -#ifndef FILTER_H -#define FILTER_H - -#include <stdlib.h> -#include <stdio.h> - -#include "library.h" - -struct imgtool_filter; - -enum -{ - /* --- the following bits of info are returned as 64-bit signed integers --- */ - FILTINFO_INT_FIRST = 0x00000, - FILTINFO_INT_STATESIZE, - - /* --- the following bits of info are returned as pointers to data or functions --- */ - FILTINFO_PTR_FIRST = 0x10000, - FILTINFO_PTR_READFILE, - FILTINFO_PTR_WRITEFILE, - FILTINFO_PTR_CHECKSTREAM, - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - FILTINFO_STR_FIRST = 0x20000, - FILTINFO_STR_NAME, - FILTINFO_STR_HUMANNAME, - FILTINFO_STR_EXTENSION -}; - -extern const filter_getinfoproc filters[]; - -filter_getinfoproc filter_lookup(const char *name); - -/* ----------------------------------------------------------------------- */ - -INT64 filter_get_info_int(filter_getinfoproc get_info, UINT32 state); -void *filter_get_info_ptr(filter_getinfoproc get_info, UINT32 state); -void *filter_get_info_fct(filter_getinfoproc get_info, UINT32 state); -const char *filter_get_info_string(filter_getinfoproc get_info, UINT32 state); - -/* ----------------------------------------------------------------------- */ - -extern void filter_eoln_getinfo(UINT32 state, union filterinfo *info); -extern void filter_cocobas_getinfo(UINT32 state, union filterinfo *info); -extern void filter_dragonbas_getinfo(UINT32 state, union filterinfo *info); -extern void filter_macbinary_getinfo(UINT32 state, union filterinfo *info); -extern void filter_vzsnapshot_getinfo(UINT32 state, union filterinfo *info); -extern void filter_vzbas_getinfo(UINT32 state, union filterinfo *info); -extern void filter_thombas5_getinfo(UINT32 state, union filterinfo *info); -extern void filter_thombas7_getinfo(UINT32 state, union filterinfo *info); -extern void filter_thombas128_getinfo(UINT32 state, union filterinfo *info); -extern void filter_thomcrypt_getinfo(UINT32 state, union filterinfo *info); -extern void filter_bml3bas_getinfo(UINT32 state, union filterinfo *info); - - -#endif /* FILTER_H */ diff --git a/src/mess/tools/imgtool/formats/coco_dsk.c b/src/mess/tools/imgtool/formats/coco_dsk.c deleted file mode 100644 index 9674ed9de11..00000000000 --- a/src/mess/tools/imgtool/formats/coco_dsk.c +++ /dev/null @@ -1,1194 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/********************************************************************* - - formats/coco_dsk.c - - Tandy Color Computer / Dragon disk images - -*********************************************************************/ - -#include <string.h> -#include <time.h> -#include <assert.h> - -#include "formats/coco_dsk.h" -#include "formats/basicdsk.h" -#include "formats/imageutl.h" -#include "coretmpl.h" - -/* ----------------------------------------------------------------------- - * JVC (Jeff Vavasour CoCo) format - * - * Used by Jeff Vavasour's CoCo Emulators - * - * Documentation taken from Tim Linder's web site: - * http://home.netcom.com/~tlindner/JVC.html - * - * A. Header length - * The header length is determined by the file length modulo 256: - * headerSize = fileLength % 256; - * This means that the header is variable length and the minimum size - * is zero bytes, and the maximum size of 255 bytes. - * - * B. Header - * Here is a description of the header bytes: - * Byte Offset Description Default - * ----------- ----------------- ------- - * 0 Sectors per track 18 - * 1 Side count 1 - * 2 Sector size code 1 - * 3 First sector ID 1 - * 4 Sector attribute flag 0 - * - * If the sector attribute flag is zero then the track count is determined - * by the formula: - * - * (fileLength - headerSize) / (sectorsPerTrack * (128 << - * sectorSizeCode)) / sideCount - * - * If the sector attribute flag is non zero then the track count is - * determined by the more complex formula: - * - * (fileLength - headerSize) / (sectorsPerTrack * ((128 << - * sectorSizeCode) + 1) ) / sideCount - * - * If the length of the header is to short to contain the geometry desired, - * then the default values are assumed. If the header length is zero the all - * of the geometry is assumed. When creating disk images it is desirable to - * make the header length as short as possible. The header should only be - * used to deviate from the default values. - * - * The sector data begins immediately after the header. If the header length - * is zero then the sector data is at the beginning file. - * - * C. Sectors per track - * This is the number of sectors per track (ones based). A value of 18 - * means there are 18 sectors per track - * - * D. Side Count - * This is the number of sides in the disk image. Values of 1 or 2 are - * acceptable. If there are two sides then the tracks are interleaved. - * The first track in the image file is track zero side 1, the second - * track in the image file is track zero side 2. - * - * E. Sector size - * The is the same value that is stored in the wd179x ID field to - * determine sector size: - * - * 0x00 128 bytes - * 0x01 256 bytes - * 0x02 512 bytes - * 0x03 1024 bytes - * - * Other values are undefined. Every sector in the disk image must be the - * same size. - * - * F. First sector ID - * This determines the first sector ID for each track. Each successive - * sector adds one to the previous ID. If the first sector ID is 1, then - * the second sector has an ID of 2, and the third has an ID of 3. - * - * G. Sector Attribute Flag - * If this byte is non zero, then each sector contains an additional - * byte prepended to the sector data. If the attribute flag is zero then - * there are no extra bytes in front of the sector data. - * - * H. Sector attribute byte - * This byte is put at the beginning of every sector if the header flag - * is turned on. The information this byte contains is the same as the - * status register (of the wd179x) would contain when a 'Read Sector' - * command was issued. The bit fields are defined as: - * - * Bit position: - * --------------- - * 7 6 5 4 3 2 1 0 - * | | | | | | | | - * | | | | | | | +--- Not used. Set to zero. - * | | | | | | +----- Not used. Set to zero. - * | | | | | +------- Not used. Set to zero. - * | | | | +--------- Set on CRC error. - * | | | +----------- Set if sector not found. - * | | +------------- Record type: 1 - Deleted Data Mark, 0 - Data Mark. - * | +--------------- Not Used. Set to zero. - * +----------------- Not Used. Set to zero. - * - * ----------------------------------------------------------------------- */ - -static int coco_jvc_decode_header(floppy_image_legacy *floppy, UINT64 size, - struct basicdsk_geometry *geometry) -{ - UINT8 header[256]; - UINT8 sector_attribute_flag; - UINT16 physical_bytes_per_sector; - UINT32 header_size, file_size; - struct basicdsk_geometry dummy_geometry; - - if (geometry) - memset(geometry, 0, sizeof(*geometry)); - else - geometry = &dummy_geometry; - - if (size > 0xFFFFFFFF) - return -1; - file_size = (UINT32) size; - - /* read the header */ - header_size = (UINT32) file_size % 0x100; - floppy_image_read(floppy, header, 0, header_size); - geometry->offset = header_size; - - /* byte offset 0 - sectors per track */ - geometry->sectors = (header_size > 0) ? header[0] : 18; - if (geometry->sectors <= 0) - return -1; - - /* byte offset 1 - side count */ - geometry->heads = (header_size > 1) ? header[1] : 1; - if (geometry->heads <= 0) - return -1; - - /* byte offset 2 - sector size code */ - geometry->sector_length = 128 << ((header_size > 2) ? header[2] : 1); - if (geometry->sector_length <= 0) - return -1; - - /* byte offset 3 - first sector ID */ - geometry->first_sector_id = (header_size > 3) ? header[3] : 1; - - /* byte offset 4 - sector attribute flag */ - sector_attribute_flag = (header_size > 4) ? header[4] : 0; - if (sector_attribute_flag != 0) - return -1; /* we do not support sector attribute flags */ - - physical_bytes_per_sector = geometry->sector_length; - if (sector_attribute_flag) - physical_bytes_per_sector++; - - geometry->tracks = (file_size - header_size) / geometry->sectors / geometry->heads / physical_bytes_per_sector; - - /* do we have an oddball size? reject this file if not */ - if ((file_size - header_size) % physical_bytes_per_sector) - return -1; - - /* minimum of 35 tracks; support degenerate JVC files */ - if (geometry->tracks < 35) - geometry->tracks = 35; - - return 0; -} - - - -static FLOPPY_IDENTIFY(coco_jvc_identify) -{ - UINT64 size; - size = floppy_image_size(floppy); - *vote = coco_jvc_decode_header(floppy, size, NULL) ? 0 : 100; - return FLOPPY_ERROR_SUCCESS; -} - - - -static FLOPPY_CONSTRUCT(coco_jvc_construct) -{ - struct basicdsk_geometry geometry; - UINT8 header[5]; - size_t header_size; - - if (params) - { - /* create */ - memset(&geometry, 0, sizeof(geometry)); - geometry.heads = option_resolution_lookup_int(params, PARAM_HEADS); - geometry.tracks = option_resolution_lookup_int(params, PARAM_TRACKS); - geometry.sectors = option_resolution_lookup_int(params, PARAM_SECTORS); - geometry.first_sector_id = option_resolution_lookup_int(params, PARAM_FIRST_SECTOR_ID); - geometry.sector_length = option_resolution_lookup_int(params, PARAM_SECTOR_LENGTH); - - header[0] = (UINT8) geometry.sectors; - header[1] = (UINT8) geometry.heads; - header[2] = (UINT8) compute_log2(geometry.sector_length) - 7; - header[3] = (UINT8) geometry.first_sector_id; - header[4] = 0; - - /* now that we have the header computed, figure out the header size */ - header_size = 0; - if (header[0] != 18) - header_size = 1; - if (header[1] != 1) - header_size = 2; - if (header[2] != 1) - header_size = 3; - if (header[3] != 1) - header_size = 4; - if (header[4] != 0) - header_size = 5; - - geometry.offset = header_size; - - floppy_image_write(floppy, header, 0, header_size); - } - else - { - /* load */ - if (coco_jvc_decode_header(floppy, floppy_image_size(floppy), &geometry)) - return FLOPPY_ERROR_INVALIDIMAGE; - } - return basicdsk_construct(floppy, &geometry); -} - - -/* ----------------------------------------------------------------------- - * OS-9 file format - * - * This file format is largely a hack because there are a large amount of - * disk images that do not have geometry image separate from the disk image - * itself. So we support OS-9 images with are simply basic disks whose - * geometry is determined by the disk image. - * - * OS-9 images identified by an LSN; which are simply blocks of 256 bytes - * - * LSN0 - * Byte size use - * $00 3 sectors on disk - * $03 1 track size in sectors - * $04 2 bytes in allocation bit map; typically 1bit/sector so for - * 35 tracks of 18 sectors each that's $4E (single sided disk) - * 40 tracks per side, 18 sectors each = $B4 - * $06 2 sectors per bit in allocation map; normally 1 - * $08 3 LSN of root directory; normally 2 but depends on size of - * $04 value - * $0B 2 owner's user number; normally 0 - * $0D 1 disk attributes; normally $FF - * $0E 2 psuedo random number for identification - * $10 1 disk format; typical is 3 - * %00000001 0=single side 1=double side - * %00000010 0=single density (non Coco) 1=double density - * %00000100 0=48tracks/inch 1=96tracks/inch - * $11 2 sectors per track; normal is $12 skip several not needed - * for Format - * $1A 5 date of creation Y:M:D:H:M - * $1F 32 ASCII name of disk, last letter has $80 added to it, - * the full 32 bytes do not need to be used. - * - * Allocation bit map, fill with zeros and set bits from low to high as - * sectors are used. So, for a fresh disk sectors LSN0,LSN1,LSN2, and LSN3 - * will be in use so the first byte will be $FF $C0 and all others - * in the map are $00 - * - * Root directory LSN2 - * Byte size use - * $00 1 attributes will be $BF - * $01 2 owners ID will be $0000 - * $03 5 date last modified will be creation date Y:M:D:H:M - * $08 1 link count; set to $02 - * $09 4 file size in bytes, set to $40 - * $0D 3 date created Y:M:D - * $10 3 block LSN set to current sector number+1 ie $03 in this case - * $13 2 size in sectors of directory block, set to $07 - * All other bytes in sector set to $00 - * LSN3 first sector of directory with names - * Fill sector with all $00 and then set listed bytes - * $00 2 value $2EAE which is .. with last byte+$80 - * $1F 1 value $02 LSN for start of this directory as there is - * none higher in tree - * $20 1 value $AE which is . with $80 added - * $3F 1 value $02 LSN for start of this directory - * ----------------------------------------------------------------------- */ - -static floperr_t coco_os9_readheader(floppy_image_legacy *floppy, struct basicdsk_geometry *geometry) -{ - UINT8 header[0x20]; - int total_sectors; - - floppy_image_read(floppy, header, 0, sizeof(header)); - - total_sectors = (header[0x00] << 16) | (header[0x01] << 8) | header[0x02]; - - memset(geometry, 0, sizeof(*geometry)); - geometry->first_sector_id = 1; - geometry->sector_length = 256; - geometry->sectors = (header[0x11] << 8) + header[0x12]; - geometry->heads = (header[0x10] & 0x01) ? 2 : 1; - - if (!geometry->sectors) - return FLOPPY_ERROR_INVALIDIMAGE; - - geometry->tracks = total_sectors / geometry->sectors / geometry->heads; - - if (total_sectors != geometry->tracks * geometry->sectors * geometry->heads) - return FLOPPY_ERROR_INVALIDIMAGE; - - return FLOPPY_ERROR_SUCCESS; -} - - - -static floperr_t coco_os9_post_format(floppy_image_legacy *floppy, option_resolution *params) -{ - UINT8 header[0x0400]; - floperr_t err; - time_t t; - struct tm *ltime; - int heads, tracks, sectors, total_sectors; - - heads = option_resolution_lookup_int(params, PARAM_HEADS); - tracks = option_resolution_lookup_int(params, PARAM_TRACKS); - sectors = option_resolution_lookup_int(params, PARAM_SECTORS); - total_sectors = heads * tracks * sectors; - - /* write the initial header */ - time(&t); - ltime = localtime(&t); - - memset(&header, 0, sizeof(header)); - header[0x0000] = (UINT8) (total_sectors >> 16); - header[0x0001] = (UINT8) (total_sectors >> 8); - header[0x0002] = (UINT8) (total_sectors >> 0); - header[0x0003] = (UINT8) sectors; - header[0x0004] = (UINT8) (((total_sectors + 7) / 8) >> 8); - header[0x0005] = (UINT8) (((total_sectors + 7) / 8) >> 0); - header[0x0006] = 0x00; - header[0x0007] = 0x01; - header[0x0008] = 0x00; - header[0x0009] = 0x00; - header[0x000a] = 0x02; - header[0x000b] = 0x00; - header[0x000c] = 0x00; - header[0x000d] = 0xff; - header[0x000e] = floppy_random_byte(floppy); - header[0x000f] = floppy_random_byte(floppy); - header[0x0010] = (heads == 2) ? 3 : 2; - header[0x0011] = (UINT8) (sectors >> 8); - header[0x0012] = (UINT8) (sectors >> 0); - header[0x001A] = (UINT8) ltime->tm_year; - header[0x001B] = (UINT8) ltime->tm_mon + 1; - header[0x001C] = (UINT8) ltime->tm_mday; - header[0x001D] = (UINT8) ltime->tm_hour; - header[0x001E] = (UINT8) ltime->tm_min; - header[0x001F] = 0xA0; - header[0x0100] = 0xFF; - header[0x0101] = 0xC0; - header[0x0200] = 0xBF; - header[0x0201] = 0x00; - header[0x0202] = 0x00; - header[0x0203] = (UINT8) ltime->tm_year; - header[0x0204] = (UINT8) ltime->tm_mon + 1; - header[0x0205] = (UINT8) ltime->tm_mday; - header[0x0206] = (UINT8) ltime->tm_hour; - header[0x0207] = (UINT8) ltime->tm_min; - header[0x0208] = 0x02; - header[0x0209] = 0x00; - header[0x020A] = 0x00; - header[0x020B] = 0x00; - header[0x020C] = 0x40; - header[0x020D] = (UINT8) (ltime->tm_year % 100); - header[0x020E] = (UINT8) ltime->tm_mon; - header[0x020F] = (UINT8) ltime->tm_mday; - header[0x0210] = 0x00; - header[0x0211] = 0x00; - header[0x0212] = 0x03; - header[0x0213] = 0x00; - header[0x0214] = 0x07; - header[0x0300] = 0x2E; - header[0x0301] = 0xAE; - header[0x031F] = 0x02; - header[0x0320] = 0xAE; - header[0x033F] = 0x02; - - if (total_sectors % 8) - header[0x0100 + (total_sectors / 8)] = 0xFF >> (total_sectors % 8); - - err = floppy_write_sector(floppy, 0, 0, 1, 0, &header[0x0000], 256, 0); - if (err) - return err; - - err = floppy_write_sector(floppy, 0, 0, 2, 0, &header[0x0100], 256, 0); - if (err) - return err; - - err = floppy_write_sector(floppy, 0, 0, 3, 0, &header[0x0200], 256, 0); - if (err) - return err; - - err = floppy_write_sector(floppy, 0, 0, 4, 0, &header[0x0300], 256, 0); - if (err) - return err; - - return FLOPPY_ERROR_SUCCESS; -} - - - -static FLOPPY_IDENTIFY(coco_os9_identify) -{ - struct basicdsk_geometry geometry; - *vote = coco_os9_readheader(floppy, &geometry) ? 0 : 100; - return FLOPPY_ERROR_SUCCESS; -} - - - -static FLOPPY_CONSTRUCT(coco_os9_construct) -{ - floperr_t err; - struct basicdsk_geometry geometry; - - if (params) - { - /* create */ - memset(&geometry, 0, sizeof(geometry)); - geometry.heads = option_resolution_lookup_int(params, PARAM_HEADS); - geometry.tracks = option_resolution_lookup_int(params, PARAM_TRACKS); - geometry.sectors = option_resolution_lookup_int(params, PARAM_SECTORS); - geometry.first_sector_id = option_resolution_lookup_int(params, PARAM_FIRST_SECTOR_ID); - geometry.sector_length = option_resolution_lookup_int(params, PARAM_SECTOR_LENGTH); - } - else - { - /* open */ - err = coco_os9_readheader(floppy, &geometry); - if (err) - return err; - } - - /* actually construct the image */ - err = basicdsk_construct(floppy, &geometry); - floppy_callbacks(floppy)->post_format = coco_os9_post_format; - return err; -} - - - -/* ----------------------------------------------------------------------- - * VDK file format - * - * Used by Paul Burgin's PC-Dragon emulator - * - * Offset Bytes Field Description - * ------ ----- ------------ ----------- - * 0 1 magic1 Signature byte 1 ('d') - * 1 1 magic2 Signature byte 2 ('k') - * 2 2 header_len Total header length (little endian) - * 4 1 ver_actual Version of the VDK format (0x10) - * 5 1 ver_compat Backwards compatibility version (0x10) - * 6 1 source_id Identify of the file source - * 7 1 source_ver Version of the file source - * 8 1 tracks Number of tracks - * 9 1 sides Number of sides (1-2) - * 10 1 flags Various flags - * bit 0: Write protect - * bit 1: A Lock - * bit 2: F Lock - * bit 3: Disk set - * 11 1 compression Compression flags (bits 0-2) and name length - * ----------------------------------------------------------------------- */ - - - -static int coco_vdk_decode_header(floppy_image_legacy *floppy, struct basicdsk_geometry *geometry) -{ - UINT8 header[12]; - UINT8 heads, tracks, sectors; - UINT16 sector_length, offset; - UINT64 size; - - size = floppy_image_size(floppy); - - floppy_image_read(floppy, header, 0, sizeof(header)); - - if (header[0] != 'd') - return -1; - if (header[1] != 'k') - return -1; - if (header[5] != 0x10) - return -1; - if (header[11] & 0x07) - return -1; - - heads = header[9]; - tracks = header[8]; - sectors = 18; - sector_length = 0x100; - - offset = header[3] * 0x100 + header[2]; - - if (size != ((UINT32) heads * tracks * sectors * sector_length + offset)) - return -1; - - if (geometry) - { - memset(geometry, 0, sizeof(*geometry)); - geometry->heads = heads; - geometry->tracks = tracks; - geometry->sectors = sectors; - geometry->first_sector_id = 1; - geometry->sector_length = sector_length; - geometry->offset = offset; - } - return 0; -} - - - -static FLOPPY_IDENTIFY(coco_vdk_identify) -{ - *vote = coco_vdk_decode_header(floppy, NULL) ? 0 : 100; - return FLOPPY_ERROR_SUCCESS; -} - - - -static FLOPPY_CONSTRUCT(coco_vdk_construct) -{ - struct basicdsk_geometry geometry; - UINT8 header[12]; - - if (params) - { - /* create */ - memset(&geometry, 0, sizeof(geometry)); - geometry.heads = option_resolution_lookup_int(params, PARAM_HEADS); - geometry.tracks = option_resolution_lookup_int(params, PARAM_TRACKS); - geometry.sectors = 18; - geometry.first_sector_id = 1; - geometry.sector_length = 256; - geometry.offset = sizeof(header); - - memset(&header, 0, sizeof(header)); - header[0] = 'd'; - header[1] = 'k'; - header[2] = (UINT8) (sizeof(header) >> 0); - header[3] = (UINT8) (sizeof(header) >> 8); - header[4] = 0x10; - header[5] = 0x10; - header[8] = (UINT8) geometry.tracks; - header[9] = (UINT8) geometry.heads; - - floppy_image_write(floppy, header, 0, sizeof(header)); - } - else - { - /* load */ - if (coco_vdk_decode_header(floppy, &geometry)) - return FLOPPY_ERROR_INVALIDIMAGE; - } - return basicdsk_construct(floppy, &geometry); -} - - - -/* ----------------------------------------------------------------------- - * DMK file format - * - * David M. Keil's disk image format is aptly called an 'on disk' image - * format. This means that whatever written to the disk is enocded into - * the image file. IDAMS, sector headers, traling CRCs, and intra sector - * spacing. * - * - * HEADER DESCRIPTION: - * - * Offset Bytes Field Description - * ------ ----- ------------ ----------- - * 0 1 write_prot 0xff = Writed Protected, 0x00 = R/W - * 1 1 tracks Number of tracks - * 2 2 track_length Bytes per track (little endian) - * 4 1 disk_options Miscellaneous flags - * bit 0-3: Unused - * bit 4: 1=single sided 0=dbl - * bit 5: Unused - * bit 6: Single density? - * bit 6: Ignore density flags? - * 5 7 reserved Reserved for future use - * 12 4 real_disk_code If this is 0x12345678 (little endian) - * then access a real disk drive - * (unsupported) - * - * Each track begins with a track TOC, consisting of 64 little endian 16-bit - * integers. Each integer has the following format: - * bit 0-13: Offset from beginning of track to 'FE' byte of IDAM - * Note these are always sorted from first to last. All empty - * entries are 0x00 - * bit 14: Undefined (reserved) - * bit 15: Sector double density (0=SD 1=DD) - * ----------------------------------------------------------------------- */ - -struct dmk_tag -{ - int heads; - int tracks; - UINT32 track_size; -}; - -#define DMK_HEADER_LEN 16 -#define DMK_TOC_LEN 64 -#define DMK_IDAM_LENGTH 7 -#define DMK_DATA_GAP 80 -#define DMK_LEAD_IN 32 -#define DMK_EXTRA_TRACK_LENGTH 156 - -#define dmk_idam_type(x) (x)[0] -#define dmk_idam_track(x) (x)[1] -#define dmk_idam_side(x) (x)[2] -#define dmk_idam_sector(x) (x)[3] -#define dmk_idam_sectorlength(x) (x)[4] -#define dmk_idam_crc(x) (((x)[5] << 8) + (x)[6]) -#define dmk_idam_set_crc(x, crc) (x)[5] = ((crc) >> 8); (x)[6] = ((crc) >> 0); - - -static struct dmk_tag *get_dmk_tag(floppy_image_legacy *floppy) -{ - return (dmk_tag *)floppy_tag(floppy); -} - - -static floperr_t coco_dmk_get_offset(floppy_image_legacy *floppy, int head, int track, UINT64 *offset) -{ - struct dmk_tag *tag = get_dmk_tag(floppy); - - if ((head < 0) || (head >= tag->heads) || (track < 0) || (track >= tag->tracks)) - return FLOPPY_ERROR_SEEKERROR; - - *offset = track; - *offset *= tag->heads; - *offset += head; - *offset *= tag->track_size; - *offset += DMK_HEADER_LEN; - return FLOPPY_ERROR_SUCCESS; -} - - - -static UINT32 coco_dmk_min_track_size(int sectors, int sector_length) -{ - int sector_physical_length; - sector_physical_length = 8 + 3 + DMK_IDAM_LENGTH + 22 + 12 + 3 + 1 + sector_length + 2 + 24; - return DMK_TOC_LEN * 2 + DMK_LEAD_IN + (sectors * sector_physical_length); -} - - - -static floperr_t coco_dmk_read_track(floppy_image_legacy *floppy, int head, int track, UINT64 offset, void *buffer, size_t buflen) -{ - floperr_t err; - UINT64 track_offset; - - err = coco_dmk_get_offset(floppy, head, track, &track_offset); - if (err) - return err; - - floppy_image_read(floppy, buffer, offset + track_offset, buflen); - return FLOPPY_ERROR_SUCCESS; -} - - - -static floperr_t coco_dmk_write_track(floppy_image_legacy *floppy, int head, int track, UINT64 offset, const void *buffer, size_t buflen) -{ - floperr_t err; - UINT64 track_offset; - - err = coco_dmk_get_offset(floppy, head, track, &track_offset); - if (err) - return err; - - floppy_image_write(floppy, buffer, offset + track_offset, buflen); - return FLOPPY_ERROR_SUCCESS; -} - - - -static floperr_t coco_dmk_get_track_data_offset(floppy_image_legacy *floppy, int head, int track, UINT64 *offset) -{ - *offset = DMK_TOC_LEN + 1; - return FLOPPY_ERROR_SUCCESS; -} - - - -static floperr_t coco_dmk_format_track(floppy_image_legacy *floppy, int head, int track, option_resolution *params) -{ - int sectors; - int sector_length; - int interleave; - int first_sector_id; - floperr_t err; - int physical_sector; - int logical_sector; - int track_position; - UINT16 idam_offset; - UINT16 crc; - UINT8 *track_data; - void *track_data_v; - UINT32 max_track_size; - std::vector<int> sector_map; - - sectors = option_resolution_lookup_int(params, PARAM_SECTORS); - sector_length = option_resolution_lookup_int(params, PARAM_SECTOR_LENGTH); - interleave = option_resolution_lookup_int(params, PARAM_INTERLEAVE); - first_sector_id = option_resolution_lookup_int(params, PARAM_FIRST_SECTOR_ID); - - max_track_size = get_dmk_tag(floppy)->track_size; - - if (sectors > DMK_TOC_LEN) - { - err = FLOPPY_ERROR_INTERNAL; - goto done; - } - - if (max_track_size < coco_dmk_min_track_size(sectors, sector_length)) - { - err = FLOPPY_ERROR_NOSPACE; - goto done; - } - - err = floppy_load_track(floppy, head, track, TRUE, &track_data_v, NULL); - if (err) - goto done; - track_data = (UINT8 *) track_data_v; - - /* set up sector map */ - memset(§or_map[0], 0xff, sectors*sizeof(int)); - - physical_sector = 0; - for (logical_sector = 0; logical_sector < sectors; logical_sector++) - { - while(sector_map[physical_sector] >= 0) - { - physical_sector++; - physical_sector %= sectors; - } - - sector_map[physical_sector] = logical_sector + first_sector_id; - physical_sector += interleave + 1; - physical_sector %= sectors; - } - - /* set up track table of contents */ - physical_sector = 0; - track_position = DMK_TOC_LEN * 2 + DMK_LEAD_IN; - while(physical_sector < DMK_TOC_LEN) - { - if (physical_sector >= sectors) - { - /* no more sectors */ - idam_offset = 0; - } - else - { - /* this is a sector */ - logical_sector = sector_map[physical_sector]; - - /* write the sector */ - memset(&track_data[track_position], 0x00, 8); - track_position += 8; - - memset(&track_data[track_position], 0xA1, 3); - track_position += 3; - - idam_offset = track_position | 0x8000; - dmk_idam_type( &track_data[track_position]) = 0xFE; - dmk_idam_track( &track_data[track_position]) = track; - dmk_idam_side( &track_data[track_position]) = head; - dmk_idam_sector( &track_data[track_position]) = logical_sector; - dmk_idam_sectorlength( &track_data[track_position]) = compute_log2(sector_length / 128); - crc = ccitt_crc16(0xcdb4, &track_data[track_position], DMK_IDAM_LENGTH - 2); - dmk_idam_set_crc( &track_data[track_position], crc); - track_position += DMK_IDAM_LENGTH; - - memset(&track_data[track_position], 0x4E, 22); - track_position += 22; - - memset(&track_data[track_position], 0x00, 12); - track_position += 12; - - memset(&track_data[track_position], 0xA1, 3); - track_position += 3; - - /* write sector body */ - track_data[track_position] = 0xFB; - memset(&track_data[track_position + 1], floppy_get_filler(floppy), sector_length); - crc = ccitt_crc16(0xcdb4, &track_data[track_position], sector_length + 1); - track_data[track_position + sector_length + 1] = (UINT8) (crc >> 8); - track_data[track_position + sector_length + 2] = (UINT8) (crc >> 0); - track_position += sector_length + 3; - - /* write sector footer */ - memset(&track_data[track_position], 0x4E, 24); - track_position += 24; - } - - /* write the TOC entry */ - track_data[physical_sector * 2 + 0] = (UINT8) (idam_offset >> 0); - track_data[physical_sector * 2 + 1] = (UINT8) (idam_offset >> 8); - - physical_sector++; - } - - /* write track lead in */ - memset(&track_data[physical_sector * 2], 0x4e, DMK_LEAD_IN); - - /* write track footer */ - assert(max_track_size >= (UINT32)track_position); - memset(&track_data[track_position], 0x4e, max_track_size - track_position); - -done: - return err; -} - - - -static int coco_dmk_get_heads_per_disk(floppy_image_legacy *floppy) -{ - return get_dmk_tag(floppy)->heads; -} - - - -static int coco_dmk_get_tracks_per_disk(floppy_image_legacy *floppy) -{ - return get_dmk_tag(floppy)->tracks; -} - - - -static UINT32 coco_dmk_get_track_size(floppy_image_legacy *floppy, int head, int track) -{ - return get_dmk_tag(floppy)->track_size; -} - - - -static floperr_t coco_dmk_seek_sector_in_track(floppy_image_legacy *floppy, int head, int track, int sector, int sector_is_index, int dirtify, UINT8 **sector_data, UINT32 *sector_length) -{ - struct dmk_tag *tag = get_dmk_tag(floppy); - floperr_t err; - UINT32 idam_offset = 0; - UINT16 calculated_crc; - size_t i; - size_t offs; - int state; - UINT8 *track_data; - void *track_data_v; - size_t track_length; - size_t sec_len; - - err = floppy_load_track(floppy, head, track, dirtify, &track_data_v, &track_length); - if (err) - return err; - track_data = (UINT8 *) track_data_v; - - /* search for matching IDAM */ - for (i = 0; i < DMK_TOC_LEN; i++) - { - idam_offset = track_data[i * 2 + 1]; - idam_offset <<= 8; - idam_offset |= track_data[i * 2 + 0]; - idam_offset &= 0x3FFF; - - if (idam_offset == 0) - { - /* we've reached the end of the road */ - i = DMK_TOC_LEN; - break; - } - - if ((idam_offset + DMK_IDAM_LENGTH) >= tag->track_size) - continue; - - calculated_crc = ccitt_crc16(0xCDB4, &track_data[idam_offset], DMK_IDAM_LENGTH - 2); - - if (calculated_crc == dmk_idam_crc(&track_data[idam_offset])) - { - if (sector_is_index) - { - /* the sector is indexed; decrement the index and go */ - if (sector-- == 0) - break; - } - else - { - /* check IDAM integrity and check for matching sector */ - if (sector == dmk_idam_sector(&track_data[idam_offset]) -/* && (track == dmk_idam_track(&track_data[idam_offset])) */ -/* && (head == dmk_idam_side(&track_data[idam_offset])) */ - ) - break; - } - } - } - - if (i >= DMK_TOC_LEN) - return FLOPPY_ERROR_SEEKERROR; - - /* we found a matching sector ID */ - state = 0; - offs = idam_offset + DMK_IDAM_LENGTH; - - /* find pattern 0xA1A1FB; this represents the start of a data sector */ - for (i = 0; i < DMK_DATA_GAP; i++) - { - /* overflowing the track? */ - if ((i + offs) >= tag->track_size) - return FLOPPY_ERROR_SEEKERROR; - - if (track_data[offs + i] == 0xA1) - state++; - else if ((track_data[offs + i] == 0xFB) && state) - break; - else - state = 0; - } - if (i >= DMK_DATA_GAP) - return FLOPPY_ERROR_SEEKERROR; - - offs += i + 1; - sec_len = 128 << dmk_idam_sectorlength(&track_data[idam_offset]); - - if ((offs + sec_len) > track_length) - return FLOPPY_ERROR_INVALIDIMAGE; - - if (sector_data) - *sector_data = track_data + offs; - if (sector_length) - *sector_length = sec_len; - return FLOPPY_ERROR_SUCCESS; -} - - - -static floperr_t coco_dmk_get_sector_length(floppy_image_legacy *floppy, int head, int track, int sector, UINT32 *sector_length) -{ - return coco_dmk_seek_sector_in_track(floppy, head, track, sector, FALSE, FALSE, NULL, sector_length); -} - - - -static floperr_t coco_dmk_get_indexed_sector_info(floppy_image_legacy *floppy, int head, int track, int sector_index, int *cylinder, int *side, int *sector, UINT32 *sector_length, unsigned long *flags) -{ - floperr_t err; - UINT32 idam_offset; - const UINT8 *track_data; - void *track_data_v; - - if (sector_index*2 >= DMK_TOC_LEN) - return FLOPPY_ERROR_SEEKERROR; - - err = floppy_load_track(floppy, head, track, FALSE, &track_data_v, NULL); - if (err) - return err; - track_data = (UINT8 *) track_data_v; - - idam_offset = track_data[sector_index * 2 + 1]; - idam_offset <<= 8; - idam_offset |= track_data[sector_index * 2 + 0]; - idam_offset &= 0x3FFF; - - if (idam_offset == 0) - return FLOPPY_ERROR_SEEKERROR; - - if (cylinder) - *cylinder = dmk_idam_track(&track_data[idam_offset]); - if (side) - *side = dmk_idam_side(&track_data[idam_offset]); - if (sector) - *sector = dmk_idam_sector(&track_data[idam_offset]); - if (sector_length) - *sector_length = 128 << dmk_idam_sectorlength(&track_data[idam_offset]); - if (flags) - /* TODO: read DAM or DDAM and determine flags */ - *flags = 0; - return FLOPPY_ERROR_SUCCESS; -} - - - -static floperr_t internal_coco_dmk_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, int sector_is_index, void *buffer, size_t buflen) -{ - floperr_t err; - UINT32 sector_length; - UINT16 crc_on_disk; - UINT16 calculated_crc; - UINT8 *sector_data; - - err = coco_dmk_seek_sector_in_track(floppy, head, track, sector, sector_is_index, FALSE, §or_data, §or_length); - if (err) - return err; - - crc_on_disk = sector_data[sector_length + 0]; - crc_on_disk <<= 8; - crc_on_disk += sector_data[sector_length + 1]; - - calculated_crc = ccitt_crc16(0xE295, sector_data, sector_length); - if (calculated_crc != crc_on_disk) - return FLOPPY_ERROR_INVALIDIMAGE; - - memcpy(buffer, sector_data, MIN(sector_length, buflen)); - - return FLOPPY_ERROR_SUCCESS; -} - - - -static floperr_t internal_coco_dmk_write_sector(floppy_image_legacy *floppy, int head, int track, int sector, int sector_is_index, const void *buffer, size_t buflen, int ddam) -{ - floperr_t err; - UINT32 sector_length; - UINT8 *sector_data; - UINT16 crc; - - err = coco_dmk_seek_sector_in_track(floppy, head, track, sector, sector_is_index, TRUE, §or_data, §or_length); - if (err) - return err; - - if (buflen > sector_length) - return FLOPPY_ERROR_INTERNAL; - - memcpy(sector_data, buffer, buflen); - - crc = ccitt_crc16(0xE295, sector_data, sector_length); - sector_data[sector_length + 0] = crc >> 8; - sector_data[sector_length + 1] = crc >> 0; - return FLOPPY_ERROR_SUCCESS; -} - - - -static floperr_t coco_dmk_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen) -{ - return internal_coco_dmk_read_sector(floppy, head, track, sector, FALSE, buffer, buflen); -} - -static floperr_t coco_dmk_write_sector(floppy_image_legacy *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam) -{ - return internal_coco_dmk_write_sector(floppy, head, track, sector, FALSE, buffer, buflen, ddam); -} - -static floperr_t coco_dmk_read_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen) -{ - return internal_coco_dmk_read_sector(floppy, head, track, sector, TRUE, buffer, buflen); -} - -static floperr_t coco_dmk_write_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam) -{ - return internal_coco_dmk_write_sector(floppy, head, track, sector, TRUE, buffer, buflen, ddam); -} - - - -static void coco_dmk_interpret_header(floppy_image_legacy *floppy, int *heads, int *tracks, int *track_size) -{ - UINT8 header[DMK_HEADER_LEN]; - - floppy_image_read(floppy, header, 0, DMK_HEADER_LEN); - - if (tracks) - *tracks = header[1]; - if (heads) - *heads = (header[4] & 0x10) ? 1 : 2; - if (track_size) - *track_size = ((int) header[3]) * 0x100 + header[2]; -} - - - -FLOPPY_CONSTRUCT(coco_dmk_construct) -{ - struct FloppyCallbacks *callbacks; - struct dmk_tag *tag; - UINT8 header[DMK_HEADER_LEN]; - int heads, tracks, track_size, sectors, sector_length; - - if (params) - { - heads = option_resolution_lookup_int(params, PARAM_HEADS); - tracks = option_resolution_lookup_int(params, PARAM_TRACKS); - sectors = option_resolution_lookup_int(params, PARAM_SECTORS); - sector_length = option_resolution_lookup_int(params, PARAM_SECTOR_LENGTH); - - track_size = coco_dmk_min_track_size(sectors, sector_length) + DMK_EXTRA_TRACK_LENGTH; - - memset(header, 0, sizeof(header)); - header[1] = tracks; - header[2] = track_size >> 0; - header[3] = track_size >> 8; - header[4] = (heads == 2) ? 0x00 : 0x10; - - floppy_image_write(floppy, header, 0, sizeof(header)); - } - else - { - coco_dmk_interpret_header(floppy, &heads, &tracks, &track_size); - } - - tag = (dmk_tag *)floppy_create_tag(floppy, sizeof(struct dmk_tag)); - if (!tag) - return FLOPPY_ERROR_OUTOFMEMORY; - tag->heads = heads; - tag->track_size = track_size; - tag->tracks = tracks; - - callbacks = floppy_callbacks(floppy); - callbacks->read_track = coco_dmk_read_track; - callbacks->write_track = coco_dmk_write_track; - callbacks->get_track_data_offset = coco_dmk_get_track_data_offset; - callbacks->format_track = coco_dmk_format_track; - callbacks->get_heads_per_disk = coco_dmk_get_heads_per_disk; - callbacks->get_tracks_per_disk = coco_dmk_get_tracks_per_disk; - callbacks->get_track_size = coco_dmk_get_track_size; - callbacks->get_sector_length = coco_dmk_get_sector_length; - callbacks->get_indexed_sector_info = coco_dmk_get_indexed_sector_info; - callbacks->read_sector = coco_dmk_read_sector; - callbacks->write_sector = coco_dmk_write_sector; - callbacks->read_indexed_sector = coco_dmk_read_indexed_sector; - callbacks->write_indexed_sector = coco_dmk_write_indexed_sector; - - return FLOPPY_ERROR_SUCCESS; -} - - - -FLOPPY_IDENTIFY(coco_dmk_identify) -{ - int heads, tracks, track_size; - UINT64 size, expected_size; - - size = floppy_image_size(floppy); - coco_dmk_interpret_header(floppy, &heads, &tracks, &track_size); - expected_size = DMK_HEADER_LEN + (heads * tracks * track_size); - *vote = (size == expected_size) ? 100 : 0; - return FLOPPY_ERROR_SUCCESS; -} - - - -/* ----------------------------------------------------------------------- */ - -LEGACY_FLOPPY_OPTIONS_START( coco ) - LEGACY_FLOPPY_OPTION( coco_jvc, "dsk", "CoCo JVC disk image", coco_jvc_identify, coco_jvc_construct, NULL, - HEADS([1]-2) - TRACKS([35]-255) - SECTORS(1-[18]-255) - SECTOR_LENGTH(128/[256]/512/1024) - FIRST_SECTOR_ID(0-[1])) - LEGACY_FLOPPY_OPTION( coco_os9, "os9", "CoCo OS-9 disk image", coco_os9_identify, coco_os9_construct, NULL, - HEADS([1]-2) - TRACKS([35]-255) - SECTORS(1-[18]-255) - SECTOR_LENGTH([256]) - FIRST_SECTOR_ID([1])) - LEGACY_FLOPPY_OPTION( coco_vdk, "vdk", "CoCo VDK disk image", coco_vdk_identify, coco_vdk_construct, NULL, - HEADS([1]-2) - TRACKS([35]-255) - SECTORS([18]) - SECTOR_LENGTH([256]) - FIRST_SECTOR_ID([1])) - LEGACY_FLOPPY_OPTION( coco_dmk, "dsk,dmk", "CoCo DMK disk image", coco_dmk_identify, coco_dmk_construct, NULL, - HEADS([1]-2) - TRACKS([35]-255) - SECTORS(1-[18]) - SECTOR_LENGTH(128/[256]/512/1024/2048/4096/8192) - INTERLEAVE(0-[6]-17) - FIRST_SECTOR_ID(0-[1])) -LEGACY_FLOPPY_OPTIONS_END diff --git a/src/mess/tools/imgtool/formats/coco_dsk.h b/src/mess/tools/imgtool/formats/coco_dsk.h deleted file mode 100644 index 797911d40a1..00000000000 --- a/src/mess/tools/imgtool/formats/coco_dsk.h +++ /dev/null @@ -1,24 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/********************************************************************* - - formats/coco_dsk.h - - Tandy Color Computer / Dragon disk images - -*********************************************************************/ - -#ifndef COCO_DSK_H -#define COCO_DSK_H - -#include "formats/flopimg.h" - - -/**************************************************************************/ - -LEGACY_FLOPPY_OPTIONS_EXTERN(coco); - -FLOPPY_IDENTIFY(coco_dmk_identify); -FLOPPY_CONSTRUCT(coco_dmk_construct); - -#endif /* COCO_DSK_H */ diff --git a/src/mess/tools/imgtool/formats/vt_dsk.c b/src/mess/tools/imgtool/formats/vt_dsk.c deleted file mode 100644 index 4e75e843d28..00000000000 --- a/src/mess/tools/imgtool/formats/vt_dsk.c +++ /dev/null @@ -1,57 +0,0 @@ -// license:GPL-2.0+ -// copyright-holders:Juergen Buchmueller -/********************************************************************* - - formats/vt_dsk.c - - VTech Laser/VZ disk images - -*********************************************************************/ - -#include <stdio.h> -#include <string.h> -#include <assert.h> -#include "formats/vt_dsk.h" -#include "formats/basicdsk.h" - -static FLOPPY_IDENTIFY(vz_identify) -{ - UINT64 size = floppy_image_size(floppy); - *vote = ((size == 98560) || (size == 99200) || (size == 99184)) ? 100 : 0; - return FLOPPY_ERROR_SUCCESS; -} - -static FLOPPY_CONSTRUCT(vz_construct) -{ - struct basicdsk_geometry geometry; - memset(&geometry, 0, sizeof(geometry)); - - if (params) - { - geometry.heads = option_resolution_lookup_int(params, PARAM_HEADS); - geometry.tracks = option_resolution_lookup_int(params, PARAM_TRACKS); - geometry.sectors = option_resolution_lookup_int(params, PARAM_SECTORS); - geometry.first_sector_id = option_resolution_lookup_int(params, PARAM_FIRST_SECTOR_ID); - geometry.sector_length = option_resolution_lookup_int(params, PARAM_SECTOR_LENGTH); - } - else - { - geometry.heads = 1; - geometry.tracks = 40; - geometry.sectors = 16; - geometry.first_sector_id = 0; - geometry.sector_length = floppy_image_size(floppy)/geometry.tracks/geometry.sectors; - } - - return basicdsk_construct(floppy, &geometry); -} - - -LEGACY_FLOPPY_OPTIONS_START(vz) - LEGACY_FLOPPY_OPTION(vtech1, "dsk", "Laser/VZ disk image", vz_identify, vz_construct, NULL, - HEADS([1]) - TRACKS([40]) - SECTORS([16]) - SECTOR_LENGTH([154]) - FIRST_SECTOR_ID([0])) -LEGACY_FLOPPY_OPTIONS_END diff --git a/src/mess/tools/imgtool/formats/vt_dsk.h b/src/mess/tools/imgtool/formats/vt_dsk.h deleted file mode 100644 index a3f9a86b44e..00000000000 --- a/src/mess/tools/imgtool/formats/vt_dsk.h +++ /dev/null @@ -1,18 +0,0 @@ -// license:GPL-2.0+ -// copyright-holders:Juergen Buchmueller -/********************************************************************* - - formats/vt_dsk.h - - Tandy Color Computer / Dragon disk images - -*********************************************************************/ - -#ifndef VT_DSK_H -#define VT_DSK_H - -#include "formats/flopimg.h" - -LEGACY_FLOPPY_OPTIONS_EXTERN(vz); - -#endif /* VT_DSK_H */ diff --git a/src/mess/tools/imgtool/iflopimg.c b/src/mess/tools/imgtool/iflopimg.c deleted file mode 100644 index 9e8493f9477..00000000000 --- a/src/mess/tools/imgtool/iflopimg.c +++ /dev/null @@ -1,363 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/********************************************************************* - - iflopimg.c - - Bridge code for Imgtool into the standard floppy code - -*********************************************************************/ - -#include "imgtool.h" -#include "formats/flopimg.h" -#include "library.h" -#include "iflopimg.h" - -imgtoolerr_t imgtool_floppy_error(floperr_t err) -{ - switch(err) - { - case FLOPPY_ERROR_SUCCESS: - return IMGTOOLERR_SUCCESS; - - case FLOPPY_ERROR_OUTOFMEMORY: - return IMGTOOLERR_OUTOFMEMORY; - - case FLOPPY_ERROR_INVALIDIMAGE: - return IMGTOOLERR_CORRUPTIMAGE; - - case FLOPPY_ERROR_SEEKERROR: - return IMGTOOLERR_SEEKERROR; - - case FLOPPY_ERROR_UNSUPPORTED: - return IMGTOOLERR_UNIMPLEMENTED; - - default: - return IMGTOOLERR_UNEXPECTED; - } -} - - - -/********************************************************************* - Imgtool ioprocs -*********************************************************************/ - -static void imgtool_floppy_closeproc(void *file) -{ - stream_close((imgtool_stream *) file); -} - -static int imgtool_floppy_seekproc(void *file, INT64 offset, int whence) -{ - stream_seek((imgtool_stream *) file, offset, whence); - return 0; -} - -static size_t imgtool_floppy_readproc(void *file, void *buffer, size_t length) -{ - return stream_read((imgtool_stream *) file, buffer, length); -} - -static size_t imgtool_floppy_writeproc(void *file, const void *buffer, size_t length) -{ - stream_write((imgtool_stream *) file, buffer, length); - return length; -} - -static UINT64 imgtool_floppy_filesizeproc(void *file) -{ - return stream_size((imgtool_stream *) file); -} - -static const struct io_procs imgtool_ioprocs = -{ - imgtool_floppy_closeproc, - imgtool_floppy_seekproc, - imgtool_floppy_readproc, - imgtool_floppy_writeproc, - imgtool_floppy_filesizeproc -}; - -static const struct io_procs imgtool_noclose_ioprocs = -{ - NULL, - imgtool_floppy_seekproc, - imgtool_floppy_readproc, - imgtool_floppy_writeproc, - imgtool_floppy_filesizeproc -}; - - - -/********************************************************************* - Imgtool handlers -*********************************************************************/ - -struct imgtool_floppy_image -{ - floppy_image_legacy *floppy; -}; - - - - -static imgtoolerr_t imgtool_floppy_open_internal(imgtool_image *image, imgtool_stream *f, int noclose) -{ - floperr_t ferr; - imgtoolerr_t err; - struct imgtool_floppy_image *fimg; - const imgtool_class *imgclass; - const struct FloppyFormat *format; - imgtoolerr_t (*open)(imgtool_image *image, imgtool_stream *f); - - fimg = (struct imgtool_floppy_image *) imgtool_image_extra_bytes(image); - imgclass = &imgtool_image_module(image)->imgclass; - format = (const struct FloppyFormat *) imgclass->derived_param; - open = (imgtoolerr_t (*)(imgtool_image *, imgtool_stream *)) imgtool_get_info_ptr(imgclass, IMGTOOLINFO_PTR_FLOPPY_OPEN); - - /* open up the floppy */ - ferr = floppy_open(f, noclose ? &imgtool_noclose_ioprocs : &imgtool_ioprocs, - NULL, format, FLOPPY_FLAGS_READWRITE, &fimg->floppy); - if (ferr) - { - err = imgtool_floppy_error(ferr); - return err; - } - - if (open) - { - err = open(image, NULL); - if (err) - return err; - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t imgtool_floppy_open(imgtool_image *image, imgtool_stream *f) -{ - return imgtool_floppy_open_internal(image, f, FALSE); -} - - - -static imgtoolerr_t imgtool_floppy_create(imgtool_image *image, imgtool_stream *f, option_resolution *opts) -{ - floperr_t ferr; - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - struct imgtool_floppy_image *fimg; - const imgtool_class *imgclass; - const struct FloppyFormat *format; - imgtoolerr_t (*create)(imgtool_image *, imgtool_stream *, option_resolution *); - imgtoolerr_t (*open)(imgtool_image *image, imgtool_stream *f); - - fimg = (struct imgtool_floppy_image *) imgtool_image_extra_bytes(image); - imgclass = &imgtool_image_module(image)->imgclass; - format = (const struct FloppyFormat *) imgclass->derived_param; - create = (imgtoolerr_t (*)(imgtool_image *, imgtool_stream *, option_resolution *)) imgtool_get_info_ptr(imgclass, IMGTOOLINFO_PTR_FLOPPY_CREATE); - open = (imgtoolerr_t (*)(imgtool_image *, imgtool_stream *)) imgtool_get_info_ptr(imgclass, IMGTOOLINFO_PTR_FLOPPY_OPEN); - - /* open up the floppy */ - ferr = floppy_create(f, &imgtool_ioprocs, format, opts, &fimg->floppy); - if (ferr) - { - err = imgtool_floppy_error(ferr); - goto done; - } - - /* do we have to do extra stuff when creating the image? */ - if (create) - { - err = create(image, NULL, opts); - if (err) - goto done; - } - - /* do we have to do extra stuff when opening the image? */ - if (open) - { - err = open(image, NULL); - if (err) - goto done; - } - -done: - return err; -} - - - -static void imgtool_floppy_close(imgtool_image *img) -{ - floppy_close(imgtool_floppy(img)); -} - - - -static imgtoolerr_t imgtool_floppy_get_sector_size(imgtool_image *image, UINT32 track, UINT32 head, UINT32 sector, UINT32 *sector_size) -{ - floperr_t ferr; - - ferr = floppy_get_sector_length(imgtool_floppy(image), head, track, sector, sector_size); - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t imgtool_floppy_read_sector(imgtool_image *image, UINT32 track, UINT32 head, UINT32 sector, void *buffer, size_t len) -{ - floperr_t ferr; - - ferr = floppy_read_sector(imgtool_floppy(image), head, track, sector, 0, buffer, len); - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t imgtool_floppy_write_sector(imgtool_image *image, UINT32 track, UINT32 head, UINT32 sector, const void *buffer, size_t len, int ddam) -{ - floperr_t ferr; - - ferr = floppy_write_sector(imgtool_floppy(image), head, track, sector, 0, buffer, len, ddam); - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static void imgtool_floppy_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info) -{ - const struct FloppyFormat *format; - imgtool_class derived_class; - - format = (const struct FloppyFormat *) imgclass->derived_param; - memset(&derived_class, 0, sizeof(derived_class)); - derived_class.get_info = imgclass->derived_get_info; - - switch(state) - { - /* --- the following bits of info are returned as 64-bit signed integers --- */ - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: - info->i = sizeof(struct imgtool_floppy_image) + - imgtool_get_info_int(&derived_class, IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES); - break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case IMGTOOLINFO_STR_NAME: - sprintf(info->s = imgtool_temp_str(), "%s_%s", format->name, - imgtool_get_info_string(&derived_class, IMGTOOLINFO_STR_NAME)); - break; - case IMGTOOLINFO_STR_DESCRIPTION: - sprintf(info->s = imgtool_temp_str(), "%s (%s)", format->description, - imgtool_get_info_string(&derived_class, IMGTOOLINFO_STR_DESCRIPTION)); - break; - case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), format->extensions); break; - case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: info->p = (void*)format->param_guidelines; break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case IMGTOOLINFO_PTR_OPEN: info->open = imgtool_floppy_open; break; - case IMGTOOLINFO_PTR_CREATE: info->create = imgtool_floppy_create; break; - case IMGTOOLINFO_PTR_CLOSE: info->close = imgtool_floppy_close; break; - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = format->param_guidelines ? floppy_option_guide : NULL; break; - case IMGTOOLINFO_PTR_GET_SECTOR_SIZE: info->get_sector_size = imgtool_floppy_get_sector_size; break; - case IMGTOOLINFO_PTR_READ_SECTOR: info->read_sector = imgtool_floppy_read_sector; break; - case IMGTOOLINFO_PTR_WRITE_SECTOR: info->write_sector = imgtool_floppy_write_sector; break; - - default: imgclass->derived_get_info(imgclass, state, info); break; - } -} - - - -int imgtool_floppy_make_class(int index, imgtool_class *imgclass) -{ - const struct FloppyFormat *format; - - /* get the format */ - format = (const struct FloppyFormat *) - imgtool_get_info_ptr(imgclass, IMGTOOLINFO_PTR_FLOPPY_FORMAT); - assert(format); - if (!format[index].construct) - return FALSE; - - imgclass->derived_get_info = imgclass->get_info; - imgclass->get_info = imgtool_floppy_get_info; - imgclass->derived_param = (void *) &format[index]; - return TRUE; -} - - - -floppy_image_legacy *imgtool_floppy(imgtool_image *img) -{ - struct imgtool_floppy_image *fimg; - fimg = (struct imgtool_floppy_image *) imgtool_image_extra_bytes(img); - return fimg->floppy; -} - - - -static imgtoolerr_t imgtool_floppy_transfer_sector_tofrom_stream(imgtool_image *img, int head, int track, int sector, int offset, size_t length, imgtool_stream *f, int direction) -{ - floperr_t err; - floppy_image_legacy *floppy; - dynamic_buffer buffer; - - floppy = imgtool_floppy(img); - - buffer.resize(length); - - if (direction) - { - err = floppy_read_sector(floppy, head, track, sector, offset, &buffer[0], length); - if (err) - goto done; - stream_write(f, &buffer[0], length); - } - else - { - stream_read(f, &buffer[0], length); - err = floppy_write_sector(floppy, head, track, sector, offset, &buffer[0], length, 0); /* TODO: pass ddam argument from imgtool */ - if (err) - goto done; - } - - err = FLOPPY_ERROR_SUCCESS; - -done: - return imgtool_floppy_error(err); -} - - - -imgtoolerr_t imgtool_floppy_read_sector_to_stream(imgtool_image *img, int head, int track, int sector, int offset, size_t length, imgtool_stream *f) -{ - return imgtool_floppy_transfer_sector_tofrom_stream(img, head, track, sector, offset, length, f, 1); -} - - - -imgtoolerr_t imgtool_floppy_write_sector_from_stream(imgtool_image *img, int head, int track, int sector, int offset, size_t length, imgtool_stream *f) -{ - return imgtool_floppy_transfer_sector_tofrom_stream(img, head, track, sector, offset, length, f, 0); -} - - - -void *imgtool_floppy_extrabytes(imgtool_image *img) -{ - struct imgtool_floppy_image *fimg; - fimg = (struct imgtool_floppy_image *) imgtool_image_extra_bytes(img); - return fimg + 1; -} diff --git a/src/mess/tools/imgtool/iflopimg.h b/src/mess/tools/imgtool/iflopimg.h deleted file mode 100644 index 8e298330845..00000000000 --- a/src/mess/tools/imgtool/iflopimg.h +++ /dev/null @@ -1,41 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/********************************************************************* - - iflopimg.h - - Bridge code for Imgtool into the standard floppy code - -*********************************************************************/ - -#ifndef IFLOPIMG_H -#define IFLOPIMG_H - -#include "formats/flopimg.h" -#include "library.h" - -/*************************************************************************** - - Prototypes - -***************************************************************************/ - -enum -{ - IMGTOOLINFO_PTR_FLOPPY_FORMAT = IMGTOOLINFO_PTR_CLASS_SPECIFIC, - IMGTOOLINFO_PTR_FLOPPY_OPEN, - IMGTOOLINFO_PTR_FLOPPY_CREATE -}; - -int imgtool_floppy_make_class(int index, imgtool_class *imgclass); - -floppy_image_legacy *imgtool_floppy(imgtool_image *img); -imgtoolerr_t imgtool_floppy_error(floperr_t err); - -imgtoolerr_t imgtool_floppy_read_sector_to_stream(imgtool_image *img, int head, int track, int sector, int offset, size_t length, imgtool_stream *f); -imgtoolerr_t imgtool_floppy_write_sector_from_stream(imgtool_image *img, int head, int track, int sector, int offset, size_t length, imgtool_stream *f); - - -void *imgtool_floppy_extrabytes(imgtool_image *img); - -#endif /* IFLOPIMG_H */ diff --git a/src/mess/tools/imgtool/imghd.c b/src/mess/tools/imgtool/imghd.c deleted file mode 100644 index 8ac129751f9..00000000000 --- a/src/mess/tools/imgtool/imghd.c +++ /dev/null @@ -1,273 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods, Raphael Nabet -/* - Code to interface the MESS image code with MAME's harddisk core. - - We do not support diff files as it will involve some changes in the MESS - image code. - - Raphael Nabet 2003 -*/ - -#include "imgtool.h" -#include "harddisk.h" -#include "imghd.h" - - -static imgtoolerr_t map_chd_error(chd_error chderr) -{ - imgtoolerr_t err; - - switch(chderr) - { - case CHDERR_NONE: - err = IMGTOOLERR_SUCCESS; - break; - case CHDERR_OUT_OF_MEMORY: - err = IMGTOOLERR_OUTOFMEMORY; - break; - case CHDERR_FILE_NOT_WRITEABLE: - err = IMGTOOLERR_READONLY; - break; - case CHDERR_NOT_SUPPORTED: - err = IMGTOOLERR_UNIMPLEMENTED; - break; - default: - err = IMGTOOLERR_UNEXPECTED; - break; - } - return err; -} - - - -/* - imghd_create() - - Create a MAME HD image -*/ -imgtoolerr_t imghd_create(imgtool_stream *stream, UINT32 hunksize, UINT32 cylinders, UINT32 heads, UINT32 sectors, UINT32 seclen) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - dynamic_buffer cache; - chd_file chd; - chd_error rc; - UINT64 logicalbytes; - int hunknum, totalhunks; - std::string metadata; - chd_codec_type compression[4] = { CHD_CODEC_NONE }; - - /* sanity check args */ - if (hunksize >= 2048) - { - err = IMGTOOLERR_PARAMCORRUPT; - goto done; - } - if (hunksize <= 0) - hunksize = 1024; /* default value */ - - /* bail if we are read only */ - if (stream_isreadonly(stream)) - { - err = IMGTOOLERR_READONLY; - goto done; - } - - /* calculations */ - logicalbytes = (UINT64)cylinders * heads * sectors * seclen; - - /* create the new hard drive */ - rc = chd.create(*stream_core_file(stream), logicalbytes, hunksize, seclen, compression); - if (rc != CHDERR_NONE) - { - err = map_chd_error(rc); - goto done; - } - - /* open the new hard drive */ - rc = chd.open(*stream_core_file(stream)); - - if (rc != CHDERR_NONE) - { - err = map_chd_error(rc); - goto done; - } - - /* write the metadata */ - strprintf(metadata,HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, seclen); - err = (imgtoolerr_t)chd.write_metadata(HARD_DISK_METADATA_TAG, 0, metadata); - if (rc != CHDERR_NONE) - { - err = map_chd_error(rc); - goto done; - } - - /* alloc and zero buffer */ - cache.resize(hunksize); - memset(&cache[0], 0, hunksize); - - /* zero out every hunk */ - totalhunks = (logicalbytes + hunksize - 1) / hunksize; - for (hunknum = 0; hunknum < totalhunks; hunknum++) - { - rc = chd.write_units(hunknum, &cache[0]); - if (rc) - { - err = IMGTOOLERR_WRITEERROR; - goto done; - } - } - -done: - return err; -} - - - -/* - imghd_open() - - Open stream as a MAME HD image -*/ -imgtoolerr_t imghd_open(imgtool_stream *stream, struct mess_hard_disk_file *hard_disk) -{ - chd_error chderr; - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - - hard_disk->hard_disk = NULL; - hard_disk->chd = NULL; - - chderr = hard_disk->chd->open(*stream_core_file(stream), stream_isreadonly(stream)); - if (chderr) - { - err = map_chd_error(chderr); - goto done; - } - - hard_disk->hard_disk = hard_disk_open(hard_disk->chd); - if (!hard_disk->hard_disk) - { - err = IMGTOOLERR_UNEXPECTED; - goto done; - } - hard_disk->stream = stream; - -done: - if (err) - imghd_close(hard_disk); - return err; -} - - - -/* - imghd_close() - - Close MAME HD image -*/ -void imghd_close(struct mess_hard_disk_file *disk) -{ - if (disk->hard_disk) - { - hard_disk_close(disk->hard_disk); - disk->hard_disk = NULL; - } - if (disk->stream) - stream_close(disk->stream); -} - - - -/* - imghd_read() - - Read sector(s) from MAME HD image -*/ -imgtoolerr_t imghd_read(struct mess_hard_disk_file *disk, UINT32 lbasector, void *buffer) -{ - UINT32 reply; - reply = hard_disk_read(disk->hard_disk, lbasector, buffer); - return (imgtoolerr_t)(reply ? IMGTOOLERR_SUCCESS : map_chd_error((chd_error)reply)); -} - - - -/* - imghd_write() - - Write sector(s) from MAME HD image -*/ -imgtoolerr_t imghd_write(struct mess_hard_disk_file *disk, UINT32 lbasector, const void *buffer) -{ - UINT32 reply; - reply = hard_disk_write(disk->hard_disk, lbasector, buffer); - return (imgtoolerr_t)(reply ? IMGTOOLERR_SUCCESS : map_chd_error((chd_error)reply)); -} - - - -/* - imghd_get_header() - - Return pointer to the header of MAME HD image -*/ -const hard_disk_info *imghd_get_header(struct mess_hard_disk_file *disk) -{ - const hard_disk_info *reply; - reply = hard_disk_get_info(disk->hard_disk); - return reply; -} - - -static imgtoolerr_t mess_hd_image_create(imgtool_image *image, imgtool_stream *f, option_resolution *createoptions); - -enum -{ - mess_hd_createopts_blocksize = 'B', - mess_hd_createopts_cylinders = 'C', - mess_hd_createopts_heads = 'D', - mess_hd_createopts_sectors = 'E', - mess_hd_createopts_seclen = 'F' -}; - -static OPTION_GUIDE_START( mess_hd_create_optionguide ) - OPTION_INT(mess_hd_createopts_blocksize, "blocksize", "Sectors Per Block" ) - OPTION_INT(mess_hd_createopts_cylinders, "cylinders", "Cylinders" ) - OPTION_INT(mess_hd_createopts_heads, "heads", "Heads" ) - OPTION_INT(mess_hd_createopts_sectors, "sectors", "Total Sectors" ) - OPTION_INT(mess_hd_createopts_seclen, "seclen", "Sector Bytes" ) -OPTION_GUIDE_END - -#define mess_hd_create_optionspecs "B[1]-2048;C1-[32]-65536;D1-[8]-64;E1-[128]-4096;F128/256/[512]/1024/2048/4096/8192/16384/32768/65536" - - -void hd_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info) -{ - switch(state) - { - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "mess_hd"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "MESS hard disk image"); break; - case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "hd"); break; - - case IMGTOOLINFO_PTR_CREATE: info->create = mess_hd_image_create; break; - - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = mess_hd_create_optionguide; break; - case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), mess_hd_create_optionspecs); break; - } -} - - - -static imgtoolerr_t mess_hd_image_create(imgtool_image *image, imgtool_stream *f, option_resolution *createoptions) -{ - UINT32 blocksize, cylinders, heads, sectors, seclen; - - /* read options */ - blocksize = option_resolution_lookup_int(createoptions, mess_hd_createopts_blocksize); - cylinders = option_resolution_lookup_int(createoptions, mess_hd_createopts_cylinders); - heads = option_resolution_lookup_int(createoptions, mess_hd_createopts_heads); - sectors = option_resolution_lookup_int(createoptions, mess_hd_createopts_sectors); - seclen = option_resolution_lookup_int(createoptions, mess_hd_createopts_seclen); - - return imghd_create(f, blocksize, cylinders, heads, sectors, seclen); -} diff --git a/src/mess/tools/imgtool/imghd.h b/src/mess/tools/imgtool/imghd.h deleted file mode 100644 index 3dba7d40d4f..00000000000 --- a/src/mess/tools/imgtool/imghd.h +++ /dev/null @@ -1,42 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/**************************************************************************** - - imghd.h - - Bridge between Imgtool and CHD hard disk images - -****************************************************************************/ - -#ifndef IMGHD_H -#define IMGHD_H - -#include "harddisk.h" - -struct mess_hard_disk_file -{ - imgtool_stream *stream; - hard_disk_file *hard_disk; - chd_file *chd; -}; - - -/* create a new hard disk */ -imgtoolerr_t imghd_create(imgtool_stream *stream, UINT32 blocksize, UINT32 cylinders, UINT32 heads, UINT32 sectors, UINT32 seclen); - -/* opens a hard disk given an Imgtool stream */ -imgtoolerr_t imghd_open(imgtool_stream *stream, struct mess_hard_disk_file *hard_disk); - -/* close a hard disk */ -void imghd_close(struct mess_hard_disk_file *disk); - -/* reads data from a hard disk */ -imgtoolerr_t imghd_read(struct mess_hard_disk_file *disk, UINT32 lbasector, void *buffer); - -/* writes data to a hard disk */ -imgtoolerr_t imghd_write(struct mess_hard_disk_file *disk, UINT32 lbasector, const void *buffer); - -/* gets the header from a hard disk */ -const hard_disk_info *imghd_get_header(struct mess_hard_disk_file *disk); - -#endif /* IMGHD_H */ diff --git a/src/mess/tools/imgtool/imgterrs.c b/src/mess/tools/imgtool/imgterrs.c deleted file mode 100644 index bd679440309..00000000000 --- a/src/mess/tools/imgtool/imgterrs.c +++ /dev/null @@ -1,55 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - imgterrs.c - - Imgtool errors - -***************************************************************************/ - -#include "imgtool.h" -#include "imgterrs.h" -#include "osdcomm.h" - -static const char *const msgs[] = -{ - "Out of memory", - "Unexpected error", - "Argument too long", - "Read error", - "Write error", - "Image is read only", - "Corrupt image", - "Corrupt file", - "Corrupt directory", - "File not found", - "Unrecognized format", - "Not implemented", - "Parameter too small", - "Parameter too large", - "Missing parameter not found", - "Inappropriate parameter", - "Invalid parameter", - "Bad file name", - "Out of space on image", - "Input past end of file", - "Cannot specify path", - "Invalid path", - "Path not found", - "Directory not empty", - "Seek error", - "File system does not support forks", - "Fork not found", - "Invalid partition" -}; - - - -const char *imgtool_error(imgtoolerr_t err) -{ - err = (imgtoolerr_t)(ERRORCODE(err) - 1); - assert(err >= 0); - assert(err < ARRAY_LENGTH(msgs)); - return msgs[err]; -} diff --git a/src/mess/tools/imgtool/imgterrs.h b/src/mess/tools/imgtool/imgterrs.h deleted file mode 100644 index 1cdafb6cef2..00000000000 --- a/src/mess/tools/imgtool/imgterrs.h +++ /dev/null @@ -1,70 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - imgterrs.h - - Imgtool errors - -***************************************************************************/ - -#ifndef IMGTERRS_H -#define IMGTERRS_H - -/* Error codes */ -enum imgtoolerr_t -{ - IMGTOOLERR_SUCCESS, - IMGTOOLERR_OUTOFMEMORY, - IMGTOOLERR_UNEXPECTED, - IMGTOOLERR_BUFFERTOOSMALL, - IMGTOOLERR_READERROR, - IMGTOOLERR_WRITEERROR, - IMGTOOLERR_READONLY, - IMGTOOLERR_CORRUPTIMAGE, - IMGTOOLERR_CORRUPTFILE, - IMGTOOLERR_CORRUPTDIR, - IMGTOOLERR_FILENOTFOUND, - IMGTOOLERR_MODULENOTFOUND, - IMGTOOLERR_UNIMPLEMENTED, - IMGTOOLERR_PARAMTOOSMALL, - IMGTOOLERR_PARAMTOOLARGE, - IMGTOOLERR_PARAMNEEDED, - IMGTOOLERR_PARAMNOTNEEDED, - IMGTOOLERR_PARAMCORRUPT, - IMGTOOLERR_BADFILENAME, - IMGTOOLERR_NOSPACE, - IMGTOOLERR_INPUTPASTEND, - IMGTOOLERR_CANNOTUSEPATH, - IMGTOOLERR_INVALIDPATH, - IMGTOOLERR_PATHNOTFOUND, - IMGTOOLERR_DIRNOTEMPTY, - IMGTOOLERR_SEEKERROR, - IMGTOOLERR_NOFORKS, - IMGTOOLERR_FORKNOTFOUND, - IMGTOOLERR_INVALIDPARTITION -}; - - - -/* These error codes are actually modifiers that make it easier to distinguish - * the cause of an error - * - * Note - drivers should not use these modifiers - */ -#define IMGTOOLERR_SRC_MODULE 0x1000 -#define IMGTOOLERR_SRC_FUNCTIONALITY 0x2000 -#define IMGTOOLERR_SRC_IMAGEFILE 0x3000 -#define IMGTOOLERR_SRC_FILEONIMAGE 0x4000 -#define IMGTOOLERR_SRC_NATIVEFILE 0x5000 - -#define ERRORCODE(err) ((err) & 0x0fff) -#define ERRORSOURCE(err) ((err) & 0xf000) -#define ERRORPARAM(err) (((err) & 0xf0000) / 0x10000) - -#define PARAM_TO_ERROR(errcode, param) ((errcode) | ((param) * 0x10000)) - - -const char *imgtool_error(imgtoolerr_t err); - -#endif /* IMGTERRS_H */ diff --git a/src/mess/tools/imgtool/imgtool.c b/src/mess/tools/imgtool/imgtool.c deleted file mode 100644 index df44a9bbff2..00000000000 --- a/src/mess/tools/imgtool/imgtool.c +++ /dev/null @@ -1,2814 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - imgtool.c - - Core code for Imgtool - -***************************************************************************/ - -#include <string.h> -#include <ctype.h> - -#include "imgtool.h" -#include "formats/imageutl.h" -#include "library.h" -#include "modules.h" -#include "pool.h" - - -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -struct imgtool_image -{ - const imgtool_module *module; - object_pool *pool; -}; - -struct imgtool_partition -{ - imgtool_image *image; - object_pool *pool; - int partition_index; - UINT64 base_block; - UINT64 block_count; - - imgtool_class imgclass; - size_t partition_extra_bytes; - size_t directory_extra_bytes; - - char path_separator; - char alternate_path_separator; - - unsigned int prefer_ucase : 1; - unsigned int supports_creation_time : 1; - unsigned int supports_lastmodified_time : 1; - unsigned int supports_bootblock : 1; /* this module supports loading/storing the boot block */ - - imgtoolerr_t (*begin_enum) (imgtool_directory *enumeration, const char *path); - imgtoolerr_t (*next_enum) (imgtool_directory *enumeration, imgtool_dirent *ent); - void (*close_enum) (imgtool_directory *enumeration); - imgtoolerr_t (*free_space) (imgtool_partition *partition, UINT64 *size); - imgtoolerr_t (*read_file) (imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf); - imgtoolerr_t (*write_file) (imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, option_resolution *opts); - imgtoolerr_t (*delete_file) (imgtool_partition *partition, const char *filename); - imgtoolerr_t (*list_forks) (imgtool_partition *partition, const char *path, imgtool_forkent *ents, size_t len); - imgtoolerr_t (*create_dir) (imgtool_partition *partition, const char *path); - imgtoolerr_t (*delete_dir) (imgtool_partition *partition, const char *path); - imgtoolerr_t (*list_attrs) (imgtool_partition *partition, const char *path, UINT32 *attrs, size_t len); - imgtoolerr_t (*get_attrs) (imgtool_partition *partition, const char *path, const UINT32 *attrs, imgtool_attribute *values); - imgtoolerr_t (*set_attrs) (imgtool_partition *partition, const char *path, const UINT32 *attrs, const imgtool_attribute *values); - imgtoolerr_t (*attr_name) (UINT32 attribute, const imgtool_attribute *attr, char *buffer, size_t buffer_len); - imgtoolerr_t (*get_iconinfo) (imgtool_partition *partition, const char *path, imgtool_iconinfo *iconinfo); - imgtoolerr_t (*suggest_transfer)(imgtool_partition *partition, const char *path, imgtool_transfer_suggestion *suggestions, size_t suggestions_length); - imgtoolerr_t (*get_chain) (imgtool_partition *partition, const char *path, imgtool_chainent *chain, size_t chain_size); - - const option_guide *writefile_optguide; - const char *writefile_optspec; -}; - -struct imgtool_directory -{ - imgtool_partition *partition; -}; - - - -/*************************************************************************** - GLOBALS -***************************************************************************/ - -static imgtool_library *global_imgtool_library; - -static int global_omit_untested; -static void (*global_warn)(const char *message); - - -void CLIB_DECL ATTR_PRINTF(1,2) logerror(const char *format, ...) -{ - va_list arg; - va_start(arg, format); - vprintf(format, arg); - va_end(arg); -} - -/*************************************************************************** - - Imgtool initialization and basics - -***************************************************************************/ -void rtrim(char *buf) -{ - size_t buflen; - char *s; - - buflen = strlen(buf); - if (buflen) - { - for (s = &buf[buflen-1]; s >= buf && (*s >= '\0') && isspace(*s); s--) - *s = '\0'; - } -} - -char *strncpyz(char *dest, const char *source, size_t len) -{ - char *s; - if (len) { - s = strncpy(dest, source, len - 1); - dest[len-1] = '\0'; - } - else { - s = dest; - } - return s; -} - -char *strncatz(char *dest, const char *source, size_t len) -{ - size_t l; - l = strlen(dest); - dest += l; - if (len > l) - len -= l; - else - len = 0; - return strncpyz(dest, source, len); -} - -/*------------------------------------------------- - markerrorsource - marks where an error source --------------------------------------------------*/ - -static imgtoolerr_t markerrorsource(imgtoolerr_t err) -{ - switch(err) - { - case IMGTOOLERR_OUTOFMEMORY: - case IMGTOOLERR_UNEXPECTED: - case IMGTOOLERR_BUFFERTOOSMALL: - /* Do nothing */ - break; - - case IMGTOOLERR_FILENOTFOUND: - case IMGTOOLERR_BADFILENAME: - err = (imgtoolerr_t)(err | IMGTOOLERR_SRC_FILEONIMAGE); - break; - - default: - err = (imgtoolerr_t)(err | IMGTOOLERR_SRC_IMAGEFILE); - break; - } - return err; -} - -char *imgtool_basename(char *filename) -{ - char *c; - - // NULL begets NULL - if (!filename) - return NULL; - - // start at the end and return when we hit a slash or colon - for (c = filename + strlen(filename) - 1; c >= filename; c--) - if (*c == '\\' || *c == '/' || *c == ':') - return c + 1; - - // otherwise, return the whole thing - return filename; -} - -/*------------------------------------------------- - internal_error - debug function for raising - internal errors --------------------------------------------------*/ - -static void internal_error(const imgtool_module *module, const char *message) -{ -#ifdef MAME_DEBUG - printf("%s: %s\n", module->name, message); -#endif -} - - -/*------------------------------------------------- - normalize_filename - convert a filename to the - native format used by the module --------------------------------------------------*/ - -static char *normalize_filename(imgtool_partition *partition, const char *src) -{ - imgtool_charset charset; - - /* get charset from module */ - charset = (imgtool_charset) (int) imgtool_partition_get_info_int(partition, IMGTOOLINFO_INT_CHARSET); - - /* and dupe it */ - return native_from_utf8(charset, src); -} - - - -/*------------------------------------------------- - imgtool_init - initializes the imgtool core --------------------------------------------------*/ - -void imgtool_init(int omit_untested, void (*warn)(const char *message)) -{ - imgtoolerr_t err; - err = imgtool_create_cannonical_library(omit_untested, &global_imgtool_library); - assert(err == IMGTOOLERR_SUCCESS); - if (err == IMGTOOLERR_SUCCESS) - { - imgtool_library_sort(global_imgtool_library, ITLS_DESCRIPTION); - } - global_omit_untested = omit_untested; - global_warn = warn; -} - - - -/*------------------------------------------------- - imgtool_exit - closes out the imgtool core --------------------------------------------------*/ - -void imgtool_exit(void) -{ - if (global_imgtool_library) - { - imgtool_library_close(global_imgtool_library); - global_imgtool_library = NULL; - } - global_warn = NULL; -} - - - -/*------------------------------------------------- - imgtool_find_module - looks up a module --------------------------------------------------*/ - -const imgtool_module *imgtool_find_module(const char *modulename) -{ - return imgtool_library_findmodule(global_imgtool_library, modulename); -} - - - -/*------------------------------------------------- - imgtool_get_module_features - retrieves a - structure identifying this module's features - associated with an image --------------------------------------------------*/ - -imgtool_module_features imgtool_get_module_features(const imgtool_module *module) -{ - imgtool_module_features features; - memset(&features, 0, sizeof(features)); - - if (module->create) - features.supports_create = 1; - if (module->open) - features.supports_open = 1; - if (module->read_sector) - features.supports_readsector = 1; - if (module->write_sector) - features.supports_writesector = 1; - return features; -} - - - -/*------------------------------------------------- - imgtool_warn - issues a warning --------------------------------------------------*/ - -void imgtool_warn(const char *format, ...) -{ - va_list va; - char buffer[2000]; - - if (global_warn) - { - va_start(va, format); - vsprintf(buffer, format, va); - va_end(va); - global_warn(buffer); - } -} - - - -/*------------------------------------------------- - evaluate_module - evaluates a single file to - determine what module can best handle a file --------------------------------------------------*/ - -static imgtoolerr_t evaluate_module(const char *fname, - const imgtool_module *module, float *result) -{ - imgtoolerr_t err; - imgtool_image *image = NULL; - imgtool_partition *partition = NULL; - imgtool_directory *imageenum = NULL; - imgtool_dirent ent; - float current_result; - - *result = 0.0; - - err = imgtool_image_open(module, fname, OSD_FOPEN_READ, &image); - if (err) - goto done; - - if (image) - { - current_result = module->open_is_strict ? 0.9 : 0.5; - - err = imgtool_partition_open(image, 0, &partition); - if (err) - goto done; - - err = imgtool_directory_open(partition, NULL, &imageenum); - if (err) - goto done; - - memset(&ent, 0, sizeof(ent)); - do - { - err = imgtool_directory_get_next(imageenum, &ent); - if (err) - goto done; - - if (ent.corrupt) - current_result = (current_result * 99 + 1.00f) / 100; - else - current_result = (current_result + 1.00f) / 2; - } - while(!ent.eof); - - *result = current_result; - } - -done: - if (ERRORCODE(err) == IMGTOOLERR_CORRUPTIMAGE) - err = IMGTOOLERR_SUCCESS; - if (imageenum) - imgtool_directory_close(imageenum); - if (partition) - imgtool_partition_close(partition); - if (image) - imgtool_image_close(image); - return err; -} - - - -/*------------------------------------------------- - imgtool_partition_image - retrieves the image - associated with this partition --------------------------------------------------*/ - -imgtool_image *imgtool_partition_image(imgtool_partition *partition) -{ - return partition->image; -} - - - -/*------------------------------------------------- - imgtool_identify_file - attempts to determine the module - for any given image --------------------------------------------------*/ - -imgtoolerr_t imgtool_identify_file(const char *fname, imgtool_module **modules, size_t count) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - imgtool_library *library = global_imgtool_library; - imgtool_module *module = NULL; - imgtool_module *insert_module; - imgtool_module *temp_module; - size_t i = 0; - const char *extension; - float val, temp_val, *values = NULL; - - if (count <= 0) - { - err = IMGTOOLERR_UNEXPECTED; - goto done; - } - - for (i = 0; i < count; i++) - modules[i] = NULL; - if (count > 1) - count--; /* null terminate */ - - values = (float *) malloc(count * sizeof(*values)); - if (!values) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto done; - } - for (i = 0; i < count; i++) - values[i] = 0.0; - - /* figure out the file extension, if any */ - extension = strrchr(fname, '.'); - if (extension) - extension++; - - /* iterate through all modules */ - while((module = imgtool_library_iterate(library, module)) != NULL) - { - if (!extension || image_find_extension(module->extensions, extension)) - { - err = evaluate_module(fname, module, &val); - if (err) - goto done; - - insert_module = module; - for (i = 0; (val > 0.0f) && (i < count); i++) - { - if (val > values[i]) - { - temp_val = values[i]; - temp_module = modules[i]; - values[i] = val; - modules[i] = insert_module; - val = temp_val; - insert_module = temp_module; - } - } - } - } - - if (!modules[0]) - err = (imgtoolerr_t)(IMGTOOLERR_MODULENOTFOUND | IMGTOOLERR_SRC_IMAGEFILE); - -done: - if (values) - free(values); - return err; -} - - - -/*------------------------------------------------- - imgtool_image_get_sector_size - gets the size - of a particular sector on an image --------------------------------------------------*/ - -imgtoolerr_t imgtool_image_get_sector_size(imgtool_image *image, UINT32 track, UINT32 head, - UINT32 sector, UINT32 *length) -{ - /* implemented? */ - if (!image->module->get_sector_size) - return (imgtoolerr_t )(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - return image->module->get_sector_size(image, track, head, sector, length); -} - - - -/*------------------------------------------------- - imgtool_image_get_geometry - gets the geometry - of an image; note that this may disagree with - particular sectors; this is a common copy - protection scheme --------------------------------------------------*/ - -imgtoolerr_t imgtool_image_get_geometry(imgtool_image *image, UINT32 *tracks, UINT32 *heads, UINT32 *sectors) -{ - UINT32 dummy; - - /* some sanitization, to make the callbacks easier to implement */ - if (!tracks) - tracks = &dummy; - if (!heads) - heads = &dummy; - if (!sectors) - sectors = &dummy; - *tracks = 0; - *heads = 0; - *sectors = 0; - - /* implemented? */ - if (!image->module->get_geometry) - return (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - return image->module->get_geometry(image, tracks, heads, sectors); -} - - - -/*------------------------------------------------- - imgtool_image_read_sector - reads a sector on an image --------------------------------------------------*/ - -imgtoolerr_t imgtool_image_read_sector(imgtool_image *image, UINT32 track, UINT32 head, - UINT32 sector, void *buffer, size_t len) -{ - /* implemented? */ - if (!image->module->read_sector) - return (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - return image->module->read_sector(image, track, head, sector, buffer, len); -} - - - -/*------------------------------------------------- - imgtool_image_write_sector - writes a sector on an image --------------------------------------------------*/ - -imgtoolerr_t imgtool_image_write_sector(imgtool_image *image, UINT32 track, UINT32 head, - UINT32 sector, const void *buffer, size_t len) -{ - /* implemented? */ - if (!image->module->write_sector) - return (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - return image->module->write_sector(image, track, head, sector, buffer, len); -} - - - -/*------------------------------------------------- - imgtool_image_get_block_size - gets the size of - a standard block on an image --------------------------------------------------*/ - -imgtoolerr_t imgtool_image_get_block_size(imgtool_image *image, UINT32 *length) -{ - /* implemented? */ - if (image->module->block_size == 0) - return (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - *length = image->module->block_size; - return IMGTOOLERR_SUCCESS; -} - - - -/*------------------------------------------------- - imgtool_image_read_block - reads a standard - block on an image --------------------------------------------------*/ - -imgtoolerr_t imgtool_image_read_block(imgtool_image *image, UINT64 block, void *buffer) -{ - /* implemented? */ - if (!image->module->read_block) - return (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - return image->module->read_block(image, buffer, block); -} - - - -/*------------------------------------------------- - imgtool_image_write_block - writes a standard - block on an image --------------------------------------------------*/ - -imgtoolerr_t imgtool_image_write_block(imgtool_image *image, UINT64 block, const void *buffer) -{ - /* implemented? */ - if (!image->module->write_block) - return (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - return image->module->write_block(image, buffer, block); -} - - - -/*------------------------------------------------- - imgtool_image_clear_block - clears a standard - block on an image --------------------------------------------------*/ - -imgtoolerr_t imgtool_image_clear_block(imgtool_image *image, UINT64 block, UINT8 data) -{ - imgtoolerr_t err; - UINT8 *block_data = NULL; - UINT32 length; - - err = imgtool_image_get_block_size(image, &length); - if (err) - goto done; - - block_data = (UINT8*)malloc(length); - if (!block_data) - { - err = (imgtoolerr_t)IMGTOOLERR_OUTOFMEMORY; - goto done; - } - memset(block_data, data, length); - - err = imgtool_image_write_block(image, block, block_data); - if (err) - goto done; - -done: - if (block_data) - free(block_data); - return err; -} - - - -/*------------------------------------------------- - imgtool_image_list_partitions - lists the - partitions on an image --------------------------------------------------*/ - -imgtoolerr_t imgtool_image_list_partitions(imgtool_image *image, imgtool_partition_info *partitions, size_t len) -{ - /* implemented? */ - if (!image->module->list_partitions) - return (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - memset(partitions, '\0', sizeof(*partitions) * len); - return image->module->list_partitions(image, partitions, len); -} - - - -/*------------------------------------------------- - imgtool_image_malloc - allocates memory associated with an - image --------------------------------------------------*/ - -void *imgtool_image_malloc(imgtool_image *image, size_t size) -{ - return pool_malloc_lib(image->pool, size); -} - - - -/*------------------------------------------------- - imgtool_image_module - returns the module associated with - this image --------------------------------------------------*/ - -const imgtool_module *imgtool_image_module(imgtool_image *img) -{ - return img->module; -} - - - -/*------------------------------------------------- - imgtool_image_extra_bytes - returns extra bytes on an image --------------------------------------------------*/ - -void *imgtool_image_extra_bytes(imgtool_image *image) -{ - void *ptr = NULL; - if (image->module->image_extra_bytes > 0) - ptr = ((UINT8 *) image) + sizeof(*image); - assert(ptr); - return ptr; -} - - - -/*------------------------------------------------- - imgtool_image_rand - returns a random number --------------------------------------------------*/ - -UINT64 imgtool_image_rand(imgtool_image *image) -{ - /* we can't use mame_rand() here */ -#ifdef rand -#undef rand -#endif - return ((UINT64) rand()) << 32 - | ((UINT64) rand()) << 0; -} - - - -/*************************************************************************** - - Imgtool partition management - -***************************************************************************/ - -static char *pool_strdup_allow_null(object_pool *pool, char *s) -{ - return s ? pool_strdup_lib(pool, s) : NULL; -} - - - -imgtoolerr_t imgtool_partition_open(imgtool_image *image, int partition_index, imgtool_partition **partition) -{ - imgtoolerr_t err = (imgtoolerr_t)IMGTOOLERR_SUCCESS; - imgtool_partition *p = NULL; - imgtool_class imgclass; - imgtool_partition_info partition_info[32]; - UINT64 base_block, block_count; - size_t partition_extra_bytes; - object_pool *pool; - imgtoolerr_t (*open_partition)(imgtool_partition *partition, UINT64 first_block, UINT64 block_count); - - if (image->module->list_partitions) - { - /* this image supports partitions */ - if ((partition_index < 0) || (partition_index >= ARRAY_LENGTH(partition_info))) - return IMGTOOLERR_INVALIDPARTITION; - - /* retrieve the info on the partitions */ - memset(partition_info, '\0', sizeof(partition_info)); - err = image->module->list_partitions(image, partition_info, ARRAY_LENGTH(partition_info)); - if (err) - return err; - - /* is this a valid partition */ - if (!partition_info[partition_index].get_info) - return IMGTOOLERR_INVALIDPARTITION; - - /* use this partition */ - memset(&imgclass, 0, sizeof(imgclass)); - imgclass.get_info = partition_info[partition_index].get_info; - base_block = partition_info[partition_index].base_block; - block_count = partition_info[partition_index].block_count; - } - else - { - /* this image does not support partitions */ - if (partition_index != 0) - return IMGTOOLERR_INVALIDPARTITION; - - /* identify the image class */ - imgclass = imgtool_image_module(image)->imgclass; - base_block = 0; - block_count = ~0; - } - - /* does this partition type have extra bytes? */ - partition_extra_bytes = imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_PARTITION_EXTRA_BYTES); - - /* allocate the new memory pool */ - pool = pool_alloc_lib(NULL); - if (!pool) - { - err = (imgtoolerr_t)IMGTOOLERR_OUTOFMEMORY; - goto done; - } - - /* allocate the new partition object */ - p = (imgtool_partition *) pool_malloc_lib(pool, sizeof(*p) + partition_extra_bytes); - if (!p) - { - err = (imgtoolerr_t)IMGTOOLERR_OUTOFMEMORY; - goto done; - } - memset(p, 0, sizeof(*p) + partition_extra_bytes); - p->pool = pool; - - /* fill out the structure */ - p->image = image; - p->partition_index = partition_index; - p->base_block = base_block; - p->block_count = block_count; - p->imgclass = imgclass; - p->partition_extra_bytes = partition_extra_bytes; - p->directory_extra_bytes = imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES); - p->path_separator = (char) imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_PATH_SEPARATOR); - p->alternate_path_separator = (char) imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_ALTERNATE_PATH_SEPARATOR); - p->prefer_ucase = imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_PREFER_UCASE) ? 1 : 0; - p->supports_creation_time = imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_SUPPORTS_CREATION_TIME) ? 1 : 0; - p->supports_lastmodified_time = imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_SUPPORTS_LASTMODIFIED_TIME) ? 1 : 0; - p->supports_bootblock = imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_SUPPORTS_BOOTBLOCK) ? 1 : 0; - p->begin_enum = (imgtoolerr_t (*)(imgtool_directory *, const char *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_BEGIN_ENUM); - p->next_enum = (imgtoolerr_t (*)(imgtool_directory *, imgtool_dirent *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_NEXT_ENUM); - p->free_space = (imgtoolerr_t (*)(imgtool_partition *, UINT64 *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_FREE_SPACE); - p->read_file = (imgtoolerr_t (*)(imgtool_partition *, const char *, const char *, imgtool_stream *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_READ_FILE); - p->write_file = (imgtoolerr_t (*)(imgtool_partition *, const char *, const char *, imgtool_stream *, option_resolution *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_WRITE_FILE); - p->delete_file = (imgtoolerr_t (*)(imgtool_partition *, const char *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_DELETE_FILE); - p->list_forks = (imgtoolerr_t (*)(imgtool_partition *, const char *, imgtool_forkent *, size_t)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_LIST_FORKS); - p->create_dir = (imgtoolerr_t (*)(imgtool_partition *, const char *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_CREATE_DIR); - p->delete_dir = (imgtoolerr_t (*)(imgtool_partition *, const char *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_DELETE_DIR); - p->list_attrs = (imgtoolerr_t (*)(imgtool_partition *, const char *, UINT32 *, size_t)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_LIST_ATTRS); - p->get_attrs = (imgtoolerr_t (*)(imgtool_partition *, const char *, const UINT32 *, imgtool_attribute *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_GET_ATTRS); - p->set_attrs = (imgtoolerr_t (*)(imgtool_partition *, const char *, const UINT32 *, const imgtool_attribute *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_SET_ATTRS); - p->attr_name = (imgtoolerr_t (*)(UINT32, const imgtool_attribute *, char *, size_t)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_ATTR_NAME); - p->get_iconinfo = (imgtoolerr_t (*)(imgtool_partition *, const char *, imgtool_iconinfo *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_GET_ICON_INFO); - p->suggest_transfer = (imgtoolerr_t (*)(imgtool_partition *, const char *, imgtool_transfer_suggestion *, size_t)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_SUGGEST_TRANSFER); - p->get_chain = (imgtoolerr_t (*)(imgtool_partition *, const char *, imgtool_chainent *, size_t)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_GET_CHAIN); - p->writefile_optguide = (const option_guide *) imgtool_get_info_ptr(&imgclass, IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE); - p->writefile_optspec = pool_strdup_allow_null(p->pool, (char*)imgtool_get_info_ptr(&imgclass, IMGTOOLINFO_STR_WRITEFILE_OPTSPEC)); - - /* mask out if writing is untested */ - if (global_omit_untested && imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_WRITING_UNTESTED)) - { - p->write_file = NULL; - p->delete_file = NULL; - p->create_dir = NULL; - p->delete_dir = NULL; - p->writefile_optguide = NULL; - p->writefile_optspec = NULL; - } - - /* call the partition open function, if present */ - open_partition = (imgtoolerr_t (*)(imgtool_partition *, UINT64, UINT64)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_OPEN_PARTITION); - if (open_partition) - { - /* we have an open partition function */ - err = (*open_partition)(p, base_block, block_count); - if (err) - goto done; - } - -done: - *partition = err ? NULL : p; - return err; -} - - - -void imgtool_partition_close(imgtool_partition *partition) -{ - pool_free_lib(partition->pool); -} - - - -/*************************************************************************** - - Imgtool partition operations - -***************************************************************************/ - -/*------------------------------------------------- - imgtool_partition_get_attribute_name - retrieves the human readable - name for an attribute --------------------------------------------------*/ - -void imgtool_partition_get_attribute_name(imgtool_partition *partition, UINT32 attribute, const imgtool_attribute *attr_value, - char *buffer, size_t buffer_len) -{ - imgtoolerr_t err = (imgtoolerr_t)IMGTOOLERR_UNIMPLEMENTED; - - buffer[0] = '\0'; - - if (attr_value) - { - if (partition->attr_name) - err = partition->attr_name(attribute, attr_value, buffer, buffer_len); - - if (err == (imgtoolerr_t)IMGTOOLERR_UNIMPLEMENTED) - { - switch(attribute & 0xF0000) - { - case IMGTOOLATTR_INT_FIRST: - snprintf(buffer, buffer_len, "%d", (int) attr_value->i); - break; - } - } - } - else - { - switch(attribute) - { - case IMGTOOLATTR_INT_MAC_TYPE: - snprintf(buffer, buffer_len, "File type"); - break; - case IMGTOOLATTR_INT_MAC_CREATOR: - snprintf(buffer, buffer_len, "File creator"); - break; - case IMGTOOLATTR_INT_MAC_FINDERFLAGS: - snprintf(buffer, buffer_len, "Finder flags"); - break; - case IMGTOOLATTR_INT_MAC_COORDX: - snprintf(buffer, buffer_len, "X coordinate"); - break; - case IMGTOOLATTR_INT_MAC_COORDY: - snprintf(buffer, buffer_len, "Y coordinate"); - break; - case IMGTOOLATTR_INT_MAC_FINDERFOLDER: - snprintf(buffer, buffer_len, "Finder folder"); - break; - case IMGTOOLATTR_INT_MAC_ICONID: - snprintf(buffer, buffer_len, "Icon ID"); - break; - case IMGTOOLATTR_INT_MAC_SCRIPTCODE: - snprintf(buffer, buffer_len, "Script code"); - break; - case IMGTOOLATTR_INT_MAC_EXTENDEDFLAGS: - snprintf(buffer, buffer_len, "Extended flags"); - break; - case IMGTOOLATTR_INT_MAC_COMMENTID: - snprintf(buffer, buffer_len, "Comment ID"); - break; - case IMGTOOLATTR_INT_MAC_PUTAWAYDIRECTORY: - snprintf(buffer, buffer_len, "Putaway directory"); - break; - case IMGTOOLATTR_TIME_CREATED: - snprintf(buffer, buffer_len, "Creation time"); - break; - case IMGTOOLATTR_TIME_LASTMODIFIED: - snprintf(buffer, buffer_len, "Last modified time"); - break; - } - } -} - - - -/*------------------------------------------------- - imgtool_validitychecks - checks the validity - of the imgtool modules --------------------------------------------------*/ - -int imgtool_validitychecks(void) -{ - int error = 0; - int val; - imgtoolerr_t err = (imgtoolerr_t)IMGTOOLERR_SUCCESS; - const imgtool_module *module = NULL; - const option_guide *guide_entry; - imgtool_module_features features; - int created_library = FALSE; - - if (!global_imgtool_library) - { - imgtool_init(FALSE, NULL); - created_library = TRUE; - } - - while((module = imgtool_library_iterate(global_imgtool_library, module)) != NULL) - { - features = imgtool_get_module_features(module); - - if (!module->name) - { - printf("imgtool module %s has null 'name'\n", module->name); - error = 1; - } - if (!module->description) - { - printf("imgtool module %s has null 'description'\n", module->name); - error = 1; - } - if (!module->extensions) - { - printf("imgtool module %s has null 'extensions'\n", module->extensions); - error = 1; - } - -#if 0 - /* sanity checks on modules that do not support directories */ - if (!module->path_separator) - { - if (module->alternate_path_separator) - { - printf("imgtool module %s specified alternate_path_separator but not path_separator\n", module->name); - error = 1; - } - if (module->initial_path_separator) - { - printf("imgtool module %s specified initial_path_separator without directory support\n", module->name); - error = 1; - } - if (module->create_dir) - { - printf("imgtool module %s implements create_dir without directory support\n", module->name); - error = 1; - } - if (module->delete_dir) - { - printf("imgtool module %s implements delete_dir without directory support\n", module->name); - error = 1; - } - } -#endif - - /* sanity checks on sector operations */ - if (module->read_sector && !module->get_sector_size) - { - printf("imgtool module %s implements read_sector without supporting get_sector_size\n", module->name); - error = 1; - } - if (module->write_sector && !module->get_sector_size) - { - printf("imgtool module %s implements write_sector without supporting get_sector_size\n", module->name); - error = 1; - } - - /* sanity checks on creation options */ - if (module->createimage_optguide || module->createimage_optspec) - { - if (!module->create) - { - printf("imgtool module %s has creation options without supporting create\n", module->name); - error = 1; - } - if ((!module->createimage_optguide && module->createimage_optspec) - || (module->createimage_optguide && !module->createimage_optspec)) - { - printf("imgtool module %s does has partially incomplete creation options\n", module->name); - error = 1; - } - - if (module->createimage_optguide && module->createimage_optspec) - { - guide_entry = module->createimage_optguide; - while(guide_entry->option_type != OPTIONTYPE_END) - { - if (option_resolution_contains(module->createimage_optspec, guide_entry->parameter)) - { - switch(guide_entry->option_type) - { - case OPTIONTYPE_INT: - case OPTIONTYPE_ENUM_BEGIN: - err = (imgtoolerr_t)option_resolution_getdefault(module->createimage_optspec, - guide_entry->parameter, &val); - if (err) - goto done; - break; - - default: - break; - } - if (!guide_entry->identifier) - { - printf("imgtool module %s creation option %d has null identifier\n", - module->name, (int) (guide_entry - module->createimage_optguide)); - error = 1; - } - if (!guide_entry->display_name) - { - printf("imgtool module %s creation option %d has null display_name\n", - module->name, (int) (guide_entry - module->createimage_optguide)); - error = 1; - } - } - guide_entry++; - } - } - } - } - -done: - if (created_library) - imgtool_exit(); - if (err) - { - printf("imgtool: %s\n", imgtool_error(err)); - error = 1; - } - return error; -} - - - -/*------------------------------------------------- - imgtool_temp_str - provides a temporary string - buffer used for string passing --------------------------------------------------*/ - -char *imgtool_temp_str(void) -{ - static int index; - static char temp_string_pool[32][256]; - return temp_string_pool[index++ % ARRAY_LENGTH(temp_string_pool)]; -} - - - -/*************************************************************************** - - Image handling functions - -***************************************************************************/ - -static imgtoolerr_t internal_open(const imgtool_module *module, const char *fname, - int read_or_write, option_resolution *createopts, imgtool_image **outimg) -{ - imgtoolerr_t err; - imgtool_stream *f = NULL; - imgtool_image *image = NULL; - object_pool *pool = NULL; - size_t size; - - if (outimg) - *outimg = NULL; - - /* is the requested functionality implemented? */ - if ((read_or_write == OSD_FOPEN_RW_CREATE) ? !module->create : !module->open) - { - err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - /* create a memory pool */ - pool = pool_alloc_lib(NULL); - if (!pool) - { - err = (imgtoolerr_t)(IMGTOOLERR_OUTOFMEMORY); - goto done; - } - - /* open the stream */ - f = stream_open(fname, read_or_write); - if (!f) - { - err = (imgtoolerr_t)(IMGTOOLERR_FILENOTFOUND | IMGTOOLERR_SRC_IMAGEFILE); - goto done; - } - - /* setup the image structure */ - size = sizeof(imgtool_image) + module->image_extra_bytes; - image = (imgtool_image *) pool_malloc_lib(pool, size); - if (!image) - { - err = (imgtoolerr_t)IMGTOOLERR_OUTOFMEMORY; - goto done; - } - memset(image, '\0', size); - image->pool = pool; - image->module = module; - - /* actually call create or open */ - if (read_or_write == OSD_FOPEN_RW_CREATE) - err = module->create(image, f, createopts); - else - err = module->open(image, f); - if (err) - { - err = markerrorsource(err); - goto done; - } - -done: - if (err) - { - if (f) - stream_close(f); - if (pool) - pool_free_lib(pool); - image = NULL; - } - - if (outimg) - *outimg = image; - else if (image) - imgtool_image_close(image); - return err; -} - - - -/*------------------------------------------------- - imgtool_image_open - open an image --------------------------------------------------*/ - -imgtoolerr_t imgtool_image_open(const imgtool_module *module, const char *fname, int read_or_write, imgtool_image **outimg) -{ - read_or_write = read_or_write ? OSD_FOPEN_RW : OSD_FOPEN_READ; - return internal_open(module, fname, read_or_write, NULL, outimg); -} - - - -/*------------------------------------------------- - imgtool_image_open_byname - open an image --------------------------------------------------*/ - -imgtoolerr_t imgtool_image_open_byname(const char *modulename, const char *fname, int read_or_write, imgtool_image **outimg) -{ - const imgtool_module *module; - - module = imgtool_find_module(modulename); - if (!module) - return (imgtoolerr_t)(IMGTOOLERR_MODULENOTFOUND | IMGTOOLERR_SRC_MODULE); - - return imgtool_image_open(module, fname, read_or_write, outimg); -} - - - -/*------------------------------------------------- - imgtool_image_close - close an image --------------------------------------------------*/ - -void imgtool_image_close(imgtool_image *image) -{ - if (image->module->close) - image->module->close(image); - pool_free_lib(image->pool); -} - - - -/*------------------------------------------------- - imgtool_image_create - creates an image --------------------------------------------------*/ - -imgtoolerr_t imgtool_image_create(const imgtool_module *module, const char *fname, - option_resolution *opts, imgtool_image **image) -{ - imgtoolerr_t err; - option_resolution *alloc_resolution = NULL; - - /* allocate dummy options if necessary */ - if (!opts && module->createimage_optguide) - { - alloc_resolution = option_resolution_create(module->createimage_optguide, module->createimage_optspec); - if (!alloc_resolution) - { - err = (imgtoolerr_t)IMGTOOLERR_OUTOFMEMORY; - goto done; - } - opts = alloc_resolution; - } - if (opts) - option_resolution_finish(opts); - - err = internal_open(module, fname, OSD_FOPEN_RW_CREATE, opts, image); - if (err) - goto done; - -done: - if (alloc_resolution) - option_resolution_close(alloc_resolution); - return err; -} - - - -/*------------------------------------------------- - imgtool_image_create_byname - creates an image --------------------------------------------------*/ - -imgtoolerr_t imgtool_image_create_byname(const char *modulename, const char *fname, - option_resolution *opts, imgtool_image **image) -{ - const imgtool_module *module; - - module = imgtool_find_module(modulename); - if (!module) - return (imgtoolerr_t)(IMGTOOLERR_MODULENOTFOUND | IMGTOOLERR_SRC_MODULE); - - return imgtool_image_create(module, fname, opts, image); -} - - - -/*------------------------------------------------- - imgtool_image_info - returns format specific information - about an image --------------------------------------------------*/ - -imgtoolerr_t imgtool_image_info(imgtool_image *image, char *string, size_t len) -{ - if (len > 0) - { - string[0] = '\0'; - if (image->module->info) - image->module->info(image, string, len); - } - return IMGTOOLERR_SUCCESS; -} - - - -#define PATH_MUSTBEDIR 0x00000001 -#define PATH_LEAVENULLALONE 0x00000002 -#define PATH_CANBEBOOTBLOCK 0x00000004 - -/*------------------------------------------------- - cannonicalize_path - normalizes a path string - into a NUL delimited list --------------------------------------------------*/ - -static imgtoolerr_t cannonicalize_path(imgtool_partition *partition, UINT32 flags, - const char **path, char **alloc_path) -{ - imgtoolerr_t err = (imgtoolerr_t)IMGTOOLERR_SUCCESS; - char *new_path = NULL; - char path_separator, alt_path_separator; - const char *s; - int in_path_separator, i, j; - - path_separator = partition->path_separator; - alt_path_separator = partition->alternate_path_separator; - - /* is this path NULL? if so, is that ignored? */ - if (!*path && (flags & PATH_LEAVENULLALONE)) - goto done; - - /* is this the special filename for bootblocks? */ - if (*path == FILENAME_BOOTBLOCK) - { - if (!(flags & PATH_CANBEBOOTBLOCK)) - err = (imgtoolerr_t)IMGTOOLERR_UNEXPECTED; - else if (!partition->supports_bootblock) - err = (imgtoolerr_t)IMGTOOLERR_FILENOTFOUND; - goto done; - } - - if (path_separator == '\0') - { - if (flags & PATH_MUSTBEDIR) - { - /* do we specify a path when paths are not supported? */ - if (*path && **path) - { - err = (imgtoolerr_t)(IMGTOOLERR_CANNOTUSEPATH | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - *path = NULL; /* normalize empty path */ - } - } - else - { - s = *path ? *path : ""; - - /* allocate space for a new cannonical path */ - new_path = (char*)malloc(strlen(s) + 4); - if (!new_path) - { - err = (imgtoolerr_t)IMGTOOLERR_OUTOFMEMORY; - goto done; - } - - /* copy the path */ - in_path_separator = TRUE; - i = j = 0; - do - { - if ((s[i] != '\0') && (s[i] != path_separator) && (s[i] != alt_path_separator)) - { - new_path[j++] = s[i]; - in_path_separator = FALSE; - } - else if (!in_path_separator) - { - new_path[j++] = '\0'; - in_path_separator = TRUE; - } - } - while(s[i++] != '\0'); - new_path[j++] = '\0'; - new_path[j++] = '\0'; - *path = new_path; - } - -done: - *alloc_path = new_path; - return err; -} - - - -static imgtoolerr_t cannonicalize_fork(imgtool_partition *partition, const char **fork) -{ - /* does this module support forks? */ - if (partition->list_forks) - { - /* this module supports forks; make sure that fork is non-NULL */ - if (!*fork) - *fork = ""; - } - else - { - /* this module does not support forks; make sure that fork is NULL */ - if (*fork) - return IMGTOOLERR_NOFORKS; - } - return IMGTOOLERR_SUCCESS; -} - - - -/*------------------------------------------------- - imgtool_partition_get_directory_entry - retrieves - the nth directory entry within a partition --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_get_directory_entry(imgtool_partition *partition, const char *path, int index, imgtool_dirent *ent) -{ - imgtoolerr_t err; - imgtool_directory *imgenum = NULL; - - if (index < 0) - { - err = (imgtoolerr_t)IMGTOOLERR_PARAMTOOSMALL; - goto done; - } - - err = imgtool_directory_open(partition, path, &imgenum); - if (err) - goto done; - - do - { - err = imgtool_directory_get_next(imgenum, ent); - if (err) - goto done; - - if (ent->eof) - { - err = (imgtoolerr_t)IMGTOOLERR_FILENOTFOUND; - goto done; - } - } - while(index--); - -done: - if (err) - memset(ent->filename, 0, sizeof(ent->filename)); - if (imgenum) - imgtool_directory_close(imgenum); - return err; -} - - - -/*------------------------------------------------- - imgtool_partition_get_file_size - returns free - space on a partition, in bytes --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_get_file_size(imgtool_partition *partition, const char *fname, UINT64 *filesize) -{ - imgtoolerr_t err; - imgtool_directory *imgenum; - imgtool_dirent ent; - const char *path; - - path = NULL; /* TODO: Need to parse off the path */ - - *filesize = -1; - memset(&ent, 0, sizeof(ent)); - - err = imgtool_directory_open(partition, path, &imgenum); - if (err) - goto done; - - do - { - err = imgtool_directory_get_next(imgenum, &ent); - if (err) - goto done; - - if (!core_stricmp(fname, ent.filename)) - { - *filesize = ent.filesize; - goto done; - } - } - while(ent.filename[0]); - - err = (imgtoolerr_t)IMGTOOLERR_FILENOTFOUND; - -done: - if (imgenum) - imgtool_directory_close(imgenum); - return err; -} - - - -/*------------------------------------------------- - imgtool_partition_list_file_attributes - identifies - all attributes on a file --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_list_file_attributes(imgtool_partition *partition, const char *path, UINT32 *attrs, size_t len) -{ - imgtoolerr_t err; - char *alloc_path = NULL; - char *new_fname = NULL; - - memset(attrs, 0, sizeof(*attrs) * len); - - if (!partition->list_attrs) - { - err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - new_fname = normalize_filename(partition, path); - if (new_fname == NULL) - { - err = (imgtoolerr_t)(IMGTOOLERR_BADFILENAME | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - path = new_fname; - - /* cannonicalize path */ - err = cannonicalize_path(partition, PATH_LEAVENULLALONE, &path, &alloc_path); - if (err) - goto done; - - err = partition->list_attrs(partition, path, attrs, len); - if (err) - goto done; - -done: - if (alloc_path != NULL) - free(alloc_path); - if (new_fname != NULL) - osd_free(new_fname); - return err; -} - - - -/*------------------------------------------------- - imgtool_partition_get_file_attributes - retrieves - attributes on a file --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_get_file_attributes(imgtool_partition *partition, const char *path, const UINT32 *attrs, imgtool_attribute *values) -{ - imgtoolerr_t err; - char *alloc_path = NULL; - char *new_fname = NULL; - - if (!partition->get_attrs) - { - err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - new_fname = normalize_filename(partition, path); - if (new_fname == NULL) - { - err = (imgtoolerr_t)(IMGTOOLERR_BADFILENAME | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - path = new_fname; - - /* cannonicalize path */ - err = cannonicalize_path(partition, PATH_LEAVENULLALONE, &path, &alloc_path); - if (err) - goto done; - - err = partition->get_attrs(partition, path, attrs, values); - if (err) - goto done; - -done: - if (alloc_path != NULL) - free(alloc_path); - if (new_fname != NULL) - osd_free(new_fname); - return err; -} - - - -/*------------------------------------------------- - imgtool_partition_put_file_attributes - sets - attributes on a file --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_put_file_attributes(imgtool_partition *partition, const char *path, const UINT32 *attrs, const imgtool_attribute *values) -{ - imgtoolerr_t err; - char *alloc_path = NULL; - - if (!partition->set_attrs) - { - err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - /* cannonicalize path */ - err = cannonicalize_path(partition, PATH_LEAVENULLALONE, &path, &alloc_path); - if (err) - goto done; - - err = partition->set_attrs(partition, path, attrs, values); - if (err) - goto done; - -done: - if (alloc_path) - free(alloc_path); - return err; -} - - - -/*------------------------------------------------- - imgtool_partition_get_file_attributes - retrieves - an attribute on a single file --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_get_file_attribute(imgtool_partition *partition, const char *path, UINT32 attr, imgtool_attribute *value) -{ - UINT32 attrs[2]; - attrs[0] = attr; - attrs[1] = 0; - return imgtool_partition_get_file_attributes(partition, path, attrs, value); -} - - - -/*------------------------------------------------- - imgtool_partition_put_file_attribute - sets - attributes on a single file --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_put_file_attribute(imgtool_partition *partition, const char *path, UINT32 attr, imgtool_attribute value) -{ - UINT32 attrs[2]; - attrs[0] = attr; - attrs[1] = 0; - return imgtool_partition_put_file_attributes(partition, path, attrs, &value); -} - - - -/*------------------------------------------------- - imgtool_partition_get_icon_info - retrieves the - icon for a file stored on a partition --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_get_icon_info(imgtool_partition *partition, const char *path, imgtool_iconinfo *iconinfo) -{ - imgtoolerr_t err; - char *alloc_path = NULL; - char *new_fname = NULL; - - if (!partition->get_iconinfo) - { - err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - new_fname = normalize_filename(partition, path); - if (new_fname == NULL) - { - err = (imgtoolerr_t)(IMGTOOLERR_BADFILENAME | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - path = new_fname; - - /* cannonicalize path */ - err = cannonicalize_path(partition, 0, &path, &alloc_path); - if (err) - goto done; - - memset(iconinfo, 0, sizeof(*iconinfo)); - err = partition->get_iconinfo(partition, path, iconinfo); - if (err) - goto done; - -done: - if (alloc_path) - free(alloc_path); - if (new_fname) - osd_free(new_fname); - return err; -} - - - -/*------------------------------------------------- - imgtool_partition_suggest_file_filters - suggests - a list of filters appropriate for a file on a - partition --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_suggest_file_filters(imgtool_partition *partition, const char *path, - imgtool_stream *stream, imgtool_transfer_suggestion *suggestions, size_t suggestions_length) -{ - imgtoolerr_t err; - int i, j; - char *alloc_path = NULL; - imgtoolerr_t (*check_stream)(imgtool_stream *stream, imgtool_suggestion_viability_t *viability); - size_t position; - - /* clear out buffer */ - memset(suggestions, 0, sizeof(*suggestions) * suggestions_length); - - if (!partition->suggest_transfer) - { - err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - /* cannonicalize path */ - err = cannonicalize_path(partition, PATH_LEAVENULLALONE, &path, &alloc_path); - if (err) - goto done; - - /* invoke the module's suggest call */ - err = partition->suggest_transfer(partition, path, suggestions, suggestions_length); - if (err) - goto done; - - /* Loop on resulting suggestions, and do the following: - * 1. Call check_stream if present, and remove disqualified streams - * 2. Fill in missing descriptions - */ - i = j = 0; - while(suggestions[i].viability) - { - if (stream && suggestions[i].filter) - { - check_stream = (imgtoolerr_t (*)(imgtool_stream *, imgtool_suggestion_viability_t *)) filter_get_info_fct(suggestions[i].filter, FILTINFO_PTR_CHECKSTREAM); - if (check_stream) - { - position = stream_tell(stream); - err = check_stream(stream, &suggestions[i].viability); - stream_seek(stream, position, SEEK_SET); - if (err) - goto done; - } - } - - /* the check_stream proc can remove the option by clearing out the viability */ - if (suggestions[i].viability) - { - /* we may have to move this suggestion, if one was removed */ - if (i != j) - memcpy(&suggestions[j], &suggestions[i], sizeof(*suggestions)); - - /* if the description is missing, fill it in */ - if (!suggestions[j].description) - { - if (suggestions[j].filter) - suggestions[j].description = filter_get_info_string(suggestions[i].filter, FILTINFO_STR_HUMANNAME); - else - suggestions[j].description = "Raw"; - } - - j++; - } - i++; - } - suggestions[j].viability = (imgtool_suggestion_viability_t)0; - -done: - if (alloc_path) - free(alloc_path); - return err; -} - - - -/*------------------------------------------------- - imgtool_partition_get_chain - retrieves the block - chain for a file or directory on a partition --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_get_chain(imgtool_partition *partition, const char *path, imgtool_chainent *chain, size_t chain_size) -{ - size_t i; - - assert(chain_size > 0); - - if (!partition->get_chain) - return (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - /* initialize the chain array, so the module's get_chain function can be lazy */ - for (i = 0; i < chain_size; i++) - { - chain[i].level = 0; - chain[i].block = ~0; - } - - return partition->get_chain(partition, path, chain, chain_size - 1); -} - - - -/*------------------------------------------------- - imgtool_partition_get_chain_string - retrieves - the block chain for a file or directory on a - partition --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_get_chain_string(imgtool_partition *partition, const char *path, char *buffer, size_t buffer_len) -{ - imgtoolerr_t err; - imgtool_chainent chain[512]; - UINT64 last_block; - UINT8 cur_level = 0; - int len, i; - int comma_needed = FALSE; - - /* determine the last block identifier */ - chain[0].block = ~0; - last_block = chain[0].block; - - err = imgtool_partition_get_chain(partition, path, chain, ARRAY_LENGTH(chain)); - if (err) - return err; - - len = snprintf(buffer, buffer_len, "["); - buffer += len; - buffer_len -= len; - - for (i = 0; chain[i].block != last_block; i++) - { - while(cur_level < chain[i].level) - { - len = snprintf(buffer, buffer_len, " ["); - buffer += len; - buffer_len -= len; - cur_level++; - comma_needed = FALSE; - } - while(cur_level > chain[i].level) - { - len = snprintf(buffer, buffer_len, "]"); - buffer += len; - buffer_len -= len; - cur_level--; - } - - if (comma_needed) - { - len = snprintf(buffer, buffer_len, ", "); - buffer += len; - buffer_len -= len; - } - - len = snprintf(buffer, buffer_len, "%u", (unsigned) chain[i].block); - buffer += len; - buffer_len -= len; - comma_needed = TRUE; - } - - do - { - len = snprintf(buffer, buffer_len, "]"); - buffer += len; - buffer_len -= len; - } - while(cur_level-- > 0); - - return IMGTOOLERR_SUCCESS; -} - - - -/*------------------------------------------------- - imgtool_partition_get_free_space - returns the - amount of free space on a partition --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_get_free_space(imgtool_partition *partition, UINT64 *sz) -{ - imgtoolerr_t err; - UINT64 size; - - if (!partition->free_space) - return (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - - err = partition->free_space(partition, &size); - if (err) - return (imgtoolerr_t)(err | IMGTOOLERR_SRC_IMAGEFILE); - - if (sz) - *sz = size; - return IMGTOOLERR_SUCCESS; -} - - - -/*------------------------------------------------- - imgtool_partition_read_file - starts reading - from a file on a partition with a stream --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_read_file(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf, filter_getinfoproc filter) -{ - imgtoolerr_t err; - char *alloc_path = NULL; - union filterinfo u; - - if (!partition->read_file) - { - err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - if (filter) - { - /* use a filter */ - filter(FILTINFO_PTR_READFILE, &u); - if (!u.read_file) - { - err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - err = u.read_file(partition, filename, fork, destf); - if (err) - { - err = markerrorsource(err); - goto done; - } - } - else - { - /* cannonicalize path */ - err = cannonicalize_path(partition, PATH_CANBEBOOTBLOCK, &filename, &alloc_path); - if (err) - goto done; - - err = cannonicalize_fork(partition, &fork); - if (err) - goto done; - - /* invoke the actual module */ - err = partition->read_file(partition, filename, fork, destf); - if (err) - { - err = markerrorsource(err); - goto done; - } - } - -done: - if (alloc_path) - free(alloc_path); - return err; -} - - - -/*------------------------------------------------- - imgtool_partition_write_file - starts writing - to a new file on an image with a stream --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_write_file(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, option_resolution *opts, filter_getinfoproc filter) -{ - imgtoolerr_t err; - char *buf = NULL; - char *s; - option_resolution *alloc_resolution = NULL; - char *alloc_path = NULL; - UINT64 free_space; - UINT64 file_size; - union filterinfo u; - - if (!partition->write_file) - { - err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - if (filter) - { - /* use a filter */ - filter(FILTINFO_PTR_WRITEFILE, &u); - if (!u.write_file) - { - err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - err = u.write_file(partition, filename, fork, sourcef, opts); - if (err) - { - err = markerrorsource(err); - goto done; - } - } - else - { - /* does this partition prefer upper case file names? */ - if (partition->prefer_ucase) - { - buf = (char*)malloc(strlen(filename) + 1); - if (!buf) - { - err = (imgtoolerr_t)(IMGTOOLERR_OUTOFMEMORY); - goto done; - } - strcpy(buf, filename); - for (s = buf; *s; s++) - *s = toupper(*s); - filename = buf; - } - - /* cannonicalize path */ - err = cannonicalize_path(partition, PATH_CANBEBOOTBLOCK, &filename, &alloc_path); - if (err) - goto done; - - err = cannonicalize_fork(partition, &fork); - if (err) - goto done; - - /* allocate dummy options if necessary */ - if (!opts && partition->writefile_optguide) - { - alloc_resolution = option_resolution_create(partition->writefile_optguide, partition->writefile_optspec); - if (!alloc_resolution) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto done; - } - opts = alloc_resolution; - } - if (opts) - option_resolution_finish(opts); - - /* if free_space is implemented; do a quick check to see if space is available */ - if (partition->free_space) - { - err = partition->free_space(partition, &free_space); - if (err) - { - err = markerrorsource(err); - goto done; - } - - file_size = stream_size(sourcef); - - if (file_size > free_space) - { - err = markerrorsource(IMGTOOLERR_NOSPACE); - goto done; - } - } - - /* actually invoke the write file handler */ - err = partition->write_file(partition, filename, fork, sourcef, opts); - if (err) - { - err = markerrorsource(err); - goto done; - } - } - -done: - if (buf) - free(buf); - if (alloc_path) - free(alloc_path); - if (alloc_resolution) - option_resolution_close(alloc_resolution); - return err; -} - - - -/*------------------------------------------------- - imgtool_partition_get_file - read a file from - an image, storing it into a native file --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_get_file(imgtool_partition *partition, const char *filename, const char *fork, - const char *dest, filter_getinfoproc filter) -{ - imgtoolerr_t err; - imgtool_stream *f; - char *new_fname = NULL; - char *alloc_dest = NULL; - const char *filter_extension = NULL; - - if (!dest) - { - /* determine the filter extension, if appropriate */ - if (filter != NULL) - filter_extension = filter_get_info_string(filter, FILTINFO_STR_EXTENSION); - - if (filter_extension != NULL) - { - alloc_dest = (char*)malloc(strlen(filename) + 1 + strlen(filter_extension) + 1); - if (!alloc_dest) - return IMGTOOLERR_OUTOFMEMORY; - - sprintf(alloc_dest, "%s.%s", filename, filter_extension); - dest = alloc_dest; - } - else - { - if (filename == FILENAME_BOOTBLOCK) - dest = "boot.bin"; - else - dest = filename; - } - } - - f = stream_open(dest, OSD_FOPEN_WRITE); - if (!f) - { - err = (imgtoolerr_t)(IMGTOOLERR_FILENOTFOUND | IMGTOOLERR_SRC_NATIVEFILE); - goto done; - } - - new_fname = normalize_filename(partition, filename); - if (new_fname == NULL) - { - err = (imgtoolerr_t)(IMGTOOLERR_BADFILENAME | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - err = imgtool_partition_read_file(partition, new_fname, fork, f, filter); - if (err) - goto done; - -done: - if (f != NULL) - stream_close(f); - if (alloc_dest != NULL) - free(alloc_dest); - if (new_fname != NULL) - osd_free(new_fname); - return err; -} - - - -/*------------------------------------------------- - imgtool_partition_put_file - read a native file - and store it on a partition --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_put_file(imgtool_partition *partition, const char *newfname, const char *fork, - const char *source, option_resolution *opts, filter_getinfoproc filter) -{ - imgtoolerr_t err; - imgtool_stream *f = NULL; - imgtool_charset charset; - char *alloc_newfname = NULL; - - if (!newfname) - newfname = (const char *) imgtool_basename((char *) source); - - charset = (imgtool_charset) (int) imgtool_partition_get_info_int(partition, IMGTOOLINFO_INT_CHARSET); - if (charset != IMGTOOL_CHARSET_UTF8) - { - /* convert to native format */ - alloc_newfname = native_from_utf8(charset, newfname); - if (alloc_newfname == NULL) - { - err = (imgtoolerr_t)(IMGTOOLERR_BADFILENAME | IMGTOOLERR_SRC_NATIVEFILE); - goto done; - } - - newfname = alloc_newfname; - } - - f = stream_open(source, OSD_FOPEN_READ); - if (f) - err = imgtool_partition_write_file(partition, newfname, fork, f, opts, filter); - else - err = (imgtoolerr_t)(IMGTOOLERR_FILENOTFOUND | IMGTOOLERR_SRC_NATIVEFILE); - -done: - /* clean up */ - if (f != NULL) - stream_close(f); - if (alloc_newfname != NULL) - osd_free(alloc_newfname); - return err; -} - - - -/*------------------------------------------------- - imgtool_partition_delete_file - delete a file - on a partition --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_delete_file(imgtool_partition *partition, const char *fname) -{ - imgtoolerr_t err; - char *alloc_path = NULL; - char *new_fname = NULL; - - if (!partition->delete_file) - { - err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - new_fname = normalize_filename(partition, fname); - if (new_fname == NULL) - { - err = (imgtoolerr_t)(IMGTOOLERR_BADFILENAME | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - fname = new_fname; - - /* cannonicalize path */ - err = cannonicalize_path(partition, 0, &fname, &alloc_path); - if (err) - goto done; - - err = partition->delete_file(partition, fname); - if (err) - { - err = markerrorsource(err); - goto done; - } - -done: - if (alloc_path) - free(alloc_path); - if (new_fname) - osd_free(new_fname); - return err; -} - - - -/*------------------------------------------------- - imgtool_partition_list_file_forks - lists all - forks on an image --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_list_file_forks(imgtool_partition *partition, const char *path, imgtool_forkent *ents, size_t len) -{ - imgtoolerr_t err; - char *alloc_path = NULL; - char *new_fname = NULL; - - if (!partition->list_forks) - { - err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - new_fname = normalize_filename(partition, path); - if (new_fname == NULL) - { - err = (imgtoolerr_t)(IMGTOOLERR_BADFILENAME | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - path = new_fname; - - /* cannonicalize path */ - err = cannonicalize_path(partition, 0, &path, &alloc_path); - if (err) - goto done; - - err = partition->list_forks(partition, path, ents, len); - if (err) - goto done; - -done: - if (alloc_path) - free(alloc_path); - if (new_fname) - osd_free(new_fname); - return err; -} - - - -/*------------------------------------------------- - imgtool_partition_create_directory - creates a - directory on a partition --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_create_directory(imgtool_partition *partition, const char *path) -{ - imgtoolerr_t err; - char *alloc_path = NULL; - char *new_path = NULL; - - /* implemented? */ - if (!partition->create_dir) - { - err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - new_path = normalize_filename(partition, path); - if (new_path == NULL) - { - err = (imgtoolerr_t)(IMGTOOLERR_BADFILENAME | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - path = new_path; - - /* cannonicalize path */ - err = cannonicalize_path(partition, PATH_MUSTBEDIR, &path, &alloc_path); - if (err) - goto done; - - err = partition->create_dir(partition, path); - if (err) - goto done; - -done: - if (alloc_path) - free(alloc_path); - if (new_path) - osd_free(new_path); - return err; -} - - - -/*------------------------------------------------- - imgtool_partition_delete_directory - deletes a - directory on a partition --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_delete_directory(imgtool_partition *partition, const char *path) -{ - imgtoolerr_t err; - char *alloc_path = NULL; - char *new_path = NULL; - - /* implemented? */ - if (!partition->delete_dir) - { - err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - new_path = normalize_filename(partition, path); - if (new_path == NULL) - { - err = (imgtoolerr_t)(IMGTOOLERR_BADFILENAME | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - path = new_path; - - /* cannonicalize path */ - err = cannonicalize_path(partition, PATH_MUSTBEDIR, &path, &alloc_path); - if (err) - goto done; - - err = partition->delete_dir(partition, path); - if (err) - goto done; - -done: - if (alloc_path) - free(alloc_path); - if (new_path) - osd_free(new_path); - return err; -} - - - -/*------------------------------------------------- - imgtool_partition_get_block_size - gets the - size of a standard block on a partition --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_get_block_size(imgtool_partition *partition, UINT32 *length) -{ - return imgtool_image_get_block_size(partition->image, length); -} - - - -/*------------------------------------------------- - imgtool_partition_read_block - reads a standard - block on a partition --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_read_block(imgtool_partition *partition, UINT64 block, void *buffer) -{ - if (block >= partition->block_count) - return IMGTOOLERR_SEEKERROR; - return imgtool_image_read_block(partition->image, block + partition->base_block, buffer); -} - - - -/*------------------------------------------------- - imgtool_partition_write_block - writes a - standard block on a partition --------------------------------------------------*/ - -imgtoolerr_t imgtool_partition_write_block(imgtool_partition *partition, UINT64 block, const void *buffer) -{ - if (block >= partition->block_count) - return IMGTOOLERR_SEEKERROR; - return imgtool_image_write_block(partition->image, block + partition->base_block, buffer); -} - - - -/*------------------------------------------------- - imgtool_partition_get_features - retrieves a - structure identifying this partition's features - associated with an image --------------------------------------------------*/ - -imgtool_partition_features imgtool_partition_get_features(imgtool_partition *partition) -{ - imgtool_partition_features features; - memset(&features, 0, sizeof(features)); - - if (partition->read_file) - features.supports_reading = 1; - if (partition->write_file) - features.supports_writing = 1; - if (partition->delete_file) - features.supports_deletefile = 1; - if (partition->path_separator) - features.supports_directories = 1; - if (partition->free_space) - features.supports_freespace = 1; - if (partition->create_dir) - features.supports_createdir = 1; - if (partition->delete_dir) - features.supports_deletedir = 1; - if (partition->supports_creation_time) - features.supports_creation_time = 1; - if (partition->supports_lastmodified_time) - features.supports_lastmodified_time = 1; - if (!features.supports_writing && !features.supports_createdir && !features.supports_deletefile && !features.supports_deletedir) - features.is_read_only = 1; - return features; -} - - - -/*------------------------------------------------- - imgtool_partition_get_info_ptr - retrieves a - pointer associated with a partition's format --------------------------------------------------*/ - -void *imgtool_partition_get_info_ptr(imgtool_partition *partition, UINT32 state) -{ - return imgtool_get_info_ptr(&partition->imgclass, state); -} - - - -/*------------------------------------------------- - imgtool_partition_get_info_string - retrieves a - string associated with a partition's format --------------------------------------------------*/ - -const char *imgtool_partition_get_info_string(imgtool_partition *partition, UINT32 state) -{ - return imgtool_get_info_string(&partition->imgclass, state); -} - - - -/*------------------------------------------------- - imgtool_partition_get_info_int - retrieves a - pointer associated with a partition's format --------------------------------------------------*/ - -UINT64 imgtool_partition_get_info_int(imgtool_partition *partition, UINT32 state) -{ - return imgtool_get_info_int(&partition->imgclass, state); -} - - - -/*------------------------------------------------- - imgtool_partition_extra_bytes - returns extra - bytes on a partition --------------------------------------------------*/ - -void *imgtool_partition_extra_bytes(imgtool_partition *partition) -{ - void *ptr = NULL; - if (partition->partition_extra_bytes > 0) - ptr = ((UINT8 *) partition) + sizeof(*partition); - assert(ptr); - return ptr; -} - - - -/*------------------------------------------------- - imgtool_partition_rand - returns random number --------------------------------------------------*/ - -UINT64 imgtool_partition_rand(imgtool_partition *partition) -{ - return imgtool_image_rand(partition->image); -} - - - -/*************************************************************************** - - Path handling functions - -***************************************************************************/ - -/*------------------------------------------------- - imgtool_partition_get_root_path - retrieves - the path root of this partition --------------------------------------------------*/ - -const char *imgtool_partition_get_root_path(imgtool_partition *partition) -{ - int initial_path_separator; - char path_separator; - char *buf; - int pos = 0; - - initial_path_separator = imgtool_partition_get_info_int(partition, IMGTOOLINFO_INT_INITIAL_PATH_SEPARATOR) ? 1 : 0; - path_separator = (char) imgtool_partition_get_info_int(partition, IMGTOOLINFO_INT_PATH_SEPARATOR); - buf = imgtool_temp_str(); - - if (initial_path_separator) - buf[pos++] = path_separator; - buf[pos] = '\0'; - return buf; -} - - - -/*------------------------------------------------- - imgtool_partition_path_concatenate - retrieves - a pointer associated with a partition's format --------------------------------------------------*/ - -const char *imgtool_partition_path_concatenate(imgtool_partition *partition, const char *path1, const char *path2) -{ - char path_separator; - size_t len; - char *buffer; - size_t buffer_len; - - path_separator = (char) imgtool_partition_get_info_int(partition, IMGTOOLINFO_INT_PATH_SEPARATOR); - len = strlen(path1); - - /* prepare buffer */ - buffer = imgtool_temp_str(); - buffer_len = 256; - - if (!strcmp(path2, ".")) - { - /* keep the same directory */ - snprintf(buffer, buffer_len, "%s", path1); - } - else if (!strcmp(path2, "..")) - { - /* up one directory */ - while((len > 0) && (path1[len - 1] == path_separator)) - len--; - while((len > 0) && (path1[len - 1] != path_separator)) - len--; - while((len > 1) && (path1[len - 1] == path_separator)) - len--; - snprintf(buffer, buffer_len, "%s", path1); - buffer[len] = '\0'; - } - else - { - /* append a path */ - if ((*path1 != 0) && (path1[strlen(path1) - 1] != path_separator)) - snprintf(buffer, buffer_len, "%s%c%s", path1, path_separator, path2); - else - snprintf(buffer, buffer_len, "%s%s", path1, path2); - } - return buffer; -} - - - -/*------------------------------------------------- - imgtool_partition_get_base_name - retrieves - a base name for a partition specific path --------------------------------------------------*/ - -const char *imgtool_partition_get_base_name(imgtool_partition *partition, const char *path) -{ - char path_separator; - const char *new_path = path; - int i; - - path_separator = (char) imgtool_partition_get_info_int(partition, IMGTOOLINFO_INT_PATH_SEPARATOR); - - for (i = 0; path[i]; i++) - { - if (path[i] == path_separator) - new_path = &path[i + 1]; - } - return new_path; -} - - - -/*************************************************************************** - - Directory handling functions - -***************************************************************************/ - -/*------------------------------------------------- - imgtool_directory_open - begins - enumerating files on a partition --------------------------------------------------*/ - -imgtoolerr_t imgtool_directory_open(imgtool_partition *partition, const char *path, imgtool_directory **outenum) -{ - imgtoolerr_t err = (imgtoolerr_t)IMGTOOLERR_SUCCESS; - imgtool_directory *enumeration = NULL; - char *alloc_path = NULL; - char *new_path = NULL; - size_t size; - - /* sanity checks */ - assert(partition); - assert(outenum); - - *outenum = NULL; - - if (!partition->next_enum) - { - err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); - goto done; - } - - new_path = normalize_filename(partition, path); - path = new_path; - - err = cannonicalize_path(partition, PATH_MUSTBEDIR, &path, &alloc_path); - if (err) - goto done; - - size = sizeof(imgtool_directory) + partition->directory_extra_bytes; - enumeration = (imgtool_directory *) malloc(size); - if (!enumeration) - { - err = (imgtoolerr_t)IMGTOOLERR_OUTOFMEMORY; - goto done; - } - memset(enumeration, '\0', size); - enumeration->partition = partition; - - if (partition->begin_enum) - { - err = partition->begin_enum(enumeration, path); - if (err) - { - err = markerrorsource(err); - goto done; - } - } - -done: - if (alloc_path != NULL) - free(alloc_path); - if (new_path != NULL) - osd_free(new_path); - if (err && (enumeration != NULL)) - { - free(enumeration); - enumeration = NULL; - } - *outenum = enumeration; - return err; -} - - - -/*------------------------------------------------- - imgtool_directory_close - closes a directory --------------------------------------------------*/ - -void imgtool_directory_close(imgtool_directory *directory) -{ - imgtool_partition *partition; - partition = imgtool_directory_partition(directory); - if (partition->close_enum) - partition->close_enum(directory); - free(directory); -} - - - -/*------------------------------------------------- - imgtool_directory_get_next - continues - enumerating files within a partition --------------------------------------------------*/ - -imgtoolerr_t imgtool_directory_get_next(imgtool_directory *directory, imgtool_dirent *ent) -{ - imgtoolerr_t err; - imgtool_partition *partition; - int charset; - - partition = imgtool_directory_partition(directory); - - /* This makes it so that drivers don't have to take care of clearing - * the attributes if they don't apply - */ - memset(ent, 0, sizeof(*ent)); - - err = partition->next_enum(directory, ent); - if (err) - return markerrorsource(err); - - charset = imgtool_partition_get_info_int(partition, IMGTOOLINFO_INT_CHARSET); - - if (charset) - { - char *new_fname = utf8_from_native((imgtool_charset)charset, ent->filename); - - if (!new_fname) - return IMGTOOLERR_BADFILENAME; - - strcpy(ent->filename, new_fname); - osd_free(new_fname); - } - - /* don't trust the module! */ - if (!partition->supports_creation_time && (ent->creation_time != 0)) - { - internal_error(NULL, "next_enum() specified creation_time, which is marked as unsupported by this module"); - return IMGTOOLERR_UNEXPECTED; - } - if (!partition->supports_lastmodified_time && (ent->lastmodified_time != 0)) - { - internal_error(NULL, "next_enum() specified lastmodified_time, which is marked as unsupported by this module"); - return IMGTOOLERR_UNEXPECTED; - } - if (!partition->path_separator && ent->directory) - { - internal_error(NULL, "next_enum() returned a directory, which is marked as unsupported by this module"); - return IMGTOOLERR_UNEXPECTED; - } - return IMGTOOLERR_SUCCESS; -} - - - -/*------------------------------------------------- - imgtool_directory_module - returns the module associated - with this directory --------------------------------------------------*/ - -const imgtool_module *imgtool_directory_module(imgtool_directory *directory) -{ - return directory->partition->image->module; -} - - - -/*------------------------------------------------- - imgtool_directory_extrabytes - returns extra - bytes on a directory --------------------------------------------------*/ - -void *imgtool_directory_extrabytes(imgtool_directory *directory) -{ - assert(directory->partition->directory_extra_bytes > 0); - return ((UINT8 *) directory) + sizeof(*directory); -} - - - -/*------------------------------------------------- - imgtool_directory_partition - returns the - partition associated with this directory --------------------------------------------------*/ - -imgtool_partition *imgtool_directory_partition(imgtool_directory *directory) -{ - return directory->partition; -} - - - -/*------------------------------------------------- - imgtool_directory_image - returns the image - associated with this directory --------------------------------------------------*/ - -imgtool_image *imgtool_directory_image(imgtool_directory *directory) -{ - return directory->partition->image; -} - - - -/*------------------------------------------------- - unknown_partition_get_info - represents an - unknown partition --------------------------------------------------*/ - -void unknown_partition_get_info(const imgtool_class *imgclass, UINT32 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(), "unknown"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "Unknown partition type"); break; - } -} diff --git a/src/mess/tools/imgtool/imgtool.h b/src/mess/tools/imgtool/imgtool.h deleted file mode 100644 index e688dfb60f1..00000000000 --- a/src/mess/tools/imgtool/imgtool.h +++ /dev/null @@ -1,169 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - imgtool.h - - Main headers for Imgtool core - -***************************************************************************/ - -#ifndef IMGTOOL_H -#define IMGTOOL_H - -#include <stdlib.h> -#include <stdio.h> -#include <assert.h> - -#include "corestr.h" -#include "formats/flopimg.h" -#include "opresolv.h" -#include "library.h" -#include "filter.h" - -/* ----------------------------------------------------------------------- */ - -#define EOLN_CR "\x0d" -#define EOLN_LF "\x0a" -#define EOLN_CRLF "\x0d\x0a" - -#define FILENAME_BOOTBLOCK ((const char *) 1) - -enum -{ - OSD_FOPEN_READ, - OSD_FOPEN_WRITE, - OSD_FOPEN_RW, - OSD_FOPEN_RW_CREATE -}; - -/* --------------------------------------------------------------------------- - * Image calls - * - * These are the calls that front ends should use for manipulating images. You - * should never call the module functions directly because they may not be - * implemented (i.e. - the function pointers are NULL). The img_* functions are - * aware of these issues and will make the appropriate checks as well as - * marking up return codes with the source. In addition, some of the img_* - * calls are high level calls that simply image manipulation - * - * Calls that return 'int' that are not explictly noted otherwise return - * imgtool error codes - * --------------------------------------------------------------------------- - */ - -struct imgtool_module_features -{ - unsigned int supports_create : 1; - unsigned int supports_open : 1; - unsigned int supports_readsector : 1; - unsigned int supports_writesector : 1; - unsigned int is_read_only : 1; -}; - -struct imgtool_partition_features -{ - unsigned int supports_reading : 1; - unsigned int supports_writing : 1; - unsigned int supports_deletefile : 1; - unsigned int supports_directories : 1; - unsigned int supports_freespace : 1; - unsigned int supports_createdir : 1; - unsigned int supports_deletedir : 1; - unsigned int supports_creation_time : 1; - unsigned int supports_lastmodified_time : 1; - unsigned int supports_forks : 1; - unsigned int supports_geticoninfo : 1; - unsigned int is_read_only : 1; -}; - -/* ----- initialization and basics ----- */ -void imgtool_init(int omit_untested, void (*warning)(const char *message)); -void imgtool_exit(void); -const imgtool_module *imgtool_find_module(const char *modulename); -imgtool_module_features imgtool_get_module_features(const imgtool_module *module); -void imgtool_warn(const char *format, ...) ATTR_PRINTF(1,2); -char *imgtool_basename(char *filename); - -/* ----- image management ----- */ -imgtoolerr_t imgtool_identify_file(const char *filename, imgtool_module **modules, size_t count); -imgtoolerr_t imgtool_image_open(const imgtool_module *module, const char *filename, int read_or_write, imgtool_image **outimg); -imgtoolerr_t imgtool_image_open_byname(const char *modulename, const char *filename, int read_or_write, imgtool_image **outimg); -imgtoolerr_t imgtool_image_create(const imgtool_module *module, const char *fname, option_resolution *opts, imgtool_image **image); -imgtoolerr_t imgtool_image_create_byname(const char *modulename, const char *fname, option_resolution *opts, imgtool_image **image); -void imgtool_image_close(imgtool_image *image); -imgtoolerr_t imgtool_image_info(imgtool_image *image, char *string, size_t len); -imgtoolerr_t imgtool_image_get_sector_size(imgtool_image *image, UINT32 track, UINT32 head, UINT32 sector, UINT32 *length); -imgtoolerr_t imgtool_image_get_geometry(imgtool_image *image, UINT32 *tracks, UINT32 *heads, UINT32 *sectors); -imgtoolerr_t imgtool_image_read_sector(imgtool_image *image, UINT32 track, UINT32 head, UINT32 sector, void *buffer, size_t len); -imgtoolerr_t imgtool_image_write_sector(imgtool_image *image, UINT32 track, UINT32 head, UINT32 sector, const void *buffer, size_t len); -imgtoolerr_t imgtool_image_get_block_size(imgtool_image *image, UINT32 *length); -imgtoolerr_t imgtool_image_read_block(imgtool_image *image, UINT64 block, void *buffer); -imgtoolerr_t imgtool_image_write_block(imgtool_image *image, UINT64 block, const void *buffer); -imgtoolerr_t imgtool_image_clear_block(imgtool_image *image, UINT64 block, UINT8 data); -imgtoolerr_t imgtool_image_list_partitions(imgtool_image *image, imgtool_partition_info *partitions, size_t len); -void *imgtool_image_malloc(imgtool_image *image, size_t size); -const imgtool_module *imgtool_image_module(imgtool_image *image); -void *imgtool_image_extra_bytes(imgtool_image *image); -UINT64 imgtool_image_rand(imgtool_image *image); - -/* ----- partition management ----- */ -imgtoolerr_t imgtool_partition_open(imgtool_image *image, int partition_index, imgtool_partition **partition); -void imgtool_partition_close(imgtool_partition *partition); -imgtool_image *imgtool_partition_image(imgtool_partition *partition); - -/* ----- partition operations ----- */ -imgtoolerr_t imgtool_partition_get_directory_entry(imgtool_partition *partition, const char *path, int index, imgtool_dirent *ent); -imgtoolerr_t imgtool_partition_get_file_size(imgtool_partition *partition, const char *filename, UINT64 *filesize); -imgtoolerr_t imgtool_partition_get_free_space(imgtool_partition *partition, UINT64 *sz); -imgtoolerr_t imgtool_partition_read_file(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf, filter_getinfoproc filter); -imgtoolerr_t imgtool_partition_write_file(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, option_resolution *resolution, filter_getinfoproc filter); -imgtoolerr_t imgtool_partition_get_file(imgtool_partition *partition, const char *filename, const char *fork, const char *dest, filter_getinfoproc filter); -imgtoolerr_t imgtool_partition_put_file(imgtool_partition *partition, const char *newfname, const char *fork, const char *source, option_resolution *opts, filter_getinfoproc filter); -imgtoolerr_t imgtool_partition_delete_file(imgtool_partition *partition, const char *fname); -imgtoolerr_t imgtool_partition_list_file_forks(imgtool_partition *partition, const char *path, imgtool_forkent *ents, size_t len); -imgtoolerr_t imgtool_partition_create_directory(imgtool_partition *partition, const char *path); -imgtoolerr_t imgtool_partition_delete_directory(imgtool_partition *partition, const char *path); -imgtoolerr_t imgtool_partition_list_file_attributes(imgtool_partition *partition, const char *path, UINT32 *attrs, size_t len); -imgtoolerr_t imgtool_partition_get_file_attributes(imgtool_partition *partition, const char *path, const UINT32 *attrs, imgtool_attribute *values); -imgtoolerr_t imgtool_partition_put_file_attributes(imgtool_partition *partition, const char *path, const UINT32 *attrs, const imgtool_attribute *values); -imgtoolerr_t imgtool_partition_get_file_attribute(imgtool_partition *partition, const char *path, UINT32 attr, imgtool_attribute *value); -imgtoolerr_t imgtool_partition_put_file_attribute(imgtool_partition *partition, const char *path, UINT32 attr, imgtool_attribute value); -void imgtool_partition_get_attribute_name(imgtool_partition *partition, UINT32 attribute, const imgtool_attribute *attr_value, char *buffer, size_t buffer_len); -imgtoolerr_t imgtool_partition_get_icon_info(imgtool_partition *partition, const char *path, imgtool_iconinfo *iconinfo); -imgtoolerr_t imgtool_partition_suggest_file_filters(imgtool_partition *partition, const char *path, imgtool_stream *stream, imgtool_transfer_suggestion *suggestions, size_t suggestions_length); -imgtoolerr_t imgtool_partition_get_block_size(imgtool_partition *partition, UINT32 *length); -imgtoolerr_t imgtool_partition_read_block(imgtool_partition *partition, UINT64 block, void *buffer); -imgtoolerr_t imgtool_partition_write_block(imgtool_partition *partition, UINT64 block, const void *buffer); -imgtoolerr_t imgtool_partition_get_chain(imgtool_partition *partition, const char *path, imgtool_chainent *chain, size_t chain_size); -imgtoolerr_t imgtool_partition_get_chain_string(imgtool_partition *partition, const char *path, char *buffer, size_t buffer_len); -imgtool_partition_features imgtool_partition_get_features(imgtool_partition *partition); -void * imgtool_partition_get_info_ptr(imgtool_partition *partition, UINT32 state); -const char * imgtool_partition_get_info_string(imgtool_partition *partition, UINT32 state); -UINT64 imgtool_partition_get_info_int(imgtool_partition *partition, UINT32 state); -void * imgtool_partition_extra_bytes(imgtool_partition *partition); -UINT64 imgtool_partition_rand(imgtool_partition *partition); - -/* ----- path management ----- */ -const char * imgtool_partition_get_root_path(imgtool_partition *partition); -const char * imgtool_partition_path_concatenate(imgtool_partition *partition, const char *path1, const char *path2); -const char * imgtool_partition_get_base_name(imgtool_partition *partition, const char *path); - -/* ----- directory management ----- */ -imgtoolerr_t imgtool_directory_open(imgtool_partition *partition, const char *path, imgtool_directory **outenum); -void imgtool_directory_close(imgtool_directory *enumeration); -imgtoolerr_t imgtool_directory_get_next(imgtool_directory *enumeration, imgtool_dirent *ent); -const imgtool_module *imgtool_directory_module(imgtool_directory *enumeration); -void *imgtool_directory_extrabytes(imgtool_directory *enumeration); -imgtool_partition *imgtool_directory_partition(imgtool_directory *directory); -imgtool_image *imgtool_directory_image(imgtool_directory *enumeration); - -/* ----- special ----- */ -int imgtool_validitychecks(void); -void unknown_partition_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info); - -char *strncpyz(char *dest, const char *source, size_t len); -char *strncatz(char *dest, const char *source, size_t len); -void rtrim(char *buf); - -#endif /* IMGTOOL_H */ diff --git a/src/mess/tools/imgtool/library.c b/src/mess/tools/imgtool/library.c deleted file mode 100644 index e2ce14d4461..00000000000 --- a/src/mess/tools/imgtool/library.c +++ /dev/null @@ -1,282 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/**************************************************************************** - - library.c - - Code relevant to the Imgtool library; analgous to the MESS/MAME driver - list. - -****************************************************************************/ - -#include <string.h> - -#include "imgtool.h" -#include "library.h" -#include "pool.h" - -struct imgtool_library -{ - object_pool *pool; - imgtool_module *first; - imgtool_module *last; -}; - - - -imgtool_library *imgtool_library_create(void) -{ - imgtool_library *library; - object_pool *pool; - - /* create a memory pool */ - pool = pool_alloc_lib(NULL); - if (!pool) - goto error; - - /* allocate the main structure */ - library = (imgtool_library *)pool_malloc_lib(pool, sizeof(imgtool_library)); - if (!library) - goto error; - - /* initialize the structure */ - memset(library, 0, sizeof(*library)); - library->pool = pool; - - return library; - -error: - if (pool) - pool_free_lib(pool); - return NULL; -} - - - -void imgtool_library_close(imgtool_library *library) -{ - pool_free_lib(library->pool); -} - - - -static void imgtool_library_add_class(imgtool_library *library, const imgtool_class *imgclass) -{ - imgtool_module *module; - char *s1, *s2; - - /* allocate the module and place it in the chain */ - module = (imgtool_module *)imgtool_library_malloc(library, sizeof(*module)); - memset(module, 0, sizeof(*module)); - module->previous = library->last; - if (library->last) - library->last->next = module; - else - library->first = module; - library->last = module; - - /* extensions have a weird format */ - s1 = imgtool_get_info_string(imgclass, IMGTOOLINFO_STR_FILE_EXTENSIONS); - s2 = (char*)imgtool_library_malloc(library, strlen(s1) + 1); - strcpy(s2, s1); - module->extensions = s2; - - module->imgclass = *imgclass; - module->name = imgtool_library_strdup(library, imgtool_get_info_string(imgclass, IMGTOOLINFO_STR_NAME)); - module->description = imgtool_library_strdup(library, imgtool_get_info_string(imgclass, IMGTOOLINFO_STR_DESCRIPTION)); - module->eoln = imgtool_library_strdup_allow_null(library, imgtool_get_info_string(imgclass, IMGTOOLINFO_STR_EOLN)); - module->initial_path_separator = imgtool_get_info_int(imgclass, IMGTOOLINFO_INT_INITIAL_PATH_SEPARATOR) ? 1 : 0; - module->open_is_strict = imgtool_get_info_int(imgclass, IMGTOOLINFO_INT_OPEN_IS_STRICT) ? 1 : 0; - module->tracks_are_called_cylinders = imgtool_get_info_int(imgclass, IMGTOOLINFO_INT_TRACKS_ARE_CALLED_CYLINDERS) ? 1 : 0; - module->writing_untested = imgtool_get_info_int(imgclass, IMGTOOLINFO_INT_WRITING_UNTESTED) ? 1 : 0; - module->creation_untested = imgtool_get_info_int(imgclass, IMGTOOLINFO_INT_CREATION_UNTESTED) ? 1 : 0; - module->open = (imgtoolerr_t (*)(imgtool_image *, imgtool_stream *)) imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_OPEN); - module->create = (imgtoolerr_t (*)(imgtool_image *, imgtool_stream *, option_resolution *)) imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_CREATE); - module->close = (void (*)(imgtool_image *)) imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_CLOSE); - module->info = (void (*)(imgtool_image *, char *, size_t)) imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_INFO); - module->read_sector = (imgtoolerr_t (*)(imgtool_image *, UINT32, UINT32, UINT32, void *, size_t)) imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_READ_SECTOR); - module->write_sector = (imgtoolerr_t (*)(imgtool_image *, UINT32, UINT32, UINT32, const void *, size_t)) imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_WRITE_SECTOR); - module->get_geometry = (imgtoolerr_t (*)(imgtool_image *, UINT32 *, UINT32 *, UINT32 *))imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_GET_GEOMETRY); - module->get_sector_size = (imgtoolerr_t (*)(imgtool_image *, UINT32, UINT32, UINT32, UINT32 *))imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_GET_SECTOR_SIZE); - module->read_block = (imgtoolerr_t (*)(imgtool_image *, void *, UINT64)) imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_READ_BLOCK); - module->write_block = (imgtoolerr_t (*)(imgtool_image *, const void *, UINT64)) imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_WRITE_BLOCK); - module->list_partitions = (imgtoolerr_t (*)(imgtool_image *, imgtool_partition_info *, size_t)) imgtool_get_info_fct(imgclass, IMGTOOLINFO_PTR_LIST_PARTITIONS); - module->block_size = imgtool_get_info_int(imgclass, IMGTOOLINFO_INT_BLOCK_SIZE); - module->createimage_optguide = (const option_guide *) imgtool_get_info_ptr(imgclass, IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE); - module->createimage_optspec = imgtool_library_strdup_allow_null(library, (const char*)imgtool_get_info_ptr(imgclass, IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC)); - module->image_extra_bytes += imgtool_get_info_int(imgclass, IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES); -} - - - -void imgtool_library_add(imgtool_library *library, imgtool_get_info get_info) -{ - int (*make_class)(int index, imgtool_class *imgclass); - imgtool_class imgclass; - int i, result; - - /* try this class */ - memset(&imgclass, 0, sizeof(imgclass)); - imgclass.get_info = get_info; - - /* do we have derived getinfo functions? */ - make_class = (int (*)(int index, imgtool_class *imgclass)) - imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_MAKE_CLASS); - - if (make_class) - { - i = 0; - do - { - /* clear out the class */ - memset(&imgclass, 0, sizeof(imgclass)); - imgclass.get_info = get_info; - - /* make the class */ - result = make_class(i++, &imgclass); - if (result) - imgtool_library_add_class(library, &imgclass); - } - while(result); - } - else - { - imgtool_library_add_class(library, &imgclass); - } -} - - - -const imgtool_module *imgtool_library_unlink(imgtool_library *library, - const char *module) -{ - imgtool_module *m; - imgtool_module **previous; - imgtool_module **next; - - for (m = library->first; m; m = m->next) - { - if (!core_stricmp(m->name, module)) - { - previous = m->previous ? &m->previous->next : &library->first; - next = m->next ? &m->next->previous : &library->last; - *previous = m->next; - *next = m->previous; - m->previous = NULL; - m->next = NULL; - return m; - } - } - return NULL; -} - - - -static int module_compare(const imgtool_module *m1, - const imgtool_module *m2, imgtool_libsort_t sort) -{ - int rc = 0; - switch(sort) - { - case ITLS_NAME: - rc = strcmp(m1->name, m2->name); - break; - case ITLS_DESCRIPTION: - rc = core_stricmp(m1->name, m2->name); - break; - } - return rc; -} - - - -void imgtool_library_sort(imgtool_library *library, imgtool_libsort_t sort) -{ - imgtool_module *m1; - imgtool_module *m2; - imgtool_module *target; - imgtool_module **before; - imgtool_module **after; - - for (m1 = library->first; m1; m1 = m1->next) - { - target = m1; - for (m2 = m1->next; m2; m2 = m2->next) - { - while(module_compare(target, m2, sort) > 0) - target = m2; - } - - if (target != m1) - { - /* unlink the target */ - before = target->previous ? &target->previous->next : &library->first; - after = target->next ? &target->next->previous : &library->last; - *before = target->next; - *after = target->previous; - - /* now place the target before m1 */ - target->previous = m1->previous; - target->next = m1; - before = m1->previous ? &m1->previous->next : &library->first; - *before = target; - m1->previous = target; - - /* since we changed the order, we have to replace ourselves */ - m1 = target; - } - } -} - - - -const imgtool_module *imgtool_library_findmodule( - imgtool_library *library, const char *module_name) -{ - const imgtool_module *module; - - assert(library); - module = library->first; - while(module && module_name && strcmp(module->name, module_name)) - module = module->next; - return module; -} - - - -imgtool_module *imgtool_library_iterate(imgtool_library *library, const imgtool_module *module) -{ - return module ? module->next : library->first; -} - - - -imgtool_module *imgtool_library_index(imgtool_library *library, int i) -{ - imgtool_module *module; - module = library->first; - while(module && i--) - module = module->next; - return module; -} - - - -void *imgtool_library_malloc(imgtool_library *library, size_t mem) -{ - return pool_malloc_lib(library->pool, mem); -} - - - -char *imgtool_library_strdup(imgtool_library *library, const char *s) -{ - return pool_strdup_lib(library->pool, s); -} - - - -char *imgtool_library_strdup_allow_null(imgtool_library *library, const char *s) -{ - return s ? imgtool_library_strdup(library, s) : NULL; -} diff --git a/src/mess/tools/imgtool/library.h b/src/mess/tools/imgtool/library.h deleted file mode 100644 index 25c923c1f4d..00000000000 --- a/src/mess/tools/imgtool/library.h +++ /dev/null @@ -1,408 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/**************************************************************************** - - library.h - - Code relevant to the Imgtool library; analgous to the MESS/MAME driver - list. - - Unlike MESS and MAME which have static driver lists, Imgtool has a - concept of a library and this library is built at startup time. - dynamic for which modules are added to. This makes "dynamic" modules - much easier - -****************************************************************************/ - -#ifndef LIBRARY_H -#define LIBRARY_H - -#include <time.h> - -#include "corestr.h" -#include "opresolv.h" -#include "stream.h" -#include "unicode.h" -#include "charconv.h" - - -struct imgtool_image; -struct imgtool_partition; -struct imgtool_directory; -struct imgtool_library; - -enum imgtool_suggestion_viability_t -{ - SUGGESTION_END, - SUGGESTION_POSSIBLE, - SUGGESTION_RECOMMENDED -}; - -union filterinfo -{ - INT64 i; /* generic integers */ - void * p; /* generic pointers */ - void * f; /* generic function pointers */ - const char *s; /* generic strings */ - - imgtoolerr_t (*read_file)(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf); - imgtoolerr_t (*write_file)(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, option_resolution *opts); - imgtoolerr_t (*check_stream)(imgtool_stream *stream, imgtool_suggestion_viability_t *viability); -}; - -typedef void (*filter_getinfoproc)(UINT32 state, union filterinfo *info); - -enum imgtool_libsort_t -{ - ITLS_NAME, - ITLS_DESCRIPTION -}; - -struct imgtool_dirent -{ - char filename[1024]; - char attr[64]; - UINT64 filesize; - - time_t creation_time; - time_t lastmodified_time; - time_t lastaccess_time; - - char softlink[1024]; - char comment[256]; - - /* flags */ - unsigned int eof : 1; - unsigned int corrupt : 1; - unsigned int directory : 1; - unsigned int hardlink : 1; -}; - -struct imgtool_chainent -{ - UINT8 level; - UINT64 block; -}; - -enum imgtool_forktype_t -{ - FORK_END, - FORK_DATA, - FORK_RESOURCE, - FORK_ALTERNATE -}; - -struct imgtool_forkent -{ - imgtool_forktype_t type; - UINT64 size; - char forkname[64]; -}; - -struct imgtool_transfer_suggestion -{ - imgtool_suggestion_viability_t viability; - filter_getinfoproc filter; - const char *fork; - const char *description; -}; - -enum -{ - /* --- the following bits of info are returned as 64-bit signed integers --- */ - IMGTOOLATTR_INT_FIRST = 0x00000, - 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_ICONID, - IMGTOOLATTR_INT_MAC_SCRIPTCODE, - IMGTOOLATTR_INT_MAC_EXTENDEDFLAGS, - IMGTOOLATTR_INT_MAC_COMMENTID, - IMGTOOLATTR_INT_MAC_PUTAWAYDIRECTORY, - - /* --- the following bits of info are returned as pointers to data or functions --- */ - IMGTOOLATTR_PTR_FIRST = 0x10000, - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - IMGTOOLATTR_STR_FIRST = 0x20000, - - /* --- the following bits of info are returned as time_t values --- */ - IMGTOOLATTR_TIME_FIRST = 0x30000, - IMGTOOLATTR_TIME_CREATED, - IMGTOOLATTR_TIME_LASTMODIFIED -}; - -union imgtool_attribute -{ - INT64 i; - time_t t; -}; - -struct imgtool_iconinfo -{ - unsigned icon16x16_specified : 1; - unsigned icon32x32_specified : 1; - UINT32 icon16x16[16][16]; - UINT32 icon32x32[32][32]; -}; - -enum -{ - /* --- the following bits of info are returned as 64-bit signed integers --- */ - IMGTOOLINFO_INT_FIRST = 0x00000, - IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES, - IMGTOOLINFO_INT_PARTITION_EXTRA_BYTES, - IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES, - IMGTOOLINFO_INT_PATH_SEPARATOR, - IMGTOOLINFO_INT_ALTERNATE_PATH_SEPARATOR, - IMGTOOLINFO_INT_PREFER_UCASE, - IMGTOOLINFO_INT_INITIAL_PATH_SEPARATOR, - IMGTOOLINFO_INT_OPEN_IS_STRICT, - IMGTOOLINFO_INT_SUPPORTS_CREATION_TIME, - IMGTOOLINFO_INT_SUPPORTS_LASTMODIFIED_TIME, - IMGTOOLINFO_INT_TRACKS_ARE_CALLED_CYLINDERS, - IMGTOOLINFO_INT_WRITING_UNTESTED, - IMGTOOLINFO_INT_CREATION_UNTESTED, - IMGTOOLINFO_INT_SUPPORTS_BOOTBLOCK, - IMGTOOLINFO_INT_BLOCK_SIZE, - IMGTOOLINFO_INT_CHARSET, - - IMGTOOLINFO_INT_CLASS_SPECIFIC = 0x08000, - - /* --- the following bits of info are returned as pointers to data or functions --- */ - IMGTOOLINFO_PTR_FIRST = 0x10000, - - IMGTOOLINFO_PTR_OPEN, - IMGTOOLINFO_PTR_CREATE, - IMGTOOLINFO_PTR_CLOSE, - IMGTOOLINFO_PTR_OPEN_PARTITION, - IMGTOOLINFO_PTR_CREATE_PARTITION, - IMGTOOLINFO_PTR_INFO, - IMGTOOLINFO_PTR_BEGIN_ENUM, - IMGTOOLINFO_PTR_NEXT_ENUM, - IMGTOOLINFO_PTR_CLOSE_ENUM, - IMGTOOLINFO_PTR_FREE_SPACE, - IMGTOOLINFO_PTR_READ_FILE, - IMGTOOLINFO_PTR_WRITE_FILE, - IMGTOOLINFO_PTR_DELETE_FILE, - IMGTOOLINFO_PTR_LIST_FORKS, - IMGTOOLINFO_PTR_CREATE_DIR, - IMGTOOLINFO_PTR_DELETE_DIR, - IMGTOOLINFO_PTR_LIST_ATTRS, - IMGTOOLINFO_PTR_GET_ATTRS, - IMGTOOLINFO_PTR_SET_ATTRS, - IMGTOOLINFO_PTR_ATTR_NAME, - IMGTOOLINFO_PTR_GET_ICON_INFO, - IMGTOOLINFO_PTR_SUGGEST_TRANSFER, - IMGTOOLINFO_PTR_GET_CHAIN, - IMGTOOLINFO_PTR_GET_SECTOR_SIZE, - IMGTOOLINFO_PTR_GET_GEOMETRY, - IMGTOOLINFO_PTR_READ_SECTOR, - IMGTOOLINFO_PTR_WRITE_SECTOR, - IMGTOOLINFO_PTR_READ_BLOCK, - IMGTOOLINFO_PTR_WRITE_BLOCK, - IMGTOOLINFO_PTR_APPROVE_FILENAME_CHAR, - IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE, - IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE, - IMGTOOLINFO_PTR_MAKE_CLASS, - IMGTOOLINFO_PTR_LIST_PARTITIONS, - - IMGTOOLINFO_PTR_CLASS_SPECIFIC = 0x18000, - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - IMGTOOLINFO_STR_FIRST = 0x20000, - - IMGTOOLINFO_STR_NAME, - IMGTOOLINFO_STR_DESCRIPTION, - IMGTOOLINFO_STR_FILE, - IMGTOOLINFO_STR_FILE_EXTENSIONS, - IMGTOOLINFO_STR_EOLN, - IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC, - IMGTOOLINFO_STR_WRITEFILE_OPTSPEC, - - IMGTOOLINFO_STR_CLASS_SPECIFIC = 0x28000 -}; - - - -union imgtoolinfo; - -struct imgtool_class; -typedef void (*imgtool_get_info)(const imgtool_class *, UINT32, union imgtoolinfo *); - -struct imgtool_class -{ - imgtool_get_info get_info; - imgtool_get_info derived_get_info; - void *derived_param; -}; - - - -struct imgtool_partition_info -{ - imgtool_get_info get_info; - UINT64 base_block; - UINT64 block_count; -}; - - - -union imgtoolinfo -{ - INT64 i; /* generic integers */ - void * p; /* generic pointers */ - void * f; /* generic function pointers */ - char * s; /* generic strings */ - - imgtoolerr_t (*open) (imgtool_image *image, imgtool_stream *stream); - void (*close) (imgtool_image *image); - imgtoolerr_t (*create) (imgtool_image *image, imgtool_stream *stream, option_resolution *opts); - imgtoolerr_t (*create_partition) (imgtool_image *image, UINT64 first_block, UINT64 block_count); - void (*info) (imgtool_image *image, char *string, size_t len); - imgtoolerr_t (*begin_enum) (imgtool_directory *enumeration, const char *path); - imgtoolerr_t (*next_enum) (imgtool_directory *enumeration, imgtool_dirent *ent); - void (*close_enum) (imgtool_directory *enumeration); - imgtoolerr_t (*open_partition) (imgtool_partition *partition, UINT64 first_block, UINT64 block_count); - imgtoolerr_t (*free_space) (imgtool_partition *partition, UINT64 *size); - imgtoolerr_t (*read_file) (imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf); - imgtoolerr_t (*write_file) (imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, option_resolution *opts); - imgtoolerr_t (*delete_file) (imgtool_partition *partition, const char *filename); - imgtoolerr_t (*list_forks) (imgtool_partition *partition, const char *path, imgtool_forkent *ents, size_t len); - imgtoolerr_t (*create_dir) (imgtool_partition *partition, const char *path); - imgtoolerr_t (*delete_dir) (imgtool_partition *partition, const char *path); - imgtoolerr_t (*list_attrs) (imgtool_partition *partition, const char *path, UINT32 *attrs, size_t len); - imgtoolerr_t (*get_attrs) (imgtool_partition *partition, const char *path, const UINT32 *attrs, imgtool_attribute *values); - imgtoolerr_t (*set_attrs) (imgtool_partition *partition, const char *path, const UINT32 *attrs, const imgtool_attribute *values); - imgtoolerr_t (*attr_name) (UINT32 attribute, const imgtool_attribute *attr, char *buffer, size_t buffer_len); - imgtoolerr_t (*get_iconinfo) (imgtool_partition *partition, const char *path, imgtool_iconinfo *iconinfo); - imgtoolerr_t (*suggest_transfer) (imgtool_partition *partition, const char *path, imgtool_transfer_suggestion *suggestions, size_t suggestions_length); - imgtoolerr_t (*get_chain) (imgtool_partition *partition, const char *path, imgtool_chainent *chain, size_t chain_size); - imgtoolerr_t (*get_sector_size) (imgtool_image *image, UINT32 track, UINT32 head, UINT32 sector, UINT32 *sector_size); - imgtoolerr_t (*get_geometry) (imgtool_image *image, UINT32 *tracks, UINT32 *heads, UINT32 *sectors); - imgtoolerr_t (*read_sector) (imgtool_image *image, UINT32 track, UINT32 head, UINT32 sector, void *buffer, size_t len); - imgtoolerr_t (*write_sector) (imgtool_image *image, UINT32 track, UINT32 head, UINT32 sector, const void *buffer, size_t len, int ddam); - imgtoolerr_t (*read_block) (imgtool_image *image, void *buffer, UINT64 block); - imgtoolerr_t (*write_block) (imgtool_image *image, const void *buffer, UINT64 block); - imgtoolerr_t (*list_partitions) (imgtool_image *image, imgtool_partition_info *partitions, size_t len); - int (*approve_filename_char)(unicode_char ch); - int (*make_class)(int index, imgtool_class *imgclass); - - const option_guide *createimage_optguide; - const option_guide *writefile_optguide; -}; - - - -INLINE INT64 imgtool_get_info_int(const imgtool_class *imgclass, UINT32 state) -{ - union imgtoolinfo info; - info.i = 0; - imgclass->get_info(imgclass, state, &info); - return info.i; -} - -INLINE void *imgtool_get_info_ptr(const imgtool_class *imgclass, UINT32 state) -{ - union imgtoolinfo info; - info.p = NULL; - imgclass->get_info(imgclass, state, &info); - return info.p; -} - -INLINE void *imgtool_get_info_fct(const imgtool_class *imgclass, UINT32 state) -{ - union imgtoolinfo info; - info.f = NULL; - imgclass->get_info(imgclass, state, &info); - return info.f; -} - -INLINE char *imgtool_get_info_string(const imgtool_class *imgclass, UINT32 state) -{ - union imgtoolinfo info; - info.s = NULL; - imgclass->get_info(imgclass, state, &info); - return info.s; -} - -/* circular string buffer */ -char *imgtool_temp_str(void); - - - -struct imgtool_module -{ - imgtool_module *previous; - imgtool_module *next; - - imgtool_class imgclass; - - const char *name; - const char *description; - const char *extensions; - const char *eoln; - - size_t image_extra_bytes; - - /* flags */ - unsigned int initial_path_separator : 1; - unsigned int open_is_strict : 1; - unsigned int tracks_are_called_cylinders : 1; /* used for hard drivers */ - unsigned int writing_untested : 1; /* used when we support writing, but not in main build */ - unsigned int creation_untested : 1; /* used when we support creation, but not in main build */ - - imgtoolerr_t (*open) (imgtool_image *image, imgtool_stream *f); - void (*close) (imgtool_image *image); - void (*info) (imgtool_image *image, char *string, size_t len); - imgtoolerr_t (*create) (imgtool_image *image, imgtool_stream *f, option_resolution *opts); - imgtoolerr_t (*get_sector_size)(imgtool_image *image, UINT32 track, UINT32 head, UINT32 sector, UINT32 *sector_size); - imgtoolerr_t (*get_geometry) (imgtool_image *image, UINT32 *track, UINT32 *heads, UINT32 *sectors); - imgtoolerr_t (*read_sector) (imgtool_image *image, UINT32 track, UINT32 head, UINT32 sector, void *buffer, size_t len); - imgtoolerr_t (*write_sector) (imgtool_image *image, UINT32 track, UINT32 head, UINT32 sector, const void *buffer, size_t len); - imgtoolerr_t (*read_block) (imgtool_image *image, void *buffer, UINT64 block); - imgtoolerr_t (*write_block) (imgtool_image *image, const void *buffer, UINT64 block); - imgtoolerr_t (*list_partitions)(imgtool_image *image, imgtool_partition_info *partitions, size_t len); - - UINT32 block_size; - - const option_guide *createimage_optguide; - const char *createimage_optspec; - - const void *extra; -}; - -/* creates an imgtool library */ -imgtool_library *imgtool_library_create(void); - -/* closes an imgtool library */ -void imgtool_library_close(imgtool_library *library); - -/* adds a module to an imgtool library */ -void imgtool_library_add(imgtool_library *library, imgtool_get_info get_info); - -/* seeks out and removes a module from an imgtool library */ -const imgtool_module *imgtool_library_unlink(imgtool_library *library, - const char *module); - -/* sorts an imgtool library */ -void imgtool_library_sort(imgtool_library *library, imgtool_libsort_t sort); - -/* finds a module */ -const imgtool_module *imgtool_library_findmodule( - imgtool_library *library, const char *module_name); - -/* memory allocators for pooled library memory */ -void *imgtool_library_malloc(imgtool_library *library, size_t mem); -char *imgtool_library_strdup(imgtool_library *library, const char *s); -char *imgtool_library_strdup_allow_null(imgtool_library *library, const char *s); - -imgtool_module *imgtool_library_iterate( - imgtool_library *library, const imgtool_module *module); -imgtool_module *imgtool_library_index( - imgtool_library *library, int i); - -#endif /* LIBRARY_H */ diff --git a/src/mess/tools/imgtool/main.c b/src/mess/tools/imgtool/main.c deleted file mode 100644 index 6825b71fa81..00000000000 --- a/src/mess/tools/imgtool/main.c +++ /dev/null @@ -1,972 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - main.c - - Imgtool command line front end - -***************************************************************************/ - -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <stdlib.h> -#include <time.h> - -#include "imgtool.h" -#include "main.h" -#include "modules.h" -/* ---------------------------------------------------------------------- */ - -static void writeusage(FILE *f, int write_word_usage, const struct command *c, char *argv[]) -{ - fprintf(f, "%s %s %s %s\n", - (write_word_usage ? "Usage:" : " "), - imgtool_basename(argv[0]), - c->name, - c->usage ? c->usage : ""); -} - - - -/* ----------------------------------------------------------------------- */ - -static int parse_options(int argc, char *argv[], int minunnamed, int maxunnamed, - option_resolution *resolution, filter_getinfoproc *filter, const char **fork) -{ - int i; - int lastunnamed = 0; - char *s; - char *name = NULL; - char *value = NULL; - optreserr_t oerr; - static char buf[256]; - - if (filter) - *filter = NULL; - if (fork) - *fork = NULL; - - for (i = 0; i < argc; i++) - { - /* Named or unamed arg */ - if ((argv[i][0] != '-') || (argv[i][1] != '-')) - { - /* Unnamed */ - if (i >= maxunnamed) - goto error; /* Too many unnamed */ - lastunnamed = i + 1; - } - else - { - /* Named */ - name = argv[i] + 2; - s = strchr(name, '='); - if (!s) - goto error; - *s = 0; - value = s + 1; - - if (!strcmp(name, "filter")) - { - /* filter option */ - if (!filter) - goto error; /* this command doesn't use filters */ - if (*filter) - goto optionalreadyspecified; - *filter = filter_lookup(value); - if (!(*filter)) - goto filternotfound; - - } - else if (!strcmp(name, "fork")) - { - /* fork option */ - if (!fork) - goto error; /* this command doesn't use filters */ - if (*fork) - goto optionalreadyspecified; - - snprintf(buf, ARRAY_LENGTH(buf), "%s", value); - *fork = buf; - } - else - { - /* Other named option */ - if (i < minunnamed) - goto error; /* Too few unnamed */ - - oerr = option_resolution_add_param(resolution, name, value); - if (oerr) - goto opterror; - } - } - } - return lastunnamed; - -filternotfound: - fprintf(stderr, "%s: Unknown filter type\n", value); - return -1; - -optionalreadyspecified: - fprintf(stderr, "Cannot specify multiple %ss\n", name); - return -1; - -opterror: - fprintf(stderr, "%s: %s\n", name, option_resolution_error_string(oerr)); - return -1; - -error: - fprintf(stderr, "%s: Unrecognized option\n", argv[i]); - return -1; -} - - - -void reporterror(imgtoolerr_t err, const struct command *c, const char *format, const char *imagename, - const char *filename, const char *newname, option_resolution *opts) -{ - const char *src = "imgtool"; - const char *err_name; - - err_name = imgtool_error(err); - - switch(ERRORSOURCE(err)) { - case IMGTOOLERR_SRC_MODULE: - src = format; - break; - case IMGTOOLERR_SRC_FUNCTIONALITY: - src = c->name; - break; - case IMGTOOLERR_SRC_IMAGEFILE: - src = imagename; - break; - case IMGTOOLERR_SRC_FILEONIMAGE: - src = filename; - break; - case IMGTOOLERR_SRC_NATIVEFILE: - src = newname ? newname : filename; - break; - } - fflush(stdout); - fflush(stderr); - - if (!src) - src = c->name; - fprintf(stderr, "%s: %s\n", src, err_name); -} - - - -static const char *interpret_filename(const char *filename) -{ - if (!strcmp(filename, "??BOOT??") - || !strcmp(filename, "\'??BOOT??\'") - || !strcmp(filename, "\"??BOOT??\"")) - filename = FILENAME_BOOTBLOCK; - return filename; -} - - - -/* ----------------------------------------------------------------------- */ - -static int cmd_dir(const struct command *c, int argc, char *argv[]) -{ - imgtoolerr_t err; - int total_count, total_size, freespace_err; - UINT64 freespace; - imgtool_image *image = NULL; - imgtool_partition *partition = NULL; - imgtool_directory *imgenum = NULL; - imgtool_dirent ent; - char buf[512]; - char last_modified[19]; - const char *path; - int partition_index = 0; - - /* attempt to open image */ - err = imgtool_image_open_byname(argv[0], argv[1], OSD_FOPEN_READ, &image); - if (err) - goto done; - - /* attempt to open partition */ - err = imgtool_partition_open(image, partition_index, &partition); - if (err) - goto done; - - path = argc > 2 ? argv[2] : NULL; - - err = imgtool_directory_open(partition, path, &imgenum); - if (err) - goto done; - - memset(&ent, 0, sizeof(ent)); - last_modified[0] = '\0'; - total_count = 0; - total_size = 0; - - fprintf(stdout, "Contents of %s:%s\n", argv[1], path ? path : ""); - - imgtool_image_info(image, buf, sizeof(buf)); - if (buf[0]) - fprintf(stdout, "%s\n", buf); - fprintf(stdout, "------------------------------ -------- --------------- ------------------\n"); - - while (((err = imgtool_directory_get_next(imgenum, &ent)) == 0) && !ent.eof) - { - if (ent.directory) - snprintf(buf, sizeof(buf), "<DIR>"); - else - snprintf(buf, sizeof(buf), "%u", (unsigned int) ent.filesize); - - if (ent.lastmodified_time != 0) - strftime(last_modified, sizeof(last_modified), "%d-%b-%y %H:%M:%S", - localtime(&ent.lastmodified_time)); - - if (ent.hardlink) - strcat(ent.filename, " <hl>"); - - fprintf(stdout, "%-30s %8s %15s %18s\n", ent.filename, buf, ent.attr, last_modified); - - if (ent.softlink && ent.softlink[0] != '\0') - fprintf(stdout, "-> %s\n", ent.softlink); - - if (ent.comment && ent.comment[0] != '\0') - fprintf(stdout, ": %s\n", ent.comment); - - total_count++; - total_size += ent.filesize; - - memset(&ent, 0, sizeof(ent)); - } - - freespace_err = imgtool_partition_get_free_space(partition, &freespace); - - if (err) - goto done; - - fprintf(stdout, "------------------------ ------ ---------------\n"); - fprintf(stdout, "%8i File(s) %8i bytes\n", total_count, total_size); - if (!freespace_err) - fprintf(stdout, " %8u bytes free\n", (unsigned int) freespace); - -done: - if (imgenum) - imgtool_directory_close(imgenum); - if (partition) - imgtool_partition_close(partition); - if (image) - imgtool_image_close(image); - if (err) - reporterror(err, c, argv[0], argv[1], NULL, NULL, NULL); - return err ? -1 : 0; -} - - - -static int cmd_get(const struct command *c, int argc, char *argv[]) -{ - imgtoolerr_t err; - imgtool_image *image = NULL; - imgtool_partition *partition = NULL; - const char *filename; - char *new_filename; - int unnamedargs = 0; - filter_getinfoproc filter; - const char *fork; - int partition_index = 0; - - err = imgtool_image_open_byname(argv[0], argv[1], OSD_FOPEN_READ, &image); - if (err) - goto done; - - err = imgtool_partition_open(image, partition_index, &partition); - if (err) - goto done; - - filename = interpret_filename(argv[2]); - - unnamedargs = parse_options(argc, argv, 3, 4, NULL, &filter, &fork); - if (unnamedargs < 0) - goto done; - - new_filename = (unnamedargs == 4) ? argv[3] : NULL; - - err = imgtool_partition_get_file(partition, filename, fork, new_filename, filter); - if (err) - goto done; - - err = IMGTOOLERR_SUCCESS; - -done: - if (err) - reporterror(err, c, argv[0], argv[1], argv[2], argv[3], NULL); - if (partition) - imgtool_partition_close(partition); - if (image) - imgtool_image_close(image); - return (err || (unnamedargs < 0)) ? -1 : 0; -} - - - -static int cmd_put(const struct command *c, int argc, char *argv[]) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - int i; - imgtool_image *image = NULL; - imgtool_partition *partition = NULL; - const char *filename = NULL; - int unnamedargs; - filter_getinfoproc filter; - const imgtool_module *module; - option_resolution *resolution = NULL; - const char *fork; - const char *new_filename; - char **filename_list; - int filename_count; - int partition_index = 0; - const option_guide *writefile_optguide; - const char *writefile_optspec; - - module = imgtool_find_module(argv[0]); - if (!module) - { - err = (imgtoolerr_t)(IMGTOOLERR_MODULENOTFOUND | IMGTOOLERR_SRC_MODULE); - goto done; - } - - /* ugh I hate the way this function is set up, this is because the - * arguments depend on the partition; something that requires some - * rudimentary parsing */ - if (argc >= 2) - { - /* open up the image */ - err = imgtool_image_open(module, argv[1], OSD_FOPEN_RW, &image); - if (err) - goto done; - - /* open up the partition */ - err = imgtool_partition_open(image, partition_index, &partition); - if (err) - goto done; - - writefile_optguide = (const option_guide *) imgtool_partition_get_info_ptr(partition, IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE); - writefile_optspec = (const char *)imgtool_partition_get_info_ptr(partition, IMGTOOLINFO_STR_WRITEFILE_OPTSPEC); - - if (writefile_optguide && writefile_optspec) - { - resolution = option_resolution_create(writefile_optguide, writefile_optspec); - if (!resolution) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto done; - } - } - } - - unnamedargs = parse_options(argc, argv, 4, 0xffff, resolution, &filter, &fork); - if (unnamedargs < 0) - return -1; - - /* pick out which args are filenames, and which one is the destination */ - new_filename = interpret_filename(argv[unnamedargs - 1]); - filename_list = &argv[2]; - filename_count = unnamedargs - 3; - - /* loop through the filenames, and put them */ - for (i = 0; i < filename_count; i++) - { - filename = filename_list[i]; - printf("Putting file '%s'...\n", filename); - err = imgtool_partition_put_file(partition, new_filename, fork, filename, resolution, filter); - if (err) - goto done; - } - -done: - if (partition) - imgtool_partition_close(partition); - if (image) - imgtool_image_close(image); - if (resolution) - option_resolution_close(resolution); - if (err) - reporterror(err, c, argv[0], argv[1], filename, NULL, resolution); - return err ? -1 : 0; -} - - - -static int cmd_getall(const struct command *c, int argc, char *argv[]) -{ - imgtoolerr_t err; - imgtool_image *image = NULL; - imgtool_partition *partition = NULL; - imgtool_directory *imgenum = NULL; - imgtool_dirent ent; - filter_getinfoproc filter; - int unnamedargs; - const char *path = NULL; - int arg; - int partition_index = 0; - - err = imgtool_image_open_byname(argv[0], argv[1], OSD_FOPEN_READ, &image); - if (err) - goto done; - - err = imgtool_partition_open(image, partition_index, &partition); - if (err) - goto done; - - arg = 2; - if ((argc > 2) && (argv[2][0] != '-')) - { - path = argv[arg++]; - } - - unnamedargs = parse_options(argc, argv, arg, arg, NULL, &filter, NULL); - if (unnamedargs < 0) - goto done; - - err = imgtool_directory_open(partition, path, &imgenum); - if (err) - goto done; - - memset(&ent, 0, sizeof(ent)); - - while (((err = imgtool_directory_get_next(imgenum, &ent)) == 0) && !ent.eof) - { - fprintf(stdout, "Retrieving %s (%u bytes)\n", ent.filename, (unsigned int) ent.filesize); - - err = imgtool_partition_get_file(partition, ent.filename, NULL, NULL, filter); - if (err) - goto done; - } - -done: - if (imgenum) - imgtool_directory_close(imgenum); - if (partition) - imgtool_partition_close(partition); - if (image) - imgtool_image_close(image); - if (err) - reporterror(err, c, argv[0], argv[1], NULL, NULL, NULL); - return err ? -1 : 0; -} - - - -static int cmd_del(const struct command *c, int argc, char *argv[]) -{ - imgtoolerr_t err; - imgtool_image *image = NULL; - imgtool_partition *partition = NULL; - int partition_index = 0; - - err = imgtool_image_open_byname(argv[0], argv[1], OSD_FOPEN_RW, &image); - if (err) - goto done; - - err = imgtool_partition_open(image, partition_index, &partition); - if (err) - goto done; - - err = imgtool_partition_delete_file(partition, argv[2]); - if (err) - goto done; - -done: - if (partition) - imgtool_partition_close(partition); - if (image) - imgtool_image_close(image); - if (err) - reporterror(err, c, argv[0], argv[1], argv[2], NULL, NULL); - return err ? -1 : 0; -} - - - -static int cmd_mkdir(const struct command *c, int argc, char *argv[]) -{ - imgtoolerr_t err; - imgtool_image *image = NULL; - imgtool_partition *partition = NULL; - int partition_index = 0; - - err = imgtool_image_open_byname(argv[0], argv[1], OSD_FOPEN_RW, &image); - if (err) - goto done; - - err = imgtool_partition_open(image, partition_index, &partition); - if (err) - goto done; - - err = imgtool_partition_create_directory(partition, argv[2]); - if (err) - goto done; - -done: - if (partition) - imgtool_partition_close(partition); - if (image) - imgtool_image_close(image); - if (err) - reporterror(err, c, argv[0], argv[1], argv[2], NULL, NULL); - return err ? -1 : 0; -} - - - -static int cmd_rmdir(const struct command *c, int argc, char *argv[]) -{ - imgtoolerr_t err; - imgtool_image *image = NULL; - imgtool_partition *partition = NULL; - int partition_index = 0; - - err = imgtool_image_open_byname(argv[0], argv[1], OSD_FOPEN_RW, &image); - if (err) - goto done; - - err = imgtool_partition_open(image, partition_index, &partition); - if (err) - goto done; - - err = imgtool_partition_delete_directory(partition, argv[2]); - if (err) - goto done; - -done: - if (partition) - imgtool_partition_close(partition); - if (image) - imgtool_image_close(image); - if (err) - reporterror(err, c, argv[0], argv[1], argv[2], NULL, NULL); - return err ? -1 : 0; -} - - - -static int cmd_identify(const struct command *c, int argc, char *argv[]) -{ - imgtool_module *modules[128]; - imgtoolerr_t err; - int i; - - err = imgtool_identify_file(argv[0], modules, ARRAY_LENGTH(modules)); - if (err) - goto error; - - for (i = 0; modules[i]; i++) - { - printf("%.16s %s\n", modules[i]->name, modules[i]->description); - } - - return 0; - -error: - reporterror(err, c, NULL, argv[0], NULL, NULL, 0); - return -1; -} - - - -static int cmd_create(const struct command *c, int argc, char *argv[]) -{ - imgtoolerr_t err; - int unnamedargs; - const imgtool_module *module; - option_resolution *resolution = NULL; - - module = imgtool_find_module(argv[0]); - if (!module) - { - err = (imgtoolerr_t)(IMGTOOLERR_MODULENOTFOUND | IMGTOOLERR_SRC_MODULE); - goto error; - } - - if (module->createimage_optguide && module->createimage_optspec) - { - resolution = option_resolution_create(module->createimage_optguide, module->createimage_optspec); - if (!resolution) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto error; - } - } - - unnamedargs = parse_options(argc, argv, 2, 3, resolution, NULL, NULL); - if (unnamedargs < 0) - return -1; - - err = imgtool_image_create(module, argv[1], resolution, NULL); - if (err) - goto error; - - if (resolution) - option_resolution_close(resolution); - return 0; - -error: - if (resolution) - option_resolution_close(resolution); - reporterror(err, c, argv[0], argv[1], NULL, NULL, 0); - return -1; -} - - - -static int cmd_readsector(const struct command *c, int argc, char *argv[]) -{ - imgtoolerr_t err; - imgtool_image *img; - imgtool_stream *stream = NULL; - dynamic_buffer buffer; - UINT32 size, track, head, sector; - - /* attempt to open image */ - err = imgtool_image_open_byname(argv[0], argv[1], OSD_FOPEN_READ, &img); - if (err) - goto done; - - track = atoi(argv[2]); - head = atoi(argv[3]); - sector = atoi(argv[4]); - - err = imgtool_image_get_sector_size(img, track, head, sector, &size); - if (err) - goto done; - - buffer.resize(size); - - err = imgtool_image_read_sector(img, track, head, sector, &buffer[0], size); - if (err) - goto done; - - - stream = stream_open(argv[5], OSD_FOPEN_WRITE); - if (!stream) - { - err = (imgtoolerr_t)(IMGTOOLERR_FILENOTFOUND | IMGTOOLERR_SRC_NATIVEFILE); - goto done; - } - - stream_write(stream, &buffer[0], size); - -done: - if (stream) - stream_close(stream); - if (err) - reporterror(err, c, argv[0], argv[1], NULL, NULL, 0); - return err ? -1 : 0; -} - - - -static int cmd_writesector(const struct command *c, int argc, char *argv[]) -{ - imgtoolerr_t err; - imgtool_image *img; - imgtool_stream *stream = NULL; - dynamic_buffer buffer; - UINT32 size, track, head, sector; - - /* attempt to open image */ - err = imgtool_image_open_byname(argv[0], argv[1], OSD_FOPEN_RW, &img); - if (err) - goto done; - - track = atoi(argv[2]); - head = atoi(argv[3]); - sector = atoi(argv[4]); - - stream = stream_open(argv[5], OSD_FOPEN_READ); - if (!stream) - { - err = (imgtoolerr_t)(IMGTOOLERR_FILENOTFOUND | IMGTOOLERR_SRC_NATIVEFILE); - goto done; - } - - size = (UINT32) stream_size(stream); - - buffer.resize(size); - - stream_read(stream, &buffer[0], size); - - err = imgtool_image_write_sector(img, track, head, sector, &buffer[0], size); - if (err) - goto done; - -done: - if (stream) - stream_close(stream); - if (err) - reporterror(err, c, argv[0], argv[1], NULL, NULL, 0); - return err ? -1 : 0; -} - - - -static int cmd_listformats(const struct command *c, int argc, char *argv[]) -{ - const imgtool_module *mod; - - fprintf(stdout, "Image formats supported by imgtool:\n\n"); - - mod = imgtool_find_module(NULL); - while(mod) - { - fprintf(stdout, " %-25s%s\n", mod->name, mod->description); - mod = mod->next; - } - - return 0; -} - - - -static int cmd_listfilters(const struct command *c, int argc, char *argv[]) -{ - int i; - - fprintf(stdout, "Filters supported by imgtool:\n\n"); - - for (i = 0; filters[i]; i++) - { - fprintf(stdout, " %-11s%s\n", - filter_get_info_string(filters[i], FILTINFO_STR_NAME), - filter_get_info_string(filters[i], FILTINFO_STR_HUMANNAME)); - } - - return 0; -} - -static void listoptions(const option_guide *opt_guide, const char *opt_spec) -{ - char opt_name[32]; - const char *opt_desc; - struct OptionRange range[32]; - char range_buffer[512]; - char buf[32]; - int i; - - assert(opt_guide); - - fprintf(stdout, "Option Allowed values Description\n"); - fprintf(stdout, "---------------- ------------------------------ -----------\n"); - - while(opt_guide->option_type != OPTIONTYPE_END) - { - range_buffer[0] = 0; - snprintf(opt_name, ARRAY_LENGTH(opt_name), "--%s", opt_guide->identifier); - opt_desc = opt_guide->display_name; - - /* is this option relevant? */ - if (!strchr(opt_spec, opt_guide->parameter)) - { - opt_guide++; - continue; - } - - switch(opt_guide->option_type) { - case OPTIONTYPE_INT: - option_resolution_listranges(opt_spec, opt_guide->parameter, - range, ARRAY_LENGTH(range)); - - for (i = 0; range[i].max >= 0; i++) - { - if (range[i].min == range[i].max) - snprintf(buf, ARRAY_LENGTH(buf), "%i", range[i].min); - else - snprintf(buf, ARRAY_LENGTH(buf), "%i-%i", range[i].min, range[i].max); - - if (i > 0) - strncatz(range_buffer, "/", sizeof(range_buffer)); - strncatz(range_buffer, buf, sizeof(range_buffer)); - } - break; - - case OPTIONTYPE_ENUM_BEGIN: - i = 0; - while(opt_guide[1].option_type == OPTIONTYPE_ENUM_VALUE) - { - if (i > 0) - strncatz(range_buffer, "/", sizeof(range_buffer)); - strncatz(range_buffer, opt_guide[1].identifier, sizeof(range_buffer)); - - opt_guide++; - i++; - } - break; - - case OPTIONTYPE_STRING: - snprintf(range_buffer, sizeof(range_buffer), "(string)"); - break; - default: - assert(0); - break; - } - - fprintf(stdout, "%16s %-30s %s\n", - opt_name, - range_buffer, - opt_desc); - opt_guide++; - } -} - - - -static int cmd_listdriveroptions(const struct command *c, int argc, char *argv[]) -{ - const imgtool_module *mod; - const option_guide *opt_guide; - const char *opt_spec; - - mod = imgtool_find_module(argv[0]); - if (!mod) - goto error; - - fprintf(stdout, "Driver specific options for module '%s':\n\n", argv[0]); - - /* list write options */ - opt_guide = (const option_guide *) imgtool_get_info_ptr(&mod->imgclass, IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE); - opt_spec = imgtool_get_info_string(&mod->imgclass, IMGTOOLINFO_STR_WRITEFILE_OPTSPEC); - if (opt_guide) - { - fprintf(stdout, "Image specific file options (usable on the 'put' command):\n\n"); - listoptions(opt_guide, opt_spec); - puts("\n"); - } - else - { - fprintf(stdout, "No image specific file options\n\n"); - } - - /* list create options */ - opt_guide = mod->createimage_optguide; - if (opt_guide) - { - fprintf(stdout, "Image specific creation options (usable on the 'create' command):\n\n"); - listoptions(opt_guide, mod->createimage_optspec); - puts("\n"); - } - else - { - fprintf(stdout, "No image specific creation options\n\n"); - } - - return 0; - -error: - reporterror((imgtoolerr_t)(IMGTOOLERR_MODULENOTFOUND|IMGTOOLERR_SRC_MODULE), c, argv[0], NULL, NULL, NULL, NULL); - return -1; -} - - - -/* ----------------------------------------------------------------------- */ - -static const struct command cmds[] = -{ - { "create", cmd_create, "<format> <imagename> [--(createoption)=value]", 2, 8, 0}, - { "dir", cmd_dir, "<format> <imagename> [path]", 2, 3, 0 }, - { "get", cmd_get, "<format> <imagename> <filename> [newname] [--filter=filter] [--fork=fork]", 3, 4, 0 }, - { "put", cmd_put, "<format> <imagename> <filename>... <destname> [--(fileoption)==value] [--filter=filter] [--fork=fork]", 3, 0xffff, 0 }, - { "getall", cmd_getall, "<format> <imagename> [path] [--filter=filter]", 2, 3, 0 }, - { "del", cmd_del, "<format> <imagename> <filename>...", 3, 3, 1 }, - { "mkdir", cmd_mkdir, "<format> <imagename> <dirname>", 3, 3, 0 }, - { "rmdir", cmd_rmdir, "<format> <imagename> <dirname>...", 3, 3, 1 }, - { "readsector", cmd_readsector, "<format> <imagename> <track> <head> <sector> <filename>", 6, 6, 0 }, - { "writesector", cmd_writesector, "<format> <imagename> <track> <head> <sector> <filename>", 6, 6, 0 }, - { "identify", cmd_identify, "<imagename>", 1, 1 }, - { "listformats", cmd_listformats, NULL, 0, 0, 0 }, - { "listfilters", cmd_listfilters, NULL, 0, 0, 0 }, - { "listdriveroptions", cmd_listdriveroptions, "<format>", 1, 1, 0 } -}; - -int CLIB_DECL main(int argc, char *argv[]) -{ - int i; - int result; - const struct command *c; - const char *sample_format = "coco_jvc_rsdos"; - -#ifdef MAME_DEBUG - if (imgtool_validitychecks()) - return -1; -#endif /* MAME_DEBUG */ - - putchar('\n'); - - if (argc > 1) - { - /* figure out what command they are running, and run it */ - for (i = 0; i < ARRAY_LENGTH(cmds); i++) - { - c = &cmds[i]; - if (!core_stricmp(c->name, argv[1])) - { - /* check argument count */ - if (c->minargs > (argc - 2)) - goto cmderror; - - /* initialize the imgtool core */ - imgtool_init(TRUE, NULL); - - if (c->lastargrepeats && (argc > c->maxargs)) - { - for (i = c->maxargs+1; i < argc; i++) - { - argv[c->maxargs+1] = argv[i]; - - result = c->cmdproc(c, c->maxargs, argv + 2); - if (result) - goto done; - } - result = 0; - goto done; - } - else - { - if ((c->maxargs > 0) && (c->maxargs < (argc - 2))) - goto cmderror; - - result = c->cmdproc(c, argc - 2, argv + 2); - goto done; - } - } - } - } - - /* Usage */ - fprintf(stderr, "imgtool - Generic image manipulation tool for use with MESS\n\n"); - for (i = 0; i < ARRAY_LENGTH(cmds); i++) - { - writeusage(stdout, (i == 0), &cmds[i], argv); - } - - fprintf(stderr, "\n<format> is the image format, e.g. %s\n", sample_format); - fprintf(stderr, "<imagename> is the image filename; can specify a ZIP file for image name\n"); - - fprintf(stderr, "\nExample usage:\n"); - fprintf(stderr, "\t%s dir %s myimageinazip.zip\n", imgtool_basename(argv[0]), sample_format); - fprintf(stderr, "\t%s get %s myimage.dsk myfile.bin mynewfile.txt\n", imgtool_basename(argv[0]), sample_format); - fprintf(stderr, "\t%s getall %s myimage.dsk\n", imgtool_basename(argv[0]), sample_format); - result = 0; - goto done; - -cmderror: - writeusage(stdout, 1, &cmds[i], argv); - result = -1; - -done: - imgtool_exit(); - return result; -} diff --git a/src/mess/tools/imgtool/main.h b/src/mess/tools/imgtool/main.h deleted file mode 100644 index d4089686437..00000000000 --- a/src/mess/tools/imgtool/main.h +++ /dev/null @@ -1,20 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -#include "imgtool.h" - -struct command -{ - const char *name; - int (*cmdproc)(const struct command *c, int argc, char *argv[]); - const char *usage; - int minargs; - int maxargs; - int lastargrepeats; -}; - -void reporterror(imgtoolerr_t err, const struct command *c, const char *format, const char *imagename, - const char *filename, const char *newname, option_resolution *opts); - -#ifdef MAME_DEBUG -int cmd_testsuite(struct command *c, int argc, char *argv[]); -#endif diff --git a/src/mess/tools/imgtool/modules.c b/src/mess/tools/imgtool/modules.c deleted file mode 100644 index e5f0c43690c..00000000000 --- a/src/mess/tools/imgtool/modules.c +++ /dev/null @@ -1,119 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - modules.c - - List of Imgtool modules - -***************************************************************************/ - -#include "imgtool.h" -#include "modules.h" - -#ifndef MODULES_RECURSIVE -#define MODULES_RECURSIVE - -/* step 1: declare all external references */ -#define MODULE(name) extern void name##_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info); -#include "modules.c" -#undef MODULE - -/* step 2: define the modules[] array */ -#define MODULE(name) name##_get_info, -static void (*const modules[])(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info) = -{ -#include "modules.c" -}; - -/* step 3: declare imgtool_create_cannonical_library() */ -imgtoolerr_t imgtool_create_cannonical_library(int omit_untested, imgtool_library **library) -{ - imgtoolerr_t err; - size_t i; - imgtool_library *lib; - imgtool_module *module; - - /* list of modules that we drop */ - static const char *const irrelevant_modules[] = - { - "coco_os9_rsdos" - }; - - lib = imgtool_library_create(); - if (!lib) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto error; - } - - /* create all modules */ - for (i = 0; i < ARRAY_LENGTH(modules); i++) - imgtool_library_add(lib, modules[i]); - - /* remove irrelevant modules */ - for (i = 0; i < ARRAY_LENGTH(irrelevant_modules); i++) - { - imgtool_library_unlink(lib, irrelevant_modules[i]); - } - - /* if we are omitting untested, go through and block out the functionality in question */ - if (omit_untested) - { - module = NULL; - while((module = imgtool_library_iterate(lib, module)) != NULL) - { - if (module->writing_untested) - { - module->write_sector = NULL; - } - if (module->creation_untested) - { - module->create = NULL; - module->createimage_optguide = NULL; - module->createimage_optspec = NULL; - } - } - } - - *library = lib; - return IMGTOOLERR_SUCCESS; - -error: - if (lib) - imgtool_library_close(lib); - return err; - -} - - -#else /* MODULES_RECURSIVE */ - -MODULE(amiga_floppy) -MODULE(concept) -MODULE(mac_mfs) -MODULE(mac_hfs) -MODULE(hd) -MODULE(rsdos) -MODULE(vzdos) -MODULE(os9) -MODULE(ti99_old) -MODULE(ti99_v9t9) -MODULE(ti99_pc99fm) -MODULE(ti99_pc99mfm) -MODULE(ti99_ti99hd) -MODULE(ti990) -MODULE(pc_floppy) -MODULE(pc_chd) -MODULE(prodos_525) -MODULE(prodos_35) -MODULE(thom_fd_basic) -MODULE(thom_qd_basic) -MODULE(thom_sap_basic) -MODULE(cybiko) -MODULE(cybikoxt) -MODULE(psion) -MODULE(bml3) -MODULE(hp48) - -#endif /* MODULES_RECURSIVE */ diff --git a/src/mess/tools/imgtool/modules.h b/src/mess/tools/imgtool/modules.h deleted file mode 100644 index 6f5a3786c6b..00000000000 --- a/src/mess/tools/imgtool/modules.h +++ /dev/null @@ -1,18 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/**************************************************************************** - - modules.h - - Code that creates the "canonical" Imgtool library - -****************************************************************************/ - -#ifndef MODULES_H -#define MODULES_H - -#include "library.h" - -imgtoolerr_t imgtool_create_cannonical_library(int omit_untested, imgtool_library **library); - -#endif /* MODULES_H */ diff --git a/src/mess/tools/imgtool/modules/amiga.c b/src/mess/tools/imgtool/modules/amiga.c deleted file mode 100644 index 7723748cbd2..00000000000 --- a/src/mess/tools/imgtool/modules/amiga.c +++ /dev/null @@ -1,2411 +0,0 @@ -// license:GPL-2.0+ -// copyright-holders:Dirk Best -/**************************************************************************** - - amiga.c - - Amiga floppies - -****************************************************************************/ - - -/***************************************************************************** - Includes -*****************************************************************************/ - - -#include <time.h> -#include <string.h> -#include <ctype.h> - -#include "imgtool.h" -#include "iflopimg.h" -#include "formats/imageutl.h" - - - -/***************************************************************************** - Data structures -*****************************************************************************/ - - -#define BSIZE (512) /* Block size is always 512 bytes for floppies */ -#define TSIZE ((BSIZE/4) - 56) /* Size of data tables */ -#define MSIZE ((BSIZE/4) - 1) /* Size of bitmaps */ - - -enum disk_type -{ - DT_UNKNOWN = -1, - DT_OFS = 0, - DT_FFS = 1, - DT_OFS_INTL = 2, - DT_FFS_INTL = 3, - DT_OFS_INTL_DIRC = 4, - DT_FFS_INTL_DIRC = 5 -}; - - -enum -{ - T_INVALID = 0, - T_HEADER = 2, - T_DATA = 8, - T_LIST = 16, - T_DIRCACHE = 33 -}; - - -enum sec_type -{ - ST_INVALID = 0, - ST_ROOT = 1, - ST_USERDIR = 2, - ST_FILE = -3, - ST_LINKFILE = -4, - ST_LINKDIR = 4, - ST_SOFTLINK = 3 -}; - - -struct amiga_date -{ - UINT32 days; /* days since 1 jan 78 */ - UINT32 mins; /* minutes past midnight */ - UINT32 ticks; /* ticks (1/50 sec) past last minute */ -}; - - -struct root_block -{ - UINT32 ht_size; /* Hash table size in long */ - UINT32 chksum; /* Rootblock checksum */ - UINT32 ht[TSIZE]; /* Hash table (entry block number) */ - UINT32 bm_flag; /* bitmap flag, -1 means VALID */ - UINT32 bm_pages[25]; /* bitmap blocks pointers (first one at bm_pages[0]) */ - amiga_date r; /* last root alteration date */ - UINT8 name_len; /* volume name length */ - UINT8 diskname[30]; /* volume name */ - amiga_date v; /* last disk alteration date */ - amiga_date c; /* filesystem creation date */ - UINT32 extension; /* FFS: first directory cache block, 0 otherwise */ -}; - - -struct bitmap_block -{ - UINT32 chksum; /* checksum, normal algorithm */ - UINT32 map[MSIZE]; /* bitmap */ -}; - - -struct bitmap_ext_block -{ - UINT32 map[MSIZE]; /* bitmap */ - UINT32 next; /* next extension block */ -}; - - -struct file_block -{ - UINT32 header_key; /* self pointer (to this block) */ - UINT32 high_seq; /* number of data block ptr stored here */ - UINT32 first_data; /* first data block ptr */ - UINT32 chksum; /* same algorithm as rootblock */ - UINT32 data_blocks[TSIZE]; /* data blk ptr */ - UINT16 uid; /* UserID */ - UINT16 gid; /* GroupID */ - UINT32 protect; /* protection flags (0 by default) */ - UINT32 byte_size; /* file size in bytes */ - UINT8 comm_len; /* file comment length */ - UINT8 comment[79]; /* comment (max. 79 chars permitted) */ - amiga_date date; /* last change date */ - UINT8 name_len; /* filename length */ - UINT8 filename[30]; /* filename (max. 30 chars permitted) */ - UINT32 real_entry; /* FFS: unused, set to 0 */ - UINT32 next_link; /* FFS: hardlinks chained list (first == newest */ - UINT32 hash_chain; /* next entry ptr with same hash */ - UINT32 parent; /* parent directory */ - UINT32 extension; /* pointer to 1st file extension block */ -}; - - -struct file_ext_block -{ - UINT32 header_key; /* self pointer (to this block) */ - UINT32 high_seq; /* number of data block ptr stored here */ - UINT32 chksum; /* same algorithm as rootblock */ - UINT32 data_blocks[TSIZE]; /* data blk ptr */ - UINT32 parent; /* file header block */ - UINT32 extension; /* pointer to next file extension block */ -}; - - -struct data_block -{ - UINT32 header_key; /* self pointer (to this block) */ - UINT32 seq_num; /* file data block number */ - UINT32 data_size; /* data size */ - UINT32 next_data; /* next data block ptr */ - UINT32 chksum; /* checksum, rootblock algorithm */ - UINT8 data[BSIZE-24]; /* file data */ -}; - - -struct dir_block -{ - UINT32 header_key; /* self pointer (to this block) */ - UINT32 chksum; /* same algorithm as rootblock */ - UINT32 ht[TSIZE]; /* hash table (entry block number) */ - UINT8 uid; /* UserID */ - UINT8 gid; /* GroupID */ - UINT32 protect; /* protection flags (0 by default) */ - UINT8 comm_len; /* file comment length */ - UINT8 comment[79]; /* comment (max. 79 chars permitted) */ - amiga_date date; /* last access date */ - UINT8 name_len; /* directory name length */ - UINT8 dirname[30]; /* directory name (max. 30 chars permitted) */ - UINT32 next_link; /* FFS: hardlinks chained list (first == newest */ - UINT32 hash_chain; /* next entry ptr with same hash */ - UINT32 parent; /* parent directory */ - UINT32 extension; /* FFS: first directory cache block */ -}; - - -struct hardlink_block -{ - UINT32 header_key; /* self pointer (to this block) */ - UINT32 chksum; /* same algorithm as rootblock */ - UINT32 protect; /* protection flags (0 by default) */ - UINT8 comm_len; /* file comment length */ - UINT8 comment[79]; /* comment (max. 79 chars permitted) */ - amiga_date date; /* last access date */ - UINT8 name_len; /* hard link name length */ - UINT8 hlname[30]; /* hard link name (max. 30 chars permitted) */ - UINT32 real_entry; /* FFS: pointer to "real" file or directory */ - UINT32 next_link; /* FFS: hardlinks chained list (first == newest */ - UINT32 hash_chain; /* next entry ptr with same hash */ - UINT32 parent; /* parent directory */ - UINT32 sec_type; /* secondary type, ST_LINKFILE/ST_LINKDIR */ -}; - - -struct softlink_block -{ - UINT32 header_key; /* self pointer (to this block) */ - UINT32 chksum; /* same algorithm as rootblock */ - UINT8 symbolic_name[BSIZE-224]; /* path name to referenced object */ - UINT32 protect; /* protection flags (0 by default) */ - UINT8 comm_len; /* file comment length */ - UINT8 comment[79]; /* comment (max. 79 chars permitted) */ - amiga_date date; /* last access date */ - UINT8 name_len; /* soft link name length */ - UINT8 slname[30]; /* soft link name (max. 30 chars permitted) */ - UINT32 hash_chain; /* next entry ptr with same hash */ - UINT32 parent; /* parent directory */ -}; - - -/* Basic Amiga floppy disk image info */ -struct amiga_floppy -{ - imgtool_stream *stream; - UINT8 sectors; -}; - - -/* iterator used to walk through directory entries */ -struct amiga_iterator -{ - unsigned int index; /* current file index */ - int block; /* block number we are iterating */ - UINT32 next_block; /* next block in hash chain */ - int ht_index; /* current index in the hash table */ - unsigned int eof : 1; /* end of file listing reached? */ -}; - - -/***************************************************************************** - Prototypes -*****************************************************************************/ - - -static imgtoolerr_t amiga_image_read_sector(imgtool_image* img, - UINT32 track, UINT32 head, UINT32 sector, void *buf, size_t len); -static imgtoolerr_t amiga_image_write_sector(imgtool_image* img, - UINT32 track, UINT32 head, UINT32 sector, const void *buf, size_t len, int ddam); - - - -/***************************************************************************** - Utility functions -*****************************************************************************/ - - -/* Amiga version of the toupper function */ -static int intl_toupper(int c) -{ - return (c>='a' && c<='z') || (c>=224 && c<=254 && c!=247) ? c - ('a'-'A') : c ; -} - - -/* Amiga filename case insensitive string compare */ -static int intl_stricmp(const char *s1, const char *s2) -{ - for (;;) - { - int c1 = intl_toupper(*s1++); - int c2 = intl_toupper(*s2++); - - if (c1 == 0 || c1 != c2) - return c1 - c2; - } -} - - -/* Calculate the hash value for a filename */ -static int hash_name(const char *name, int intl) -{ - int i, l = strlen(name); - UINT32 hash = l; - - for(i = 0; i < l; i++) - { - hash *= 13; - hash += (UINT8) (intl ? intl_toupper(name[i]) : toupper(name[i])); - hash &= 0x7ff; - } - - return hash % TSIZE; /* 0 < hash < 71 in case of BSIZE=512 */ -} - - -/* Returns TRUE if year is a leap year */ -static int is_leap(int year) -{ - return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); -} - - -/* Convert amiga time to standard time */ -static time_t amiga_crack_time(amiga_date *date) -{ - int month_days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - int year = 1978, month = 1, year_days = 365; /* base date */ - int day = date->days; - struct tm t; - - /* initialize struct */ - memset(&t, 0, sizeof(t)); - - /* first calculate the year */ - while (day >= year_days) - { - day -= year_days; - year_days = is_leap(++year) ? 366 : 365; - } - - /* then the month */ - while(day >= month_days[month-1]) - { - day -= month_days[month-1]; - if (month == 2 && is_leap(year)) - day -= 1; - month++; - } - - /* fill the struct with our calculated values */ - t.tm_year = year - 1900; - t.tm_mon = month - 1; - t.tm_mday = day + 1; - t.tm_hour = date->mins / 60; - t.tm_min = date->mins % 60; - t.tm_sec = date->ticks / 50; - - return mktime(&t); -} - - -/* convert standard time to amiga time */ -static void amiga_setup_time(time_t time, amiga_date *dest) -{ - struct tm t = *localtime(&time); - int year; - - dest->days = 0; - - for (year = 1978; year < t.tm_year + 1900; year++) - { - dest->days += is_leap(year) ? 366 : 365; - } - - dest->days += t.tm_yday; - dest->mins = t.tm_hour * 60 + t.tm_min; - dest->ticks = t.tm_sec * 50; -} - - -/* convert flags to human readable form */ -static void amiga_decode_flags(UINT32 flags, char *dest) -{ - /* test for flags */ - dest[0] = (flags & 0x80) ? 'h' : '-'; - dest[1] = (flags & 0x40) ? 's' : '-'; - dest[2] = (flags & 0x20) ? 'p' : '-'; - dest[3] = (flags & 0x10) ? 'a' : '-'; - dest[4] = (flags & 0x08) ? '-' : 'r'; - dest[5] = (flags & 0x04) ? '-' : 'w'; - dest[6] = (flags & 0x02) ? '-' : 'e'; - dest[7] = (flags & 0x01) ? '-' : 'd'; - dest[8] = '\0'; -} - - -static void copy_integer_array_be(UINT32 *dest, const UINT32 *source, int size) -{ - int i; - - for (i = 0; i < size; i++) - { - dest[i] = BIG_ENDIANIZE_INT32(source[i]); - } -} - - -/* This function converts an array of UINT32s to an amiga_date */ -static void copy_date_be(amiga_date *dest, const UINT32 *source) -{ - dest->days = BIG_ENDIANIZE_INT32(source[0]); - dest->mins = BIG_ENDIANIZE_INT32(source[1]); - dest->ticks = BIG_ENDIANIZE_INT32(source[2]); -} - - -/* Calculate the block checksum of a byte array */ -static UINT32 block_checksum(UINT8 *buffer, int length) -{ - UINT32 chksum = 0; - int i; - - for (i = 0; i < length/4; i++) - { - chksum += pick_integer_be(buffer, i*4, 4); - } - - return -chksum; -} - - -/* Returns the total number of blocks in the image */ -static int get_total_blocks(imgtool_image *img) -{ - amiga_floppy *f = (amiga_floppy *)imgtool_image_extra_bytes(img); - - return 2 * 80 * f->sectors; -} - - -/* Returns track, head and sector for a block */ -static void find_block(amiga_floppy *f, int block, int *track, - int *head, int *sector) -{ - *track = block / f->sectors; - *head = (block - *track * f->sectors) / f->sectors; - *sector = (block - *track * f->sectors) % f->sectors; -} - - -/* Generic read block */ -static imgtoolerr_t read_block(imgtool_image *img, int block, UINT8 *buffer) -{ - imgtoolerr_t ret; - int track, head, sector; - - find_block((amiga_floppy *) imgtool_image_extra_bytes(img), block, &track, &head, §or); - - /* get block from image */ - ret = amiga_image_read_sector(img, track, head, sector, buffer, BSIZE); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -/* Generic write block */ -static imgtoolerr_t write_block(imgtool_image *img, int block, const UINT8 *buffer) -{ - imgtoolerr_t ret; - int track, head, sector; - - find_block((amiga_floppy *) imgtool_image_extra_bytes(img), block, &track, &head, §or); - - /* write block to image */ - ret = amiga_image_write_sector(img, track, head, sector, buffer, BSIZE, 0); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -/* Return the type a block */ -static sec_type get_block_type(imgtool_image *img, int block) -{ - imgtoolerr_t ret; - UINT8 buffer[BSIZE]; - - /* get data */ - ret = read_block(img, block, buffer); - if (ret) return ST_INVALID; - - /* return type */ - switch ((INT32) pick_integer_be(buffer, BSIZE-4, 4)) - { - case 1: return ST_ROOT; - case 2: return ST_USERDIR; - case -3: return ST_FILE; - case -4: return ST_LINKFILE; - case 4: return ST_LINKDIR; - case 3: return ST_SOFTLINK; - default: return ST_INVALID; - } -} - - -/* Read a bitmap block */ -static imgtoolerr_t read_bitmap_block(imgtool_image *img, int block, bitmap_block *bm) -{ - imgtoolerr_t ret; - UINT8 buffer[BSIZE]; - - /* read block */ - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* fill in data */ - bm->chksum = pick_integer_be(buffer, 0, 4); - copy_integer_array_be(bm->map, (UINT32 *) &buffer[4], MSIZE); - - return IMGTOOLERR_SUCCESS; -} - - -/* Write a bitmap block */ -static imgtoolerr_t write_bitmap_block(imgtool_image *img, int block, const bitmap_block *bm) -{ - imgtoolerr_t ret; - UINT8 buffer[BSIZE]; - - /* Setup buffer */ - place_integer_be(buffer, 0, 4, bm->chksum); - copy_integer_array_be((UINT32 *) &buffer[4], bm->map, MSIZE); - - /* write block */ - ret = write_block(img, block, buffer); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -#ifdef UNUSED_FUNCTION -/* Read a bitmap extended block */ -static imgtoolerr_t read_bitmap_ext_block(imgtool_image *img, int block, bitmap_ext_block *bm) -{ - imgtoolerr_t ret; - UINT8 buffer[BSIZE]; - - /* read block */ - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* fill in data */ - copy_integer_array_be(bm->map, (UINT32 *) &buffer, MSIZE); - bm->next = pick_integer_be(buffer, BSIZE-4, 4); - - return IMGTOOLERR_SUCCESS; -} -#endif - - -/* Read the root block */ -static imgtoolerr_t read_root_block(imgtool_image *img, root_block *root) -{ - imgtoolerr_t ret; - UINT8 buffer[BSIZE]; - - /* get raw root block from image */ - ret = read_block(img, get_total_blocks(img)/2, buffer); - if (ret) return ret; - - /* 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); - copy_integer_array_be(root->ht, (UINT32 *) &buffer[24], TSIZE); - root->bm_flag = pick_integer_be(buffer, BSIZE-200, 4); - copy_integer_array_be(root->bm_pages, (UINT32 *) &buffer[BSIZE-196], 25); - copy_date_be(&root->r, (UINT32 *) &buffer[BSIZE-92]); - root->name_len = pick_integer_be(buffer, BSIZE-80, 1); - memcpy(root->diskname, &buffer[BSIZE-79], 30); - copy_date_be(&root->v, (UINT32 *) &buffer[BSIZE-40]); - copy_date_be(&root->c, (UINT32 *) &buffer[BSIZE-28]); - root->extension = pick_integer_be(buffer, BSIZE-8, 4); - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t write_root_block(imgtool_image *img, const root_block *root) -{ - imgtoolerr_t ret; - UINT8 buffer[BSIZE]; - - /* 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); - copy_integer_array_be((UINT32 *) &buffer[24], root->ht, TSIZE); - place_integer_be(buffer, BSIZE-200, 4, root->bm_flag); - copy_integer_array_be((UINT32 *) &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); - 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); - - /* write root block to image */ - ret = write_block(img, get_total_blocks(img)/2, buffer); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -/* Read a file block */ -static imgtoolerr_t read_file_block(imgtool_image *img, int block, file_block *fb) -{ - imgtoolerr_t ret; - UINT8 buffer[BSIZE]; - - /* read block */ - ret = read_block(img, block, buffer); - 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); - copy_integer_array_be(fb->data_blocks, (UINT32 *) &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); - memcpy(fb->comment, &buffer[BSIZE-183], 79); - copy_date_be(&fb->date, (UINT32 *) &buffer[BSIZE-92]); - fb->name_len = pick_integer_be(buffer, BSIZE-80, 1); - memcpy(fb->filename, (UINT32 *) &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); - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t read_file_ext_block(imgtool_image *img, int block, file_ext_block *fe) -{ - imgtoolerr_t ret; - UINT8 buffer[BSIZE]; - - /* read block */ - ret = read_block(img, block, buffer); - 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); - copy_integer_array_be(fe->data_blocks, (UINT32 *) &buffer[24], TSIZE); - fe->parent = pick_integer_be(buffer, BSIZE-12, 4); - fe->extension = pick_integer_be(buffer, BSIZE-8, 4); - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t read_data_block(imgtool_image *img, int block, data_block *d) -{ - imgtoolerr_t ret; - UINT8 buffer[BSIZE]; - - /* read block */ - ret = read_block(img, block, buffer); - 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); - memcpy(d->data, &buffer[24], BSIZE-24); - - return IMGTOOLERR_SUCCESS; -} - - -/* Read a directory block */ -static imgtoolerr_t read_dir_block(imgtool_image *img, int block, dir_block *db) -{ - imgtoolerr_t ret; - UINT8 buffer[BSIZE]; - - /* read block */ - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* fill in data */ - db->header_key = pick_integer_be(buffer, 4, 4); - db->chksum = pick_integer_be(buffer, 20, 4); - copy_integer_array_be(db->ht, (UINT32 *) &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); - memcpy(db->comment, &buffer[BSIZE-183], 79); - copy_date_be(&db->date, (UINT32 *) &buffer[BSIZE-92]); - db->name_len = pick_integer_be(buffer, BSIZE-80, 1); - memcpy(db->dirname, (UINT32 *) &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); - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t write_dir_block(imgtool_image *img, int block, const dir_block *db) -{ - UINT8 buffer[BSIZE]; - - /* Setup buffer */ - 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); - copy_integer_array_be((UINT32 *) &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 *) &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 *) &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); - - /* Write block to disk */ - return write_block(img, block, buffer); -} - - -static imgtoolerr_t read_hardlink_block(imgtool_image *img, int block, hardlink_block *hl) -{ - imgtoolerr_t ret; - UINT8 buffer[BSIZE]; - - /* read block */ - ret = read_block(img, block, buffer); - 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); - memcpy(hl->comment, &buffer[BSIZE-183], 79); - copy_date_be(&hl->date, (UINT32 *) &buffer[BSIZE-92]); - hl->name_len = pick_integer_be(buffer, BSIZE-80, 1); - memcpy(hl->hlname, (UINT32 *) &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); - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t read_softlink_block(imgtool_image *img, int block, softlink_block *sl) -{ - imgtoolerr_t ret; - UINT8 buffer[BSIZE]; - - /* read block */ - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* fill in data */ - sl->header_key = pick_integer_be(buffer, 4, 4); - sl->chksum = pick_integer_be(buffer, 20, 4); - 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); - memcpy(sl->comment, &buffer[BSIZE-183], 79); - copy_date_be(&sl->date, (UINT32 *) &buffer[BSIZE-92]); - sl->name_len = pick_integer_be(buffer, BSIZE-80, 1); - memcpy(sl->slname, (UINT32 *) &buffer[BSIZE-79], 30); - sl->hash_chain = pick_integer_be(buffer, BSIZE-16, 4); - sl->parent = pick_integer_be(buffer, BSIZE-12, 4); - - return IMGTOOLERR_SUCCESS; -} - - -/* Returns the disk type */ -static disk_type get_disk_type(imgtool_image *img) -{ - imgtoolerr_t ret; - UINT8 buffer[BSIZE]; - - ret = read_block(img, 0, buffer); - if (ret) return DT_UNKNOWN; - - switch(buffer[3]) - { - case 0: return DT_OFS; - case 1: return DT_FFS; - case 2: return DT_OFS_INTL; - case 3: return DT_FFS_INTL; - case 4: return DT_OFS_INTL_DIRC; - case 5: return DT_FFS_INTL_DIRC; - default: return DT_UNKNOWN; - } -} - - -/* Returns TRUE if the disk is formatted with the FastFileSystem */ -static int is_ffs(imgtool_image *img) -{ - disk_type t = get_disk_type(img); - - return ((t == DT_FFS || - t == DT_FFS_INTL || - t == DT_FFS_INTL_DIRC) ? TRUE : FALSE); -} - - -/* Returns TRUE if the disk uses the international mode */ -static int is_intl(imgtool_image *img) -{ - disk_type t = get_disk_type(img); - - return ((t == DT_OFS_INTL || - t == DT_FFS_INTL || - t == DT_OFS_INTL_DIRC || - 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) -{ - 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 *ht) -{ - imgtoolerr_t ret; - - switch (get_block_type(img, block)) - { - case ST_USERDIR: - { - dir_block dir; - - /* get the directory block */ - ret = read_dir_block(img, block, &dir); - if (ret) return ret; - - /* copy data */ - memcpy(ht, &dir.ht, TSIZE*4); - - return IMGTOOLERR_SUCCESS; - } - - case ST_ROOT: - { - root_block root; - - /* get the root block */ - ret = read_root_block(img, &root); - if (ret) return ret; - - /* copy data */ - memcpy(ht, &root.ht, TSIZE*4); - - return IMGTOOLERR_SUCCESS; - } - - default: - return IMGTOOLERR_UNEXPECTED; - } -} - - -static imgtoolerr_t set_hash_table(imgtool_image *img, int block, const UINT32 *ht) -{ - UINT8 buffer[BSIZE]; - imgtoolerr_t ret; - - /* Read block */ - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* Copy new hash table into it */ - copy_integer_array_be((UINT32 *) &buffer[24], ht, TSIZE); - - /* Write it back again */ - ret = write_block(img, block, buffer); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - -#ifdef UNUSED_FUNCTION -static imgtoolerr_t get_root_hash_table(imgtool_image *img, UINT32 *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) -{ - UINT8 buffer[BSIZE]; - imgtoolerr_t ret; - - /* Read the block */ - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* Copy filename out of the buffer */ - memset(dest, 0, 31); - memcpy(dest, &buffer[BSIZE-79], buffer[BSIZE-80]); - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t get_hash_chain(imgtool_image *img, int block, UINT32 *chain) -{ - UINT8 buffer[BSIZE]; - imgtoolerr_t ret; - - /* Read block */ - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* Get chain value */ - *chain = pick_integer_be(buffer, BSIZE-16, 4); - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t set_hash_chain(imgtool_image *img, int block, UINT32 chain) -{ - UINT8 buffer[BSIZE]; - imgtoolerr_t ret; - - /* Read block */ - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* Copy new hash chain value into it */ - place_integer_be(buffer, BSIZE-16, 4, chain); - - /* Write it back again */ - ret = write_block(img, block, buffer); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t walk_hash_chain(imgtool_image *img, const char *path, int start_block, int *prev_block, int *block) -{ - imgtoolerr_t err; - UINT32 hash_chain; - char name[31]; - - /* choose compare function depending on intl mode */ - int (*cmp)(const char *, const char *) = is_intl(img) ? &intl_stricmp : &core_stricmp; - - /* initialize filenames */ - memset(name, 0, sizeof(name)); - - switch (get_block_type(img, start_block)) - { - case ST_USERDIR: - { - dir_block dir; - - /* read block */ - err = read_dir_block(img, start_block, &dir); - if (err) return err; - - /* copy filename string and next hash */ - memcpy(name, dir.dirname, dir.name_len); - hash_chain = dir.hash_chain; - - break; - } - - case ST_FILE: - { - file_block file; - - /* read block */ - err = read_file_block(img, start_block, &file); - if (err) return err; - - /* copy filename string and next hash */ - memcpy(name, file.filename, file.name_len); - hash_chain = file.hash_chain; - - break; - } - - case ST_SOFTLINK: - { - softlink_block sl; - - /* read block */ - err = read_softlink_block(img, start_block, &sl); - if (err) return err; - - /* copy filename string and next hash */ - memcpy(name, sl.slname, sl.name_len); - hash_chain = sl.hash_chain; - - break; - } - - case ST_LINKDIR: - case ST_LINKFILE: - { - hardlink_block hl; - - /* read block */ - err = read_hardlink_block(img, start_block, &hl); - if (err) return err; - - /* copy filename string and next hash */ - memcpy(name, hl.hlname, hl.name_len); - hash_chain = hl.hash_chain; - break; - } - - default: - return IMGTOOLERR_UNEXPECTED; - - } - - /* if we haven't found the right filename but there are linked entries, - * walk up the chain */ - if ((*cmp)(name, path) != 0 && hash_chain != 0) - { - *prev_block = start_block; - return walk_hash_chain(img, path, hash_chain, prev_block, block); - } - - /* found the correct block, return */ - if ((*cmp)(name, path) == 0) - { - *block = start_block; - return IMGTOOLERR_SUCCESS; - } - - /* we should never get here */ - return IMGTOOLERR_UNEXPECTED; -} - - -/* Returns the block number for a dir/file/link entry given as NUL delimited - * list of path parts, for example "dir1\0dir2\0dir3" returns the block number - * for directory "dir3" */ -static imgtoolerr_t find_entry(imgtool_image *img, const char *path, int start_block, int *block) -{ - imgtoolerr_t ret; - const char *next_path; - int current_block, prev; - UINT32 ht[TSIZE]; - - /* get the hash table */ - ret = get_hash_table(img, start_block, ht); - if (ret) return ret; - - /* calculate hash and get block for initial entry */ - current_block = ht[hash_name(path, is_intl(img))]; - - /* check if there was a match in the hash table */ - if (current_block == 0) - { - return IMGTOOLERR_PATHNOTFOUND; - } - - /* walk the linked hash list */ - ret = walk_hash_chain(img, path, current_block, &prev, block); - if (ret) return ret; - - /* follow links */ - switch (get_block_type(img, *block)) - { - case ST_SOFTLINK: - - /* TODO: Softlink support */ - return IMGTOOLERR_UNIMPLEMENTED; - - case ST_LINKDIR: - case ST_LINKFILE: - { - hardlink_block hl; - - ret = read_hardlink_block(img, *block, &hl); - if (ret) return ret; - - *block = hl.real_entry; - - break; - } - - default: - break; - } - - /* get next path part */ - next_path = path + strlen(path) + 1; - - /* if there are more path parts, search the next block */ - if (next_path[0]) - { - return find_entry(img, next_path, *block, block); - } - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t get_block_chksum(imgtool_image *img, int block, UINT32 *chksum, int bitmap) -{ - imgtoolerr_t ret; - UINT8 buffer[BSIZE]; - - /* get block data */ - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* clear old checksum */ - if (bitmap) - { - memset(buffer, 0, 4); - } - else - { - memset(&buffer[20], 0, 4); - } - - /* calulate checksum */ - *chksum = block_checksum(buffer, BSIZE); - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t fix_chksum(imgtool_image *img, int block, int bitmap) -{ - imgtoolerr_t ret; - UINT8 buffer[BSIZE]; - UINT32 chksum; - - /* calculate block checksum */ - ret = get_block_chksum(img, block, &chksum, bitmap); - if (ret) return ret; - - /* read block data */ - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* update checksum */ - if (bitmap) - { - place_integer_be(buffer, 0, 4, chksum); - } - else - { - place_integer_be(buffer, 20, 4, chksum); - } - - /* write back new block data */ - ret = write_block(img, block, buffer); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t fix_block_chksum(imgtool_image *img, int block) -{ - return fix_chksum(img, block, FALSE); -} - - -static imgtoolerr_t fix_bitmap_chksum(imgtool_image *img, int block) -{ - return fix_chksum(img, block, TRUE); -} - - -/* Set a block as used */ -static imgtoolerr_t bitmap_mark(imgtool_image *img, int block, int used) -{ - imgtoolerr_t ret; - bitmap_block bm; - root_block root; - int page; - - block -= 2; /* subtract boot block sectors, 2 only for floppies! */ - - ret = read_root_block(img, &root); - if (ret) return ret; - - /* figure out bitmap block location */ - page = root.bm_pages[block / (MSIZE * 32)]; - - /* get bitmap */ - ret = read_bitmap_block(img, page, &bm); - if (ret) return ret; - - /* subtract pages we skip */ - block -= MSIZE * 32 * (block / (MSIZE * 32)); - - /* mark as used or free */ - if (used) - { - bm.map[block/32] &= ~(1 << block % 32); - } - else - { - bm.map[block/32] |= (1 << block % 32); - } - - /* write changed bitmap block back to disk */ - ret = write_bitmap_block(img, page, &bm); - if (ret) return ret; - - /* update checksum */ - ret = fix_bitmap_chksum(img, page); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t bitmap_mark_used(imgtool_image *img, int block) -{ - return bitmap_mark(img, block, TRUE); -} - - -static imgtoolerr_t bitmap_mark_free(imgtool_image *img, int block) -{ - return bitmap_mark(img, block, FALSE); -} - - -static imgtoolerr_t update_block_modified_date(imgtool_image *img, int block) -{ - UINT8 buffer[BSIZE]; - imgtoolerr_t ret; - amiga_date date; - time_t now; - - ret = read_block(img, block, buffer); - if (ret) return ret; - - /* Set new time */ - time(&now); - 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); - - /* Write block back to disk */ - ret = write_block(img, block, buffer); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t clear_hash_table_entry(imgtool_image *img, int parent, char *filename) -{ - imgtoolerr_t ret; - UINT32 ht[TSIZE], chain; - int index, entry, prev, block; - - ret = get_hash_table(img, parent, ht); - if (ret) return ret; - - /* Calculate hash and get block for initial entry */ - index = hash_name(filename, is_intl(img)); - entry = ht[index]; - - /* Walk the hash chain to get the real entry */ - ret = walk_hash_chain(img, filename, entry, &prev, &block); - if (ret) return ret; - - /* Get chained value from block */ - ret = get_hash_chain(img, block, &chain); - if (ret) return ret; - - /* Check if we need to change the hash table */ - if (entry == block) - { - /* Set new value (might be 0 if there were no linked entries) */ - ht[index] = chain; - - /* Save changed hash table */ - ret = set_hash_table(img, parent, ht); - if (ret) return ret; - - /* Update last modified date */ - ret = update_block_modified_date(img, parent); - if (ret) return ret; - - /* Calculate new checksum */ - ret = fix_block_chksum(img, parent); - if (ret) return ret; - } - else - { - /* Save chained value to previous chain element */ - ret = set_hash_chain(img, prev, chain); - if (ret) return ret; - - /* Calculate new checksum */ - ret = fix_block_chksum(img, prev); - if (ret) return ret; - } - - /* Mark our block as free */ - ret = bitmap_mark_free(img, block); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -/* Returns the number of the first bit that is set in the array */ -static int get_first_bit(UINT32 *array, int size) -{ - int i; - - for (i = 0; i < size; i++) - { - if (array[i] != 0) - { - UINT32 v = array[i]; - int c; - - /* get first bit that is set */ - for (c = 0; (v & 1) == 0; c++) v >>= 1; - - /* return bit number */ - return i * 32 + c; - } - } - - return -1; -} - - -#ifdef UNUSED_FUNCTION -static imgtoolerr_t walk_bitmap_ext_blocks(imgtool_image *img, int start, int *block) -{ - imgtoolerr_t ret; - bitmap_ext_block bm_ext; - int bit; - - /* if we don't have a valid block, bail out */ - if (start == 0) - { - return IMGTOOLERR_NOSPACE; - } - - /* get the extended bitmap block */ - ret = read_bitmap_ext_block(img, start, &bm_ext); - if (ret) return ret; - - /* get the first bit that is set in the map */ - bit = get_first_bit(bm_ext.map, MSIZE); - - /* if we found one, return */ - if (bit != -1) - { - *block += bit; - return IMGTOOLERR_SUCCESS; - } - - /* increase on each call */ - *block += MSIZE * 32; - - /* else continue walking the list */ - return walk_bitmap_ext_blocks(img, bm_ext.next, block); -} -#endif - - -/* Searches for a block marked as free - * TODO: bm_ext support for HDs */ -static imgtoolerr_t find_free_block(imgtool_image *img, int *block) -{ - imgtoolerr_t ret; - root_block root; - int i; - - /* get root block */ - ret = read_root_block(img, &root); - if (ret) return ret; - - /* iterate bitmap pointers */ - for (i = 0; i < 25; i++) - { - bitmap_block bm; - - /* get bitmap block pointed to */ - ret = read_bitmap_block(img, root.bm_pages[i], &bm); - if (ret) return ret; - - *block = i * 32 * MSIZE + get_first_bit(bm.map, MSIZE); - - if (*block != -1) - { - *block += 2; - return IMGTOOLERR_SUCCESS; - } - } - - /* if we get here we haven't found a free block */ - return IMGTOOLERR_NOSPACE; -} - - -static imgtoolerr_t add_entry(imgtool_image *img, int parent, int block) -{ - imgtoolerr_t ret; - UINT32 ht[TSIZE]; - char name[31]; - int hash; - - ret = get_blockname(img, block, name); - if (ret) return ret; - - ret = get_hash_table(img, parent, ht); - if (ret) return ret; - - hash = hash_name(name, is_intl(img)); - - /* Check if there is already an entry with that name */ - if (ht[hash] != 0) - { - /* Save the old value to our hash chain */ - ret = set_hash_chain(img, block, ht[hash]); - if (ret) return ret; - } - - /* Write our block number into the table */ - ht[hash] = block; - - /* Write table back to disk */ - ret = set_hash_table(img, parent, ht); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -/* Recursively create new directory entries */ -static imgtoolerr_t makedir(imgtool_image *img, const char *path, int parent) -{ - imgtoolerr_t ret; - dir_block dir; - time_t now; - int block; - - if (!path) - { - return IMGTOOLERR_PARAMNEEDED; - } - - if (!path[0]) - { - return IMGTOOLERR_SUCCESS; - } - - /* Get a free block */ - ret = find_free_block(img, &block); - if (ret) return ret; - - /* Initialize entry */ - memset(&dir, 0, sizeof(dir_block)); - - /* Copy data */ - time(&now); - amiga_setup_time(now, &dir.date); - dir.name_len = strlen(path); - memcpy(dir.dirname, path, dir.name_len); - dir.header_key = block; - dir.parent = parent; - - /* Write block */ - ret = write_dir_block(img, block, &dir); - if (ret) return ret; - - /* Fix checksum */ - ret = fix_block_chksum(img, block); - if (ret) return ret; - - /* Link the new entry in the parent */ - ret = add_entry(img, parent, block); - if (ret) return ret; - - /* Mark it as used */ - ret = bitmap_mark_used(img, block); - if (ret) return ret; - - /* Create the next entry */ - return makedir(img, path + strlen(path) + 1, block); -} - - -/* Recursively checks the path parts and creates directories for them */ -static imgtoolerr_t checkdir(imgtool_image *img, const char *path, int parent) -{ - imgtoolerr_t ret; - int block; - char first_part[31]; - - memset(first_part, 0, sizeof(first_part)); - strcpy(first_part, path); - - /* Directories all the way down, bail out */ - if (!path[0]) - { - return IMGTOOLERR_CANNOTUSEPATH; - } - - /* Search for the entry */ - ret = find_entry(img, first_part, parent, &block); - - switch (ret) - { - case IMGTOOLERR_PATHNOTFOUND: - - /* There is no entry with this name yet, so we can just create them */ - return makedir(img, path, parent); - - case IMGTOOLERR_SUCCESS: - - if (get_block_type(img, block) == ST_USERDIR) - { - /* Go down one level */ - return checkdir(img, path + strlen(path) + 1, block); - } - else - { - /* There is an entry but it's not a directory, create it */ - return makedir(img, path, parent); - } - - default: return ret; - } -} - - -/* Writes the file data from the specified block into the stream */ -static imgtoolerr_t write_file_block_data(imgtool_image *img, int block, int size, imgtool_stream *destf) -{ - imgtoolerr_t ret; - UINT8 buffer[BSIZE]; - - /* Check if we even need to write something */ - if (size == 0) - { - return IMGTOOLERR_SUCCESS; - } - - if (is_ffs(img)) - { - /* Get block and read directly into buffer */ - ret = read_block(img, block, buffer); - if (ret) return ret; - } - else - { - data_block db; - UINT32 chksum; - - ret = read_data_block(img, block, &db); - if (ret) return ret; - - /* Verify data checksum */ - ret = get_block_chksum(img, block, &chksum, FALSE); - if (ret) return ret; - - if (db.chksum != chksum) - { - return IMGTOOLERR_CORRUPTFILE; - } - - /* Copy data to buffer */ - memcpy(buffer, db.data, size); - } - - /* Write data to stream */ - if (stream_write (destf, buffer, size) != size) - { - return IMGTOOLERR_WRITEERROR; - } - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t walk_data_block_ptr(imgtool_image *img, UINT32 *ptr, int *filesize, imgtool_stream *destf, int write) -{ - int i, blocksize = is_ffs(img) ? BSIZE : BSIZE-24; - imgtoolerr_t ret; - - for (i = TSIZE-1; i >= 0; i--) - { - /* We write either blocksize bytes or whats remaining */ - int bytes_left = (*filesize >= blocksize) ? blocksize : *filesize; - - if (write) - { - ret = write_file_block_data(img, ptr[i], bytes_left, destf); - if (ret) return ret; - } - else - { - ret = bitmap_mark_free(img, ptr[i]); - if (ret) return ret; - } - - *filesize -= bytes_left; - - /* Check if we are finished early */ - if (*filesize == 0) break; - } - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t write_data_block_ptr(imgtool_image *img, UINT32 *ptr, int *filesize, imgtool_stream *destf) -{ - return walk_data_block_ptr(img, ptr, filesize, destf, TRUE); -} - - -/* Marks all blocks pointed to by the data block pointers as free */ -static imgtoolerr_t clear_data_block_ptr(imgtool_image *img, UINT32 *ptr, int *filesize) -{ - return walk_data_block_ptr(img, ptr, filesize, NULL, FALSE); -} - - -static imgtoolerr_t walk_file_ext_data(imgtool_image *img, int block, int *filesize, imgtool_stream *destf, int write) -{ - file_ext_block file_ext; - imgtoolerr_t ret; - - /* Get file extension block */ - ret = read_file_ext_block(img, block, &file_ext); - if (ret) return ret; - - /* Write all data pointers in the table */ - ret = walk_data_block_ptr(img, file_ext.data_blocks, filesize, destf, write); - if (ret) return ret; - - /* Check if we are finished */ - if (*filesize != 0) - { - if (file_ext.extension == 0) - { - /* We are not finished, but there are no more extension blocks */ - return IMGTOOLERR_CORRUPTFILE; - } - else - { - /* Write the next file extension block */ - return walk_file_ext_data(img, file_ext.extension, filesize, destf, write); - } - } - - /* Mark ourself as free if we not writing */ - if (!write) - { - ret = bitmap_mark_free(img, block); - if (ret) return ret; - } - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t write_file_ext_data(imgtool_image *img, int block, int *filesize, imgtool_stream *destf) -{ - return walk_file_ext_data(img, block, filesize, destf, TRUE); -} - - -static imgtoolerr_t clear_file_ext_data(imgtool_image *img, int block, int *filesize) -{ - return walk_file_ext_data(img, block, filesize, NULL, FALSE); -} - - -/* Updates the disk alteration date stored in the root block */ -static imgtoolerr_t update_disk_alteration_date(imgtool_image *img) -{ - imgtoolerr_t ret; - root_block root; - time_t now; - - /* Get root block */ - ret = read_root_block(img, &root); - if (ret) return ret; - - /* Get current time */ - time(&now); - amiga_setup_time(now, &root.v); - - /* Write back new root block */ - ret = write_root_block(img, &root); - if (ret) return ret; - - /* And update its checksum */ - ret = fix_block_chksum(img, get_total_blocks(img)/2); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -/***************************************************************************** - Imgtool functions -*****************************************************************************/ - - -static imgtoolerr_t amiga_image_open(imgtool_image *img, imgtool_stream *stream) -{ - amiga_floppy *f = (amiga_floppy *) imgtool_image_extra_bytes(img); - UINT64 size = stream_size(stream); - - f->stream = stream; - f->sectors = size/BSIZE/80/2; - - if (f->sectors != 11 && f->sectors != 22) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - - return IMGTOOLERR_SUCCESS; -} - - -static void amiga_image_exit(imgtool_image *img) -{ -} - - -static void amiga_image_info(imgtool_image *img, char *string, size_t len) -{ - imgtoolerr_t ret; - root_block root; - char info[255]; - time_t t_c, t_v, t_r; - char c[19], v[19], r[19]; - - ret = read_root_block(img, &root); - if (ret) return; - - t_c = amiga_crack_time(&root.c); - t_v = amiga_crack_time(&root.v); - t_r = amiga_crack_time(&root.r); - - strftime(c, sizeof(c), "%d-%b-%y %H:%M:%S", localtime(&t_c)); - strftime(v, sizeof(v), "%d-%b-%y %H:%M:%S", localtime(&t_v)); - strftime(r, sizeof(r), "%d-%b-%y %H:%M:%S", localtime(&t_r)); - - strcpy(info, "Volume name: "); - strncat(info, (char *)root.diskname, root.name_len); - strcat(info, "\nVolume created: "); - strcat(info, c); - strcat(info, "\nVolume modified: "); - strcat(info, v); - strcat(info, "\n Root modified: "); - strcat(info, r); - - strncpy(string, info, len); -} - - -static imgtoolerr_t amiga_image_read_sector(imgtool_image* img, UINT32 track, UINT32 head, UINT32 sector, void *buf, size_t len) -{ - amiga_floppy *f = (amiga_floppy *) imgtool_image_extra_bytes(img); - - /* skip ahead to the area we want to read */ - stream_seek(f->stream, track * (head+1) * f->sectors * BSIZE + sector * BSIZE, SEEK_CUR); - - if (stream_read(f->stream, buf, len) != len) - { - return IMGTOOLERR_READERROR; - } - - /* reset stream */ - stream_seek(f->stream, 0, 0); - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t amiga_image_write_sector(imgtool_image* img, UINT32 track, UINT32 head, UINT32 sector, const void *buf, size_t len, int ddam) -{ - amiga_floppy *f = (amiga_floppy *) imgtool_image_extra_bytes(img); - - /* skip ahead to the area we want to write */ - stream_seek(f->stream, track * (head+1) * f->sectors * BSIZE + sector * BSIZE, SEEK_CUR); - - /* write data */ - if (stream_write(f->stream, buf, len) != len) - { - return IMGTOOLERR_WRITEERROR; - } - - /* reset stream */ - stream_seek(f->stream, 0, 0); - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t amiga_image_get_sector_size(imgtool_image* img, UINT32 track, UINT32 head, UINT32 sector, UINT32 *sector_size) -{ - *sector_size = BSIZE; - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t amiga_image_beginenum(imgtool_directory *enumeration, const char *path) -{ - int blocks = get_total_blocks(imgtool_directory_image(enumeration)); - imgtoolerr_t ret; - amiga_iterator *iter; - - iter = (amiga_iterator *) imgtool_directory_extrabytes(enumeration); - if (!iter) return IMGTOOLERR_OUTOFMEMORY; - - iter->index = 1; - iter->ht_index = 0; - iter->eof = 0; - - if (path[0]) - { - /* search for the directory block, start with the root block */ - ret = find_entry(imgtool_directory_image(enumeration), path, blocks/2, &iter->block); - if (ret) return ret; - } - else - { - /* we didn't get a path, use the root directory */ - iter->block = blocks / 2; - } - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t amiga_image_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent) -{ - amiga_iterator *iter = (amiga_iterator *) imgtool_directory_extrabytes(enumeration); - imgtoolerr_t ret; - UINT32 ht[TSIZE]; - int block; - - /* finished listing all entries? */ - if (iter->eof == 1 || iter->ht_index == TSIZE) - { - ent->eof = 1; - return IMGTOOLERR_SUCCESS; - } - - /* get hash table */ - ret = get_hash_table(imgtool_directory_image(enumeration), iter->block, ht); - if (ret) return ret; - - /* skip empty hash table entries */ - while (ht[iter->ht_index] == 0) - { - iter->ht_index++; - /* check if we are already at the end */ - if (iter->ht_index == TSIZE) - { - ent->eof = 1; - return IMGTOOLERR_SUCCESS; - } - } - - /* get block number */ - block = (iter->next_block == 0) ? ht[iter->ht_index] : iter->next_block; - - switch (get_block_type(imgtool_directory_image(enumeration), block)) - { - case ST_FILE: - { - file_block file; - - /* get block */ - ret = read_file_block(imgtool_directory_image(enumeration), block, &file); - if (ret) return ret; - - /* fill directory entry */ - strncpyz(ent->filename, (char *)file.filename, file.name_len + 1); - ent->filesize = file.byte_size; - ent->lastmodified_time = amiga_crack_time(&file.date); - amiga_decode_flags(file.protect, ent->attr); - strncpyz(ent->comment, (char *)file.comment, file.comm_len + 1); - - iter->next_block = file.hash_chain; - - break; - } - - case ST_USERDIR: - { - dir_block dir; - - /* get block */ - ret = read_dir_block(imgtool_directory_image(enumeration), block, &dir); - if (ret) return ret; - - /* fill directory entry */ - strncpyz(ent->filename, (char *)dir.dirname, dir.name_len + 1); - ent->lastmodified_time = amiga_crack_time(&dir.date); - amiga_decode_flags(dir.protect, ent->attr); - strncpyz(ent->comment, (char *)dir.comment, dir.comm_len + 1); - ent->directory = 1; - - iter->next_block = dir.hash_chain; - - break; - } - - case ST_SOFTLINK: - { - softlink_block sl; - - /* get block */ - ret = read_softlink_block(imgtool_directory_image(enumeration), block, &sl); - if (ret) return ret; - - /* fill directory entry */ - strncpyz(ent->filename, (char *)sl.slname, sl.name_len + 1); - ent->lastmodified_time = amiga_crack_time(&sl.date); - amiga_decode_flags(sl.protect, ent->attr); - strncpyz(ent->comment, (char *)sl.comment, sl.comm_len + 1); - strcpy(ent->softlink, (char *)sl.symbolic_name); - - iter->next_block = sl.hash_chain; - - break; - } - - case ST_LINKDIR: - - ent->directory = 1; - - case ST_LINKFILE: - { - hardlink_block hl; - - /* get block */ - ret = read_hardlink_block(imgtool_directory_image(enumeration), block, &hl); - if (ret) return ret; - - /* get filesize from linked file */ - if (!ent->directory) - { - file_block file; - ret = read_file_block(imgtool_directory_image(enumeration), hl.real_entry, &file); - if (ret) return ret; - ent->filesize = file.byte_size; - } - - /* fill directory entry */ - strncpyz(ent->filename, (char *)hl.hlname, hl.name_len + 1); - ent->lastmodified_time = amiga_crack_time(&hl.date); - amiga_decode_flags(hl.protect, ent->attr); - strncpyz(ent->comment, (char *)hl.comment, hl.comm_len + 1); - ent->hardlink = 1; - - iter->next_block = hl.hash_chain; - - break; - } - - default: - return IMGTOOLERR_UNIMPLEMENTED; - } - - /* if there are no linked entries, go to the next hash table entry */ - if (iter->next_block == 0) - { - iter->ht_index++; - } - - /* jump to next index */ - iter->index++; - - return IMGTOOLERR_SUCCESS; -} - - -static void amiga_image_closeenum(imgtool_directory *enumeration) -{ - free(enumeration); -} - - -static imgtoolerr_t amiga_image_freespace(imgtool_partition *partition, UINT64 *size) -{ - imgtoolerr_t ret; - imgtool_image *image = imgtool_partition_image(partition); - const int data_size = is_ffs(image) ? BSIZE : BSIZE-24; - root_block root; - bitmap_block bm; - int blocks, blocks_processed = 0, pages, i, c; - UINT32 v; - - /* initialize size */ - *size = 0; - - /* get root block */ - ret = read_root_block(image, &root); - if (ret) return ret; - - /* get total number of blocks in the image */ - blocks = get_total_blocks(image); - - /* subtract the two bootblock blocks (only for floppies!) */ - blocks -= 2; - - /* iterate all bitmap pages */ - for (pages = 0; pages < 25; pages++) - { - ret = read_bitmap_block(image, root.bm_pages[pages], &bm); - if (ret) return ret; - - for (i = 0; i < MSIZE; i++) - { - v = bm.map[i]; - - /* clear half used value */ - if ((blocks_processed + 32) > blocks) - v &= ~(~0 << (blocks - blocks_processed)); - - /* count bits */ - for (c = 0; v; c++) - v &= v - 1; - - *size += c * data_size; - - blocks_processed += 32; - - if (blocks_processed >= blocks) - return IMGTOOLERR_SUCCESS; - } - } - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t amiga_image_readfile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf) -{ - imgtool_image *img = imgtool_partition_image(partition); - imgtoolerr_t ret; - file_block file; - int filesize, block; - - /* Search for the block number */ - ret = find_entry(img, filename, get_total_blocks(img)/2, &block); - if (ret == IMGTOOLERR_PATHNOTFOUND) return IMGTOOLERR_FILENOTFOUND; - if (ret) return ret; /* Other errors */ - - /* Phase 1: Follow data pointers */ - ret = read_file_block(img, block, &file); - if (ret) return ret; - - filesize = file.byte_size; - - /* Write out file data pointed to by data block pointers */ - ret = write_data_block_ptr(img, file.data_blocks, &filesize, destf); - if (ret) return ret; - - /* Check if we are done already */ - if (filesize == 0) return IMGTOOLERR_SUCCESS; - - /* Phase 2: Follow file extension blocks */ - ret = write_file_ext_data(img, file.extension, &filesize, destf); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -/* When a file is deleted, only its File header block number is cleared from - * the Directory block (or from the same-hash-value list) and the bitmap is - * updated. File header block, Data blocks and File extension blocks are not - * cleared, but the bitmap blocks are updated. */ -static imgtoolerr_t amiga_image_deletefile(imgtool_partition *partition, const char *fname) -{ - imgtool_image *img = imgtool_partition_image(partition); - imgtoolerr_t ret; - int parent, block; - char filename[31]; - - /* Initialize filename */ - memset(filename, 0, sizeof(filename)); - - /* Search for the block number */ - ret = find_entry(img, fname, get_total_blocks(img)/2, &block); - if (ret == IMGTOOLERR_PATHNOTFOUND) return IMGTOOLERR_FILENOTFOUND; - if (ret) return ret; - - /* Get the parent block, where we need to clear the hash */ - switch (get_block_type(img, block)) - { - case ST_FILE: - { - file_block file; - int filesize; - - ret = read_file_block(img, block, &file); - if (ret) return ret; - - filesize = file.byte_size; - parent = file.parent; - memcpy(filename, file.filename, file.name_len); - - /* Clear all linked data sectors */ - ret = clear_data_block_ptr(img, file.data_blocks, &filesize); - if (ret) return ret; - - /* Clear extended file data sectors */ - if (filesize != 0) - { - ret = clear_file_ext_data(img, file.extension, &filesize); - if (ret) return ret; - } - - break; - } - - case ST_LINKFILE: - { - softlink_block link; - - ret = read_softlink_block(img, block, &link); - if (ret) return ret; - - parent = link.parent; - memcpy(filename, link.slname, link.name_len); - - break; - } - - default: - return IMGTOOLERR_UNEXPECTED; - } - - /* Clear hash table entry */ - ret = clear_hash_table_entry(img, parent, filename); - if (ret) return ret; - - /* Update disk alteration date */ - ret = update_disk_alteration_date(img); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t amiga_image_writefile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, option_resolution *opts) -{ - return IMGTOOLERR_UNIMPLEMENTED; -} - - -static imgtoolerr_t amiga_image_create(imgtool_image *img, imgtool_stream *stream, option_resolution *opts) -{ - amiga_floppy *f = (amiga_floppy *) imgtool_image_extra_bytes(img); - const char *dskname = option_resolution_lookup_string(opts, 'N'); - imgtoolerr_t ret; - UINT8 buffer[BSIZE]; - root_block root; - bitmap_block bm; - time_t now; - int blocks; - - f->stream = stream; - - switch (option_resolution_lookup_int(opts, 'S')) - { - case 0: f->sectors = 11; break; - case 1: f->sectors = 22; break; - default: return IMGTOOLERR_PARAMCORRUPT; - } - - /* initialize with zeros */ - memset(buffer, 0, BSIZE); - - /* add DOS magic string and flags */ - buffer[0] = 'D'; - buffer[1] = 'O'; - buffer[2] = 'S'; - buffer[3] = 0; - - /* File system */ - buffer[3] += (option_resolution_lookup_int(opts, 'F')); - - /* File system mode */ - buffer[3] += (option_resolution_lookup_int(opts, 'M')); - - /* write first bootblock sector */ - ret = write_block(img, 0, buffer); - if (ret) return ret; - - /* reset with zeros */ - memset(buffer, 0, BSIZE); - - /* write second bootblock sector */ - ret = write_block(img, 1, buffer); - if (ret) return ret; - - /* rootblock */ - memset(&root, 0, sizeof(root_block)); - - blocks = get_total_blocks(img); - - root.chksum = 0; - root.ht_size = TSIZE; - root.bm_flag = -1; - root.bm_pages[0] = blocks/2 + 1; /* generally it's located here */ - - time(&now); - amiga_setup_time(now, &root.r); - amiga_setup_time(now, &root.v); - amiga_setup_time(now, &root.c); - - /* volume name */ - if (dskname) - { - root.name_len = strlen(dskname); - memcpy(&root.diskname, dskname, root.name_len); - } - else - { - root.name_len = strlen("Empty"); - memcpy(&root.diskname, "Empty", root.name_len); - } - - /* write root block to disk */ - ret = write_root_block(img, &root); - if (ret) return ret; - - /* calculate block checksum */ - ret = fix_block_chksum(img, blocks/2); - if (ret) return ret; - - /* bitmap block */ - memset(&bm, 0xff, sizeof(bitmap_block)); - - /* write bitmap block to disk */ - ret = write_bitmap_block(img, root.bm_pages[0], &bm); - if (ret) return ret; - - /* set root and bitmap block as used */ - ret = bitmap_mark_used(img, blocks/2); - if (ret) return ret; - - ret = bitmap_mark_used(img, root.bm_pages[0]); - if (ret) return ret; - - /* write empty last block so that we don't get a truncated image */ - memset(buffer, 0, BSIZE); - - ret = write_block(img, blocks - 1, buffer); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t amiga_image_createdir(imgtool_partition *partition, const char *path) -{ - imgtool_image *img = imgtool_partition_image(partition); - imgtoolerr_t ret; - - /* Create directories */ - ret = checkdir(img, path, get_total_blocks(img)/2); - if (ret) return ret; - - /* Update disk alteration date */ - ret = update_disk_alteration_date(img); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t amiga_image_getattrs(imgtool_partition *partition, const char *path, const UINT32 *attrs, imgtool_attribute *values) -{ - return IMGTOOLERR_UNIMPLEMENTED; -} - - -static imgtoolerr_t amiga_image_setattrs(imgtool_partition *partition, const char *path, const UINT32 *attrs, const imgtool_attribute *values) -{ - return IMGTOOLERR_UNIMPLEMENTED; -} - - -static imgtoolerr_t amiga_image_geticoninfo(imgtool_partition *partition, const char *path, imgtool_iconinfo *iconinfo) -{ - return IMGTOOLERR_UNIMPLEMENTED; -} - - -static imgtoolerr_t amiga_image_suggesttransfer(imgtool_partition *partition, const char *fname, imgtool_transfer_suggestion *suggestions, size_t suggestions_length) -{ - return IMGTOOLERR_UNIMPLEMENTED; -} - - - -/***************************************************************************** - Create image options -*****************************************************************************/ - - -static OPTION_GUIDE_START(amiga_createimage_optionguide) - OPTION_STRING( 'N', "name", "Volume name" ) - OPTION_ENUM_START( 'S', "density", "Density" ) - OPTION_ENUM( 0, "dd", "Double Density" ) - OPTION_ENUM( 1, "hd", "High Density" ) - OPTION_ENUM_END - OPTION_ENUM_START( 'F', "filesystem", "File system" ) - OPTION_ENUM( 0, "ofs", "OldFileSystem" ) - OPTION_ENUM( 1, "ffs", "FastFileSystem" ) - OPTION_ENUM_END - OPTION_ENUM_START( 'M', "mode", "File system options" ) - OPTION_ENUM( 0, "none", "None" ) - OPTION_ENUM( 2, "intl", "International Mode" ) - OPTION_ENUM( 4, "dirc", "International Mode with Directory Cache" ) - OPTION_ENUM_END -OPTION_GUIDE_END - - - -/***************************************************************************** - Imgtool module declaration -*****************************************************************************/ - - -/* Amiga floppy disk attributes */ -void amiga_floppy_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info) -{ - switch(state) - { - /* --- the following bits of info are returned as 64-bit signed integers --- */ - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: info->i = sizeof(amiga_floppy); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(amiga_iterator); break; - case IMGTOOLINFO_INT_SUPPORTS_LASTMODIFIED_TIME: info->i = 1; break; - case IMGTOOLINFO_INT_PATH_SEPARATOR: info->i = '/'; break; - case IMGTOOLINFO_INT_CHARSET: info->i = IMGTOOL_CHARSET_ISO_8859_1; break; - - /* --- the following bits of info are returned as NULL-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; - case IMGTOOLINFO_STR_FILE: strcpy(info->s = imgtool_temp_str(), __FILE__); break; - case IMGTOOLINFO_STR_EOLN: strcpy(info->s = imgtool_temp_str(), EOLN_LF); break; - case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), "S[0]-1;F[0]-1;M[0]/2/4"); break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case IMGTOOLINFO_PTR_OPEN: info->open = amiga_image_open; break; - case IMGTOOLINFO_PTR_CLOSE: info->close = amiga_image_exit; break; - case IMGTOOLINFO_PTR_READ_SECTOR: info->read_sector = amiga_image_read_sector; break; - case IMGTOOLINFO_PTR_WRITE_SECTOR: info->write_sector = amiga_image_write_sector; break; - case IMGTOOLINFO_PTR_GET_SECTOR_SIZE: info->get_sector_size = amiga_image_get_sector_size; break; - case IMGTOOLINFO_PTR_CREATE: info->create = amiga_image_create; break; - case IMGTOOLINFO_PTR_INFO: info->info = amiga_image_info; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = amiga_image_beginenum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = amiga_image_nextenum; break; - case IMGTOOLINFO_PTR_CLOSE_ENUM: info->close_enum = amiga_image_closeenum; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = amiga_image_freespace; break; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = amiga_image_readfile; break; - case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = amiga_image_writefile; break; - case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = amiga_image_deletefile; break; - case IMGTOOLINFO_PTR_CREATE_DIR: info->create_dir = amiga_image_createdir; break; - case IMGTOOLINFO_PTR_GET_ATTRS: info->get_attrs = amiga_image_getattrs; break; - case IMGTOOLINFO_PTR_SET_ATTRS: info->set_attrs = amiga_image_setattrs; break; - case IMGTOOLINFO_PTR_GET_ICON_INFO: info->get_iconinfo = amiga_image_geticoninfo; break; - case IMGTOOLINFO_PTR_SUGGEST_TRANSFER: info->suggest_transfer = amiga_image_suggesttransfer; break; - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = amiga_createimage_optionguide; break; - } -} diff --git a/src/mess/tools/imgtool/modules/bml3.c b/src/mess/tools/imgtool/modules/bml3.c deleted file mode 100644 index 1ed1b645f69..00000000000 --- a/src/mess/tools/imgtool/modules/bml3.c +++ /dev/null @@ -1,928 +0,0 @@ -// license:GPL-2.0+ -// copyright-holders:Jonathan Edwards -/**************************************************************************** - - bml3.c - - Hitachi bml3 disk images - - By Jonathan Edwards, based on rsdos.c (both use Microsoft BASIC) - -****************************************************************************/ - -/* Supported Hitachi floppy formats are: - - 3" or 5"1/4 single density, single-sided: 40 tracks, 16 sectors/track, 128 bytes/sector - - (used with MP-1805 floppy disk controller card) - - 5"1/4 double density, double-sided: 40 tracks, 16 sectors/track, 256 bytes/sector - - (first track on first head may be single density) - - (used with MP-1802 floppy disk controller card) -*/ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include "imgtool.h" -#include "iflopimg.h" - -#define MAX_SECTOR_SIZE 256 - -struct bml3_diskinfo -{ - UINT16 sector_size; /* 128 or 256 */ - UINT8 heads; /* 1 or 2 */ - UINT8 fat_start_sector; /* in cylinder 20, start sector of FAT */ - UINT8 fat_start_offset; /* start byte of FAT in sector */ - UINT8 fat_sectors; /* the number of sectors in the FAT */ - UINT8 dirent_start_sector; /* in cylinder 20, start sector of directory entries */ - UINT8 granule_sectors; /* how many sectors per granule */ - UINT8 first_granule_cylinder; /* the number of the first cylinder with granule numbers assigned */ - UINT8 variant; /* 0 - older version, uses EOF to terminate files, 1 - newer version, stores file length */ -}; - -/* this structure mirrors the structure of a directory entry on disk */ -struct bml3_dirent -{ - char fname[8]; - char fext[3]; - UINT8 ftype; - UINT8 asciiflag; - UINT8 first_granule; - UINT16 lastsectorbytes; - // TODO there are some 'unused' bytes here that are sometimes used to store a timestamp, maybe support this? -}; - -struct bml3_direnum -{ - int index; - int eof; -}; - -#define MAX_GRANULEMAP_SIZE 256 - -struct granule_list_t { - UINT8 granules[MAX_GRANULEMAP_SIZE]; - UINT8 granule_count; - UINT8 last_granule_sectors; -}; - -#define BML3_OPTIONS_FTYPE 'T' -#define BML3_OPTIONS_ASCII 'M' - -static imgtoolerr_t bml3_diskimage_deletefile(imgtool_partition *partition, const char *fname); - - - -/********************************************************************* - Imgtool module code -*********************************************************************/ - -static bml3_diskinfo *bml3_get_diskinfo(imgtool_image *image) -{ - return (bml3_diskinfo *) imgtool_floppy_extrabytes(image); -} - - - -static int max_dirents(imgtool_image *image) -{ - bml3_diskinfo *info = bml3_get_diskinfo(image); - return (16 * info->heads + 1 - info->dirent_start_sector)*(info->sector_size/32); -} - - - -static void dirent_location(imgtool_image *image, int index_loc, UINT8 *head, UINT8 *track, UINT8 *sector, UINT8 *offset) -{ - bml3_diskinfo *info = bml3_get_diskinfo(image); - *track = 20; - *sector = info->dirent_start_sector + index_loc / (info->sector_size / 32); - *head = 0; - if (*sector > 16) { - // wrap to second head - *sector -= 16; - (*head)++; - } - *offset = index_loc % (info->sector_size/32) * 32; -} - - - -static floperr_t get_bml3_dirent(imgtool_image *f, int index_loc, struct bml3_dirent *ent) -{ - floperr_t err; - UINT8 head, track, sector, offset; - UINT8 buf[32]; - bml3_diskinfo *info = bml3_get_diskinfo(f); - dirent_location(f, index_loc, &head, &track, §or, &offset); - err = floppy_read_sector(imgtool_floppy(f), head, track, sector, offset, (void *) buf, sizeof(buf)); - memset(ent, 0, sizeof(*ent)); - switch (info->variant) { - case 0: - memcpy(&ent->fname, &buf[0], 8); - ent->ftype = buf[11]; - ent->asciiflag = buf[12]; - ent->first_granule = buf[14]; - break; - case 1: - memcpy(&ent->fname, &buf[0], 8); - memcpy(&ent->fext, &buf[8], 3); - ent->ftype = buf[11]; - ent->asciiflag = buf[12]; - ent->first_granule = buf[13]; - ent->lastsectorbytes = (buf[14] << 8) | buf[15]; - break; - default: - return FLOPPY_ERROR_INVALIDIMAGE; - } - return err; -} - - - -static floperr_t put_bml3_dirent(imgtool_image *f, int index_loc, const struct bml3_dirent *ent) -{ - floperr_t err; - UINT8 head, track, sector, offset; - UINT8 buf[32]; - bml3_diskinfo *info = bml3_get_diskinfo(f); - if (index_loc >= max_dirents(f)) - return (floperr_t)IMGTOOLERR_FILENOTFOUND; - dirent_location(f, index_loc, &head, &track, §or, &offset); - memset(buf, 0, sizeof(buf)); - switch (info->variant) { - case 0: - memcpy(&buf[0], &ent->fname, 8); - buf[11] = ent->ftype; - buf[12] = ent->asciiflag; - buf[14] = ent->first_granule; - break; - case 1: - memcpy(&buf[0], &ent->fname, 8); - memcpy(&buf[8], &ent->fext, 3); - buf[11] = ent->ftype; - buf[12] = ent->asciiflag; - buf[13] = ent->first_granule; - buf[14] = ent->lastsectorbytes >> 8; - buf[15] = ent->lastsectorbytes & 0xff; - break; - default: - return FLOPPY_ERROR_INVALIDIMAGE; - } - err = floppy_write_sector(imgtool_floppy(f), head, track, sector, offset, (void *) buf, sizeof(buf), 0); /* TODO: pass ddam argument from imgtool */ - return err; -} - - - -/* fnamebuf must have at least 13 bytes */ -static void get_dirent_fname(char *fnamebuf, const struct bml3_dirent *ent) -{ - char *s; - - memset(fnamebuf, 0, 13); - memcpy(fnamebuf, ent->fname, sizeof(ent->fname)); - rtrim(fnamebuf); - s = fnamebuf + strlen(fnamebuf); - *(s++) = '.'; - memcpy(s, ent->fext, sizeof(ent->fext)); - rtrim(s); - - /* If no extension, remove period */ - if (*s == '\0') - s[-1] = '\0'; -} - - - -static imgtoolerr_t lookup_bml3_file(imgtool_image *f, const char *fname, struct bml3_dirent *ent, int *position) -{ - int i; - floperr_t ferr; - char fnamebuf[13]; - - i = 0; - fnamebuf[0] = '\0'; - - do - { - do - { - ferr = get_bml3_dirent(f, i++, ent); - if (ferr) - return imgtool_floppy_error(ferr); - } - while(ent->fname[0] == '\0'); - - - if (ent->fname[0] != -1) - get_dirent_fname(fnamebuf, ent); - } - while((ent->fname[0] != -1) && core_stricmp(fnamebuf, fname)); - - if (ent->fname[0] == -1) - return IMGTOOLERR_FILENOTFOUND; - - if (position) - *position = i - 1; - return (imgtoolerr_t)0; -} - - - -static UINT8 get_granule_count(imgtool_image *img) -{ - // UINT16 tracks; - UINT16 disk_granules; - bml3_diskinfo *info = bml3_get_diskinfo(img); - - // This always returns 82 for D88, so not quite right - // tracks = floppy_get_tracks_per_disk(imgtool_floppy(img)); - - // The number of granules is primarily constrained by the disk capacity. - disk_granules = (40 - 1 - info->first_granule_cylinder) * info->heads * (16 / info->granule_sectors); - // Also, granule numbers from 0xC0 upwards are reserved for terminating a granule chain - return (UINT8)((disk_granules < 0xC0) ? disk_granules : 0xC0); -} - -/* granule_map must be an array of MAX_GRANULEMAP_SIZE bytes */ -static floperr_t get_granule_map(imgtool_image *img, UINT8 *granule_map, UINT8 *granule_count) -{ - bml3_diskinfo *info = bml3_get_diskinfo(img); - UINT8 count; - - count = get_granule_count(img); - if (granule_count) - *granule_count = count; - - // The first byte of the granule map sector is ignored (and expected to be 0) - return floppy_read_sector(imgtool_floppy(img), 0, 20, info->fat_start_sector, info->fat_start_offset, granule_map, count); -} - - - -static floperr_t put_granule_map(imgtool_image *img, const UINT8 *granule_map, UINT8 granule_count) -{ - bml3_diskinfo *info = bml3_get_diskinfo(img); - return floppy_write_sector(imgtool_floppy(img), 0, 20, info->fat_start_sector, info->fat_start_offset, granule_map, granule_count, 0); /* TODO: pass ddam argument from imgtool */ -} - - - - -static void granule_location(imgtool_image *image, UINT8 granule, UINT8 *head, UINT8 *track, UINT8 *sector) -{ - bml3_diskinfo *info = bml3_get_diskinfo(image); - UINT16 abs_track = granule * info->granule_sectors / 16; - *head = abs_track % info->heads; - *track = abs_track / info->heads + info->first_granule_cylinder; - // skip filesystem cylinder - if (*track >= 20) - (*track)++; - *sector = granule * info->granule_sectors % 16 + 1; -} - - - -static imgtoolerr_t transfer_granule(imgtool_image *img, UINT8 granule, int length, imgtool_stream *f, imgtoolerr_t (*proc)(imgtool_image *, int, int, int, int, size_t, imgtool_stream *)) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - UINT8 head, track, sector; - granule_location(img, granule, &head, &track, §or); - if (length > 0) - err = proc(img, head, track, sector, 0, length, f); - return err; -} - - -static imgtoolerr_t transfer_from_granule(imgtool_image *img, UINT8 granule, int length, imgtool_stream *destf) -{ - return transfer_granule(img, granule, length, destf, imgtool_floppy_read_sector_to_stream); -} - - - -static imgtoolerr_t transfer_to_granule(imgtool_image *img, UINT8 granule, int length, imgtool_stream *sourcef) -{ - return transfer_granule(img, granule, length, sourcef, imgtool_floppy_write_sector_from_stream); -} - - - -static floperr_t read_granule(imgtool_image *img, UINT8 granule, int offset, int length, UINT8 *buf) -{ - UINT8 head, track, sector; - granule_location(img, granule, &head, &track, §or); - return floppy_read_sector(imgtool_floppy(img), head, track, sector, offset, buf, length); -} - - - -static floperr_t write_granule(imgtool_image *img, UINT8 granule, int offset, int length, const UINT8 *buf) -{ - UINT8 head, track, sector; - granule_location(img, granule, &head, &track, §or); - return floppy_write_sector(imgtool_floppy(img), head, track, sector, offset, buf, length, 0); /* TODO: pass ddam argument from imgtool */ -} - - - -static imgtoolerr_t list_granules(struct bml3_dirent *ent, imgtool_image *img, struct granule_list_t *granule_list) -{ - floperr_t ferr; - UINT8 max_granules; - UINT8 granule; - UINT8 usedmap[MAX_GRANULEMAP_SIZE]; /* Used to detect infinite loops */ - UINT8 granule_map[MAX_GRANULEMAP_SIZE]; - bml3_diskinfo *info = bml3_get_diskinfo(img); - - ferr = get_granule_map(img, granule_map, &max_granules); - if (ferr) - return imgtool_floppy_error(ferr); - - memset(usedmap, 0, max_granules); - - granule = ent->first_granule; - granule_list->granule_count = 0; - - while(!usedmap[granule] && granule < max_granules) - { - usedmap[granule] = 1; - granule_list->granules[granule_list->granule_count++] = granule; - granule = granule_map[granule]; - } - - granule_list->last_granule_sectors = granule - 0xc0; - if (info->variant == 0) { - // add final incomplete sector - granule_list->last_granule_sectors++; - } - - // A value of zero (variant 1) and max (variant 0) seem to indicate a file open for writing. - // Strictly speaking this means the image is corrupt, although a real system will happily read - // garbage from the file. - if (granule_list->last_granule_sectors > info->granule_sectors) - return IMGTOOLERR_CORRUPTIMAGE; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t get_file_size(struct bml3_dirent *ent, imgtool_image *img, const struct granule_list_t *granule_list, size_t *size) -{ - floperr_t ferr; - size_t last_sector_bytes = 0; - bml3_diskinfo *info = bml3_get_diskinfo(img); - - // TODO are these special cases valid, or maybe indicate a corrupt image? - if (granule_list->granule_count == 0) { - *size = 0; - return IMGTOOLERR_SUCCESS; - } - else if (granule_list->last_granule_sectors == 0) { - *size = info->sector_size * ((granule_list->granule_count - 1) * info->granule_sectors); - return IMGTOOLERR_SUCCESS; - } - - // determine size excluding final sector - *size = info->sector_size * ((granule_list->granule_count - 1) * info->granule_sectors + granule_list->last_granule_sectors - 1); - - // determine bytes used in final sector - switch (info->variant) { - case 0: - // look for EOF (ASCII SUB) and trailing NULs in final sector - { - UINT8 buf[MAX_SECTOR_SIZE]; - ferr = read_granule(img, granule_list->granules[granule_list->granule_count-1], info->sector_size * (granule_list->last_granule_sectors - 1), info->sector_size, buf); - if (ferr) - return imgtool_floppy_error(ferr); - for (last_sector_bytes = info->sector_size - 1; ; last_sector_bytes--) { - if (buf[last_sector_bytes] != 0) - break; - if (last_sector_bytes == 0) - break; - } - if (buf[last_sector_bytes] != 0x1a) { - last_sector_bytes++; - } - } - break; - case 1: - last_sector_bytes = ent->lastsectorbytes; - break; - } - - // TODO is it valid for last_sector_bytes == 0? - if (last_sector_bytes > info->sector_size) { - return IMGTOOLERR_CORRUPTIMAGE; - } - *size += last_sector_bytes; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t process_bml3_file(struct bml3_dirent *ent, imgtool_image *img, imgtool_stream *destf, size_t *size) -{ - imgtoolerr_t err; - size_t remaining_size, granule_size; - bml3_diskinfo *info = bml3_get_diskinfo(img); - struct granule_list_t granule_list; - granule_list.granule_count = 0; - - err = list_granules(ent, img, &granule_list); - if (err) - return err; - err = get_file_size(ent, img, &granule_list, size); - if (err) - return err; - - if (destf) { - remaining_size = *size; - granule_size = info->granule_sectors * info->sector_size; - - for (int c = 0; c < granule_list.granule_count; c++) { - if (granule_size >= remaining_size) - granule_size = remaining_size; - transfer_from_granule(img, granule_list.granules[c], granule_size, destf); - remaining_size -= granule_size; - } - } - return IMGTOOLERR_SUCCESS; -} - - - -/* create a new directory entry with a specified name */ -static imgtoolerr_t prepare_dirent(UINT8 variant, struct bml3_dirent *ent, const char *fname) -{ - const char *fname_end; - const char *fname_ext; - int fname_ext_len; - - memset(ent, '\0', sizeof(*ent)); - memset(ent->fname, ' ', sizeof(ent->fname)); - memset(ent->fext, ' ', sizeof(ent->fext)); - - 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); - - switch (variant) { - case 0: - /* 8-character max filename */ - if (((fname_end - fname) > 8) || (fname_ext_len > 0)) - return IMGTOOLERR_BADFILENAME; - break; - case 1: - /*8.3 filename */ - if (((fname_end - fname) > 8) || (fname_ext_len > 3)) - return IMGTOOLERR_BADFILENAME; - break; - default: - return IMGTOOLERR_CORRUPTIMAGE; - } - - memcpy(ent->fname, fname, fname_end - fname); - memcpy(ent->fext, fname_ext, fname_ext_len); - - /* By default, set as a type 2 binary file */ - ent->ftype = 2; - ent->asciiflag = 0; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t bml3_diskimage_open(imgtool_image *image, imgtool_stream *stream) -{ - // imgtoolerr_t err; - floperr_t ferr; - bml3_diskinfo *info = bml3_get_diskinfo(image); - floppy_image_legacy *floppy = imgtool_floppy(image); - const struct FloppyCallbacks *callbacks = floppy_callbacks(floppy); - - // probe disk geometry to guess format - int heads_per_disk = callbacks->get_heads_per_disk(floppy); - UINT32 sector_length; - 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); - - if (heads_per_disk == 2 && sector_length == 128 && sectors_per_track == 16) { - // single-sided, single-density - info->sector_size = 128; - info->heads = 1; - info->fat_start_sector = 1; - info->fat_start_offset = 5; - info->fat_sectors = 2; - info->dirent_start_sector = 7; - info->granule_sectors = 4; - info->first_granule_cylinder = 0; - info->variant = 0; - } - else if (heads_per_disk == 2 && sector_length == 256 && sectors_per_track == 16) { - // double-sided, double-density - info->sector_size = 256; - info->heads = 2; - info->fat_start_sector = 2; - info->fat_start_offset = 1; - info->fat_sectors = 1; - info->dirent_start_sector = 5; - info->granule_sectors = 8; - info->first_granule_cylinder = 1; - info->variant = 1; - } - else { - // invalid or unsupported format - return IMGTOOLERR_CORRUPTIMAGE; - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t bml3_diskimage_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent) -{ - floperr_t ferr; - imgtoolerr_t err; - size_t filesize; - struct bml3_direnum *rsenum; - struct bml3_dirent rsent; - char fname[13]; - imgtool_image *image; - - image = imgtool_directory_image(enumeration); - rsenum = (struct bml3_direnum *) imgtool_directory_extrabytes(enumeration); - - /* Did we hit the end of file before? */ - if (rsenum->eof) - goto eof; - - do - { - if (rsenum->index >= max_dirents(image)) - goto eof; - - ferr = get_bml3_dirent(image, rsenum->index++, &rsent); - if (ferr) - return imgtool_floppy_error(ferr); - } - while(rsent.fname[0] == '\0'); - - /* Now are we at the eof point? */ - if (rsent.fname[0] == -1) - { - rsenum->eof = 1; -eof: - ent->eof = 1; - } - else - { - /* Not the end of file */ - err = process_bml3_file(&rsent, image, NULL, &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; - - 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')); - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t bml3_diskimage_freespace(imgtool_partition *partition, UINT64 *size) -{ - floperr_t ferr; - UINT8 i; - size_t s = 0; - UINT8 granule_count; - UINT8 granule_map[MAX_GRANULEMAP_SIZE]; - imgtool_image *image = imgtool_partition_image(partition); - bml3_diskinfo *info = bml3_get_diskinfo(image); - - ferr = get_granule_map(image, granule_map, &granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - for (i = 0; i < granule_count; i++) - { - if (granule_map[i] == 0xff) - s += (info->granule_sectors * info->sector_size); - } - *size = s; - return (imgtoolerr_t)FLOPPY_ERROR_SUCCESS; -} - - - -static imgtoolerr_t delete_entry(imgtool_image *img, struct bml3_dirent *ent, int pos) -{ - floperr_t ferr; - unsigned char g, i; - UINT8 granule_count; - UINT8 granule_map[MAX_GRANULEMAP_SIZE]; - - /* Write a NUL in the filename, marking it deleted */ - ent->fname[0] = 0; - ferr = put_bml3_dirent(img, pos, ent); - if (ferr) - return imgtool_floppy_error(ferr); - - ferr = get_granule_map(img, granule_map, &granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - /* Now free up the granules */ - g = ent->first_granule; - while (g < granule_count) - { - i = granule_map[g]; - granule_map[g] = 0xff; - g = i; - } - - ferr = put_granule_map(img, granule_map, granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t bml3_diskimage_readfile(imgtool_partition *partition, const char *fname, const char *fork, imgtool_stream *destf) -{ - imgtoolerr_t err; - struct bml3_dirent ent; - size_t size; - imgtool_image *img = imgtool_partition_image(partition); - - err = lookup_bml3_file(img, fname, &ent, NULL); - if (err) - return err; - - err = process_bml3_file(&ent, img, destf, &size); - if (err) - return err; - - if (size == (size_t) -1) - return IMGTOOLERR_CORRUPTIMAGE; - - return (imgtoolerr_t)0; -} - - - -static imgtoolerr_t bml3_diskimage_writefile(imgtool_partition *partition, const char *fname, const char *fork, imgtool_stream *sourcef, option_resolution *writeoptions) -{ - floperr_t ferr; - imgtoolerr_t err; - imgtool_image *img = imgtool_partition_image(partition); - bml3_diskinfo *info = bml3_get_diskinfo(img); - struct bml3_dirent ent, ent2; - size_t i; - UINT64 sz, read_sz; - UINT64 freespace = 0; - unsigned char *gptr; - UINT8 granule_count; - UINT8 granule_map[MAX_GRANULEMAP_SIZE]; - UINT8 eof_buf[MAX_SECTOR_SIZE]; - - // one-time setup of eof_buf - memset(eof_buf, 0, sizeof(eof_buf)); - eof_buf[0] = 0x1A; - - /* can we write to this image? */ - if (floppy_is_read_only(imgtool_floppy(img))) - return IMGTOOLERR_READONLY; - - err = bml3_diskimage_freespace(partition, &freespace); - if (err) - return err; - - /* is there enough space? */ - sz = read_sz = stream_size(sourcef); - if (info->variant == 0) { - // also need to write EOF - sz++; - } - if (sz > freespace) - return IMGTOOLERR_NOSPACE; - - /* setup our directory entry */ - err = prepare_dirent(info->variant, &ent, fname); - if (err) - return err; - - ent.ftype = option_resolution_lookup_int(writeoptions, BML3_OPTIONS_FTYPE); - ent.asciiflag = ((UINT8) option_resolution_lookup_int(writeoptions, BML3_OPTIONS_ASCII)) - 1; - gptr = &ent.first_granule; - - ferr = get_granule_map(img, granule_map, &granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - unsigned char g = 0x00; - UINT32 granule_bytes = info->granule_sectors * info->sector_size; - - do - { - while (granule_map[g] != 0xff) - { - g++; - if ((g >= granule_count) || (g == 0)) - return IMGTOOLERR_UNEXPECTED; /* We should have already verified that there is enough space */ - } - *gptr = g; - gptr = &granule_map[g]; - - - i = MIN(read_sz, granule_bytes); - if (i > 0) { - err = transfer_to_granule(img, g, i, sourcef); - if (err) - return err; - read_sz -= i; - sz -= i; - } - if (i < info->granule_sectors * info->sector_size && sz > 0) { - // write EOF and trailing NULs in the final sector - ferr = write_granule(img, g, i, (info->granule_sectors * info->sector_size - i - 1) % info->sector_size + 1, eof_buf); - if (ferr) - return imgtool_floppy_error(ferr); - sz--; - i++; - } - - /* Go to next granule */ - g++; - } - while(sz > 0); - - /* Now that we are done with the file, we need to specify the final entry - * in the file allocation table - */ - *gptr = 0xc0 + ((i + info->sector_size-1) / info->sector_size) - (info->variant == 0 ? 1 : 0); - ent.lastsectorbytes = (i - 1) % info->sector_size + 1; - - /* delete file if it already exists */ - err = bml3_diskimage_deletefile(partition, fname); - if (err && err != IMGTOOLERR_FILENOTFOUND) - return err; - - /* Now we need to find an empty directory entry */ - i = -1; - do - { - ferr = get_bml3_dirent(img, ++i, &ent2); - if (ferr) - return imgtool_floppy_error(ferr); - } - while(ent2.fname[0] != '\0' && ent2.fname[0] != -1); - - ferr = put_bml3_dirent(img, i, &ent); - if (ferr) - return imgtool_floppy_error(ferr); - - /* write the granule map back out */ - ferr = put_granule_map(img, granule_map, granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t bml3_diskimage_deletefile(imgtool_partition *partition, const char *fname) -{ - imgtoolerr_t err; - imgtool_image *image = imgtool_partition_image(partition); - int pos = 0; - struct bml3_dirent ent; - - err = lookup_bml3_file(image, fname, &ent, &pos); - if (err) - return err; - - return delete_entry(image, &ent, pos); -} - - - -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 = imgtool_partition_image(partition); - struct bml3_dirent ent; - int pos; - - if (fname) - { - err = lookup_bml3_file(image, fname, &ent, &pos); - if (err) - return err; - - if (ent.asciiflag == 0xFF) - { - /* ASCII file */ - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = filter_eoln_getinfo; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = NULL; - } - else if (ent.ftype == 0) - { - /* tokenized BASIC file */ - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = filter_bml3bas_getinfo; - } - } - else - { - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = filter_eoln_getinfo; - suggestions[2].viability = SUGGESTION_POSSIBLE; - suggestions[2].filter = filter_bml3bas_getinfo; - } - - return IMGTOOLERR_SUCCESS; -} - - - -/********************************************************************* - Imgtool module declaration -*********************************************************************/ - -static OPTION_GUIDE_START( bml3_writefile_optionguide ) - OPTION_ENUM_START( BML3_OPTIONS_FTYPE, "ftype", "File type" ) - OPTION_ENUM( 0, "basic", "Basic" ) - OPTION_ENUM( 1, "data", "Data" ) - OPTION_ENUM( 2, "binary", "Binary" ) - OPTION_ENUM( 3, "assembler", "Assembler Source" ) - OPTION_ENUM_END - OPTION_ENUM_START( BML3_OPTIONS_ASCII, "ascii", "Ascii flag" ) - OPTION_ENUM( 0, "ascii", "Ascii" ) - OPTION_ENUM( 1, "binary", "Binary" ) - OPTION_ENUM_END -OPTION_GUIDE_END - - - -void bml3_get_info(const imgtool_class *imgclass, UINT32 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_IMAGE_EXTRA_BYTES: info->i = sizeof(bml3_diskinfo); 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 --- */ - 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; - case IMGTOOLINFO_STR_EOLN: strcpy(info->s = imgtool_temp_str(), "\r"); break; - case IMGTOOLINFO_STR_WRITEFILE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), "T0-[2]-3;M0-[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_OPEN: info->open = bml3_diskimage_open; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = bml3_diskimage_nextenum; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = bml3_diskimage_freespace; break; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = bml3_diskimage_readfile; break; - case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = bml3_diskimage_writefile; break; - case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = bml3_diskimage_deletefile; break; - case IMGTOOLINFO_PTR_SUGGEST_TRANSFER: info->suggest_transfer = bml3_diskimage_suggesttransfer; break; - case IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE: info->writefile_optguide = bml3_writefile_optionguide; break; - case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_default; break; - } -} diff --git a/src/mess/tools/imgtool/modules/concept.c b/src/mess/tools/imgtool/modules/concept.c deleted file mode 100644 index a5c5a37b1ad..00000000000 --- a/src/mess/tools/imgtool/modules/concept.c +++ /dev/null @@ -1,492 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/* - Handlers for concept floppy images - - Disk images are in MESS format. - - Raphael Nabet, 2003 -*/ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <limits.h> -#include "imgtool.h" - -struct UINT16xE -{ - UINT8 bytes[2]; -}; - -/* - get_UINT16xE - - Read a 16-bit word, whether it is little-endian or big-endian - - little_endian (I): non-zero if word is little-endian, zero if word is - big-endian - word (I): pointer to word to read - - Returns value of word in native format -*/ -INLINE UINT16 get_UINT16xE(int little_endian, UINT16xE word) -{ - return little_endian ? (word.bytes[0] | (word.bytes[1] << 8)) : ((word.bytes[0] << 8) | word.bytes[1]); -} - -#if 0 -/* - set_UINT16xE - - Write a 16-bit word, whether it is little-endian or big-endian - - little_endian (I): non-zero if word is little-endian, zero if word is - big-endian - word (O): pointer to word to write - data (I): value to write in word, in native format -*/ -INLINE void set_UINT16xE(int little_endian, UINT16xE *word, UINT16 data) -{ - if (little_endian) - { - word->bytes[0] = data & 0xff; - word->bytes[1] = (data >> 8) & 0xff; - } - else - { - word->bytes[0] = (data >> 8) & 0xff; - word->bytes[1] = data & 0xff; - } -} -#endif - -/* - Disk structure: - - Track 0 Sector 0 & 1: bootstrap loader - Track 0 Sector 2 through 5: disk directory - Remaining sectors are used for data. -*/ - -/* - device directory record (Disk sector 2-5) -*/ - -struct concept_vol_hdr_entry -{ - UINT16xE first_block; - UINT16xE next_block; - UINT16xE ftype; - - unsigned char volname[8]; - UINT16xE last_block; - UINT16xE num_files; - UINT16xE last_boot; - UINT16xE last_access; - char mem_flipped; - char disk_flipped; - UINT16xE unused; -}; - -struct concept_file_dir_entry -{ - UINT16xE first_block; - UINT16xE next_block; - UINT16xE ftype; - - unsigned char filename[16]; - UINT16xE last_byte; - UINT16xE last_access; -}; - -struct concept_dev_dir -{ - concept_vol_hdr_entry vol_hdr; - concept_file_dir_entry file_dir[77]; - char unused[20]; -}; - -/* - concept disk image descriptor -*/ -struct concept_image -{ - imgtool_stream *file_handle; /* imgtool file handle */ - concept_dev_dir dev_dir; /* cached copy of device directory */ -}; - -/* - concept catalog iterator, used when imgtool reads the catalog -*/ -struct concept_iterator -{ - concept_image *image; - int index; /* current index */ -}; - - -static imgtoolerr_t concept_image_init(imgtool_image *img, imgtool_stream *f); -static void concept_image_exit(imgtool_image *img); -static void concept_image_info(imgtool_image *img, char *string, size_t len); -static imgtoolerr_t concept_image_beginenum(imgtool_directory *enumeration, const char *path); -static imgtoolerr_t concept_image_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent); -static void concept_image_closeenum(imgtool_directory *enumeration); -static imgtoolerr_t concept_image_freespace(imgtool_partition *partition, UINT64 *size); -static imgtoolerr_t concept_image_readfile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf); -#if 0 -static imgtoolerr_t concept_image_writefile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, option_resolution *writeoptions); -static imgtoolerr_t concept_image_deletefile(imgtool_partition *partition, const char *filename); -static imgtoolerr_t concept_image_create(const imgtool_module *mod, imgtool_stream *f, option_resolution *createoptions); -#endif - -void concept_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info) -{ - switch(state) - { - /* --- the following bits of info are returned as 64-bit signed integers --- */ - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: info->i = sizeof(concept_image); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(concept_iterator); break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "concept"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "Concept floppy disk image"); break; - case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "img"); 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_OPEN: info->open = concept_image_init; break; - case IMGTOOLINFO_PTR_CLOSE: info->close = concept_image_exit; break; - case IMGTOOLINFO_PTR_INFO: info->info = concept_image_info; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = concept_image_beginenum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = concept_image_nextenum; break; - case IMGTOOLINFO_PTR_CLOSE_ENUM: info->close_enum = concept_image_closeenum; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = concept_image_freespace; break; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = concept_image_readfile; break; - case IMGTOOLINFO_PTR_WRITE_FILE: /* info->write_file = concept_image_writefile */; break; - case IMGTOOLINFO_PTR_DELETE_FILE: /* info->delete_file = concept_image_deletefile */; break; - case IMGTOOLINFO_PTR_CREATE: /* info->create = concept_image_create */; break; - } -} - -/* - read_physical_record - - Read one 512-byte physical record from a disk image - - file_handle: imgtool file handle - secnum: physical record address - dest: pointer to destination buffer - - Return non-zero on error -*/ -static int read_physical_record(imgtool_stream *file_handle, int secnum, void *dest) -{ - int reply; - - /* seek to sector */ - reply = stream_seek(file_handle, secnum*512, SEEK_SET); - if (reply) - return 1; - /* read it */ - reply = stream_read(file_handle, dest, 512); - if (reply != 512) - return 1; - - return 0; -} - -#ifdef UNUSED_FUNCTION -/* - write_physical_record - - Write one 512-byte physical record to a disk image - - file_handle: imgtool file handle - secnum: logical sector address - src: pointer to source buffer - - Return non-zero on error -*/ -static int write_physical_record(imgtool_stream *file_handle, int secnum, const void *src) -{ - int reply; - - /* seek to sector */ - reply = stream_seek(file_handle, secnum*512, SEEK_SET); - if (reply) - return 1; - /* read it */ - reply = stream_write(file_handle, src, 512); - if (reply != 512) - return 1; - - return 0; -} -#endif - -/* - Search for a file name on a concept_image - - image (I): image reference - filename (I): name of the file to search - entry_index (O): index of file in disk catalog - - Return non-zero on error -*/ -static int get_catalog_entry(concept_image *image, const unsigned char *filename, int *entry_index) -{ - int filename_len = filename[0]; - int i; - - if (filename_len > 15) - /* file name is bad */ - return 1; - - for (i = 0; i < 77; i++) - { - if (!memcmp(filename, image->dev_dir.file_dir[i].filename, filename_len+1)) - { - /* file found */ - *entry_index = i; - return 0; - } - } - - /* file not found */ - return 1; -} - -/* - Open a file as a concept_image. -*/ -static imgtoolerr_t concept_image_init(imgtool_image *img, imgtool_stream *f) -{ - concept_image *image = (concept_image *) imgtool_image_extra_bytes(img); - int reply; - int i; - unsigned totphysrecs; - - image->file_handle = f; - - /* read device directory */ - for (i=0; i<4; i++) - { - reply = read_physical_record(f, i+2, ((char *) & image->dev_dir)+i*512); - if (reply) - return IMGTOOLERR_READERROR; - } - - /* do primitive checks */ - totphysrecs = get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.vol_hdr.last_block) - - get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.vol_hdr.first_block); - - if ((get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.vol_hdr.first_block) != 0) - || (get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.vol_hdr.next_block) != 6) - || (totphysrecs < 6) /*|| (stream_size(f) != totphysrecs*512)*/ - || (image->dev_dir.vol_hdr.volname[0] > 7)) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - - return IMGTOOLERR_SUCCESS; -} - -/* - close a concept_image -*/ -static void concept_image_exit(imgtool_image *img) -{ - /*concept_image *image = (concept_image *) imgtool_image_extra_bytes(img);*/ -} - -/* - get basic information on a concept_image - - Currently returns the volume name -*/ -static void concept_image_info(imgtool_image *img, char *string, size_t len) -{ - concept_image *image = (concept_image *) imgtool_image_extra_bytes(img); - char vol_name[8]; - - memcpy(vol_name, image->dev_dir.vol_hdr.volname + 1, image->dev_dir.vol_hdr.volname[0]); - vol_name[image->dev_dir.vol_hdr.volname[0]] = 0; - - snprintf(string, len, "%s", vol_name); -} - -/* - Open the disk catalog for enumeration -*/ -static imgtoolerr_t concept_image_beginenum(imgtool_directory *enumeration, const char *path) -{ - concept_iterator *iter; - - iter = (concept_iterator *) imgtool_directory_extrabytes(enumeration); - iter->image = (concept_image *) imgtool_image_extra_bytes(imgtool_directory_image(enumeration)); - iter->index = 0; - return IMGTOOLERR_SUCCESS; -} - -/* - Enumerate disk catalog next entry -*/ -static imgtoolerr_t concept_image_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent) -{ - concept_iterator *iter = (concept_iterator *) imgtool_directory_extrabytes(enumeration); - - - ent->corrupt = 0; - ent->eof = 0; - - if ((iter->image->dev_dir.file_dir[iter->index].filename[0] == 0) || (iter->index > 77)) - { - ent->eof = 1; - } - else if (iter->image->dev_dir.file_dir[iter->index].filename[0] > 15) - { - ent->corrupt = 1; - } - else - { - 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); - memcpy(ent->filename, iter->image->dev_dir.file_dir[iter->index].filename + 1, len); - ent->filename[len] = 0; - - /* parse flags */ - switch (get_UINT16xE(iter->image->dev_dir.vol_hdr.disk_flipped, iter->image->dev_dir.file_dir[iter->index].ftype) & 0xf) - { - case 0: - case 8: - type = "DIRHDR"; - break; - case 2: - type = "CODE"; - break; - case 3: - type = "TEXT"; - break; - case 5: - type = "DATA"; - break; - default: - type = "???"; - break; - } - snprintf(ent->attr, ARRAY_LENGTH(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) - - get_UINT16xE(iter->image->dev_dir.vol_hdr.disk_flipped, iter->image->dev_dir.file_dir[iter->index].first_block); - - iter->index++; - } - - return (imgtoolerr_t)0; -} - -/* - Free enumerator -*/ -static void concept_image_closeenum(imgtool_directory *enumeration) -{ -} - -/* - Compute free space on disk image -*/ -static imgtoolerr_t concept_image_freespace(imgtool_partition *partition, UINT64 *size) -{ - imgtool_image *img = imgtool_partition_image(partition); - concept_image *image = (concept_image*) img; - int free_blocks; - int i; - - /* first get number of data blocks */ - free_blocks = get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.vol_hdr.last_block) - - get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.vol_hdr.next_block); - - /* next substract length of each file */ - for (i=0; (image->dev_dir.file_dir[i].filename[0] != 0) && (i <= 77); i++) - { - free_blocks -= get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.file_dir[i].next_block) - - get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.file_dir[i].first_block); - } - - *size = free_blocks; - - return IMGTOOLERR_SUCCESS; -} - -/* - Extract a file from a concept_image. -*/ -static imgtoolerr_t concept_image_readfile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf) -{ - imgtool_image *img = imgtool_partition_image(partition); - concept_image *image = (concept_image *) imgtool_image_extra_bytes(img); - size_t filename_len = strlen(filename); - unsigned char concept_fname[16]; - int catalog_index; - int i; - UINT8 buf[512]; - - if (filename_len > 15) - return IMGTOOLERR_BADFILENAME; - - concept_fname[0] = filename_len; - memcpy(concept_fname+1, filename, filename_len); - - if (get_catalog_entry(image, concept_fname, &catalog_index)) - return IMGTOOLERR_FILENOTFOUND; - - for (i = get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.file_dir[catalog_index].first_block); - i < get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.file_dir[catalog_index].next_block); - i++) - { - if (read_physical_record(image->file_handle, i, buf)) - return IMGTOOLERR_READERROR; - - if (stream_write(destf, buf, 512) != 512) - return IMGTOOLERR_WRITEERROR; - } - - return (imgtoolerr_t)0; -} - -#if 0 -/* - Add a file to a concept_image. -*/ -static imgtoolerr_t concept_image_writefile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, option_resolution *writeoptions) -{ - /* ... */ - - return 0; -} - -/* - Delete a file from a concept_image. -*/ -static imgtoolerr_t concept_image_deletefile(imgtool_partition *partition, const char *filename) -{ - /* ... */ - - return 0; -} - -/* - Create a blank concept_image. -*/ -static imgtoolerr_t concept_image_create(const imgtool_module *mod, imgtool_stream *f, option_resolution *createoptions) -{ - /* ... */ - - return 0; -} -#endif diff --git a/src/mess/tools/imgtool/modules/cybiko.c b/src/mess/tools/imgtool/modules/cybiko.c deleted file mode 100644 index 1fc2afd319b..00000000000 --- a/src/mess/tools/imgtool/modules/cybiko.c +++ /dev/null @@ -1,578 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tim Schuerewegen -/* - - Cybiko Classic File System - - (c) 2007 Tim Schuerewegen - -*/ - -#include "imgtool.h" - -#include <zlib.h> - -struct cybiko_file_system -{ - imgtool_stream *stream; - UINT32 page_count, page_size, block_count_boot, block_count_file; - UINT16 write_count; -}; - -struct cybiko_iter -{ - UINT16 block; -}; - -struct cfs_file -{ - char name[64]; // name of the file - UINT32 date; // date/time of the file (seconds since 1900/01/01) - UINT32 size; // size of the file - UINT32 blocks; // number of blocks occupied by the file -}; - -enum -{ - BLOCK_TYPE_INVALID, - BLOCK_TYPE_BOOT, - BLOCK_TYPE_FILE -}; - -#define MAX_PAGE_SIZE (264 * 2) - -#define INVALID_FILE_ID 0xFFFF - -enum -{ - FLASH_TYPE_INVALID, - FLASH_TYPE_AT45DB041, - FLASH_TYPE_AT45DB081, - FLASH_TYPE_AT45DB161 -}; - -#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_FILENAME(x) (char*)(x + 7) - -#define FILE_HEADER_SIZE 0x48 - -// 2208988800 is the number of seconds between 1900/01/01 and 1970/01/01 - -static time_t time_crack( UINT32 cfs_time) -{ - return (time_t)(cfs_time - 2208988800UL); -} - -static UINT32 time_setup( time_t ansi_time) -{ - return (UINT32)(ansi_time + 2208988800UL); -} - -static UINT32 buffer_read_32_be( UINT8 *buffer) -{ - return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3] << 0); -} - -static UINT16 buffer_read_16_be( UINT8 *buffer) -{ - return (buffer[0] << 8) | (buffer[1] << 0); -} - -static void buffer_write_32_be( UINT8 *buffer, UINT32 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 *buffer, UINT16 data) -{ - buffer[0] = (data >> 8) & 0xFF; - buffer[1] = (data >> 0) & 0xFF; -} - -// page = crc1 (4) + wcnt (2) + crc2 (2) + data (x) + unk (2) - -static UINT32 page_buffer_calc_checksum_1( UINT8 *buffer, UINT32 size, int block_type) -{ - return crc32( 0, buffer + 8, (block_type == BLOCK_TYPE_BOOT) ? 250 : size - 10); -} - -static UINT16 page_buffer_calc_checksum_2( UINT8 *buffer) -{ - UINT16 val = 0xAF17; - val ^= buffer_read_16_be( buffer + 0); - val ^= buffer_read_16_be( buffer + 2); - val ^= buffer_read_16_be( buffer + 4); - return FLIPENDIAN_INT16(val); -} - -static int page_buffer_verify( UINT8 *buffer, UINT32 size, int block_type) -{ - UINT32 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); - 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); - if (checksum_calc != checksum_page) return FALSE; - // ok - return TRUE; -} - -static int cfs_block_to_page( cybiko_file_system *cfs, int block_type, UINT32 block, UINT32 *page) -{ - switch (block_type) - { - case BLOCK_TYPE_BOOT : if (page) *page = block; return TRUE; - case BLOCK_TYPE_FILE : if (page) *page = block + cfs->block_count_boot; return TRUE; - default : return FALSE; - } -} - -static int cfs_page_to_block( cybiko_file_system *cfs, UINT32 page, int *block_type, UINT32 *block) -{ - UINT32 tmp = page; - // boot block - if (tmp < cfs->block_count_boot) - { - if (block_type) *block_type = BLOCK_TYPE_BOOT; - if (block) *block = tmp; - return TRUE; - } - tmp -= cfs->block_count_boot; - // file block - if (tmp < cfs->block_count_file) - { - if (block_type) *block_type = BLOCK_TYPE_FILE; - if (block) *block = tmp; - return TRUE; - } - tmp -= cfs->block_count_file; - // error - return FALSE; -} - -static int cfs_page_read( cybiko_file_system *cfs, UINT8 *buffer, UINT32 page) -{ - if (page >= cfs->page_count) return FALSE; - stream_seek( cfs->stream, page * cfs->page_size, SEEK_SET); - stream_read( cfs->stream, buffer, cfs->page_size); - return TRUE; -} - -static int cfs_page_write( cybiko_file_system *cfs, UINT8 *buffer, UINT32 page) -{ - if (page >= cfs->page_count) return FALSE; - stream_seek( cfs->stream, page * cfs->page_size, SEEK_SET); - stream_write( cfs->stream, buffer, cfs->page_size); - return TRUE; -} - -static int cfs_block_read( cybiko_file_system *cfs, UINT8 *buffer, int block_type, UINT32 block) -{ - UINT8 buffer_page[MAX_PAGE_SIZE]; - UINT32 page; - if (!cfs_block_to_page( cfs, block_type, block, &page)) return FALSE; - if (!cfs_page_read( cfs, buffer_page, page)) return FALSE; - memcpy( buffer, buffer_page + 8, cfs->page_size - 10); - return TRUE; -} - -static int cfs_block_write( cybiko_file_system *cfs, UINT8 *buffer, int block_type, UINT32 block) -{ - UINT8 buffer_page[MAX_PAGE_SIZE]; - UINT32 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); - if (!cfs_block_to_page( cfs, block_type, block, &page)) return FALSE; - if (!cfs_page_write( cfs, buffer_page, page)) return FALSE; - return TRUE; -} - -static int cfs_file_delete( cybiko_file_system *cfs, UINT16 file_id) -{ - UINT8 buffer[MAX_PAGE_SIZE]; - int i; - for (i=0;i<cfs->block_count_file;i++) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return FALSE; - if (BLOCK_USED(buffer) && (BLOCK_FILE_ID(buffer) == file_id)) - { - buffer[0] &= ~0x80; - if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_FILE, i)) return FALSE; - } - } - return TRUE; -} - -static int cfs_file_info( cybiko_file_system *cfs, UINT16 file_id, cfs_file *file) -{ - UINT8 buffer[MAX_PAGE_SIZE]; - int i; - file->blocks = file->size = 0; - for (i=0;i<cfs->block_count_file;i++) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return FALSE; - if (BLOCK_USED(buffer) && (BLOCK_FILE_ID(buffer) == file_id)) - { - 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->size += buffer[1]; - file->blocks++; - } - } - return (file->blocks > 0) ? TRUE : FALSE; -} - -static int cfs_file_find( cybiko_file_system *cfs, const char *filename, UINT16 *file_id) -{ - UINT8 buffer[MAX_PAGE_SIZE]; - int i; - for (i=0;i<cfs->block_count_file;i++) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return FALSE; - if (BLOCK_USED(buffer) && (strncmp( filename, BLOCK_FILENAME(buffer), 40) == 0)) - { - *file_id = i; - return TRUE; - } - } - return FALSE; -} - -static int cfs_verify( cybiko_file_system *cfs) -{ - UINT8 buffer[MAX_PAGE_SIZE]; - int i, block_type; - for (i=0;i<cfs->page_count;i++) - { - if (!cfs_page_read( cfs, buffer, i)) return FALSE; - if (!cfs_page_to_block( cfs, i, &block_type, NULL)) return FALSE; - if (!page_buffer_verify( buffer, cfs->page_size, block_type)) return FALSE; - } - return TRUE; -} - -static int cfs_init( cybiko_file_system *cfs, imgtool_stream *stream, int flash_type) -{ - cfs->stream = stream; - switch (flash_type) - { - case FLASH_TYPE_AT45DB041 : cfs->page_count = 2048; cfs->page_size = 264; break; - case FLASH_TYPE_AT45DB081 : cfs->page_count = 4096; cfs->page_size = 264; break; - case FLASH_TYPE_AT45DB161 : cfs->page_count = 4096; cfs->page_size = 528; break; - default : return FALSE; - } - cfs->block_count_boot = 5; - cfs->block_count_file = cfs->page_count - cfs->block_count_boot; - cfs->write_count = 0; - return TRUE; -} - -static int cfs_format( cybiko_file_system *cfs) -{ - UINT8 buffer[MAX_PAGE_SIZE]; - int i; - // boot blocks - memset( buffer, 0xFF, sizeof( buffer)); - for (i=0;i<cfs->block_count_boot;i++) - { - if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_BOOT, i)) return FALSE; - } - // file blocks - memset( buffer, 0xFF, sizeof( buffer)); - buffer[0] &= ~0x80; - for (i=0;i<cfs->block_count_file;i++) - { - if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_FILE, i)) return FALSE; - } - // ok - return TRUE; -} - -static UINT16 cfs_calc_free_blocks( cybiko_file_system *cfs) -{ - UINT8 buffer[MAX_PAGE_SIZE]; - int i; - UINT16 blocks = 0; - for (i=0;i<cfs->block_count_file;i++) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return 0; - if (!BLOCK_USED(buffer)) blocks++; - } - return blocks; -} - -static UINT32 cfs_calc_free_space( cybiko_file_system *cfs, UINT16 blocks) -{ - UINT32 free_space; - free_space = blocks * (cfs->page_size - 0x10); - if (free_space > 0) free_space -= FILE_HEADER_SIZE; - return free_space; -} - -static int flash_size_to_flash_type( size_t size) -{ - switch (size) - { - case 0x084000 : return FLASH_TYPE_AT45DB041; - case 0x108000 : return FLASH_TYPE_AT45DB081; - case 0x210000 : return FLASH_TYPE_AT45DB161; - default : return FLASH_TYPE_INVALID; - } -} - -static int flash_option_to_flash_type( int option) -{ - switch (option) - { - case 0 : return FLASH_TYPE_AT45DB041; - case 1 : return FLASH_TYPE_AT45DB081; - case 2 : return FLASH_TYPE_AT45DB161; - default : return FLASH_TYPE_INVALID; - } -} - -static imgtoolerr_t cybiko_image_open( imgtool_image *image, imgtool_stream *stream) -{ - cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image); - int flash_type; - // init - flash_type = flash_size_to_flash_type( stream_size( stream)); - if (!cfs_init( cfs, stream, flash_type)) return IMGTOOLERR_CORRUPTIMAGE; - // verify - if (!cfs_verify( cfs)) return IMGTOOLERR_CORRUPTIMAGE; - // ok - return IMGTOOLERR_SUCCESS; -} - -static void cybiko_image_close( imgtool_image *image) -{ - cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image); - stream_close( cfs->stream); -} - -static imgtoolerr_t cybiko_image_create( imgtool_image *image, imgtool_stream *stream, option_resolution *opts) -{ - cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image); - int flash_type; - // init - flash_type = flash_option_to_flash_type( option_resolution_lookup_int( opts, 'F')); - if (!cfs_init( cfs, stream, flash_type)) return IMGTOOLERR_CORRUPTIMAGE; - // format - if (!cfs_format( cfs)) return IMGTOOLERR_CORRUPTIMAGE; - // ok - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_begin_enum( imgtool_directory *enumeration, const char *path) -{ - cybiko_iter *iter = (cybiko_iter*)imgtool_directory_extrabytes( enumeration); - iter->block = 0; - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_next_enum( imgtool_directory *enumeration, imgtool_dirent *ent) -{ - imgtool_image *image = imgtool_directory_image( enumeration); - cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image); - cybiko_iter *iter = (cybiko_iter*)imgtool_directory_extrabytes( enumeration); - UINT8 buffer[MAX_PAGE_SIZE]; - UINT16 file_id = INVALID_FILE_ID; - cfs_file file; - // find next file - while (iter->block < cfs->block_count_file) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, iter->block++)) return IMGTOOLERR_READERROR; - if (BLOCK_USED(buffer) && (BLOCK_PART_ID(buffer) == 0)) - { - file_id = BLOCK_FILE_ID(buffer); - break; - } - } - // get file information - if ((file_id != INVALID_FILE_ID) && cfs_file_info( cfs, file_id, &file)) - { - strcpy( ent->filename, file.name); - ent->filesize = file.size; - ent->lastmodified_time = time_crack( file.date); - ent->filesize = file.size; - } - else - { - ent->eof = 1; - } - // ok - return IMGTOOLERR_SUCCESS; -} - -static void cybiko_image_close_enum( imgtool_directory *enumeration) -{ - // nothing -} - -static imgtoolerr_t cybiko_image_free_space( imgtool_partition *partition, UINT64 *size) -{ - imgtool_image *image = imgtool_partition_image( partition); - cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image); - if (size) *size = cfs_calc_free_space( cfs, cfs_calc_free_blocks( cfs)); - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_read_file( imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf) -{ - imgtool_image *image = imgtool_partition_image( partition); - cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image); - UINT8 buffer[MAX_PAGE_SIZE]; - UINT16 file_id, part_id = 0, old_part_id; - int i; - // find file - if (!cfs_file_find( cfs, filename, &file_id)) return IMGTOOLERR_FILENOTFOUND; - // read file - do - { - old_part_id = part_id; - for (i=0;i<cfs->block_count_file;i++) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return IMGTOOLERR_READERROR; - if (BLOCK_USED(buffer) && (BLOCK_FILE_ID(buffer) == file_id) && (BLOCK_PART_ID(buffer) == part_id)) - { - stream_write( destf, buffer + 6 + ((part_id == 0) ? FILE_HEADER_SIZE : 0), buffer[1]); - part_id++; - } - } - } while (old_part_id != part_id); - // ok - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_write_file( imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, option_resolution *opts) -{ - imgtool_image *image = imgtool_partition_image( partition); - cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image); - UINT8 buffer[MAX_PAGE_SIZE]; - UINT16 file_id, part_id = 0, free_blocks; - UINT64 bytes_left; - cfs_file file; - int i; - // find file - if (!cfs_file_find( cfs, filename, &file_id)) file_id = INVALID_FILE_ID; - // check free space - free_blocks = cfs_calc_free_blocks( cfs); - if (file_id != INVALID_FILE_ID) - { - if (!cfs_file_info( cfs, file_id, &file)) return IMGTOOLERR_UNEXPECTED; - free_blocks += file.blocks; - } - if (cfs_calc_free_space( cfs, free_blocks) < stream_size( sourcef)) return IMGTOOLERR_NOSPACE; - // delete file - if (file_id != INVALID_FILE_ID) - { - if (!cfs_file_delete( cfs, file_id)) return IMGTOOLERR_UNEXPECTED; - } - // create/write destination file - bytes_left = stream_size( sourcef); - i = 0; - while ((bytes_left > 0) && (i < cfs->block_count_file)) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return IMGTOOLERR_READERROR; - if (!BLOCK_USED(buffer)) - { - if (part_id == 0) file_id = i; - memset( buffer, 0xFF, cfs->page_size - 0x10); - 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); - if (part_id == 0) - { - buffer[6] = 0; - strcpy( BLOCK_FILENAME(buffer), filename); - buffer_write_32_be( buffer + 6 + FILE_HEADER_SIZE - 4, time_setup( time( NULL))); - stream_read( sourcef, buffer + 6 + FILE_HEADER_SIZE, buffer[1]); - } - else - { - stream_read( sourcef, buffer + 6, buffer[1]); - } - if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_FILE, i)) return IMGTOOLERR_WRITEERROR; - bytes_left -= buffer[1]; - part_id++; - } - i++; - } - // ok - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_delete_file( imgtool_partition *partition, const char *filename) -{ - imgtool_image *image = imgtool_partition_image( partition); - cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image); - UINT16 file_id; - // find file - if (!cfs_file_find( cfs, filename, &file_id)) return IMGTOOLERR_FILENOTFOUND; - // delete file - if (!cfs_file_delete( cfs, file_id)) return IMGTOOLERR_UNEXPECTED; - // ok - return IMGTOOLERR_SUCCESS; -} - -static OPTION_GUIDE_START( cybiko_image_createimage_optguide ) - OPTION_ENUM_START( 'F', "flash", "Flash Type" ) - OPTION_ENUM( 0, "AT45DB041", "AT45DB041 (528 KByte)" ) - OPTION_ENUM( 1, "AT45DB081", "AT45DB081 (1056 KByte)" ) - OPTION_ENUM( 2, "AT45DB161", "AT45DB161 (2112 KByte)" ) - OPTION_ENUM_END -OPTION_GUIDE_END - -//OPTION_GUIDE_START( cybiko_image_writefile_optguide ) -// OPTION_INT( 'B', "boot", "Boot Flag" ) -//OPTION_GUIDE_END - -void cybiko_get_info( const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info) -{ - switch (state) - { - // --- the following bits of info are returned as 64-bit signed integers --- - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES : info->i = sizeof( cybiko_file_system); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES : info->i = sizeof( cybiko_iter); break; -// case IMGTOOLINFO_INT_SUPPORTS_CREATION_TIME : info->i = 1; break; - case IMGTOOLINFO_INT_SUPPORTS_LASTMODIFIED_TIME : info->i = 1; break; -// case IMGTOOLINFO_INT_BLOCK_SIZE : info->i = 264; break; - // --- the following bits of info are returned as pointers to data or functions --- - case IMGTOOLINFO_PTR_OPEN : info->open = cybiko_image_open; break; - case IMGTOOLINFO_PTR_CREATE : info->create = cybiko_image_create; break; - case IMGTOOLINFO_PTR_CLOSE : info->close = cybiko_image_close; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM : info->begin_enum = cybiko_image_begin_enum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM : info->next_enum = cybiko_image_next_enum; break; - case IMGTOOLINFO_PTR_CLOSE_ENUM : info->close_enum = cybiko_image_close_enum; break; - case IMGTOOLINFO_PTR_FREE_SPACE : info->free_space = cybiko_image_free_space; break; - case IMGTOOLINFO_PTR_READ_FILE : info->read_file = cybiko_image_read_file; break; - case IMGTOOLINFO_PTR_WRITE_FILE : info->write_file = cybiko_image_write_file; break; - case IMGTOOLINFO_PTR_DELETE_FILE : info->delete_file = cybiko_image_delete_file; break; - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE : info->createimage_optguide = cybiko_image_createimage_optguide; break; -// case IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE : info->writefile_optguide = cybiko_image_writefile_optguide; break; - // --- the following bits of info are returned as NULL-terminated strings --- - case IMGTOOLINFO_STR_NAME : strcpy( info->s = imgtool_temp_str(), "cybiko"); break; - case IMGTOOLINFO_STR_DESCRIPTION : strcpy( info->s = imgtool_temp_str(), "Cybiko Classic File System"); break; - case IMGTOOLINFO_STR_FILE : strcpy( info->s = imgtool_temp_str(), __FILE__); break; - case IMGTOOLINFO_STR_FILE_EXTENSIONS : strcpy( info->s = imgtool_temp_str(), "bin,nv"); break; - case IMGTOOLINFO_STR_EOLN : strcpy( info->s = imgtool_temp_str(), "\r\n"); break; - case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC : strcpy( info->s = imgtool_temp_str(), "F[0]-2"); break; -// case IMGTOOLINFO_STR_WRITEFILE_OPTSPEC : strcpy( info->s = imgtool_temp_str(), "B[0]-1"); break; - } -} diff --git a/src/mess/tools/imgtool/modules/cybikoxt.c b/src/mess/tools/imgtool/modules/cybikoxt.c deleted file mode 100644 index a1908dc9c76..00000000000 --- a/src/mess/tools/imgtool/modules/cybikoxt.c +++ /dev/null @@ -1,539 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tim Schuerewegen -/* - - Cybiko Xtreme File System - - (c) 2010 Tim Schuerewegen - -*/ - -#include "imgtool.h" - -#include <zlib.h> - -struct cybiko_file_system -{ - imgtool_stream *stream; - UINT32 page_count, page_size, block_count_boot, block_count_file; - UINT16 write_count; -}; - -struct cybiko_iter -{ - UINT16 block; -}; - -struct cfs_file -{ - char name[64]; // name of the file - UINT32 date; // date/time of the file (seconds since 1900/01/01) - UINT32 size; // size of the file - UINT32 blocks; // number of blocks occupied by the file -}; - -enum -{ - BLOCK_TYPE_INVALID, - BLOCK_TYPE_BOOT, - BLOCK_TYPE_FILE -}; - -#define MAX_PAGE_SIZE (264 * 2) - -#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_FILENAME(x) (char*)(x + 7) - -#define FILE_HEADER_SIZE 0x48 - -// 2208988800 is the number of seconds between 1900/01/01 and 1970/01/01 - -static time_t time_crack( UINT32 cfs_time) -{ - return (time_t)(cfs_time - 2208988800UL); -} - -static UINT32 time_setup( time_t ansi_time) -{ - return (UINT32)(ansi_time + 2208988800UL); -} - -static UINT32 buffer_read_32_be( UINT8 *buffer) -{ - return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3] << 0); -} - -static UINT16 buffer_read_16_be( UINT8 *buffer) -{ - return (buffer[0] << 8) | (buffer[1] << 0); -} - -static void buffer_write_32_be( UINT8 *buffer, UINT32 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 *buffer, UINT16 data) -{ - buffer[0] = (data >> 8) & 0xFF; - buffer[1] = (data >> 0) & 0xFF; -} - -// page = crc (2) + data (x) - -static UINT16 page_buffer_calc_checksum( UINT8 *data, UINT32 size) -{ - int i; - UINT32 val = 0; - for (i = 0; i < size; i++) - { - val = (val ^ data[i] ^ i) << 1; - val = val | ((val >> 16) & 0x0001); - } - return val; -} - -static int page_buffer_verify( UINT8 *buffer, UINT32 size, int block_type) -{ - // checksum - if (block_type == BLOCK_TYPE_FILE) - { - UINT32 checksum_page, checksum_calc; - checksum_calc = page_buffer_calc_checksum( buffer + 2, size - 2); - checksum_page = buffer_read_16_be( buffer + 0); - if (checksum_calc != checksum_page) return FALSE; - } - // ok - return TRUE; -} - -static int cfs_block_to_page( cybiko_file_system *cfs, int block_type, UINT32 block, UINT32 *page) -{ - switch (block_type) - { - case BLOCK_TYPE_BOOT : if (page) *page = block; return TRUE; - case BLOCK_TYPE_FILE : if (page) *page = block + cfs->block_count_boot; return TRUE; - default : return FALSE; - } -} - -static int cfs_page_to_block( cybiko_file_system *cfs, UINT32 page, int *block_type, UINT32 *block) -{ - UINT32 tmp = page; - // boot block - if (tmp < cfs->block_count_boot) - { - if (block_type) *block_type = BLOCK_TYPE_BOOT; - if (block) *block = tmp; - return TRUE; - } - tmp -= cfs->block_count_boot; - // file block - if (tmp < cfs->block_count_file) - { - if (block_type) *block_type = BLOCK_TYPE_FILE; - if (block) *block = tmp; - return TRUE; - } - tmp -= cfs->block_count_file; - // error - return FALSE; -} - -static int cfs_page_read( cybiko_file_system *cfs, UINT8 *buffer, UINT32 page) -{ - if (page >= cfs->page_count) return FALSE; - stream_seek( cfs->stream, page * cfs->page_size, SEEK_SET); - stream_read( cfs->stream, buffer, cfs->page_size); - return TRUE; -} - -static int cfs_page_write( cybiko_file_system *cfs, UINT8 *buffer, UINT32 page) -{ - if (page >= cfs->page_count) return FALSE; - stream_seek( cfs->stream, page * cfs->page_size, SEEK_SET); - stream_write( cfs->stream, buffer, cfs->page_size); - return TRUE; -} - -static int cfs_block_read( cybiko_file_system *cfs, UINT8 *buffer, int block_type, UINT32 block) -{ - UINT8 buffer_page[MAX_PAGE_SIZE]; - UINT32 page; - if (!cfs_block_to_page( cfs, block_type, block, &page)) return FALSE; - if (!cfs_page_read( cfs, buffer_page, page)) return FALSE; - memcpy( buffer, buffer_page + 2, cfs->page_size - 2); - return TRUE; -} - -static int cfs_block_write( cybiko_file_system *cfs, UINT8 *buffer, int block_type, UINT32 block) -{ - UINT8 buffer_page[MAX_PAGE_SIZE]; - UINT32 page; - UINT16 checksum; - memcpy( buffer_page + 2, buffer, cfs->page_size - 2); - if (block_type == BLOCK_TYPE_BOOT) - { - checksum = 0xFFFF; - } - else - { - checksum = page_buffer_calc_checksum( buffer_page + 2, cfs->page_size - 2); - } - buffer_write_16_be( 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; -} - -static int cfs_file_delete( cybiko_file_system *cfs, UINT16 file_id) -{ - UINT8 buffer[MAX_PAGE_SIZE]; - int i; - for (i=0;i<cfs->block_count_file;i++) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return FALSE; - if (BLOCK_USED(buffer) && (BLOCK_FILE_ID(buffer) == file_id)) - { - buffer[0] &= ~0x80; - if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_FILE, i)) return FALSE; - } - } - return TRUE; -} - -static int cfs_file_info( cybiko_file_system *cfs, UINT16 file_id, cfs_file *file) -{ - UINT8 buffer[MAX_PAGE_SIZE]; - int i; - file->blocks = file->size = 0; - for (i=0;i<cfs->block_count_file;i++) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return FALSE; - if (BLOCK_USED(buffer) && (BLOCK_FILE_ID(buffer) == file_id)) - { - 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->size += buffer[1]; - file->blocks++; - } - } - return (file->blocks > 0) ? TRUE : FALSE; -} - -static int cfs_file_find( cybiko_file_system *cfs, const char *filename, UINT16 *file_id) -{ - UINT8 buffer[MAX_PAGE_SIZE]; - int i; - for (i=0;i<cfs->block_count_file;i++) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return FALSE; - if (BLOCK_USED(buffer) && (BLOCK_PART_ID(buffer) == 0) && (strcmp( filename, BLOCK_FILENAME(buffer)) == 0)) - { - *file_id = i; - return TRUE; - } - } - return FALSE; -} - -static int cfs_verify( cybiko_file_system *cfs) -{ - UINT8 buffer[MAX_PAGE_SIZE]; - int i, block_type; - for (i=0;i<cfs->page_count;i++) - { - if (!cfs_page_read( cfs, buffer, i)) return FALSE; - if (!cfs_page_to_block( cfs, i, &block_type, NULL)) return FALSE; - if (!page_buffer_verify( buffer, cfs->page_size, block_type)) return FALSE; - } - return TRUE; -} - -static int cfs_init( cybiko_file_system *cfs, imgtool_stream *stream) -{ - cfs->stream = stream; - cfs->page_count = 2005; - cfs->page_size = 258; - cfs->block_count_boot = 5; - cfs->block_count_file = cfs->page_count - cfs->block_count_boot; - cfs->write_count = 0; - return TRUE; -} - -static int cfs_format( cybiko_file_system *cfs) -{ - UINT8 buffer[MAX_PAGE_SIZE]; - int i; - // boot blocks - memset( buffer, 0xFF, sizeof( buffer)); - for (i=0;i<cfs->block_count_boot;i++) - { - if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_BOOT, i)) return FALSE; - } - // file blocks - memset( buffer, 0xFF, sizeof( buffer)); - buffer[0] &= ~0x80; - for (i=0;i<cfs->block_count_file;i++) - { - if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_FILE, i)) return FALSE; - } - // padding - buffer[0] = 0xFF; - for (i=0;i<0x1B56;i++) - { - stream_write( cfs->stream, buffer, 1); - } - // ok - return TRUE; -} - -static UINT16 cfs_calc_free_blocks( cybiko_file_system *cfs) -{ - UINT8 buffer[MAX_PAGE_SIZE]; - int i; - UINT16 blocks = 0; - for (i=0;i<cfs->block_count_file;i++) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return 0; - if (!BLOCK_USED(buffer)) blocks++; - } - return blocks; -} - -static UINT32 cfs_calc_free_space( cybiko_file_system *cfs, UINT16 blocks) -{ - UINT32 free_space; - free_space = blocks * ((cfs->page_size - 2) - 6); - if (free_space > 0) free_space -= FILE_HEADER_SIZE; - return free_space; -} - -static imgtoolerr_t cybiko_image_open( imgtool_image *image, imgtool_stream *stream) -{ - cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image); - // init - if (!cfs_init( cfs, stream)) return IMGTOOLERR_CORRUPTIMAGE; - // verify - if (!cfs_verify( cfs)) return IMGTOOLERR_CORRUPTIMAGE; - // ok - return IMGTOOLERR_SUCCESS; -} - -static void cybiko_image_close( imgtool_image *image) -{ - cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image); - stream_close( cfs->stream); -} - -static imgtoolerr_t cybiko_image_create( imgtool_image *image, imgtool_stream *stream, option_resolution *opts) -{ - cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image); - // init - if (!cfs_init( cfs, stream)) return IMGTOOLERR_CORRUPTIMAGE; - // format - if (!cfs_format( cfs)) return IMGTOOLERR_CORRUPTIMAGE; - // ok - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_begin_enum( imgtool_directory *enumeration, const char *path) -{ - cybiko_iter *iter = (cybiko_iter*)imgtool_directory_extrabytes( enumeration); - iter->block = 0; - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_next_enum( imgtool_directory *enumeration, imgtool_dirent *ent) -{ - imgtool_image *image = imgtool_directory_image( enumeration); - cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image); - cybiko_iter *iter = (cybiko_iter*)imgtool_directory_extrabytes( enumeration); - UINT8 buffer[MAX_PAGE_SIZE]; - UINT16 file_id = INVALID_FILE_ID; - cfs_file file; - // find next file - while (iter->block < cfs->block_count_file) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, iter->block++)) return IMGTOOLERR_READERROR; - if (BLOCK_USED(buffer) && (BLOCK_PART_ID(buffer) == 0)) - { - file_id = BLOCK_FILE_ID(buffer); - break; - } - } - // get file information - if ((file_id != INVALID_FILE_ID) && cfs_file_info( cfs, file_id, &file)) - { - strcpy( ent->filename, file.name); - ent->filesize = file.size; - ent->lastmodified_time = time_crack( file.date); - ent->filesize = file.size; - } - else - { - ent->eof = 1; - } - // ok - return IMGTOOLERR_SUCCESS; -} - -static void cybiko_image_close_enum( imgtool_directory *enumeration) -{ - // nothing -} - -static imgtoolerr_t cybiko_image_free_space( imgtool_partition *partition, UINT64 *size) -{ - imgtool_image *image = imgtool_partition_image( partition); - cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image); - if (size) *size = cfs_calc_free_space( cfs, cfs_calc_free_blocks( cfs)); - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_read_file( imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf) -{ - imgtool_image *image = imgtool_partition_image( partition); - cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image); - UINT8 buffer[MAX_PAGE_SIZE]; - UINT16 file_id, part_id = 0, old_part_id; - int i; - // check filename - if (strlen( filename) > 58) return IMGTOOLERR_BADFILENAME; - // find file - if (!cfs_file_find( cfs, filename, &file_id)) return IMGTOOLERR_FILENOTFOUND; - // read file - do - { - old_part_id = part_id; - for (i=0;i<cfs->block_count_file;i++) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return IMGTOOLERR_READERROR; - if (BLOCK_USED(buffer) && (BLOCK_FILE_ID(buffer) == file_id) && (BLOCK_PART_ID(buffer) == part_id)) - { - stream_write( destf, buffer + 6 + ((part_id == 0) ? FILE_HEADER_SIZE : 0), buffer[1]); - part_id++; - } - } - } while (old_part_id != part_id); - // ok - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_write_file( imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, option_resolution *opts) -{ - imgtool_image *image = imgtool_partition_image( partition); - cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image); - UINT8 buffer[MAX_PAGE_SIZE]; - UINT16 file_id, part_id = 0, free_blocks; - UINT64 bytes_left; - cfs_file file; - int i; - // check filename - if (strlen( filename) > 58) return IMGTOOLERR_BADFILENAME; - // find file - if (!cfs_file_find( cfs, filename, &file_id)) file_id = INVALID_FILE_ID; - // check free space - free_blocks = cfs_calc_free_blocks( cfs); - if (file_id != INVALID_FILE_ID) - { - if (!cfs_file_info( cfs, file_id, &file)) return IMGTOOLERR_UNEXPECTED; - free_blocks += file.blocks; - } - if (cfs_calc_free_space( cfs, free_blocks) < stream_size( sourcef)) return IMGTOOLERR_NOSPACE; - // delete file - if (file_id != INVALID_FILE_ID) - { - if (!cfs_file_delete( cfs, file_id)) return IMGTOOLERR_UNEXPECTED; - } - // create/write destination file - bytes_left = stream_size( sourcef); - i = 0; - while (i < cfs->block_count_file) - { - if (!cfs_block_read( cfs, buffer, BLOCK_TYPE_FILE, i)) return IMGTOOLERR_READERROR; - if (!BLOCK_USED(buffer)) - { - if (part_id == 0) file_id = i; - memset( buffer, 0xFF, cfs->page_size - 0x02); - 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); - if (part_id == 0) - { - buffer[6] = 0x20; - strcpy( BLOCK_FILENAME(buffer), filename); - buffer_write_32_be( buffer + 6 + FILE_HEADER_SIZE - 4, time_setup( time( NULL))); - stream_read( sourcef, buffer + 6 + FILE_HEADER_SIZE, buffer[1]); - } - else - { - stream_read( sourcef, buffer + 6, buffer[1]); - } - if (!cfs_block_write( cfs, buffer, BLOCK_TYPE_FILE, i)) return IMGTOOLERR_WRITEERROR; - bytes_left -= buffer[1]; - if (bytes_left == 0) break; - part_id++; - } - i++; - } - // ok - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t cybiko_image_delete_file( imgtool_partition *partition, const char *filename) -{ - imgtool_image *image = imgtool_partition_image( partition); - cybiko_file_system *cfs = (cybiko_file_system*)imgtool_image_extra_bytes( image); - UINT16 file_id; - // check filename - if (strlen( filename) > 58) return IMGTOOLERR_BADFILENAME; - // find file - if (!cfs_file_find( cfs, filename, &file_id)) return IMGTOOLERR_FILENOTFOUND; - // delete file - if (!cfs_file_delete( cfs, file_id)) return IMGTOOLERR_UNEXPECTED; - // ok - return IMGTOOLERR_SUCCESS; -} - -void cybikoxt_get_info( const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info) -{ - switch (state) - { - // --- the following bits of info are returned as 64-bit signed integers --- - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES : info->i = sizeof( cybiko_file_system); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES : info->i = sizeof( cybiko_iter); break; -// case IMGTOOLINFO_INT_SUPPORTS_CREATION_TIME : info->i = 1; break; - case IMGTOOLINFO_INT_SUPPORTS_LASTMODIFIED_TIME : info->i = 1; break; -// case IMGTOOLINFO_INT_BLOCK_SIZE : info->i = 264; break; - // --- the following bits of info are returned as pointers to data or functions --- - case IMGTOOLINFO_PTR_OPEN : info->open = cybiko_image_open; break; - case IMGTOOLINFO_PTR_CREATE : info->create = cybiko_image_create; break; - case IMGTOOLINFO_PTR_CLOSE : info->close = cybiko_image_close; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM : info->begin_enum = cybiko_image_begin_enum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM : info->next_enum = cybiko_image_next_enum; break; - case IMGTOOLINFO_PTR_CLOSE_ENUM : info->close_enum = cybiko_image_close_enum; break; - case IMGTOOLINFO_PTR_FREE_SPACE : info->free_space = cybiko_image_free_space; break; - case IMGTOOLINFO_PTR_READ_FILE : info->read_file = cybiko_image_read_file; break; - case IMGTOOLINFO_PTR_WRITE_FILE : info->write_file = cybiko_image_write_file; break; - case IMGTOOLINFO_PTR_DELETE_FILE : info->delete_file = cybiko_image_delete_file; break; - // --- the following bits of info are returned as NULL-terminated strings --- - case IMGTOOLINFO_STR_NAME : strcpy( info->s = imgtool_temp_str(), "cybikoxt"); break; - case IMGTOOLINFO_STR_DESCRIPTION : strcpy( info->s = imgtool_temp_str(), "Cybiko Xtreme File System"); break; - case IMGTOOLINFO_STR_FILE : strcpy( info->s = imgtool_temp_str(), __FILE__); break; - case IMGTOOLINFO_STR_FILE_EXTENSIONS : strcpy( info->s = imgtool_temp_str(), "bin,nv"); break; - case IMGTOOLINFO_STR_EOLN : strcpy( info->s = imgtool_temp_str(), "\r\n"); break; - } -} diff --git a/src/mess/tools/imgtool/modules/fat.c b/src/mess/tools/imgtool/modules/fat.c deleted file mode 100644 index 4f2fca17c25..00000000000 --- a/src/mess/tools/imgtool/modules/fat.c +++ /dev/null @@ -1,2111 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/**************************************************************************** - - fat.c - - PC FAT disk images - -***************************************************************************** - - Master boot record format: - - Offset Length Description - ------ ------ ----------- - 0 446 Boot machine code - 446 16 Partion #1 info - 462 16 Partion #2 info - 478 16 Partion #3 info - 494 16 Partion #4 info - 510 2 Magic bytes (0x55 0xAA) - - - Partition info format: - - Offset Length Description - ------ ------ ----------- - 0 1 Active byte (0x80=active 0x00=inactive) - 1 1 Starting head - 2 1 Starting sector (bits 5-0) and high bits of starting track (bits 6-5) - 3 1 Low bits of starting track - 4 1 Partition type: - 0x00 Unused - 0x?1 FAT12 (0-15 MB) - 0x?2 XENIX - 0x?4 FAT16 (16-32 MB) - 0x?6 FAT16` (32 MB-2 GB) - 0x?7 HPFS or NTFS - 0x?A Boot Manager - 0x?B FAT32 (512 MB-2 TB) - 0x?C FAT32 (512 MB-2 TB LBA) - 0x1? OS/2 Boot manager/Win95 hidden - 0xC? DR-DOS secured partition - 0xD? Multiuser DOS secured partition - 0xE? SpeedStor extended partition - 5 1 Ending head - 6 1 Ending sector (bits 5-0) and high bits of ending track (bits 6-5) - 7 1 Low bits of ending track - 8 4 Sector index of beginning of partition - 12 4 Total sectors in partition - - - Boot sector format: - - Offset Length Description - ------ ------ ----------- - 0 3 Jump instruction (to skip over header on boot) - 3 8 OEM Name - 11 2 Bytes per sector - 13 1 Sectors per cluster - 14 2 Reserved sector count (including boot sector) - 16 1 Number of FATs (file allocation tables) - 17 2 Number of root directory entries - 19 2 Total sectors (bits 0-15) - 21 1 Media descriptor - 22 2 Sectors per FAT - 24 2 Sectors per track - 26 2 Number of heads - 28 4 Hidden sectors - 32 4 Total sectors (bits 16-47) - 36 1 Physical drive number - 37 1 Current head - 38 1 Signature - 39 4 ID - 43 11 Volume Label - 54 8 FAT file system type - 62 448 Boot machine code - 510 2 Magic bytes (0x55 0xAA) - - For more information: - http://support.microsoft.com/kb/q140418/ - - - Directory Entry Format: - - Offset Length Description - ------ ------ ----------- - 0 8 DOS File Name (padded with spaces) - 8 3 DOS File Extension (padded with spaces) - 11 1 File Attributes - 12 2 Unknown - 14 4 Time of Creation - 18 2 Last Access Time - 20 2 EA-Index (OS/2 stuff) - 22 4 Last Modified Time - 26 2 First Cluster - 28 4 File Size - - - Dates and times are stored in separate words; when together, the time is - first and the date is second. - - Time: - bits 15-11 Hour - bits 10- 5 Minute - bits 4- 0 Second / 2 - - Date: - bits 15- 9 Year - 1980 - bits 8- 5 Month - bits 4- 0 Day - - LFN Entry Format: - - Offset Length Description - ------ ------ ----------- - 0 1 Sequence Number (bit 6 is set on highest sequence) - 1 10 Name characters (five UTF-16LE chars) - 11 1 Attributes (always 0x0F) - 12 1 Reserved (always 0x00) - 13 1 Checksum of short filename entry - 14 12 Name characters (six UTF-16LE chars) - 26 2 Entry Cluster (always 0x00) - 28 4 Name characters (two UTF-16LE chars) - - Valid characters in DOS file names: - - Upper case letters A-Z - - Numbers 0-9 - - Space (though there is no way to identify a trailing space) - - ! # $ % & ( ) - @ ^ _ ` { } ~ - - Characters 128-255 (though the code page is indeterminate) - - For more information: - http://en.wikipedia.org/wiki/File_Allocation_Table - -****************************************************************************/ - -#include <time.h> -#include <ctype.h> -#include "imgtool.h" -#include "formats/imageutl.h" -#include "unicode.h" -#include "fat.h" - -#define FAT_DIRENT_SIZE 32 -#define FAT_SECLEN 512 - -#define LOG(x) - -struct fat_partition_info -{ - UINT32 fat_bits; - UINT32 sectors_per_cluster; - UINT32 cluster_size; - UINT32 reserved_sectors; - UINT32 fat_count; - UINT32 root_entries; - UINT32 sectors_per_fat; - UINT64 total_sectors; - UINT32 total_clusters; -}; - -struct fat_file -{ - unsigned int root : 1; - unsigned int directory : 1; - unsigned int eof : 1; - UINT32 index; - UINT32 filesize; - UINT32 first_cluster; - UINT32 parent_first_cluster; - UINT32 cluster; - UINT32 cluster_index; - UINT32 dirent_sector_index; - UINT32 dirent_sector_offset; -}; - -struct fat_dirent -{ - char long_filename[512]; - char short_filename[13]; - unsigned int directory : 1; - unsigned int eof : 1; - UINT32 filesize; - UINT32 first_cluster; - UINT32 dirent_sector_index; - UINT32 dirent_sector_offset; - time_t creation_time; - time_t lastmodified_time; -}; - -struct fat_freeentry_info -{ - UINT32 required_size; - UINT32 candidate_position; - UINT32 position; -}; - -struct fat_mediatype -{ - UINT8 media_descriptor; - UINT8 heads; - UINT8 tracks; - UINT8 sectors; -}; - -enum creation_policy_t -{ - CREATE_NONE, - CREATE_FILE, - CREATE_DIR -}; - - - -static const fat_mediatype known_media[] = -{ - { 0xF0, 2, 80, 36 }, - { 0xF0, 2, 80, 18 }, - { 0xF9, 2, 80, 9 }, - { 0xF9, 2, 80, 15 }, - { 0xFD, 2, 40, 9 }, - { 0xFF, 2, 40, 8 }, - { 0xFC, 1, 40, 9 }, - { 0xFE, 1, 40, 8 }, - { 0xF8, 0, 0, 0 } -}; - -/* boot sector code taken from FreeDOS */ -static const UINT8 boot_sector_code[] = -{ - 0xfa, 0xfc, 0x31, 0xc0, 0x8e, 0xd8, 0xbd, 0x00, 0x7c, 0xb8, 0xe0, 0x1f, - 0x8e, 0xc0, 0x89, 0xee, 0x89, 0xef, 0xb9, 0x00, 0x01, 0xf3, 0xa5, 0xea, - 0x5e, 0x7c, 0xe0, 0x1f, 0x00, 0x00, 0x60, 0x00, 0x8e, 0xd8, 0x8e, 0xd0, - 0x8d, 0x66, 0xa0, 0xfb, 0x80, 0x7e, 0x24, 0xff, 0x75, 0x03, 0x88, 0x56, - 0x24, 0xc7, 0x46, 0xc0, 0x10, 0x00, 0xc7, 0x46, 0xc2, 0x01, 0x00, 0x8b, - 0x76, 0x1c, 0x8b, 0x7e, 0x1e, 0x03, 0x76, 0x0e, 0x83, 0xd7, 0x00, 0x89, - 0x76, 0xd2, 0x89, 0x7e, 0xd4, 0x8a, 0x46, 0x10, 0x98, 0xf7, 0x66, 0x16, - 0x01, 0xc6, 0x11, 0xd7, 0x89, 0x76, 0xd6, 0x89, 0x7e, 0xd8, 0x8b, 0x5e, - 0x0b, 0xb1, 0x05, 0xd3, 0xeb, 0x8b, 0x46, 0x11, 0x31, 0xd2, 0xf7, 0xf3, - 0x89, 0x46, 0xd0, 0x01, 0xc6, 0x83, 0xd7, 0x00, 0x89, 0x76, 0xda, 0x89, - 0x7e, 0xdc, 0x8b, 0x46, 0xd6, 0x8b, 0x56, 0xd8, 0x8b, 0x7e, 0xd0, 0xc4, - 0x5e, 0x5a, 0xe8, 0xac, 0x00, 0xc4, 0x7e, 0x5a, 0xb9, 0x0b, 0x00, 0xbe, - 0xf1, 0x7d, 0x57, 0xf3, 0xa6, 0x5f, 0x26, 0x8b, 0x45, 0x1a, 0x74, 0x0b, - 0x83, 0xc7, 0x20, 0x26, 0x80, 0x3d, 0x00, 0x75, 0xe7, 0x72, 0x68, 0x50, - 0xc4, 0x5e, 0x5a, 0x8b, 0x7e, 0x16, 0x8b, 0x46, 0xd2, 0x8b, 0x56, 0xd4, - 0xe8, 0x7e, 0x00, 0x58, 0x1e, 0x07, 0x8e, 0x5e, 0x5c, 0xbf, 0x00, 0x20, - 0xab, 0x89, 0xc6, 0x01, 0xf6, 0x01, 0xc6, 0xd1, 0xee, 0xad, 0x73, 0x04, - 0xb1, 0x04, 0xd3, 0xe8, 0x80, 0xe4, 0x0f, 0x3d, 0xf8, 0x0f, 0x72, 0xe8, - 0x31, 0xc0, 0xab, 0x0e, 0x1f, 0xc4, 0x5e, 0x5a, 0xbe, 0x00, 0x20, 0xad, - 0x09, 0xc0, 0x75, 0x05, 0x88, 0xd3, 0xff, 0x6e, 0x5a, 0x48, 0x48, 0x8b, - 0x7e, 0x0d, 0x81, 0xe7, 0xff, 0x00, 0xf7, 0xe7, 0x03, 0x46, 0xda, 0x13, - 0x56, 0xdc, 0xe8, 0x34, 0x00, 0xeb, 0xe0, 0x5e, 0xac, 0x56, 0xb4, 0x0e, - 0xcd, 0x10, 0x3c, 0x2e, 0x75, 0xf5, 0xc3, 0xe8, 0xf1, 0xff, 0x45, 0x72, - 0x72, 0x6f, 0x72, 0x21, 0x20, 0x48, 0x69, 0x74, 0x20, 0x61, 0x20, 0x6b, - 0x65, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x74, - 0x2e, 0x30, 0xe4, 0xcd, 0x13, 0xcd, 0x16, 0xcd, 0x19, 0x56, 0x89, 0x46, - 0xc8, 0x89, 0x56, 0xca, 0x8c, 0x46, 0xc6, 0x89, 0x5e, 0xc4, 0xe8, 0xbe, - 0xff, 0x2e, 0xb4, 0x41, 0xbb, 0xaa, 0x55, 0x8a, 0x56, 0x24, 0x84, 0xd2, - 0x74, 0x19, 0xcd, 0x13, 0x72, 0x15, 0xd1, 0xe9, 0x81, 0xdb, 0x54, 0xaa, - 0x75, 0x0d, 0x8d, 0x76, 0xc0, 0x89, 0x5e, 0xcc, 0x89, 0x5e, 0xce, 0xb4, - 0x42, 0xeb, 0x26, 0x8b, 0x4e, 0xc8, 0x8b, 0x56, 0xca, 0x8a, 0x46, 0x18, - 0xf6, 0x66, 0x1a, 0x91, 0xf7, 0xf1, 0x92, 0xf6, 0x76, 0x18, 0x89, 0xd1, - 0x88, 0xc6, 0x86, 0xe9, 0xd0, 0xc9, 0xd0, 0xc9, 0x08, 0xe1, 0x41, 0xc4, - 0x5e, 0xc4, 0xb8, 0x01, 0x02, 0x8a, 0x56, 0x24, 0xcd, 0x13, 0x0f, 0x82, - 0x75, 0xff, 0x8b, 0x46, 0x0b, 0xf6, 0x76, 0xc0, 0x01, 0x46, 0xc6, 0x83, - 0x46, 0xc8, 0x01, 0x83, 0x56, 0xca, 0x00, 0x4f, 0x75, 0x98, 0x8e, 0x46, - 0xc6, 0x5e, 0xc3, 0x4d, 0x45, 0x54, 0x41, 0x4b, 0x45, 0x52, 0x4e, 0x53, - 0x59, 0x53, 0x00, 0x00, 0x55, 0xaa -}; - -static const char fat8_string[8] = { 'F', 'A', 'T', ' ', ' ', ' ', ' ', ' ' }; -static const char fat12_string[8] = { 'F', 'A', 'T', '1', '2', ' ', ' ', ' ' }; -static const char fat16_string[8] = { 'F', 'A', 'T', '1', '6', ' ', ' ', ' ' }; -static const char fat32_string[8] = { 'F', 'A', 'T', '3', '2', ' ', ' ', ' ' }; - - - -static fat_partition_info *fat_get_partition_info(imgtool_partition *partition) -{ - return (fat_partition_info *) imgtool_partition_extra_bytes(partition); -} - - - -static imgtoolerr_t fat_read_sector(imgtool_partition *partition, UINT32 sector_index, - int offset, void *buffer, size_t buffer_len) -{ - //const fat_partition_info *disk_info; - imgtoolerr_t err; - UINT8 data[FAT_SECLEN]; - UINT32 block_size; - size_t len; - - //disk_info = fat_get_partition_info(partition); - - /* sanity check */ - err = imgtool_partition_get_block_size(partition, &block_size); - if (err) - return err; - assert(block_size == sizeof(data)); - - while(buffer_len > 0) - { - err = imgtool_partition_read_block(partition, sector_index++, data); - if (err) - return err; - - len = MIN(buffer_len, sizeof(data) - offset); - memcpy(buffer, data + offset, len); - - buffer = ((UINT8 *) buffer) + len; - buffer_len -= len; - offset = 0; - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_write_sector(imgtool_partition *partition, UINT32 sector_index, - int offset, const void *buffer, size_t buffer_len) -{ - //const fat_partition_info *disk_info; - imgtoolerr_t err; - UINT8 data[FAT_SECLEN]; - const void *write_data; - UINT32 block_size; - size_t len; - - //disk_info = fat_get_partition_info(partition); - - /* sanity check */ - err = imgtool_partition_get_block_size(partition, &block_size); - if (err) - return err; - assert(block_size == sizeof(data)); - - while(buffer_len > 0) - { - len = MIN(buffer_len, sizeof(data) - offset); - - if ((offset != 0) || (buffer_len < sizeof(data))) - { - err = imgtool_partition_read_block(partition, sector_index, data); - if (err) - return err; - memcpy(data + offset, buffer, len); - write_data = data; - } - else - { - write_data = buffer; - } - - err = imgtool_partition_write_block(partition, sector_index++, write_data); - if (err) - return err; - - buffer = ((UINT8 *) buffer) + len; - buffer_len -= len; - offset = 0; - } - return IMGTOOLERR_SUCCESS; -} - - -#ifdef UNUSED_FUNCTION -static imgtoolerr_t fat_clear_sector(imgtool_partition *partition, UINT32 sector_index, UINT8 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 first_block, UINT64 block_count) -{ - UINT8 header[FAT_SECLEN]; - imgtoolerr_t err; - fat_partition_info *info; - UINT32 fat_bits, total_sectors_l, total_sectors_h, sector_size; - UINT64 available_sectors; - //int has_extended_bios_param_block = TRUE; - - info = fat_get_partition_info(partition); - - /* read the boot/root sector */ - err = fat_read_sector(partition, 0, 0, header, sizeof(header)); - if (err) - return err; - - /* magic bytes present? */ - if ((header[510] != 0x55) || (header[511] != 0xAA)) - return IMGTOOLERR_CORRUPTIMAGE; - - /* determine which type of FAT is on this disk */ - if (!memcmp(&header[54], fat8_string, sizeof(fat8_string))) - fat_bits = 8; - else if (!memcmp(&header[54], fat12_string, sizeof(fat12_string))) - fat_bits = 12; - else if (!memcmp(&header[54], fat16_string, sizeof(fat16_string))) - fat_bits = 16; - else if (!memcmp(&header[54], fat32_string, sizeof(fat32_string))) - fat_bits = 32; - else - { - fat_bits = 8; - //has_extended_bios_param_block = FALSE; - } - - 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); - - if (info->sectors_per_cluster == 0) - return IMGTOOLERR_CORRUPTIMAGE; - - info->total_sectors = total_sectors_l + (((UINT64) 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; - info->total_clusters = (available_sectors + info->sectors_per_cluster - 1) / info->sectors_per_cluster; - info->cluster_size = FAT_SECLEN * info->sectors_per_cluster; - - if (info->fat_count == 0) - return IMGTOOLERR_CORRUPTIMAGE; - if (sector_size != FAT_SECLEN) - return IMGTOOLERR_CORRUPTIMAGE; - if (info->sectors_per_fat == 0) - return IMGTOOLERR_CORRUPTIMAGE; - if (info->sectors_per_cluster == 0) - return IMGTOOLERR_CORRUPTIMAGE; - if (info->reserved_sectors == 0) - return IMGTOOLERR_CORRUPTIMAGE; - if (info->total_clusters * info->fat_bits > info->sectors_per_fat * FAT_SECLEN * 8) - return IMGTOOLERR_CORRUPTIMAGE; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_partition_create(imgtool_image *image, UINT64 first_block, UINT64 block_count) -{ - imgtoolerr_t err; - UINT32 heads, tracks, sectors_per_track; - UINT32 fat_bits, sectors_per_cluster, reserved_sectors, hidden_sectors; - UINT32 root_dir_count, root_dir_sectors; - UINT32 sectors_per_fat, fat_count, i; - UINT32 boot_sector_offset; - UINT64 total_clusters; - UINT8 media_descriptor; - //const char *title; - const char *fat_bits_string; - UINT8 header[FAT_SECLEN]; -#if 0 - UINT64 first_fat_entries; -#endif - - /* check for limits */ - if (block_count > U64(0xFFFFFFFFFFFF)) - return IMGTOOLERR_PARAMTOOLARGE; - - /* get the geometry */ - err = imgtool_image_get_geometry(image, &tracks, &heads, §ors_per_track); - if (err) - return err; - - /* cap our sector count so that we only use FAT12/16 */ - sectors_per_cluster = (block_count + 65524 - 1) / 65524; - - /* compute the FAT file system type */ - if ((block_count / sectors_per_cluster) <= 4084) - { - fat_bits = 12; - fat_bits_string = fat12_string; - } - else if ((block_count / sectors_per_cluster) <= 65524) - { - fat_bits = 16; - fat_bits_string = fat16_string; - } - else - { - fat_bits = 32; - fat_bits_string = fat32_string; - } - - /* figure out media type */ - i = 0; - while((known_media[i].heads > 0) && ((known_media[i].heads != heads) - || (known_media[i].tracks != tracks) - || (known_media[i].sectors != sectors_per_track))) - { - i++; - } - media_descriptor = known_media[i].media_descriptor; - - /* other miscellaneous settings */ - //title = ""; - fat_count = 2; - root_dir_count = 512; - hidden_sectors = 0; - reserved_sectors = 1; - - /* calculated settings */ - root_dir_sectors = (root_dir_count * FAT_DIRENT_SIZE + FAT_SECLEN - 1) / FAT_SECLEN; - total_clusters = (block_count - reserved_sectors - hidden_sectors - root_dir_sectors) - / sectors_per_cluster; - sectors_per_fat = (total_clusters * fat_bits + (FAT_SECLEN * 8) - 1) - / (FAT_SECLEN * 8); - - /* 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) (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) (block_count >> 16)); - place_integer_le(header, 36, 1, 0xFF); - place_integer_le(header, 38, 1, 0x28); - place_integer_le(header, 39, 4, imgtool_image_rand(image)); - memcpy(&header[43], " ", 11); - memcpy(&header[54], fat_bits_string, 8); - - /* store boot code */ - boot_sector_offset = sizeof(header) - sizeof(boot_sector_code); - if (boot_sector_offset < 62) - return IMGTOOLERR_UNEXPECTED; /* sanity check */ - if (boot_sector_offset > 510) - return IMGTOOLERR_UNEXPECTED; /* sanity check */ - memcpy(&header[boot_sector_offset], boot_sector_code, sizeof(boot_sector_code)); - - /* specify jump instruction */ - if (boot_sector_offset <= 129) - { - header[0] = 0xEB; /* JMP rel8 */ - header[1] = (UINT8) (boot_sector_offset - 2); /* (offset) */ - header[2] = 0x90; /* NOP */ - } - else - { - header[0] = 0xE9; /* JMP rel16 */ - header[1] = (UINT8) ((boot_sector_offset - 2) >> 0); /* (offset) */ - header[2] = (UINT8) ((boot_sector_offset - 2) >> 8); /* (offset) */ - } - - err = imgtool_image_write_block(image, first_block, header); - if (err) - return err; - - /* clear out file allocation table */ - for (i = reserved_sectors; i < (reserved_sectors + sectors_per_fat * fat_count + root_dir_sectors); i++) - { - err = imgtool_image_clear_block(image, first_block + i, 0); - if (err) - return err; - } - - // 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) media_descriptor) | 0xFFFFFF00; - first_fat_entries &= (((UINT64) 1) << fat_bits) - 1; - first_fat_entries |= ((((UINT64) 1) << fat_bits) - 1) << fat_bits; - first_fat_entries = LITTLE_ENDIANIZE_INT64(first_fat_entries); - - for (i = 0; i < fat_count; i++) - { - err = imgtool_image_write_block(image, first_block + 1 + (i * sectors_per_fat), &first_fat_entries); - if (err) - return err; - } -#endif - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_load_fat(imgtool_partition *partition, UINT8 **fat_table) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - const fat_partition_info *disk_info; - UINT8 *table; - UINT32 table_size; - UINT32 pos, len; - UINT32 sector_index; - - disk_info = fat_get_partition_info(partition); - - table_size = disk_info->sectors_per_fat * disk_info->fat_count * FAT_SECLEN; - - /* allocate the table with extra bytes, in case we "overextend" our reads */ - table = (UINT8*)malloc(table_size + sizeof(UINT64)); - if (!table) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto done; - } - memset(table, 0, table_size + sizeof(UINT64)); - - pos = 0; - sector_index = disk_info->reserved_sectors; - - while(pos < table_size) - { - len = MIN(table_size - pos, FAT_SECLEN); - - err = fat_read_sector(partition, sector_index++, 0, &table[pos], len); - if (err) - goto done; - - pos += FAT_SECLEN; - } - -done: - if (err && table) - { - free(table); - table = NULL; - } - *fat_table = table; - return err; -} - - - -static imgtoolerr_t fat_save_fat(imgtool_partition *partition, const UINT8 *fat_table) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - const fat_partition_info *disk_info; - UINT32 table_size; - UINT32 pos, len; - UINT32 sector_index; - - disk_info = fat_get_partition_info(partition); - - table_size = disk_info->sectors_per_fat * disk_info->fat_count * FAT_SECLEN; - - pos = 0; - sector_index = disk_info->reserved_sectors; - - while(pos < table_size) - { - len = MIN(table_size - pos, FAT_SECLEN); - - err = fat_write_sector(partition, sector_index++, 0, &fat_table[pos], len); - if (err) - goto done; - - pos += FAT_SECLEN; - } - -done: - return err; -} - - - -static UINT32 fat_get_fat_entry(imgtool_partition *partition, const UINT8 *fat_table, UINT32 fat_entry) -{ - const fat_partition_info *disk_info; - UINT64 entry; - UINT32 bit_index, i; - UINT32 last_entry = 0; - UINT32 bit_mask; - - disk_info = fat_get_partition_info(partition); - bit_index = fat_entry * disk_info->fat_bits; - bit_mask = 0xFFFFFFFF >> (32 - disk_info->fat_bits); - - if (fat_entry >= disk_info->total_clusters) - { - assert(0); - return 1; - } - - /* make sure that the cluster is free in all fats */ - for (i = 0; i < disk_info->fat_count; i++) - { - memcpy(&entry, fat_table + (i * FAT_SECLEN - * disk_info->sectors_per_fat) + (bit_index / 8), sizeof(entry)); - - /* we've extracted the bytes; we now need to normalize it */ - entry = LITTLE_ENDIANIZE_INT64(entry); - entry >>= bit_index % 8; - entry &= bit_mask; - - if (i == 0) - last_entry = (UINT32) entry; - else if (last_entry != (UINT32) entry) - return 1; /* if the FATs disagree; mark this as reserved */ - } - - /* normalize special clusters */ - if (last_entry >= (0xFFFFFFF0 & bit_mask)) - { - last_entry |= 0xFFFFFFF0; - if (last_entry >= 0xFFFFFFF8) - last_entry = 0xFFFFFFFF; - } - return last_entry; -} - - - -static void fat_set_fat_entry(imgtool_partition *partition, UINT8 *fat_table, UINT32 fat_entry, UINT32 value) -{ - const fat_partition_info *disk_info; - UINT64 entry; - UINT32 bit_index, i; - - disk_info = fat_get_partition_info(partition); - bit_index = fat_entry * disk_info->fat_bits; - value &= 0xFFFFFFFF >> (32 - disk_info->fat_bits); - - for (i = 0; i < disk_info->fat_count; i++) - { - memcpy(&entry, fat_table + (i * FAT_SECLEN - * disk_info->sectors_per_fat) + (bit_index / 8), sizeof(entry)); - - entry = LITTLE_ENDIANIZE_INT64(entry); - entry &= (~((UINT64) 0xFFFFFFFF >> (32 - disk_info->fat_bits)) << (bit_index % 8)) | ((1 << (bit_index % 8)) - 1); - entry |= ((UINT64) value) << (bit_index % 8); - entry = LITTLE_ENDIANIZE_INT64(entry); - - memcpy(fat_table + (i * FAT_SECLEN - * disk_info->sectors_per_fat) + (bit_index / 8), &entry, sizeof(entry)); - } -} - - - -static void fat_debug_integrity_check(imgtool_partition *partition, const UINT8 *fat_table, const fat_file *file) -{ -#ifdef MAME_DEBUG - /* debug function to test the integrity of a file */ - UINT32 cluster; - const fat_partition_info *disk_info; - - disk_info = fat_get_partition_info(partition); - cluster = file->first_cluster ? file->first_cluster : 0xFFFFFFFF; - - if (!file->root) - { - while(cluster != 0xFFFFFFFF) - { - assert((cluster >= 2) && (cluster < disk_info->total_clusters)); - cluster = fat_get_fat_entry(partition, fat_table, cluster); - } - } -#endif -} - - - -static imgtoolerr_t fat_seek_file(imgtool_partition *partition, fat_file *file, UINT32 pos) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - const fat_partition_info *disk_info; - UINT32 new_cluster; - UINT8 *fat_table = NULL; - - disk_info = fat_get_partition_info(partition); - - /* can't seek past end of file */ - if (!file->directory && (pos > file->filesize)) - pos = file->filesize; - - if (file->first_cluster == 0) - { - /* special case; the root directory */ - file->index = pos; - } - else - { - /* first, we need to check to see if we have to go back to the beginning */ - if (pos < file->index) - { - file->cluster = file->first_cluster; - file->cluster_index = 0; - file->eof = 0; - } - - /* skip ahead clusters */ - while((file->cluster_index + disk_info->cluster_size) <= pos) - { - if (!fat_table) - { - err = fat_load_fat(partition, &fat_table); - if (err) - goto done; - } - - new_cluster = fat_get_fat_entry(partition, fat_table, file->cluster); - - file->cluster = new_cluster; - file->cluster_index += disk_info->cluster_size; - - /* are we at the end of the file? */ - if (new_cluster == 0xFFFFFFFF) - { - pos = file->cluster_index; - file->eof = 1; - } - } - file->index = pos; - } - -done: - if (fat_table) - free(fat_table); - return err; -} - - - -static UINT32 fat_get_filepos_sector_index(imgtool_partition *partition, fat_file *file) -{ - UINT32 sector_index; - const fat_partition_info *disk_info; - - disk_info = fat_get_partition_info(partition); - - sector_index = disk_info->reserved_sectors + (disk_info->sectors_per_fat * disk_info->fat_count); - if (file->root) - { - /* special case for the root file */ - sector_index += file->index / FAT_SECLEN; - } - else - { - /* cluster out of range? */ - if ((file->cluster < 2) || (file->cluster >= disk_info->total_clusters)) - return 0; - - sector_index += (disk_info->root_entries * FAT_DIRENT_SIZE + FAT_SECLEN - 1) / FAT_SECLEN; - sector_index += (file->cluster - 2) * disk_info->sectors_per_cluster; - sector_index += (file->index / FAT_SECLEN) % disk_info->sectors_per_cluster; - } - return sector_index; -} - - - -static imgtoolerr_t fat_corrupt_file_error(const fat_file *file) -{ - imgtoolerr_t err; - if (file->root) - err = IMGTOOLERR_CORRUPTIMAGE; - else if (file->directory) - err = IMGTOOLERR_CORRUPTDIR; - else - err = IMGTOOLERR_CORRUPTFILE; - return err; -} - - - -static imgtoolerr_t fat_readwrite_file(imgtool_partition *partition, fat_file *file, - void *buffer, size_t buffer_len, size_t *bytes_read, int read_or_write) -{ - imgtoolerr_t err; -// const fat_partition_info *disk_info; - UINT32 sector_index; - int offset; - size_t len; - -// disk_info = - fat_get_partition_info(partition); - if (bytes_read) - *bytes_read = 0; - if (!file->directory) - buffer_len = MIN(buffer_len, file->filesize - file->index); - - while(!file->eof && (buffer_len > 0)) - { - sector_index = fat_get_filepos_sector_index(partition, file); - if (sector_index == 0) - return fat_corrupt_file_error(file); - - offset = file->index % FAT_SECLEN; - len = MIN(buffer_len, FAT_SECLEN - offset); - - /* read or write the data from the disk */ - if (read_or_write) - err = fat_write_sector(partition, sector_index, offset, buffer, len); - else - err = fat_read_sector(partition, sector_index, offset, buffer, len); - if (err) - return err; - - /* and move the file pointer ahead */ - err = fat_seek_file(partition, file, file->index + len); - if (err) - return err; - - buffer = ((UINT8 *) buffer) + len; - buffer_len -= len; - if (bytes_read) - *bytes_read += len; - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_read_file(imgtool_partition *partition, fat_file *file, - void *buffer, size_t buffer_len, size_t *bytes_read) -{ - return fat_readwrite_file(partition, file, buffer, buffer_len, bytes_read, 0); -} - - - -static imgtoolerr_t fat_write_file(imgtool_partition *partition, fat_file *file, - const void *buffer, size_t buffer_len, size_t *bytes_read) -{ - return fat_readwrite_file(partition, file, (void *) buffer, buffer_len, bytes_read, 1); -} - - - -static UINT32 fat_allocate_cluster(imgtool_partition *partition, UINT8 *fat_table) -{ - const fat_partition_info *disk_info; - UINT32 i, val; - - disk_info = fat_get_partition_info(partition); - - for (i = 2; i < disk_info->total_clusters; i++) - { - val = fat_get_fat_entry(partition, fat_table, i); - if (val == 0) - { - fat_set_fat_entry(partition, fat_table, i, 1); - return i; - } - } - return 0; -} - - - -/* sets the size of a file; ~0 means 'delete' */ -static imgtoolerr_t fat_set_file_size(imgtool_partition *partition, fat_file *file, - UINT32 new_size) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - const fat_partition_info *disk_info; - UINT32 new_cluster_count; - UINT32 old_cluster_count; - UINT32 cluster, write_cluster, last_cluster, new_pos, i; - UINT8 *fat_table = NULL; - UINT8 dirent[32]; - size_t clear_size; - void *clear_buffer = NULL; - int delete_file = FALSE; - int rest_free = FALSE; - - disk_info = fat_get_partition_info(partition); - - LOG(("fat_set_file_size(): file->first_cluster=%d new_size=0x%08x\n", file->first_cluster, new_size)); - - /* special case */ - if (new_size == ~0) - { - delete_file = TRUE; - new_size = 0; - } - - /* if this is the trivial case (not changing the size), succeed */ - if (!delete_file && (file->filesize == new_size)) - { - err = IMGTOOLERR_SUCCESS; - goto done; - } - - /* what is the new position? */ - new_pos = MIN(file->index, new_size); - - if (file->root) - { - /* this is the root directory; this is a special case */ - if (new_size > (disk_info->root_entries * FAT_DIRENT_SIZE)) - { - err = IMGTOOLERR_NOSPACE; - goto done; - } - } - else - { - old_cluster_count = (file->filesize + disk_info->cluster_size - 1) / disk_info->cluster_size; - new_cluster_count = (new_size + disk_info->cluster_size - 1) / disk_info->cluster_size; - cluster = 0; - - /* load the dirent */ - err = fat_read_sector(partition, file->dirent_sector_index, file->dirent_sector_offset, dirent, sizeof(dirent)); - if (err) - goto done; - - /* need to load the FAT whether we are growing or shrinking the file */ - if (old_cluster_count != new_cluster_count) - { - err = fat_load_fat(partition, &fat_table); - if (err) - goto done; - - cluster = 0; - i = 0; - do - { - last_cluster = cluster; - write_cluster = 0; - - /* identify the next cluster */ - if (cluster != 0) - cluster = fat_get_fat_entry(partition, fat_table, cluster); - else - cluster = file->first_cluster ? file->first_cluster : 0xFFFFFFFF; - - /* do we need to grow the file by a cluster? */ - if (i < new_cluster_count && ((cluster < 2) || (cluster >= disk_info->total_clusters))) - { - /* grow this file by a cluster */ - cluster = fat_allocate_cluster(partition, fat_table); - if (cluster == 0) - { - err = IMGTOOLERR_NOSPACE; - goto done; - } - - write_cluster = cluster; - } - else if (i >= new_cluster_count) - { - /* we are shrinking the file; we need to unlink this node */ - if ((cluster < 2) || (cluster >= disk_info->total_clusters)) - cluster = 0xFFFFFFFF; /* ack file is corrupt! recover */ - write_cluster = 0xFFFFFFFF; - } - - /* write out the entry, if appropriate */ - if (write_cluster != 0) - { - /* are we tieing up loose ends? */ - if (rest_free && (write_cluster == 0xFFFFFFFF)) - write_cluster = 0; - - if (last_cluster == 0) - file->first_cluster = (write_cluster != 0xFFFFFFFF) ? write_cluster : 0; - else - fat_set_fat_entry(partition, fat_table, last_cluster, write_cluster); - - /* did we write the last cluster? if so, the rest (if any) are free */ - if (write_cluster == 0xFFFFFFFF) - rest_free = TRUE; - } - } - while((++i < new_cluster_count) || (cluster != 0xFFFFFFFF)); - } - - /* record the new file size */ - place_integer_le(dirent, 26, 2, file->first_cluster); - place_integer_le(dirent, 28, 4, new_size); - - /* delete the file, if appropriate */ - if (delete_file) - dirent[0] = 0xE5; - - /* save the dirent */ - err = fat_write_sector(partition, file->dirent_sector_index, file->dirent_sector_offset, dirent, sizeof(dirent)); - if (err) - goto done; - - /* if we've modified the FAT, save it out */ - if (fat_table) - { - err = fat_save_fat(partition, fat_table); - if (err) - goto done; - } - - /* update the file structure */ - if (!file->directory) - file->filesize = new_size; - file->cluster = file->first_cluster; - file->index = 0; - file->cluster_index = 0; - file->eof = (new_cluster_count == 0); - } - - /* special case; clear out stale bytes on non-root directories */ - if (file->directory && !delete_file) - { - if (file->root) - clear_size = MIN(file->filesize - new_size, FAT_DIRENT_SIZE); - else - clear_size = (disk_info->cluster_size - (new_size % disk_info->cluster_size)) % disk_info->cluster_size; - - if (clear_size > 0) - { - err = fat_seek_file(partition, file, new_size); - if (err) - goto done; - - clear_buffer = malloc(clear_size); - if (!clear_buffer) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto done; - } - memset(clear_buffer, '\0', clear_size); - - err = fat_write_file(partition, file, clear_buffer, clear_size, NULL); - if (err) - goto done; - } - } - - /* seek back to original pos */ - err = fat_seek_file(partition, file, new_pos); - if (err) - goto done; - - if (fat_table) - fat_debug_integrity_check(partition, fat_table, file); - -done: - if (fat_table) - free(fat_table); - if (clear_buffer) - free(clear_buffer); - return err; -} - - - -static void prepend_lfn_bytes(utf16_char *lfn_buf, size_t lfn_buflen, size_t *lfn_len, - const UINT8 *entry, int offset, int chars) -{ - UINT16 w; - int i; - size_t move_len; - - move_len = MIN(*lfn_len + 1, lfn_buflen - chars - 1); - memmove(&lfn_buf[chars], &lfn_buf[0], move_len * sizeof(*lfn_buf)); - - for (i = 0; i < chars; i++) - { - /* read the character */ - memcpy(&w, &entry[offset + i * 2], 2); - w = LITTLE_ENDIANIZE_INT16(w); - - /* append to buffer */ - lfn_buf[i] = (w != 0xFFFF) ? w : 0; - } - *lfn_len += chars; -} - - - -static UINT8 fat_calc_filename_checksum(const UINT8 *short_filename) -{ - UINT8 checksum; - int i, j; - - checksum = 0; - for (i = 0; i < 11; i++) - { - j = checksum & 1; - checksum >>= 1; - if (j) - checksum |= 0x80; - checksum += short_filename[i]; - } - return checksum; -} - - - -static void fat_calc_dirent_lfnchecksum(UINT8 *entry, size_t entry_len) -{ - UINT8 checksum; - int i; - - checksum = fat_calc_filename_checksum(entry + entry_len - FAT_DIRENT_SIZE); - - for (i = 0; i < (entry_len / FAT_DIRENT_SIZE - 1); i++) - entry[i * FAT_DIRENT_SIZE + 13] = checksum; -} - - - -static char fat_cannonicalize_sfn_char(char ch) -{ - /* return the display version of this short file name character */ - return tolower(ch); -} - - - -static void fat_cannonicalize_sfn(char *sfn, const UINT8 *sfn_bytes) -{ - /* return the display version of this short file name */ - int i; - - memset(sfn, '\0', 13); - memcpy(sfn, sfn_bytes, 8); - rtrim(sfn); - if (sfn[0] == 0x05) - sfn[0] = (char) 0xE5; - if ((sfn_bytes[8] != ' ') || (sfn_bytes[9] != ' ') || (sfn_bytes[10] != ' ')) - { - strcat(sfn, "."); - memcpy(sfn + strlen(sfn), &sfn_bytes[8], 3); - rtrim(sfn); - } - for (i = 0; sfn[i]; i++) - sfn[i] = fat_cannonicalize_sfn_char(sfn[i]); -} - - - -static time_t fat_crack_time(UINT32 fat_time) -{ - struct tm t; - time_t now; - - time(&now); - t = *localtime(&now); - - t.tm_sec = ((fat_time >> 0) & 0x001F) * 2; - t.tm_min = ((fat_time >> 5) & 0x003F); - t.tm_hour = ((fat_time >> 11) & 0x001F); - t.tm_mday = ((fat_time >> 16) & 0x001F); - t.tm_mon = ((fat_time >> 21) & 0x000F); - t.tm_year = ((fat_time >> 25) & 0x007F) + 1980 - 1900; - - return mktime(&t); -} - - - -static UINT32 fat_setup_time(time_t ansi_time) -{ - struct tm t; - UINT32 result = 0; - - t = *localtime(&ansi_time); - - result |= (((UINT32) (t.tm_sec / 2)) & 0x001F) << 0; - result |= (((UINT32) t.tm_min) & 0x003F) << 5; - result |= (((UINT32) t.tm_hour) & 0x001F) << 11; - result |= (((UINT32) t.tm_mday) & 0x001F) << 16; - result |= (((UINT32) t.tm_mon) & 0x000F) << 21; - result |= (((UINT32) (t.tm_year + 1900 - 1980)) & 0x007F) << 25; - - return result; -} - - - -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 entry[FAT_DIRENT_SIZE]; - size_t bytes_read; - int i, j; - unicode_char ch; - utf16_char lfn_buf[512]; - size_t lfn_len = 0; - int lfn_lastentry = 0; - UINT8 lfn_checksum = 0; - UINT32 entry_index, entry_sector_index, entry_sector_offset; - - assert(file->directory); - lfn_buf[0] = '\0'; - memset(ent, 0, sizeof(*ent)); - //disk_info = fat_get_partition_info(partition); - - /* The first eight bytes of a FAT directory entry is a blank padded name - * - * The first byte can be special: - * 0x00 - entry is available and no further entry is used - * 0x05 - first character is actually 0xe5 - * 0x2E - dot entry; either '.' or '..' - * 0xE5 - entry has been erased and is available - * - * Byte 11 is the attributes; and 0x0F denotes a LFN entry - */ - do - { - entry_index = file->index; - entry_sector_index = fat_get_filepos_sector_index(partition, file); - entry_sector_offset = file->index % FAT_SECLEN; - - err = fat_read_file(partition, file, entry, sizeof(entry), &bytes_read); - if (err) - return err; - if (bytes_read < sizeof(entry)) - memset(entry, 0, sizeof(entry)); - - if (entry[11] == 0x0F) - { - /* this is an LFN entry */ - if ((lfn_lastentry == 0) - || ((entry[0] & 0x3F) != (lfn_lastentry - 1)) - || (lfn_checksum != entry[13])) - { - lfn_buf[0] = 0; - lfn_len = 0; - lfn_checksum = entry[13]; - } - lfn_lastentry = entry[0] & 0x3F; - prepend_lfn_bytes(lfn_buf, ARRAY_LENGTH(lfn_buf), - &lfn_len, entry, 28, 2); - prepend_lfn_bytes(lfn_buf, ARRAY_LENGTH(lfn_buf), - &lfn_len, entry, 14, 6); - prepend_lfn_bytes(lfn_buf, ARRAY_LENGTH(lfn_buf), - &lfn_len, entry, 1, 5); - } - else if (freeent && (freeent->position == ~0)) - { - /* do a quick check to find out if we found space */ - if ((entry[0] == '\0') || (entry[0] == 0xE5)) - { - if (freeent->candidate_position > entry_index) - freeent->candidate_position = entry_index; - - if ((entry[0] == '\0') || (freeent->candidate_position + freeent->required_size < file->index)) - freeent->position = freeent->candidate_position; - } - else - { - freeent->candidate_position = ~0; - } - } - } - while((entry[0] == 0x2E) || (entry[0] == 0xE5) || (entry[11] == 0x0F)); - - /* no more directory entries? */ - if (entry[0] == '\0') - { - ent->eof = 1; - return IMGTOOLERR_SUCCESS; - } - - /* pick apart short filename */ - fat_cannonicalize_sfn(ent->short_filename, entry); - - /* and the long filename */ - if (lfn_lastentry == 1) - { - /* only use the LFN if the checksum passes */ - if (lfn_checksum == fat_calc_filename_checksum(entry)) - { - i = 0; - j = 0; - 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); - } - while(ch != 0); - } - } - - /* other attributes */ - ent->filesize = pick_integer_le(entry, 28, 4); - ent->directory = (entry[11] & 0x10) ? 1 : 0; - ent->first_cluster = pick_integer_le(entry, 26, 2); - 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)); - return IMGTOOLERR_SUCCESS; -} - - - -enum sfn_disposition_t -{ - SFN_SUFFICIENT, /* name fully representable in short file name */ - SFN_DERIVATIVE, /* name not fully representable in short file name, but no need to tildize */ - SFN_MANGLED /* name not representable in short file name; must tildize */ -}; - -static imgtoolerr_t fat_construct_dirent(const char *filename, creation_policy_t create, - UINT8 **entry, size_t *entry_len) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - UINT8 *created_entry = NULL; - UINT8 *new_created_entry; - UINT32 now; - size_t created_entry_len = FAT_DIRENT_SIZE; - size_t created_entry_pos = 0; - unicode_char ch; - char last_short_char = ' '; - char short_char = '\0'; - char cannonical_short_char; - utf16_char buf[UTF16_CHAR_MAX]; - int i, len; - int sfn_pos = 0; - sfn_disposition_t sfn_disposition = SFN_SUFFICIENT; - int sfn_in_extension = 0; - - /* sanity check */ - if (*filename == '\0') - { - err = IMGTOOLERR_BADFILENAME; - goto done; - } - - /* construct intial entry */ - created_entry = (UINT8 *) malloc(FAT_DIRENT_SIZE); - if (!created_entry) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto done; - } - - /* set up the basics for the new dirent */ - memset(created_entry + 0, ' ', 11); - memset(created_entry + 12, '\0', FAT_DIRENT_SIZE - 12); - created_entry[11] = (create == CREATE_DIR) ? 0x10 : 0x00; - - /* 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); - - while(*filename) - { - filename += uchar_from_utf8(&ch, filename, UTF8_CHAR_MAX); - - /* 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 - short_char = '\0'; /* illegal SFN char */ - cannonical_short_char = fat_cannonicalize_sfn_char((char) ch); - if (!short_char || (short_char != cannonical_short_char)) - { - if (toupper(short_char) == toupper(cannonical_short_char)) - sfn_disposition = MAX(sfn_disposition, SFN_DERIVATIVE); - else - sfn_disposition = SFN_MANGLED; - } - - /* append the short filename char */ - if (short_char == '.') - { - /* multiple extensions or trailing spaces? */ - if (sfn_in_extension) - sfn_disposition = SFN_MANGLED; - else if (last_short_char == ' ') - sfn_disposition = MAX(sfn_disposition, SFN_DERIVATIVE); - - sfn_in_extension = 1; - sfn_pos = 8; - created_entry[created_entry_len - FAT_DIRENT_SIZE + 8] = ' '; - created_entry[created_entry_len - FAT_DIRENT_SIZE + 9] = ' '; - created_entry[created_entry_len - FAT_DIRENT_SIZE + 10] = ' '; - } - else if (sfn_pos == (sfn_in_extension ? 11 : 8)) - { - /* ran out of characters for short filename */ - sfn_disposition = SFN_MANGLED; - } - else if (short_char != '\0') - { - created_entry[created_entry_len - FAT_DIRENT_SIZE + sfn_pos++] = short_char; - } - last_short_char = short_char; - - - /* convert to UTF-16 and add a long filename entry */ - len = utf16le_from_uchar(buf, UTF16_CHAR_MAX, ch); - for (i = 0; i < len; i++) - { - switch(created_entry_pos) - { - case 0: - case 32: - /* need to grow */ - new_created_entry = (UINT8 *) malloc(created_entry_len + FAT_DIRENT_SIZE); - if (!new_created_entry) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto done; - } - - /* move existing entries forward */ - memmove(new_created_entry + 32, created_entry, created_entry_len); - - if (created_entry) free(created_entry); - created_entry = new_created_entry; - created_entry_len += 32; - - /* set up this LFN */ - memset(created_entry, '\0', 32); - memset(&created_entry[1], '\xFF', 10); - memset(&created_entry[14], '\xFF', 12); - memset(&created_entry[28], '\xFF', 4); - created_entry[11] = 0x0F; - - /* specify entry index */ - created_entry[0] = (created_entry_len / 32) - 1; - if (created_entry[0] >= 0x40) - { - err = IMGTOOLERR_BADFILENAME; - goto done; - } - created_entry_pos = 1; - break; - - case 11: - created_entry_pos = 14; - break; - - case 26: - created_entry_pos = 28; - break; - } - - memcpy(&created_entry[created_entry_pos], &buf[i], 2); - created_entry_pos += 2; - } - } - - /* trailing spaces? */ - if (short_char == ' ') - sfn_disposition = MAX(sfn_disposition, SFN_DERIVATIVE); - - if (sfn_disposition == SFN_SUFFICIENT) - { - /* the short filename suffices; remove the LFN stuff */ - memcpy(created_entry, created_entry + created_entry_len - FAT_DIRENT_SIZE, FAT_DIRENT_SIZE); - created_entry_len = FAT_DIRENT_SIZE; - free(created_entry); - new_created_entry = (UINT8 *) malloc(created_entry_len); - if (!new_created_entry) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto done; - } - created_entry = new_created_entry; - } - else - { - /* need to do finishing touches on the LFN */ - created_entry[0] |= 0x40; - - /* if necessary, mangle the name */ - if (sfn_disposition == SFN_MANGLED) - { - i = 6; - while((i > 0) && isspace(created_entry[created_entry_len - FAT_DIRENT_SIZE + i - 1])) - i--; - created_entry[created_entry_len - FAT_DIRENT_SIZE + i + 0] = '~'; - created_entry[created_entry_len - FAT_DIRENT_SIZE + i + 1] = '1'; - } - fat_calc_dirent_lfnchecksum(created_entry, created_entry_len); - } - -done: - if (err && created_entry) - { - free(created_entry); - created_entry = NULL; - } - *entry = created_entry; - *entry_len = created_entry_len; - return err; -} - - - -static void fat_bump_dirent(imgtool_partition *partition, UINT8 *entry, size_t entry_len) -{ - UINT8 *sfn_entry; - int pos, digit_count, i; - UINT32 digit_place, val = 0; - - sfn_entry = &entry[entry_len - FAT_DIRENT_SIZE]; - - digit_place = 1; - for (pos = 7; (pos >= 0) && isdigit((char) sfn_entry[pos]); pos--) - { - val += (sfn_entry[pos] - '0') * digit_place; - digit_place *= 10; - } - val++; - pos++; - - /* count the digits */ - digit_place = 1; - digit_count = 1; - while(val >= digit_place * 10) - { - digit_count++; - digit_place *= 10; - } - - /* give us some more space, if necessary */ - while ((pos > 0) && ((pos + digit_count) > 8)) - pos--; - - /* have we actually ran out of digits */ - if ((pos + digit_count) > 8) - { - /* extreme degenerate case; simply randomize the filename */ - for (i = 0; i < 6; i++) - sfn_entry[i] = 'A' + (imgtool_partition_rand(partition) % 26); - sfn_entry[6] = '~'; - sfn_entry[7] = '0'; - } - else - { - /* write the tilde, if possible */ - if (pos > 0) - sfn_entry[pos - 1] = '~'; - - /* write out the number */ - while(digit_place > 0) - { - sfn_entry[pos++] = (val / digit_place) + '0'; - val %= digit_place; - digit_place /= 10; - } - } - - /* since we changed the short file name, we need to recalc the checksums - * in the LFN entries */ - fat_calc_dirent_lfnchecksum(entry, entry_len); -} - - - -static imgtoolerr_t fat_lookup_path(imgtool_partition *partition, const char *path, - creation_policy_t create, fat_file *file) -{ - imgtoolerr_t err; - const fat_partition_info *disk_info; - fat_dirent ent; - fat_freeentry_info freeent = { 0, }; - const char *next_path_part; - UINT8 *created_entry = NULL; - size_t created_entry_len = 0; - UINT32 entry_sector_index, entry_sector_offset; - UINT32 parent_first_cluster; - int bumped_sfn; - char sfn[13]; - - disk_info = fat_get_partition_info(partition); - - memset(file, 0, sizeof(*file)); - file->root = 1; - file->directory = 1; - file->filesize = disk_info->root_entries * FAT_DIRENT_SIZE; - - while(*path) - { - if (!file->directory) - { - err = IMGTOOLERR_PATHNOTFOUND; - goto done; - } - - next_path_part = path + strlen(path) + 1; - if (create && (*next_path_part == '\0')) - { - /* this is the last entry, and we are creating a file */ - err = fat_construct_dirent(path, create, &created_entry, &created_entry_len); - if (err) - goto done; - - freeent.required_size = created_entry_len; - freeent.candidate_position = ~0; - freeent.position = ~0; - } - - do - { - err = fat_read_dirent(partition, file, &ent, created_entry ? &freeent : NULL); - if (err) - goto done; - - LOG(("fat_lookup_path(): %s/%s: %d\n", ent.short_filename, ent.long_filename, ent.dirent_sector_offset)); - } - while(!ent.eof && core_stricmp(path, ent.short_filename) && core_stricmp(path, ent.long_filename)); - - parent_first_cluster = file->first_cluster; - - if (ent.eof) - { - /* it seems that we have reached the end of this directory */ - if (!created_entry) - { - err = IMGTOOLERR_FILENOTFOUND; - goto done; - } - - if (created_entry_len > FAT_DIRENT_SIZE) - { - /* must ensure uniqueness of the short filename */ - do - { - /* rewind to the beginning of the directory */ - err = fat_seek_file(partition, file, 0); - if (err) - goto done; - - bumped_sfn = FALSE; - fat_cannonicalize_sfn(sfn, &created_entry[created_entry_len - FAT_DIRENT_SIZE]); - - do - { - err = fat_read_dirent(partition, file, &ent, NULL); - if (err) - goto done; - - if (!core_stricmp(sfn, ent.short_filename)) - { - bumped_sfn = TRUE; - fat_bump_dirent(partition, created_entry, created_entry_len); - fat_cannonicalize_sfn(sfn, &created_entry[created_entry_len - FAT_DIRENT_SIZE]); - } - } - while(!ent.eof); - } - while(bumped_sfn); - } - - LOG(("fat_lookup_path(): creating entry; pos=%u length=%u\n", freeent.position, freeent.required_size)); - - err = fat_set_file_size(partition, file, MAX(file->filesize, freeent.position + created_entry_len)); - if (err) - goto done; - - err = fat_seek_file(partition, file, freeent.position); - if (err) - goto done; - - err = fat_write_file(partition, file, created_entry, created_entry_len, NULL); - if (err) - goto done; - - /* we have to do a special seek operation to get the main dirent */ - err = fat_seek_file(partition, file, freeent.position + created_entry_len - FAT_DIRENT_SIZE); - if (err) - goto done; - entry_sector_index = fat_get_filepos_sector_index(partition, file); - entry_sector_offset = file->index % FAT_SECLEN; - - /* build the file struct for the newly created file/directory */ - memset(file, 0, sizeof(*file)); - file->directory = (created_entry[created_entry_len - FAT_DIRENT_SIZE + 11] & 0x10) ? 1 : 0; - file->dirent_sector_index = entry_sector_index; - file->dirent_sector_offset = entry_sector_offset; - } - else - { - /* update the current file */ - memset(file, 0, sizeof(*file)); - file->directory = ent.directory; - file->filesize = ent.filesize; - file->cluster = ent.first_cluster; - file->first_cluster = ent.first_cluster; - file->dirent_sector_index = ent.dirent_sector_index; - file->dirent_sector_offset = ent.dirent_sector_offset; - } - - path = next_path_part; - file->parent_first_cluster = parent_first_cluster; - } - - err = IMGTOOLERR_SUCCESS; - -done: - if (created_entry) - free(created_entry); - return err; -} - - - -static imgtoolerr_t fat_partition_beginenum(imgtool_directory *enumeration, const char *path) -{ - imgtoolerr_t err; - fat_file *file; - - file = (fat_file *) imgtool_directory_extrabytes(enumeration); - - err = fat_lookup_path(imgtool_directory_partition(enumeration), path, CREATE_NONE, file); - if (err) - return err; - if (!file->directory) - return IMGTOOLERR_PATHNOTFOUND; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_partition_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent) -{ - imgtoolerr_t err; - fat_file *file; - fat_dirent fatent; - - file = (fat_file *) imgtool_directory_extrabytes(enumeration); - err = fat_read_dirent(imgtool_directory_partition(enumeration), file, &fatent, NULL); - if (err) - return err; - - /* copy stuff from the FAT dirent to the Imgtool dirent */ - snprintf(ent->filename, ARRAY_LENGTH(ent->filename), "%s", fatent.long_filename[0] - ? fatent.long_filename : fatent.short_filename); - ent->filesize = fatent.filesize; - ent->directory = fatent.directory; - ent->eof = fatent.eof; - ent->creation_time = fatent.creation_time; - ent->lastmodified_time = fatent.lastmodified_time; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_read_bootblock(imgtool_partition *partition, imgtool_stream *stream) -{ - imgtoolerr_t err; - UINT8 block[FAT_SECLEN]; - - err = fat_read_sector(partition, 0, 0, block, sizeof(block)); - if (err) - return err; - - stream_write(stream, block, sizeof(block)); - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_write_bootblock(imgtool_partition *partition, imgtool_stream *stream) -{ - imgtoolerr_t err; - UINT8 block[FAT_SECLEN]; - UINT8 new_block[FAT_SECLEN]; - - if (stream_size(stream) != sizeof(new_block)) - return IMGTOOLERR_UNEXPECTED; - stream_read(stream, new_block, sizeof(new_block)); - - if (new_block[510] != 0x55) - return IMGTOOLERR_UNEXPECTED; - if (new_block[511] != 0xAA) - return IMGTOOLERR_UNEXPECTED; - - /* read current boot sector */ - err = fat_read_sector(partition, 0, 0, block, sizeof(block)); - if (err) - return err; - - /* merge in the new stuff */ - memcpy(&block[ 0], &new_block[ 0], 3); - memcpy(&block[62], &new_block[62], 448); - - /* and write it out */ - err = fat_write_sector(partition, 0, 0, block, sizeof(block)); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_partition_readfile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf) -{ - imgtoolerr_t err; - fat_file file; - size_t bytes_read; - char buffer[1024]; - - /* special case for bootblock */ - if (filename == FILENAME_BOOTBLOCK) - return fat_read_bootblock(partition, destf); - - err = fat_lookup_path(partition, filename, CREATE_NONE, &file); - if (err) - return err; - - if (file.directory) - return IMGTOOLERR_FILENOTFOUND; - - do - { - err = fat_read_file(partition, &file, buffer, sizeof(buffer), &bytes_read); - if (err) - return err; - - stream_write(destf, buffer, bytes_read); - } - while(bytes_read > 0); - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_partition_writefile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, option_resolution *opts) -{ - imgtoolerr_t err; - fat_file file; - UINT32 bytes_left, len; - char buffer[1024]; - - /* special case for bootblock */ - if (filename == FILENAME_BOOTBLOCK) - return fat_write_bootblock(partition, sourcef); - - err = fat_lookup_path(partition, filename, CREATE_FILE, &file); - if (err) - return err; - - if (file.directory) - return IMGTOOLERR_FILENOTFOUND; - - bytes_left = (UINT32) stream_size(sourcef); - - err = fat_set_file_size(partition, &file, bytes_left); - if (err) - return err; - - while(bytes_left > 0) - { - len = MIN(bytes_left, sizeof(buffer)); - stream_read(sourcef, buffer, len); - - err = fat_write_file(partition, &file, buffer, len, NULL); - if (err) - return err; - - bytes_left -= len; - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_partition_delete(imgtool_partition *partition, const char *filename, unsigned int dir) -{ - imgtoolerr_t err; - fat_file file; - fat_dirent ent; - - err = fat_lookup_path(partition, filename, CREATE_NONE, &file); - if (err) - return err; - if (file.directory != dir) - return IMGTOOLERR_FILENOTFOUND; - - if (dir) - { - err = fat_read_dirent(partition, &file, &ent, NULL); - if (err) - return err; - if (!ent.eof) - return IMGTOOLERR_DIRNOTEMPTY; - } - - err = fat_set_file_size(partition, &file, ~0); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_partition_deletefile(imgtool_partition *partition, const char *filename) -{ - return fat_partition_delete(partition, filename, 0); -} - - - -static imgtoolerr_t fat_partition_freespace(imgtool_partition *partition, UINT64 *size) -{ - imgtoolerr_t err; - const fat_partition_info *disk_info; - UINT8 *fat_table; - UINT32 i; - - disk_info = fat_get_partition_info(partition); - - err = fat_load_fat(partition, &fat_table); - if (err) - goto done; - - *size = 0; - for (i = 2; i < disk_info->total_clusters; i++) - { - if (fat_get_fat_entry(partition, fat_table, i) == 0) - *size += disk_info->cluster_size; - } - -done: - if (fat_table) - free(fat_table); - return err; -} - - - -static imgtoolerr_t fat_partition_createdir(imgtool_partition *partition, const char *path) -{ - imgtoolerr_t err; - fat_file file; - UINT8 initial_data[64]; - - err = fat_lookup_path(partition, path, CREATE_DIR, &file); - if (err) - return err; - if (!file.directory) - return IMGTOOLERR_FILENOTFOUND; - - err = fat_set_file_size(partition, &file, sizeof(initial_data)); - if (err) - return err; - - /* 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); - memcpy(&initial_data[32], ". ", 11); - place_integer_le(initial_data, 43, 1, 0x10); - place_integer_le(initial_data, 58, 2, file.parent_first_cluster); - - err = fat_write_file(partition, &file, initial_data, sizeof(initial_data), NULL); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_partition_deletedir(imgtool_partition *partition, const char *path) -{ - return fat_partition_delete(partition, path, 1); -} - - - -void fat_get_info(const imgtool_class *imgclass, UINT32 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_SUPPORTS_BOOTBLOCK: info->i = 1; break; - case IMGTOOLINFO_INT_PATH_SEPARATOR: info->i = '\\'; break; - case IMGTOOLINFO_INT_ALTERNATE_PATH_SEPARATOR: info->i = '/'; break; - case IMGTOOLINFO_INT_PARTITION_EXTRA_BYTES: info->i = sizeof(fat_partition_info); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(fat_file); 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\n"); break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case IMGTOOLINFO_PTR_CREATE_PARTITION: info->create_partition = fat_partition_create; break; - case IMGTOOLINFO_PTR_OPEN_PARTITION: info->open_partition = fat_partition_open; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = fat_partition_beginenum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = fat_partition_nextenum; break; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = fat_partition_readfile; break; - case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = fat_partition_writefile; break; - case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = fat_partition_deletefile; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = fat_partition_freespace; break; - case IMGTOOLINFO_PTR_CREATE_DIR: info->create_dir = fat_partition_createdir; break; - case IMGTOOLINFO_PTR_DELETE_DIR: info->delete_dir = fat_partition_deletedir; break; - } -} diff --git a/src/mess/tools/imgtool/modules/fat.h b/src/mess/tools/imgtool/modules/fat.h deleted file mode 100644 index 46f741999c3..00000000000 --- a/src/mess/tools/imgtool/modules/fat.h +++ /dev/null @@ -1,3 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -void fat_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info); diff --git a/src/mess/tools/imgtool/modules/hp48.c b/src/mess/tools/imgtool/modules/hp48.c deleted file mode 100644 index e54908c9c1e..00000000000 --- a/src/mess/tools/imgtool/modules/hp48.c +++ /dev/null @@ -1,739 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Antoine Mine -/**************************************************************************** - - hp48.c - - Memory cards for HP48 SX/GX - - Antoine Mine' 2014 - -***************************************************************************** -*/ - -/* - HP memory cards can contain two kinds of objects: - - attached libraries - - backup objects (encapsulating any kind of object) - - Attached libraries appear with a LIB attribute in imgtool's listing, and in - the global "LIBRARY" menu on the HP48. - Backup objects appear with a BAK attribute in imgtool's listing, and - in the relevant "PORTS" menu on the HP48. - - Currently, we only support storing host files into backup objects and - retreiving backup objects into files. - For attached library objects in the memory card, we only show their name, but - cannot retrieve their contents. - - To install a library contained in a host file, copy it with imgtool to - the card; it creates a backup object visible in the "PORTS" menu; - then evalue the object, store it into some port (e.g, 0 STO), - turn off the HP48 and back on; the library should now be attached and - visible in the "LIBRARY" menu. - (The process is similar to installing a library from a file you get - from the serial interface.) -*/ - - -/* - HP memory cards have size from 32 KB to 4096 KB. - However, cards with size greater than 128 KB are seen as multiple ports of - size 128 KB on the HP48 GX. In imgtool, we see them as distinct 128 KB - partitions. - Unfortunately, at the moment, partitions do not seem to be supported in the - command-line tool... - */ - - -/* - Here is the format of backup objects (addresses are in 4-bit nibbles): - - offset field size value - 0 prolog 5 02B62 prolog for overall backup object - 5 size 5 len total size in nibble without prolog - 10 name length 2 nbcar object name, in characters - 12 name 2*nbcar - - 12+2*nbcar name length 2 nbcar same value as name length at 10 - 14+2*nbcar object - - - len-5 prolog 5 02911 prolog for inlined system integer - len - 1 0 - len+1 CRC 4 - CRC from 5 to len - - total length: len+4 - - i.e., the backup object is a container containing the object name - and two objects: the backuped object itself and a system integer - that contains the CRC. - - HP48 host files start with a "HPHP48-X" header (where X can be any - single letter, which denotes a ROM revision and, implicitly, whether - the program is for the S/SX or the G/GX family). - When storing a file to the memory card, we strip the header and - embed the object into a backup object with the correct CRC. - When copying from the memory card to a host file, we extract the object - from the backup container, stripping its CRC, and add the HPHP48-X header. - - */ - - - - - -/***************************************************************************** - Includes -*****************************************************************************/ - -#include "imgtool.h" - - - -/***************************************************************************** - Data structures -*****************************************************************************/ - - -struct hp48_card -{ - imgtool_stream *stream; - int modified; - - /* size, in bytes of card data: from 32 KB to 4 MB */ - int size; - - /* we store each nibble (4-bit) into its own byte, for simpler addressing; - hence, data has 2*size - */ - UINT8* data; - -}; - -struct hp48_partition -{ - /* pointer to the beginning of the partition inside the hp48_card */ - UINT8* data; - - /* size, in bytes (128 KB or less) */ - int size; - -}; - -struct hp48_directory -{ - int pos; -}; - - -#define PROLOG_BACKUP 0x02B62 -#define PROLOG_LIBRARY 0x02B40 -#define PROLOG_SYSINT 0x02911 - -/* memory cards are composed solely of libraries and backup objects */ -#define IS_OBJECT(prolog) ((prolog) == PROLOG_LIBRARY || (prolog) == PROLOG_BACKUP) - -/* host files begin with this prefix (up to the last letter) */ -static const char* hp48_prefix = "HPHP48-R"; - - - -static OPTION_GUIDE_START( hp48_create_optionguide ) - OPTION_INT('S', "size", "Size in KB" ) -OPTION_GUIDE_END - -/* size in KB, 128 KB being the default */ -static const char hp48_create_optionspec[] = "S32/64/[128]/256/512/1024/2048/4096"; - - - -/***************************************************************************** - Utility functions -*****************************************************************************/ - - -/* byes to nibbles */ -static void unpack(UINT8* dst, UINT8* src, int nsize) -{ - int i; - - if ( nsize & 1 ) - { - dst[nsize-1] = src[nsize/2] & 0xf; - } - - for ( i = nsize/2-1; i >= 0; i-- ) - { - dst[2*i+1] = src[i] >> 4; - dst[2*i ] = src[i] & 0xf; - } -} - -/* nibbles to bytes */ -static void pack(UINT8* dst, UINT8* src, int nsize) -{ - int i; - - for ( i = 0 ; i < nsize/2; i++ ) - { - dst[i] = (src[2*i] & 0xf) | (src[2*i+1] << 4); - } - - if ( nsize & 1 ) - { - dst[nsize/2] = src[nsize-1] & 0xf; - } - } - - -static int read20(UINT8* data) -{ - return data[0] | (data[1] << 4) | (data[2] << 8) | (data[3] << 12) | (data[4] << 16); -} - -static int read8(UINT8* data) -{ - return data[0] | (data[1] << 4); -} - -static void readstring(char* dst, UINT8* data, int nb) -{ - int i; - for ( i = 0; i < nb; i++ ) - { - dst[i] = read8( data + 2*i ); - } - dst[nb] = 0; -} - -static void write20(UINT8* data, int v) -{ - data[0] = v & 0xf; - data[1] = (v >> 4) & 0xf; - data[2] = (v >> 8) & 0xf; - data[3] = (v >> 12) & 0xf; - data[4] = (v >> 16) & 0xf; -} - -static void write8(UINT8* data, int v) -{ - data[0] = v & 0xf; - data[1] = (v >> 4) & 0xf; -} - -static void writestring(UINT8* data, const char* str, int nb) -{ - int i; - for ( i = 0; i < nb; i++ ) - { - write8( data + 2*i, str[i] ); - } -} - - -/* go to the end, return its offset */ -static int find_end(hp48_partition* p) -{ - int pos = 0; - while (1) - { - if ( pos + 10 > 2*p->size) break; - - int prolog = read20( p->data + pos ); - if ( !IS_OBJECT( prolog )) break; - - pos += read20( p->data + pos + 5 ) + 5; - } - - if ( pos > 2*p->size ) pos = 2*p->size; - return pos; -} - - -/* find the backup object with the given name, returns its offset or -1 (not found) */ -static int find_file(hp48_partition* p, const char* filename, int *ptotalsize, int* pstart, int* pcontentsize) -{ - UINT8* data = p->data; - int pos = 0; - - /* find file */ - while (1) - { - if ( pos + 10 > 2*p->size) return -1; - - /* get prolog */ - int prolog = read20( data+pos ); - if ( !IS_OBJECT(prolog)) return -1; - - /* get size */ - int totalsize = read20( data+pos+5 ); - if ( totalsize < 14) return -1; - if ( pos + 5 + totalsize > 2*p->size ) return -1; - - if ( prolog == PROLOG_BACKUP ) - { - /* get name */ - int namelen = read8( data + pos + 10 ); - char name[257]; - if ( 9 + 2*namelen > totalsize ) return -1; - readstring( name, data + pos + 12, namelen ); - - /* check name */ - if ( !strcmp( name, filename ) ) - { - /* found! */ - if ( ptotalsize ) *ptotalsize = totalsize; - if ( pstart ) *pstart = pos + 14 + 2*namelen; - if ( pcontentsize ) *pcontentsize = totalsize - (9 + 2*namelen); - return pos; - } - else - { - /* skip */ - pos += totalsize + 5; - } - } - else - { - /* skip */ - pos += totalsize + 5; - } - - } - - // never executed - //return -1; -} - - -/* CRC computing. - This is the same CRC that is computed by the HP48 hardware. - */ -static UINT16 crc(UINT8* data, int len) -{ - UINT16 crc = 0; - int i; - - for ( i = 0; i < len; i++ ) - { - crc = (crc >> 4) ^ (((crc ^ data[i]) & 0xf) * 0x1081); - } - - return crc; -} - - - -/***************************************************************************** - Imgtool functions -*****************************************************************************/ - - -static imgtoolerr_t hp48_open(imgtool_image *img, imgtool_stream *stream) -{ - hp48_card* c = (hp48_card*) imgtool_image_extra_bytes( img ); - int size = stream_size( stream ); - - /* check that size is a power of 2 between 32 KB and 4 MG */ - if ( (size < 32 * 1024) || - (size > 4 * 1024 * 1024) || - (size & (size-1)) ) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - - /* store info */ - c->stream = stream; - c->modified = 0; - c->size = size; - c->data = (UINT8*) malloc( 2 * size ); - if ( !c->data ) - { - return IMGTOOLERR_READERROR; - } - - /* fully load image */ - stream_seek( stream, 0, SEEK_SET ); - if ( stream_read( stream, c->data, size ) < size ) - { - return IMGTOOLERR_READERROR; - } - unpack( c->data, c->data, 2 * size ); - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t hp48_create(imgtool_image* img, - imgtool_stream *stream, - option_resolution *opts) -{ - hp48_card* c = (hp48_card*) imgtool_image_extra_bytes( img ); - int size; - - size = option_resolution_lookup_int(opts, 'S'); - - c->stream = stream; - c->modified = 1; - c->size = size * 1024; - c->data = (UINT8*) malloc( 2 * c->size ); - if ( !c->data ) - { - return IMGTOOLERR_READERROR; - } - - /* zeroing the image seems fine */ - memset( c->data, 0, 2 * c->size ); - - return IMGTOOLERR_SUCCESS; -} - - - -static void hp48_close(imgtool_image *img) -{ - hp48_card* c = (hp48_card*) imgtool_image_extra_bytes( img ); - - if ( c->modified ) - { - /* save image */ - pack( c->data, c->data, 2 * c->size ); - stream_seek( c->stream, 0, SEEK_SET ); - stream_write( c->stream, c->data, c->size ); - } - - /* clean up */ - free( c->data ); - stream_close( c->stream ); -} - - - -/* each 128 KB chunk is a distinct partition */ -#define MAX_PORT_SIZE (128*1024) - -void hp48_partition_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info); - -static imgtoolerr_t hp48_list_partitions(imgtool_image *img, - imgtool_partition_info *partitions, - size_t len) -{ - hp48_card* c = (hp48_card*) imgtool_image_extra_bytes( img ); - - int i; - for ( i = 0; i < len && i * MAX_PORT_SIZE < c->size ; i++ ) - { - /* offset and size in bytes */ - partitions[i].base_block = i * MAX_PORT_SIZE; - partitions[i].block_count = c->size - partitions[i].base_block; - if ( partitions[i].block_count > MAX_PORT_SIZE ) - { - partitions[i].block_count = MAX_PORT_SIZE; - } - - partitions[i].get_info = hp48_partition_get_info; - } - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t hp48_open_partition(imgtool_partition *part, - UINT64 first_block, UINT64 block_count) -{ - imgtool_image* img = imgtool_partition_image( part ); - hp48_card* c = (hp48_card*) imgtool_image_extra_bytes( img ); - hp48_partition* p = (hp48_partition*) imgtool_partition_extra_bytes( part ); - - if ( first_block + block_count > c->size ) - return IMGTOOLERR_INVALIDPARTITION; - - /* store partition position */ - p->data = c->data + first_block; - p->size = block_count; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t hp48_beginenum(imgtool_directory *enumeration, - const char *path) -{ - hp48_directory* d = (hp48_directory*) imgtool_directory_extrabytes( enumeration ); - - d->pos = 0; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t hp48_nextenum(imgtool_directory *enumeration, - imgtool_dirent *ent) -{ - imgtool_partition *part = imgtool_directory_partition( enumeration ); - //imgtool_image* img = imgtool_partition_image( part ); - //hp48_card* c = (hp48_card*) imgtool_image_extra_bytes( img ); - hp48_partition* p = (hp48_partition*) imgtool_partition_extra_bytes( part ); - hp48_directory* d = (hp48_directory*) imgtool_directory_extrabytes( enumeration ); - - UINT8* data = p->data; - int pos = d->pos; - - if ( pos < 0 || pos+12 > 2*p->size ) - { - ent->eof = 1; - return IMGTOOLERR_SUCCESS; - } - - int prolog = read20( data+pos ); - - if ( IS_OBJECT(prolog) ) - { - pos += 5; - int totalsize = read20( data+pos ); - pos += 5; - - int namelen = read8( data+pos ); - pos += 2; - if ( (pos + 2*namelen > 2*p->size) || - (namelen >= sizeof(ent->filename)) ) - { - ent->eof = 1; - return IMGTOOLERR_CORRUPTFILE; - } - readstring( ent->filename, data+pos, namelen ); - - /* compute size in bytes, removing name, length & CRC fields */ - ent->filesize = ((totalsize - 19 - 2*namelen) + 1) / 2; - - switch (prolog) - { - case PROLOG_LIBRARY: strncpy( ent->attr, "LIB", sizeof(ent->attr) ); break; - case PROLOG_BACKUP: strncpy( ent->attr, "BAK", sizeof(ent->attr) ); break; - default: strncpy( ent->attr, "?", sizeof(ent->attr) ); - } - - d->pos = d->pos + totalsize + 5; - } - else - { - /* 0 or unknown object => end */ - ent->eof = 1; - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t hp48_freespace(imgtool_partition *part, UINT64 *size) -{ - //imgtool_image* img = imgtool_partition_image( part ); - //hp48_card* c = (hp48_card*) imgtool_image_extra_bytes( img ); - hp48_partition* p = (hp48_partition*) imgtool_partition_extra_bytes( part ); - - *size = p->size - (find_end(p)+1)/2; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t hp48_readfile(imgtool_partition *part, - const char *filename, - const char *fork, - imgtool_stream *destf) -{ - //imgtool_image* img = imgtool_partition_image( part ); - //hp48_card* c = (hp48_card*) imgtool_image_extra_bytes( img ); - hp48_partition* p = (hp48_partition*) imgtool_partition_extra_bytes( part ); - - /* find entry */ - int totalsize, start, size; - int pos = find_file(p, filename, &totalsize, &start, &size); - if ( pos == -1 ) - { - return IMGTOOLERR_FILENOTFOUND; - } - - /* CRC check */ - UINT16 objcrc = read20( p->data + pos + totalsize ) >> 4; - UINT16 mycrc = crc( p->data + pos + 5, totalsize - 4); - if ( objcrc != mycrc ) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - size -= 10; - - /* save header */ - stream_write( destf, hp48_prefix, 8); - - /* save contents to host file */ - int bytesize = (size + 1) / 2; - UINT8* buf = (UINT8*) malloc( bytesize ); - if (!buf) - { - return IMGTOOLERR_FILENOTFOUND; - } - pack( buf, p->data + start, size ); - stream_write( destf, buf, bytesize ); - free( buf ); - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t hp48_deletefile(imgtool_partition *part, - const char *filename) -{ - imgtool_image* img = imgtool_partition_image( part ); - hp48_card* c = (hp48_card*) imgtool_image_extra_bytes( img ); - hp48_partition* p = (hp48_partition*) imgtool_partition_extra_bytes( part ); - - /* find entry */ - int totalsize; - int pos = find_file(p, filename, &totalsize, NULL, NULL ); - if ( pos == -1 ) - { - return IMGTOOLERR_FILENOTFOUND; - } - - /* move */ - totalsize += 5; - memmove( p->data+pos, p->data+pos+totalsize, 2*p->size-(pos+totalsize) ); - memset( p->data + 2*p->size-totalsize, 0, totalsize); - c->modified = 1; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t hp48_writefile(imgtool_partition *part, - const char *filename, - const char *fork, - imgtool_stream *sourcef, - option_resolution *opts) -{ - imgtool_image* img = imgtool_partition_image( part ); - hp48_card* c = (hp48_card*) imgtool_image_extra_bytes( img ); - hp48_partition* p = (hp48_partition*) imgtool_partition_extra_bytes( part ); - - /* check header */ - char head[8]; - stream_read( sourcef, head, 8 ); - if ( memcmp( head, hp48_prefix, 7) ) - { - return IMGTOOLERR_READERROR; - } - - /* ensure that the file does not exist */ - /* TODO: resize the existing file instead, to keep it in place? */ - hp48_deletefile( part, filename ); - - /* goto end */ - //UINT8* data = p->data; - int pos = find_end(p); - - int len = strlen( filename ); - if ( len > 255 ) len = 255; - - /* check size */ - int filesize = stream_size( sourcef ) - 8; - if ( pos + 2*filesize + 24 + 2*len > 2 * p->size ) - { - return IMGTOOLERR_NOSPACE; - } - - /* load file */ - UINT8* buf = (UINT8*) malloc( filesize ); - if ( !buf ) return IMGTOOLERR_NOSPACE; - stream_read( sourcef, buf, filesize ); - - /* store backup object */ - int org = pos; - int totalsize = 2*filesize + 19 + 2*len; - write20( p->data+pos, PROLOG_BACKUP ); - pos +=5; - write20( p->data+pos, totalsize ); - pos +=5; - write8( p->data+pos, len ); - pos += 2; - writestring( p->data+pos, filename, len ); - pos += 2*len; - write8( p->data+pos, len ); - pos += 2; - unpack( p->data+pos, buf, 2*filesize ); - pos += 2*filesize; - - /* store crc */ - write20( p->data+pos, PROLOG_SYSINT ); - pos += 5; - p->data[pos] = 0; - write20( p->data+pos, crc(p->data+org+5, totalsize-4) << 4 ); - - free(buf); - - c->modified = 1; - - return IMGTOOLERR_SUCCESS; -} - - - - -/***************************************************************************** - Imgtool module declaration -*****************************************************************************/ - - - -void hp48_partition_get_info(const imgtool_class *imgclass, UINT32 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(), "hp48"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "HP48 SX/GX memory card"); break; - case IMGTOOLINFO_STR_FILE: strcpy(info->s = imgtool_temp_str(), __FILE__); break; - case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "crd"); break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case IMGTOOLINFO_PTR_OPEN_PARTITION: info->open_partition = hp48_open_partition; break; - case IMGTOOLINFO_PTR_CLOSE: info->close = hp48_close; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = hp48_beginenum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = hp48_nextenum; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = hp48_freespace; break; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = hp48_readfile; break; - case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = hp48_writefile; break; - case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = hp48_deletefile; break; - - case IMGTOOLINFO_INT_PARTITION_EXTRA_BYTES: info->i = sizeof(hp48_partition); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(hp48_directory); break; - - } -} - -void hp48_get_info(const imgtool_class *imgclass, UINT32 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(), "hp48"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "HP48 SX/GX memory card"); break; - case IMGTOOLINFO_STR_FILE: strcpy(info->s = imgtool_temp_str(), __FILE__); break; - case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "crd"); break; - case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), hp48_create_optionspec); break; - - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = hp48_create_optionguide; break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case IMGTOOLINFO_PTR_OPEN: info->open = hp48_open; break; - case IMGTOOLINFO_PTR_CREATE: info->create = hp48_create; break; - case IMGTOOLINFO_PTR_CLOSE: info->close = hp48_close; break; - case IMGTOOLINFO_PTR_LIST_PARTITIONS: info->list_partitions = hp48_list_partitions; break; - - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: info->i = sizeof(hp48_card); break; - } -} diff --git a/src/mess/tools/imgtool/modules/mac.c b/src/mess/tools/imgtool/modules/mac.c deleted file mode 100644 index 53ae4be3ec0..00000000000 --- a/src/mess/tools/imgtool/modules/mac.c +++ /dev/null @@ -1,6418 +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 bytes[2]; -}; - -struct UINT24BE -{ - UINT8 bytes[3]; -}; - -struct UINT32BE -{ - UINT8 bytes[4]; -}; - -INLINE UINT16 get_UINT16BE(UINT16BE word) -{ - return (word.bytes[0] << 8) | word.bytes[1]; -} - -INLINE void set_UINT16BE(UINT16BE *word, UINT16 data) -{ - word->bytes[0] = (data >> 8) & 0xff; - word->bytes[1] = data & 0xff; -} - -#if 0 -INLINE UINT32 get_UINT24BE(UINT24BE word) -{ - return (word.bytes[0] << 16) | (word.bytes[1] << 8) | word.bytes[2]; -} - -INLINE void set_UINT24BE(UINT24BE *word, UINT32 data) -{ - word->bytes[0] = (data >> 16) & 0xff; - word->bytes[1] = (data >> 8) & 0xff; - word->bytes[2] = data & 0xff; -} -#endif - -INLINE UINT32 get_UINT32BE(UINT32BE word) -{ - return (word.bytes[0] << 24) | (word.bytes[1] << 16) | (word.bytes[2] << 8) | word.bytes[3]; -} - -INLINE void set_UINT32BE(UINT32BE *word, UINT32 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 mac_str27[28]; -typedef UINT8 mac_str31[32]; -typedef UINT8 mac_str63[64]; -typedef UINT8 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 script; /* System 7: if high-bit is set, the script code - for displaying the file name; ignored otherwise */ - /* System 8: Extended flags MSB(?) */ - UINT8 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 script; /* System 7: if high-bit is set, the script code - for displaying the folder name; ignored otherwise */ - /* System 8: Extended flags MSB(?) */ - UINT8 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 *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 *s1, const UINT8 *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 *s1, const UINT8 *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. -*/ -INLINE void mac_strcpy(UINT8 *dest, const UINT8 *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 *dest, int n, const UINT8 *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 heads; -}; - - - -static imgtoolerr_t mac_find_block(mac_l1_imgref *image, int block, - UINT32 *track, UINT32 *head, UINT32 *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 block, void *dest) -{ - imgtoolerr_t err; - floperr_t ferr; - UINT32 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 block, const void *src) -{ - imgtoolerr_t err; - floperr_t ferr; - UINT32 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 -*/ -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 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 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 dir_num_files; - UINT16 dir_start; - UINT16 dir_blk_len; - - UINT16 ABStart; - - mac_str27 volname; - - unsigned char ABlink_dirty[13]; /* dirty flag for each disk block in the ABlink array */ - UINT8 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 stBlk; /* first allocation block of file */ -}; - -/* - HFS open file ref -*/ -struct hfs_fileref -{ - hfs_extent_3 extents; /* first 3 file extents */ - - UINT32 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 fileID; /* file ID (a.k.a. CNID in HFS/HFS+) */ - - mac_forkID forkType; /* 0x00 for data, 0xff for resource */ - - UINT32 eof; /* logical end-of-file */ - UINT32 pLen; /* physical end-of-file */ - - UINT32 crPs; /* current position in file */ - - UINT8 reload_buf; - UINT8 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 nodeSize; /* size of a node, in bytes */ - UINT32 rootNode; /* node number of root node */ - UINT32 firstLeafNode; /* node number of first leaf node */ - UINT32 attributes; /* persistent attributes about the tree */ - UINT16 treeDepth; /* maximum height (usually leaf nodes) */ - UINT16 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 VBM_start; - - UINT16 ABStart; - - mac_str27 volname; - - mac_BTref extents_BT; - mac_BTref cat_BT; - - UINT8 VBM[8192]; -}; - -/* - MFS/HFS image ref -*/ -struct mac_l2_imgref -{ - mac_l1_imgref l1_img; - - UINT16 numABs; - UINT16 blocksperAB; - - UINT16 freeABs; - - UINT32 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 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 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 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 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 raw[512]; -}; - -/* - Information extracted from catalog/directory -*/ -struct mac_dirent -{ - UINT16 dataRecType; /* type of data record */ - - mac_FInfo flFinderInfo; /* information used by the Finder */ - mac_FXInfo flXFinderInfo; /* information used by the Finder */ - - UINT8 flags; /* bit 0=1 if file locked */ - - UINT32 fileID; /* file ID in directory/catalog */ - - UINT32 dataLogicalSize; /* logical EOF of data fork */ - UINT32 dataPhysicalSize; /* physical EOF of data fork */ - UINT32 rsrcLogicalSize; /* logical EOF of resource fork */ - UINT32 rsrcPhysicalSize; /* physical EOF of resource fork */ - - UINT32 createDate; /* date and time of creation */ - UINT32 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 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 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 block_num, UINT32 *block_address); -static imgtoolerr_t hfs_file_get_nth_block_address(struct mac_fileref *fileref, UINT32 block_num, UINT32 *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 *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 parID, const mac_str255 filename, mac_forkID fork, struct mac_fileref *fileref); -static imgtoolerr_t mfs_file_setABeof(struct mac_fileref *fileref, UINT32 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 *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 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 len, void *dest) -{ - UINT32 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 *)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 len, const void *src) -{ - UINT32 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 *)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 *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 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 newEof) -{ - UINT32 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 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 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 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 unknown0[2]; /* $00: $0004 for disk, $0008 for folder??? */ - mac_point location; /* $02: location in parent window */ - UINT8 unknown1[4]; /* $06: ??? */ - UINT8 view; /* $0A: manner in which folders are displayed??? */ - UINT8 unknown2; /* $0B: ??? */ - UINT16BE par_fldr; /* $0C: parent folder ID */ - UINT8 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 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 unknown1[20]; /* ??? */ - UINT8 name[1]; /* variable-length macintosh string */ - } v2; - } u; -}; - -/* - MFS open dir ref -*/ -struct mfs_dirref -{ - struct mac_l2_imgref *l2_img; /* image pointer */ - UINT16 index; /* current file index in the disk directory */ - UINT16 cur_block; /* current block offset in directory file */ - UINT16 cur_offset; /* current byte offset in current block of directory file */ - UINT8 block_buffer[512]; /* buffer with current directory block */ -}; - - - -static imgtoolerr_t mfs_image_create(imgtool_image *image, imgtool_stream *stream, option_resolution *opts) -{ - imgtoolerr_t err; - UINT8 buffer[512]; - UINT32 heads, tracks, sector_bytes, i; - UINT32 total_disk_blocks, total_allocation_blocks, allocation_block_size; - UINT32 free_allocation_blocks; - - heads = option_resolution_lookup_int(opts, 'H'); - tracks = option_resolution_lookup_int(opts, 'T'); - sector_bytes = option_resolution_lookup_int(opts, 'L'); - - get_imgref(image)->l1_img.image = 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 *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 = 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 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 *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 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 cur_block; - UINT16 cur_offset; - UINT8 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 mfs_get_ABlink(struct mac_l2_imgref *l2_img, UINT16 AB_address) -{ - UINT16 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 AB_address, UINT16 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 block_num, UINT32 *block_address) -{ - UINT32 AB_num; - UINT32 i; - UINT16 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 lastAB, UINT32 allocABs, UINT32 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 newABeof) -{ - UINT16 AB_address = 0; - UINT16 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 keyLength; /* length of key, excluding this field */ - UINT8 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) -}; - -/* - HFS catalog B-tree key -*/ -struct hfs_catKey -{ - UINT8 keyLen; /* key length */ - UINT8 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 flags; /* file flags */ - UINT8 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 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 *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 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 *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 = 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 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 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 *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 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 parID, const mac_str255 filename, mac_forkID fork, struct mac_fileref *fileref) -{ - hfs_catKey *catrec_key; - hfs_catData *catrec_data; - UINT16 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 block_num, UINT32 *block_address) -{ - UINT32 AB_num; - UINT32 cur_AB; - UINT32 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 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 kind; /* kind of node (leaf, index, header, map) */ - UINT8 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 btreeType; /* reserved - set to 0 */ - UINT8 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 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 node_numRecords = get_UINT16BE(((BTNodeHeader *) node_buf)->numRecords); - UINT16 offset; - UINT16 next_offset; - - if (recnum >= node_numRecords) - return IMGTOOLERR_UNEXPECTED; - - offset = get_UINT16BE(((UINT16BE *)((UINT8 *) node_buf + BTref->nodeSize))[-recnum-1]); - next_offset = get_UINT16BE(((UINT16BE *)((UINT8 *) node_buf + BTref->nodeSize))[-recnum-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 *)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 *)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 *)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 *)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 node_num; - UINT32 cur_rec; - UINT32 num_recs; -}; -static imgtoolerr_t BT_check(mac_BTref *BTref, int is_extent) -{ - UINT16 node_numRecords; - BTHeaderRecord *header_rec; - UINT8 *bitmap; - - data_nodes_t *data_nodes; - int i, j; - UINT32 cur_node, prev_node; - void *rec1, *rec2; - int rec1_len, rec2_len; - void *rec1_data; - int rec1_data_len; - UINT32 totalNodes, lastLeafNode; - UINT32 freeNodes; - int compare_result; - UINT32 map_count, map_len; - UINT32 run_len; - UINT32 run_bit_len; - UINT32 actualFreeNodes; - imgtoolerr_t err; - UINT32 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)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*)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)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 *)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 *)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) - return IMGTOOLERR_CORRUPTIMAGE; - -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 *node_ID, int *record_ID, - void **record_ptr, int *record_len, - int search_exact_match, int *match_found) -{ - imgtoolerr_t err; - int i; - UINT32 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 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 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 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 data_offs; /* Offset from beginning of resource file to resource data */ - UINT32 map_offs; /* Offset from beginning of resource file to resource data */ - - UINT16 typelist_offs; /* Offset from beginning of map to resource type list */ - UINT16 namelist_offs; /* Offset from beginning of map to resource name list */ - UINT16 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 type, UINT16 id, rsrc_ref_entry *entry) -{ - imgtoolerr_t err; - rsrc_type_entry type_entry; - UINT16 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 name_offs; - UINT8 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 *len) -{ - imgtoolerr_t err; - UINT32 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 offset, UINT32 len, void *dest) -{ - imgtoolerr_t err; - UINT32 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 id, mac_str255 comment) -{ - static const UINT8 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 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, char *string, size_t len); -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 *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, 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, char *string, size_t len) -{ - struct mac_l2_imgref *image = get_imgref(img); - - switch (image->format) - { - case L2I_MFS: - mac_to_c_strncpy(string, len, image->u.mfs.volname); - break; - - case L2I_HFS: - mac_to_c_strncpy(string, len, image->u.hfs.volname); - break; - } -} - -/* - 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(imgtool_directory_image(enumeration)); - mac_iterator *iter = (mac_iterator *) imgtool_directory_extrabytes(enumeration); - 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 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 *) imgtool_directory_extrabytes(enumeration); - - 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 *size) -{ - imgtool_image *image = imgtool_partition_image(partition); - *size = ((UINT64) 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 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 = imgtool_partition_image(partition); - struct mac_l2_imgref *image = get_imgref(img); - UINT32 parID; - mac_str255 filename; - mac_dirent cat_info; - mac_fileref fileref; - UINT8 buf[512]; - UINT32 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 = MIN(data_len - i, sizeof(buf)); - - err = mac_file_read(&fileref, run_len, buf); - if (err) - return err; - if (stream_write(destf, 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, option_resolution *writeoptions) -{ - imgtool_image *img = imgtool_partition_image(partition); - struct mac_l2_imgref *image = get_imgref(img); - UINT32 parID; - mac_str255 filename; - mac_dirent cat_info; - mac_fileref fileref; - UINT32 fork_len; - /*UINT16 commentID;*/ - /*mac_str255 comment;*/ - UINT8 buf[512]; - UINT32 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 = stream_size(sourcef); - /*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 (stream_read(sourcef, 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, imgtool_forkent *ents, size_t len) -{ - imgtoolerr_t err; - UINT32 parID; - mac_str255 filename; - mac_dirent cat_info; - int fork_num = 0; - imgtool_image *img = imgtool_partition_image(partition); - 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 */ - ents[fork_num].type = FORK_DATA; - ents[fork_num].forkname[0] = '\0'; - ents[fork_num].size = cat_info.dataLogicalSize; - fork_num++; - - if (cat_info.rsrcLogicalSize > 0) - { - /* specify the resource fork */ - ents[fork_num].type = FORK_RESOURCE; - strcpy(ents[fork_num].forkname, "RESOURCE_FORK"); - ents[fork_num].size = cat_info.rsrcLogicalSize; - fork_num++; - } - - ents[fork_num].type = FORK_END; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t mac_image_getattrs(imgtool_partition *partition, const char *path, const UINT32 *attrs, imgtool_attribute *values) -{ - imgtoolerr_t err; - imgtool_image *img = imgtool_partition_image(partition); - UINT32 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); - break; - case IMGTOOLATTR_TIME_LASTMODIFIED: - values[i].t = mac_crack_time(cat_info.modifyDate); - break; - } - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t mac_image_setattrs(imgtool_partition *partition, const char *path, const UINT32 *attrs, const imgtool_attribute *values) -{ - imgtoolerr_t err; - UINT32 parID; - mac_str255 filename; - mac_dirent cat_info; - imgtool_image *img = imgtool_partition_image(partition); - 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 resource_type, - int (*discriminator)(const void *resource, UINT16 id, UINT32 length, void *param_), - void *param, UINT16 *resource_id, UINT32 *resource_length) -{ - UINT32 resource_data_offset, resource_data_length; - UINT32 resource_map_offset, resource_map_length; - UINT32 resource_typelist_count, resource_typelist_offset; - UINT32 resource_entry_offset, resource_entry_count; - UINT32 i, this_resource_type; - UINT32 this_resource_data, this_resource_length; - UINT16 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 *) 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 id, UINT32 length, void *param) -{ - const UINT16 *id_ptr = (const UINT16 *) param; - return id == *id_ptr; -} - - - -static const void *mac_get_resource(const void *resource_fork, size_t resource_fork_length, - UINT32 resource_type, UINT16 resource_id, UINT32 *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 id, UINT32 length, void *param) -{ - UINT32 this_creator_code = pick_integer_be(resource, 0, 4); - UINT32 desired_creator_code = *((UINT32 *) param); - return this_creator_code == desired_creator_code; -} - - - -static int get_pixel(const UINT8 *src, int width, int height, int bpp, - int x, int y) -{ - UINT8 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 int load_icon(UINT32 *dest, const void *resource_fork, UINT64 resource_fork_length, - UINT32 resource_type, UINT16 resource_id, int width, int height, int bpp, - const UINT32 *palette, int has_mask) -{ - int success = FALSE; - int y, x, color, is_masked; - UINT32 pixel; - const UINT8 *src; - UINT32 resource_length; - UINT32 frame_length; - UINT32 total_length; - - frame_length = width * height * bpp / 8; - total_length = frame_length * (has_mask ? 2 : 1); - - /* attempt to fetch resource */ - src = (const UINT8*)mac_get_resource(resource_fork, resource_fork_length, resource_type, - resource_id, &resource_length); - if (src && (resource_length == total_length)) - { - for (y = 0; y < height; y++) - { - for (x = 0; x < width; x ++) - { - /* first check mask bit */ - if (has_mask) - is_masked = get_pixel(src + frame_length, width, height, bpp, x, y); - else - is_masked = dest[y * width + x] >= 0x80000000; - - if (is_masked) - { - /* mask is ok; check the actual icon */ - color = get_pixel(src, width, height, bpp, x, y); - pixel = palette[color] | 0xFF000000; - } - else - { - /* masked out; nothing */ - pixel = 0; - } - - 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 mac_palette_1bpp[2] = { 0xFFFFFF, 0x000000 }; - - static const UINT32 mac_palette_4bpp[16] = - { - 0xFFFFFF, 0xFCF305, 0xFF6402, 0xDD0806, 0xF20884, 0x4600A5, - 0x0000D4, 0x02ABEA, 0x1FB714, 0x006411, 0x562C05, 0x90713A, - 0xC0C0C0, 0x808080, 0x404040, 0x000000 - }; - - static const UINT32 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 attrs[4] = - { - IMGTOOLATTR_INT_MAC_TYPE, - IMGTOOLATTR_INT_MAC_CREATOR, - IMGTOOLATTR_INT_MAC_FINDERFLAGS - }; - - imgtoolerr_t err; - imgtool_attribute attr_values[3]; - UINT32 type_code, creator_code, finder_flags; - imgtool_stream *stream = NULL; - const void *resource_fork; - UINT64 resource_fork_length; - const void *bundle; - UINT32 bundle_length, pos, fref_pos, icn_pos, i; - UINT16 local_id = 0, resource_id; - UINT32 fref_bundleentry_length, icn_bundleentry_length; - const void *fref; - UINT32 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) - goto done; - type_code = (UINT32) attr_values[0].i; - creator_code = (UINT32) attr_values[1].i; - finder_flags = (UINT32) 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 = stream_open_mem(NULL, 0); - if (!stream) - { - err = IMGTOOLERR_SUCCESS; - goto done; - } - - /* read in the resource fork */ - err = mac_image_readfile(partition, path, "RESOURCE_FORK", stream); - if (err) - goto done; - resource_fork = stream_getptr(stream); - resource_fork_length = stream_size(stream); - - /* 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) - goto done; - - /* 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 this_bundleentry_type = pick_integer_be(bundle, pos + 0, 4); - UINT32 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) - goto done; - - /* 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) - goto done; - - /* 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) - goto done; - - /* fetch 32x32 icons (ICN#, icl4, icl8) */ - if (load_icon((UINT32 *) 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 *) iconinfo->icon32x32, resource_fork, resource_fork_length, - /* icl4 */ 0x69636C34, resource_id, 32, 32, 4, mac_palette_4bpp, FALSE); - load_icon((UINT32 *) 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 *) 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 *) iconinfo->icon32x32, resource_fork, resource_fork_length, - /* ics4 */ 0x69637334, resource_id, 32, 32, 4, mac_palette_4bpp, FALSE); - load_icon((UINT32 *) iconinfo->icon32x32, resource_fork, resource_fork_length, - /* ics8 */ 0x69637338, resource_id, 32, 32, 8, mac_palette_8bpp, FALSE); - } - -done: - if (stream) - stream_close(stream); - 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 parID; - mac_str255 filename; - mac_dirent cat_info; - imgtool_image *img = imgtool_partition_image(partition); - 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; -} - - - -/************************************* - * - * Module population - * - *************************************/ - -static void generic_mac_get_info(const imgtool_class *imgclass, UINT32 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; - } -} - - - -void mac_mfs_get_info(const imgtool_class *imgclass, UINT32 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 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/mess/tools/imgtool/modules/macbin.c b/src/mess/tools/imgtool/modules/macbin.c deleted file mode 100644 index 3ef85a039d1..00000000000 --- a/src/mess/tools/imgtool/modules/macbin.c +++ /dev/null @@ -1,377 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/**************************************************************************** - - macbin.c - - 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 pad128(UINT32 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 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 header[128]; - const char *basename; - int i; - - UINT32 type_code = 0x3F3F3F3F; - UINT32 creator_code = 0x3F3F3F3F; - UINT16 finder_flags = 0; - UINT16 coord_x = 0; - UINT16 coord_y = 0; - UINT16 finder_folder = 0; - UINT8 script_code = 0; - UINT8 extended_flags = 0; - - imgtool_forkent fork_entries[4]; - const imgtool_forkent *data_fork = NULL; - const imgtool_forkent *resource_fork = NULL; - UINT32 creation_time = 0; - UINT32 lastmodified_time = 0; - imgtool_attribute attr_values[10]; - - /* get the forks */ - err = imgtool_partition_list_file_forks(partition, filename, fork_entries, sizeof(fork_entries)); - if (err) - return err; - for (i = 0; fork_entries[i].type != FORK_END; i++) - { - if (fork_entries[i].type == FORK_DATA) - data_fork = &fork_entries[i]; - else if (fork_entries[i].type == FORK_RESOURCE) - resource_fork = &fork_entries[i]; - } - - /* get the attributes */ - err = imgtool_partition_get_file_attributes(partition, 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)); - - stream_write(destf, header, sizeof(header)); - - if (data_fork) - { - err = imgtool_partition_read_file(partition, filename, "", destf, NULL); - if (err) - return err; - - stream_fill(destf, 0, pad128(data_fork->size)); - } - - if (resource_fork) - { - err = imgtool_partition_read_file(partition, filename, "RESOURCE_FORK", destf, NULL); - if (err) - return err; - - stream_fill(destf, 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 pos, UINT64 fork_len, option_resolution *opts) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - imgtool_stream *mem_stream = NULL; - size_t len; - - if (fork_len > 0) - { - mem_stream = stream_open_mem(NULL, 0); - if (!mem_stream) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto done; - } - - stream_seek(sourcef, pos, SEEK_SET); - len = stream_transfer(mem_stream, sourcef, fork_len); - if (len < fork_len) - stream_fill(mem_stream, 0, fork_len); - - stream_seek(mem_stream, 0, SEEK_SET); - err = imgtool_partition_write_file(partition, filename, fork, mem_stream, opts, NULL); - if (err) - goto done; - } - -done: - if (mem_stream) - stream_close(mem_stream); - return err; -} - - - -static imgtoolerr_t macbinary_writefile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, option_resolution *opts) -{ - static const UINT32 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 = imgtool_partition_image(partition); - UINT8 header[128]; - UINT32 datafork_size; - UINT32 resourcefork_size; - UINT64 total_size; - UINT32 creation_time; - UINT32 lastmodified_time; - //int version; - imgtool_attribute attr_values[10]; - - UINT32 type_code; - UINT32 creator_code; - UINT16 finder_flags; - UINT16 coord_x; - UINT16 coord_y; - UINT16 finder_folder; - UINT8 script_code = 0; - UINT8 extended_flags = 0; - - /* read in the header */ - memset(header, 0, sizeof(header)); - stream_read(sourcef, 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 = stream_size(sourcef); - - /* 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); - attr_values[1].t = mac_crack_time(lastmodified_time); - 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 = imgtool_partition_put_file_attributes(partition, filename, attrs, attr_values); - if (err) - return err; - } - - return IMGTOOLERR_SUCCESS; -} - - - -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; -} - - - -void filter_macbinary_getinfo(UINT32 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/mess/tools/imgtool/modules/macutil.c b/src/mess/tools/imgtool/modules/macutil.c deleted file mode 100644 index fe2e1ade51a..00000000000 --- a/src/mess/tools/imgtool/modules/macutil.c +++ /dev/null @@ -1,89 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/**************************************************************************** - - macutil.c - - Imgtool Utility code for manipulating certain Apple/Mac data structures - and conventions - -*****************************************************************************/ - -#include "macutil.h" - - -time_t mac_crack_time(UINT32 t) -{ - /* not sure if this is correct... */ - return t - (((1970 - 1904) * 365) + 17) * 24 * 60 * 60; -} - - - -UINT32 mac_setup_time(time_t t) -{ - /* not sure if this is correct... */ - return t + (((1970 - 1904) * 365) + 17) * 24 * 60 * 60; -} - - - -UINT32 mac_time_now(void) -{ - time_t now; - time(&now); - return mac_setup_time(now); -} - - - -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] = 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/mess/tools/imgtool/modules/macutil.h b/src/mess/tools/imgtool/modules/macutil.h deleted file mode 100644 index 71121dade31..00000000000 --- a/src/mess/tools/imgtool/modules/macutil.h +++ /dev/null @@ -1,42 +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 */ -time_t mac_crack_time(UINT32 t); -UINT32 mac_setup_time(time_t t); -UINT32 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/mess/tools/imgtool/modules/os9.c b/src/mess/tools/imgtool/modules/os9.c deleted file mode 100644 index 2a9e2fb0292..00000000000 --- a/src/mess/tools/imgtool/modules/os9.c +++ /dev/null @@ -1,1244 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/**************************************************************************** - - os9.c - - CoCo OS-9 disk images - -****************************************************************************/ - -#include <time.h> - -#include "imgtool.h" -#include "formats/imageutl.h" -#include "formats/coco_dsk.h" -#include "iflopimg.h" - -enum creation_policy_t -{ - CREATE_NONE, - CREATE_FILE, - CREATE_DIR -}; - -struct os9_diskinfo -{ - UINT32 total_sectors; - UINT32 sectors_per_track; - UINT32 allocation_bitmap_bytes; - UINT32 cluster_size; - UINT32 root_dir_lsn; - UINT32 owner_id; - UINT32 attributes; - UINT32 disk_id; - UINT32 format_flags; - UINT32 bootstrap_lsn; - UINT32 bootstrap_size; - UINT32 sector_size; - - unsigned int sides : 2; - unsigned int double_density : 1; - unsigned int double_track : 1; - unsigned int quad_track_density : 1; - unsigned int octal_track_density : 1; - - char name[33]; - UINT8 *allocation_bitmap; -}; - - -struct os9_fileinfo -{ - unsigned int directory : 1; - unsigned int non_sharable : 1; - unsigned int public_execute : 1; - unsigned int public_write : 1; - unsigned int public_read : 1; - unsigned int user_execute : 1; - unsigned int user_write : 1; - unsigned int user_read : 1; - - UINT32 lsn; - UINT32 owner_id; - UINT32 link_count; - UINT32 file_size; - - struct - { - UINT32 lsn; - UINT32 count; - } sector_map[48]; -}; - - -struct os9_direnum -{ - struct os9_fileinfo dir_info; - UINT32 index; -}; - - - -static void pick_string(const void *ptr, size_t offset, size_t length, char *dest) -{ - UINT8 b; - - while(length--) - { - b = ((UINT8 *) ptr)[offset++]; - *(dest++) = b & 0x7F; - if (b & 0x80) - length = 0; - } - *dest = '\0'; -} - - - -static void place_string(void *ptr, size_t offset, size_t length, const char *s) -{ - size_t i; - UINT8 b; - UINT8 *bptr; - - bptr = (UINT8 *) ptr; - bptr += offset; - - bptr[0] = 0x80; - - for (i = 0; s[i] && (i < length); i++) - { - b = ((UINT8) s[i]) & 0x7F; - if (s[i+1] == '\0') - b |= 0x80; - bptr[i] = b; - } -} - - - -static os9_diskinfo *os9_get_diskinfo(imgtool_image *image) -{ - return (os9_diskinfo *) imgtool_floppy_extrabytes(image); -} - - - -static struct os9_direnum *os9_get_dirinfo(imgtool_directory *directory) -{ - return (struct os9_direnum *) imgtool_directory_extrabytes(directory); -} - - - -static imgtoolerr_t os9_locate_lsn(imgtool_image *image, UINT32 lsn, UINT32 *head, UINT32 *track, UINT32 *sector) -{ - const os9_diskinfo *disk_info; - - disk_info = os9_get_diskinfo(image); - if (lsn > disk_info->total_sectors) - return IMGTOOLERR_CORRUPTIMAGE; - - *track = lsn / (disk_info->sectors_per_track * disk_info->sides); - *head = (lsn / disk_info->sectors_per_track) % disk_info->sides; - *sector = (lsn % disk_info->sectors_per_track) + 1; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t os9_read_lsn(imgtool_image *img, UINT32 lsn, int offset, void *buffer, size_t buffer_len) -{ - imgtoolerr_t err; - floperr_t ferr; - UINT32 head, track, sector; - - err = os9_locate_lsn(img, lsn, &head, &track, §or); - if (err) - return err; - - ferr = floppy_read_sector(imgtool_floppy(img), head, track, sector, offset, buffer, buffer_len); - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t os9_write_lsn(imgtool_image *img, UINT32 lsn, int offset, const void *buffer, size_t buffer_len) -{ - imgtoolerr_t err; - floperr_t ferr; - UINT32 head, track, sector; - - err = os9_locate_lsn(img, lsn, &head, &track, §or); - if (err) - return err; - - ferr = floppy_write_sector(imgtool_floppy(img), head, track, sector, offset, buffer, buffer_len, 0); /* TODO: pass ddam argument from imgtool */ - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static UINT32 os9_lookup_lsn(imgtool_image *img, - const struct os9_fileinfo *file_info, UINT32 *index) -{ - int i; - UINT32 lsn; - const os9_diskinfo *disk_info; - - disk_info = os9_get_diskinfo(img); - lsn = *index / disk_info->sector_size; - - i = 0; - while(lsn >= file_info->sector_map[i].count) - lsn -= file_info->sector_map[i++].count; - - lsn = file_info->sector_map[i].lsn + lsn; - *index %= disk_info->sector_size; - return lsn; -} - - - -static int os9_interpret_dirent(void *entry, char **filename, UINT32 *lsn, int *corrupt) -{ - int i; - char *entry_b = (char *) entry; - - *filename = NULL; - *lsn = 0; - if (corrupt) - *corrupt = FALSE; - - if (entry_b[28] != '\0') - { - if (corrupt) - *corrupt = TRUE; - } - - for (i = 0; (i < 28) && !(entry_b[i] & 0x80); i++) - ; - entry_b[i] &= 0x7F; - entry_b[i+1] = '\0'; - - *lsn = pick_integer_be(entry, 29, 3); - if (strcmp(entry_b, ".") && strcmp(entry_b, "..")) - *filename = entry_b; - return *filename != NULL; -} - - - -/*------------------------------------------------- - os9_decode_file_header - reads a file/directory - entry from an LSN, and decodes it --------------------------------------------------*/ - -static imgtoolerr_t os9_decode_file_header(imgtool_image *image, - int lsn, struct os9_fileinfo *info) -{ - imgtoolerr_t err; - UINT32 attributes, count; - int max_entries, i; - const os9_diskinfo *disk_info; - UINT8 header[256]; - - disk_info = os9_get_diskinfo(image); - - err = os9_read_lsn(image, lsn, 0, header, sizeof(header)); - if (err) - 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); - info->directory = (attributes & 0x80) ? 1 : 0; - info->non_sharable = (attributes & 0x40) ? 1 : 0; - info->public_execute = (attributes & 0x20) ? 1 : 0; - info->public_write = (attributes & 0x10) ? 1 : 0; - info->public_read = (attributes & 0x08) ? 1 : 0; - info->user_execute = (attributes & 0x04) ? 1 : 0; - info->user_write = (attributes & 0x02) ? 1 : 0; - info->user_read = (attributes & 0x01) ? 1 : 0; - - if (info->directory && (info->file_size % 32 != 0)) - return IMGTOOLERR_CORRUPTIMAGE; - - /* read all sector map entries */ - max_entries = (disk_info->sector_size - 16) / 5; - max_entries = MIN(max_entries, ARRAY_LENGTH(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); - if (count <= 0) - break; - - info->sector_map[i].lsn = lsn; - info->sector_map[i].count = count; - } - info->sector_map[i].lsn = 0; - info->sector_map[i].count = 0; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t os9_allocate_lsn(imgtool_image *image, UINT32 *lsn) -{ - UINT32 i; - os9_diskinfo *disk_info; - UINT8 b, mask; - - disk_info = os9_get_diskinfo(image); - - for (i = 0; i < disk_info->total_sectors; i++) - { - b = disk_info->allocation_bitmap[i / 8]; - mask = 1 << (7 - (i % 8)); - - if ((b & mask) == 0) - { - disk_info->allocation_bitmap[i / 8] |= mask; - *lsn = i; - return os9_write_lsn(image, 1, 0, disk_info->allocation_bitmap, disk_info->allocation_bitmap_bytes); - } - } - return IMGTOOLERR_NOSPACE; -} - - - -static imgtoolerr_t os9_deallocate_lsn(imgtool_image *image, UINT32 lsn) -{ - UINT8 mask; - os9_diskinfo *disk_info; - - disk_info = os9_get_diskinfo(image); - mask = 1 << (7 - (lsn % 8)); - disk_info->allocation_bitmap[lsn / 8] &= ~mask; - return os9_write_lsn(image, 1, 0, disk_info->allocation_bitmap, disk_info->allocation_bitmap_bytes); -} - - - -static UINT32 os9_get_free_lsns(imgtool_image *image) -{ - const os9_diskinfo *disk_info; - UINT32 i, free_lsns; - UINT8 b; - - disk_info = os9_get_diskinfo(image); - free_lsns = 0; - - for (i = 0; i < disk_info->total_sectors; i++) - { - b = disk_info->allocation_bitmap[i / 8]; - b >>= (7 - (i % 8)); - free_lsns += ~b & 1; - } - - return free_lsns; -} - - - -static imgtoolerr_t os9_corrupt_file_error(const struct os9_fileinfo *file_info) -{ - imgtoolerr_t err; - if (file_info->directory) - err = IMGTOOLERR_CORRUPTDIR; - else - err = IMGTOOLERR_CORRUPTFILE; - return err; -} - - - -static imgtoolerr_t os9_set_file_size(imgtool_image *image, - struct os9_fileinfo *file_info, UINT32 new_size) -{ - imgtoolerr_t err; - const os9_diskinfo *disk_info; - UINT32 new_lsn_count, current_lsn_count; - UINT32 free_lsns, lsn, i; - int sector_map_length = -1; - UINT8 header[256]; - - /* easy way out? */ - if (file_info->file_size == new_size) - return IMGTOOLERR_SUCCESS; - - disk_info = os9_get_diskinfo(image); - - free_lsns = os9_get_free_lsns(image); - current_lsn_count = (file_info->file_size + disk_info->sector_size - 1) / disk_info->sector_size; - new_lsn_count = (new_size + disk_info->sector_size - 1) / disk_info->sector_size; - - /* check to see if the file is growing and we do not have enough space */ - if ((new_lsn_count > current_lsn_count) && (new_lsn_count - current_lsn_count > free_lsns)) - return IMGTOOLERR_NOSPACE; - - if (current_lsn_count != new_lsn_count) - { - /* 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))) - { - if (file_info->sector_map[sector_map_length].count == 0) - return os9_corrupt_file_error(file_info); - - lsn += file_info->sector_map[sector_map_length].count; - sector_map_length++; - } - - /* keep in mind that the sector_map might not parallel our expected - * current LSN count; we should tolerate this abnormality */ - current_lsn_count = lsn; - - while(current_lsn_count > new_lsn_count) - { - /* shrink this file */ - lsn = file_info->sector_map[sector_map_length - 1].lsn + - file_info->sector_map[sector_map_length - 1].count - 1; - - err = os9_deallocate_lsn(image, lsn); - if (err) - return err; - - file_info->sector_map[sector_map_length - 1].count--; - while(sector_map_length > 0 && (file_info->sector_map[sector_map_length - 1].count == 0)) - sector_map_length--; - current_lsn_count--; - } - - while(current_lsn_count < new_lsn_count) - { - /* grow this file */ - err = os9_allocate_lsn(image, &lsn); - if (err) - return err; - - if ((sector_map_length > 0) && ((file_info->sector_map[sector_map_length - 1].lsn + - file_info->sector_map[sector_map_length - 1].count) == lsn)) - { - file_info->sector_map[sector_map_length - 1].count++; - } - else if (sector_map_length >= ARRAY_LENGTH(file_info->sector_map)) - { - return IMGTOOLERR_NOSPACE; - } - else - { - file_info->sector_map[sector_map_length].lsn = lsn; - file_info->sector_map[sector_map_length].count = 1; - sector_map_length++; - file_info->sector_map[sector_map_length].lsn = 0; - file_info->sector_map[sector_map_length].count = 0; - } - current_lsn_count++; - } - } - - /* now lets write back the sector */ - err = os9_read_lsn(image, file_info->lsn, 0, header, sizeof(header)); - if (err) - return err; - - file_info->file_size = new_size; - place_integer_be(header, 9, 4, file_info->file_size); - - /* do we have to write the sector map? */ - if (sector_map_length >= 0) - { - for (i = 0; i < MIN(sector_map_length + 1, ARRAY_LENGTH(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); - } - } - - err = os9_write_lsn(image, file_info->lsn, 0, header, disk_info->sector_size); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -/*------------------------------------------------- - os9_lookup_path - walks an OS-9 directory - structure to find a file, or optionally, create - a file --------------------------------------------------*/ - -static imgtoolerr_t os9_lookup_path(imgtool_image *img, const char *path, - creation_policy_t create, struct os9_fileinfo *file_info, - UINT32 *parent_lsn, UINT32 *dirent_lsn, UINT32 *dirent_index) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - struct os9_fileinfo dir_info; - UINT32 index, current_lsn, dir_size; - UINT32 entry_index = 0; - UINT32 free_entry_index = 0xffffffff; - UINT32 entry_lsn = 0; - UINT32 allocated_lsn = 0; - UINT8 entry[32]; - UINT8 block[64]; - char *filename; - const os9_diskinfo *disk_info; - - disk_info = os9_get_diskinfo(img); - current_lsn = disk_info->root_dir_lsn; - - if (parent_lsn) - *parent_lsn = 0; - - /* we have to transverse each path element */ - while(*path) - { - if (parent_lsn) - *parent_lsn = current_lsn; - - /* decode the directory header of this directory */ - err = os9_decode_file_header(img, current_lsn, &dir_info); - if (err) - goto done; - dir_size = dir_info.file_size; - - /* sanity check directory */ - if (!dir_info.directory) - { - err = (current_lsn == disk_info->root_dir_lsn) ? IMGTOOLERR_CORRUPTIMAGE : IMGTOOLERR_INVALIDPATH; - goto done; - } - - /* walk the directory */ - for (index = 0; index < dir_size; index += 32) - { - entry_index = index; - entry_lsn = os9_lookup_lsn(img, &dir_info, &entry_index); - - err = os9_read_lsn(img, entry_lsn, entry_index, entry, sizeof(entry)); - if (err) - goto done; - - /* remember first free entry found */ - if( free_entry_index == 0xffffffff ) - { - if( entry[0] == 0 ) - free_entry_index = index; - } - - if (os9_interpret_dirent(entry, &filename, ¤t_lsn, NULL)) - { - if (!strcmp(path, filename)) - break; - } - - } - - /* at the end of the file? */ - if (index >= dir_size) - { - /* if we're not creating, or we are creating but we have not fully - * transversed the directory, error out */ - if (!create || path[strlen(path) + 1]) - { - err = IMGTOOLERR_PATHNOTFOUND; - goto done; - } - - /* allocate a new LSN */ - err = os9_allocate_lsn(img, &allocated_lsn); - if (err) - goto done; - - /* write the file */ - memset(block, 0, sizeof(block)); - place_integer_be(block, 0, 1, 0x1B | ((create == CREATE_DIR) ? 0x80 : 0x00)); - err = os9_write_lsn(img, allocated_lsn, 0, block, sizeof(block)); - if (err) - goto done; - - if( free_entry_index == 0xffffffff ) - { - /* expand the directory to hold the new entry */ - err = os9_set_file_size(img, &dir_info, dir_size + 32); - if (err) - goto done; - } - else - /* use first unused entry in directory */ - dir_size = free_entry_index; - - /* now prepare the directory entry */ - memset(entry, 0, sizeof(entry)); - place_string(entry, 0, 28, path); - place_integer_be(entry, 29, 3, allocated_lsn); - - /* now write the directory entry */ - entry_index = dir_size; - entry_lsn = os9_lookup_lsn(img, &dir_info, &entry_index); - err = os9_write_lsn(img, entry_lsn, entry_index, entry, 32); - if (err) - goto done; - - /* directory entry append complete; no need to hold this lsn */ - current_lsn = allocated_lsn; - allocated_lsn = 0; - } - path += strlen(path) + 1; - } - - if (file_info) - { - err = os9_decode_file_header(img, current_lsn, file_info); - if (err) - goto done; - } - - if (dirent_lsn) - *dirent_lsn = entry_lsn; - if (dirent_index) - *dirent_index = entry_index; - -done: - if (allocated_lsn != 0) - os9_deallocate_lsn(img, allocated_lsn); - return err; -} - - - -static imgtoolerr_t os9_diskimage_open(imgtool_image *image, imgtool_stream *stream) -{ - imgtoolerr_t err; - floperr_t ferr; - os9_diskinfo *info; - UINT32 track_size_in_sectors, i; //, attributes; - UINT8 header[256]; - UINT32 allocation_bitmap_lsns; - UINT8 b, mask; - - info = os9_get_diskinfo(image); - - ferr = floppy_read_sector(imgtool_floppy(image), 0, 0, 1, 0, header, sizeof(header)); - 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->sides = (info->format_flags & 0x01) ? 2 : 1; - info->double_density = (info->format_flags & 0x02) ? 1 : 0; - info->double_track = (info->format_flags & 0x04) ? 1 : 0; - info->quad_track_density = (info->format_flags & 0x08) ? 1 : 0; - info->octal_track_density = (info->format_flags & 0x10) ? 1 : 0; - - pick_string(header, 31, 32, info->name); - - if (info->sector_size == 0) - info->sector_size = 256; - - /* does the root directory and allocation bitmap collide? */ - allocation_bitmap_lsns = (info->allocation_bitmap_bytes + info->sector_size - 1) / info->sector_size; - if (1 + allocation_bitmap_lsns > info->root_dir_lsn) - return IMGTOOLERR_CORRUPTIMAGE; - - /* is the allocation bitmap too big? */ - info->allocation_bitmap = (UINT8*)imgtool_image_malloc(image, info->allocation_bitmap_bytes); - if (!info->allocation_bitmap) - return IMGTOOLERR_OUTOFMEMORY; - memset(info->allocation_bitmap, 0, info->allocation_bitmap_bytes); - - /* sectors per track and track size don't jive? */ - if (info->sectors_per_track != track_size_in_sectors) - return IMGTOOLERR_CORRUPTIMAGE; - - /* zero sectors per track? */ - if (info->sectors_per_track == 0) - return IMGTOOLERR_CORRUPTIMAGE; - - /* do we have an odd number of sectors? */ - if (info->total_sectors % info->sectors_per_track) - return IMGTOOLERR_CORRUPTIMAGE; - - /* read the allocation bitmap */ - for (i = 0; i < allocation_bitmap_lsns; i++) - { - err = os9_read_lsn(image, 1 + i, 0, &info->allocation_bitmap[i * info->sector_size], - MIN(info->allocation_bitmap_bytes - (i * info->sector_size), info->sector_size)); - if (err) - return err; - } - - /* check to make sure that the allocation bitmap and root sector are reserved */ - for (i = 0; i <= allocation_bitmap_lsns; i++) - { - b = info->allocation_bitmap[i / 8]; - mask = 1 << (7 - (i % 8)); - if ((b & mask) == 0) - return IMGTOOLERR_CORRUPTIMAGE; - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t os9_diskimage_create(imgtool_image *img, imgtool_stream *stream, option_resolution *opts) -{ - imgtoolerr_t err; - dynamic_buffer header; - UINT32 heads, tracks, sectors, sector_bytes, first_sector_id; - UINT32 cluster_size, owner_id; - UINT32 allocation_bitmap_bits, allocation_bitmap_lsns; - UINT32 attributes, format_flags, disk_id; - UINT32 i; - INT32 total_allocated_sectors; - const char *title; - time_t t; - struct tm *ltime; - - time(&t); - ltime = localtime(&t); - - heads = option_resolution_lookup_int(opts, 'H'); - tracks = option_resolution_lookup_int(opts, 'T'); - sectors = option_resolution_lookup_int(opts, 'S'); - sector_bytes = option_resolution_lookup_int(opts, 'L'); - first_sector_id = option_resolution_lookup_int(opts, 'F'); - title = ""; - - header.resize(sector_bytes); - - if (sector_bytes > 256) - sector_bytes = 256; - cluster_size = 1; - owner_id = 1; - disk_id = 1; - attributes = 0; - allocation_bitmap_bits = heads * tracks * sectors / cluster_size; - allocation_bitmap_lsns = (allocation_bitmap_bits / 8 + sector_bytes - 1) / sector_bytes; - 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); - - /* 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 */ - - 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) - goto done; - - total_allocated_sectors = 1 + allocation_bitmap_lsns + 1 + 7; - - for (i = 0; i < allocation_bitmap_lsns; i++) - { - memset(&header[0], 0x00, sector_bytes); - - if (total_allocated_sectors > (8 * 256)) - { - memset(&header[0], 0xff, sector_bytes); - total_allocated_sectors -= (8 * 256); - } - else if (total_allocated_sectors > 1 ) - { - int offset; - UINT8 mask; - - while( total_allocated_sectors >= 0 ) - { - offset = total_allocated_sectors / 8; - mask = 1 << (7 - ( total_allocated_sectors % 8 ) ); - - header[offset] |= mask; - total_allocated_sectors--; - } - } - - err = (imgtoolerr_t)floppy_write_sector(imgtool_floppy(img), 0, 0, first_sector_id + 1 + i, 0, &header[0], sector_bytes, 0); /* TODO: pass ddam argument from imgtool */ - if (err) - goto done; - } - - memset(&header[0], 0, sector_bytes); - header[0x00] = 0xBF; - header[0x01] = 0x00; - header[0x02] = 0x00; - header[0x03] = (UINT8) ltime->tm_year; - header[0x04] = (UINT8) ltime->tm_mon + 1; - header[0x05] = (UINT8) ltime->tm_mday; - header[0x06] = (UINT8) ltime->tm_hour; - header[0x07] = (UINT8) ltime->tm_min; - header[0x08] = 0x02; - header[0x09] = 0x00; - header[0x0A] = 0x00; - header[0x0B] = 0x00; - header[0x0C] = 0x40; - header[0x0D] = (UINT8) (ltime->tm_year % 100); - header[0x0E] = (UINT8) ltime->tm_mon; - header[0x0F] = (UINT8) ltime->tm_mday; - place_integer_be(&header[0], 0x10, 3, 1 + allocation_bitmap_lsns + 1); - place_integer_be(&header[0], 0x13, 2, 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) - goto done; - - memset(&header[0], 0, sector_bytes); - header[0x00] = 0x2E; - header[0x01] = 0xAE; - header[0x1F] = 1 + allocation_bitmap_lsns; - header[0x20] = 0xAE; - header[0x3F] = 1 + allocation_bitmap_lsns; - err = (imgtoolerr_t)floppy_write_sector(imgtool_floppy(img), 0, 0, first_sector_id + 2 + allocation_bitmap_lsns, 0, &header[0], sector_bytes, 0); /* TOOD: pass ddam argument from imgtool */ - if (err) - goto done; - -done: - return err; -} - - - -static imgtoolerr_t os9_diskimage_beginenum(imgtool_directory *enumeration, const char *path) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - struct os9_direnum *os9enum; - imgtool_image *image; - - image = imgtool_directory_image(enumeration); - os9enum = os9_get_dirinfo(enumeration); - - err = os9_lookup_path(image, path, CREATE_NONE, &os9enum->dir_info, NULL, NULL, NULL); - if (err) - goto done; - - /* this had better be a directory */ - if (!os9enum->dir_info.directory) - { - err = IMGTOOLERR_CORRUPTIMAGE; - goto done; - } - -done: - return err; -} - - - -static imgtoolerr_t os9_diskimage_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent) -{ - struct os9_direnum *os9enum; - UINT32 lsn, index; - imgtoolerr_t err; - UINT8 dir_entry[32]; - char filename[29]; - struct os9_fileinfo file_info; - imgtool_image *image; - - image = imgtool_directory_image(enumeration); - os9enum = os9_get_dirinfo(enumeration); - - do - { - /* check for EOF */ - if (os9enum->index >= os9enum->dir_info.file_size) - { - ent->eof = 1; - return IMGTOOLERR_SUCCESS; - } - - /* locate the LSN and offset for this directory entry */ - index = os9enum->index; - lsn = os9_lookup_lsn(image, &os9enum->dir_info, &index); - - /* read the directory entry out of the lSN */ - err = os9_read_lsn(image, lsn, index, dir_entry, sizeof(dir_entry)); - if (err) - return err; - - if (dir_entry[0]) - { - /* read the file or directory name */ - pick_string(dir_entry, 0, 28, filename); - - /* we have certain expectations of the directory contents; the - * first directory entry should be "..", the second ".", and - * subsequent entries should never be "." or ".." */ - switch(os9enum->index) - { - case 0: - if (strcmp(filename, "..")) - imgtool_warn("First entry in directory should be \"..\" and not \"%s\"", filename); - break; - - case 32: - if (strcmp(filename, ".")) - imgtool_warn("Second entry in directory should be \".\" and not \"%s\"", filename); - break; - - default: - if (!strcmp(filename, ".") || !strcmp(filename, "..")) - imgtool_warn("Directory entry %d should not be \"%s\"", index / 32, filename); - break; - } - - /* 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)) - { - imgtool_warn("Directory \".\" does not point back to same directory"); - } - } - else - { - /* no more directory entries */ - filename[0] = '\0'; - } - - /* move on to the next directory entry */ - os9enum->index += 32; - } - while(!filename[0] || !strcmp(filename, ".") || !strcmp(filename, "..")); - - /* read file attributes */ - lsn = pick_integer_be(dir_entry, 29, 3); - err = os9_decode_file_header(imgtool_directory_image(enumeration), 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", - file_info.directory ? 'd' : '-', - file_info.non_sharable ? 's' : '-', - file_info.public_execute ? 'x' : '-', - file_info.public_write ? 'w' : '-', - file_info.public_read ? 'r' : '-', - file_info.user_execute ? 'x' : '-', - file_info.user_write ? 'w' : '-', - file_info.user_read ? 'r' : '-'); - - ent->directory = file_info.directory; - ent->corrupt = (dir_entry[28] != 0); - ent->filesize = file_info.file_size; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t os9_diskimage_freespace(imgtool_partition *partition, UINT64 *size) -{ - imgtool_image *image = imgtool_partition_image(partition); - const os9_diskinfo *disk_info; - UINT32 free_lsns; - - disk_info = os9_get_diskinfo(image); - free_lsns = os9_get_free_lsns(image); - - *size = free_lsns * disk_info->sector_size; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t os9_diskimage_readfile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf) -{ - imgtoolerr_t err; - imgtool_image *img = imgtool_partition_image(partition); - const os9_diskinfo *disk_info; - struct os9_fileinfo file_info; - UINT8 buffer[256]; - int i, j; - UINT32 file_size; - UINT32 used_size; - - disk_info = os9_get_diskinfo(img); - - err = os9_lookup_path(img, filename, CREATE_NONE, &file_info, NULL, NULL, NULL); - if (err) - return err; - if (file_info.directory) - return IMGTOOLERR_FILENOTFOUND; - file_size = file_info.file_size; - - for (i = 0; file_info.sector_map[i].count > 0; i++) - { - for (j = 0; j < file_info.sector_map[i].count; j++) - { - used_size = MIN(file_size, disk_info->sector_size); - err = os9_read_lsn(img, file_info.sector_map[i].lsn + j, 0, - buffer, used_size); - if (err) - return err; - stream_write(destf, buffer, used_size); - file_size -= used_size; - } - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t os9_diskimage_writefile(imgtool_partition *partition, const char *path, const char *fork, imgtool_stream *sourcef, option_resolution *opts) -{ - imgtoolerr_t err; - imgtool_image *image = imgtool_partition_image(partition); - struct os9_fileinfo file_info; - size_t write_size; - dynamic_buffer buf; - int i = -1; - UINT32 lsn = 0; - UINT32 count = 0; - UINT32 sz; - const os9_diskinfo *disk_info; - - disk_info = os9_get_diskinfo(image); - - buf.resize(disk_info->sector_size); - - err = os9_lookup_path(image, path, CREATE_FILE, &file_info, NULL, NULL, NULL); - if (err) - goto done; - - sz = (UINT32) stream_size(sourcef); - - err = os9_set_file_size(image, &file_info, sz); - if (err) - goto done; - - while(sz > 0) - { - write_size = (size_t) MIN(sz, (UINT64) disk_info->sector_size); - - stream_read(sourcef, &buf[0], write_size); - - while(count == 0) - { - i++; - lsn = file_info.sector_map[i].lsn; - count = file_info.sector_map[i].count; - } - - err = os9_write_lsn(image, lsn, 0, &buf[0], write_size); - if (err) - goto done; - - lsn++; - count--; - sz -= write_size; - } - -done: - return err; -} - - - -static imgtoolerr_t os9_diskimage_delete(imgtool_partition *partition, const char *path, - unsigned int delete_directory) -{ - imgtoolerr_t err; - imgtool_image *image = imgtool_partition_image(partition); - //const os9_diskinfo *disk_info; - struct os9_fileinfo file_info; - UINT32 dirent_lsn, dirent_index; - UINT32 entry_lsn, entry_index; - UINT32 i, j, lsn; - UINT8 b; - - //disk_info = os9_get_diskinfo(image); - - err = os9_lookup_path(image, path, CREATE_NONE, &file_info, NULL, &dirent_lsn, &dirent_index); - if (err) - return err; - if (file_info.directory != delete_directory) - return IMGTOOLERR_FILENOTFOUND; - - /* make sure that if we are deleting a directory, it is empty */ - if (delete_directory) - { - for (i = 64; i < file_info.file_size; i += 32) - { - entry_index = i; - entry_lsn = os9_lookup_lsn(image, &file_info, &entry_index); - - err = os9_read_lsn(image, entry_lsn, entry_index, &b, 1); - if (err) - return err; - - /* this had better be a deleted file, if not we can't delete */ - if (b != 0) - return IMGTOOLERR_DIRNOTEMPTY; - } - } - - /* zero out the file entry */ - b = '\0'; - err = os9_write_lsn(image, dirent_lsn, dirent_index, &b, 1); - if (err) - return err; - - /* get the link count */ - err = os9_read_lsn(image, file_info.lsn, 8, &b, 1); - if (err) - return err; - - if (b > 0) - b--; - if (b > 0) - { - /* link count is greater than zero */ - err = os9_write_lsn(image, file_info.lsn, 8, &b, 1); - if (err) - return err; - } - else - { - /* no more links; outright delete the file */ - err = os9_deallocate_lsn(image, file_info.lsn); - if (err) - return err; - - for (i = 0; (i < ARRAY_LENGTH(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++) - { - err = os9_deallocate_lsn(image, lsn + j); - if (err) - return err; - } - } - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t os9_diskimage_deletefile(imgtool_partition *partition, const char *path) -{ - return os9_diskimage_delete(partition, path, 0); -} - - - -static imgtoolerr_t os9_diskimage_createdir(imgtool_partition *partition, const char *path) -{ - imgtoolerr_t err; - imgtool_image *image = imgtool_partition_image(partition); - struct os9_fileinfo file_info; - UINT8 dir_data[64]; - UINT32 parent_lsn; - - err = os9_lookup_path(image, path, CREATE_DIR, &file_info, &parent_lsn, NULL, NULL); - if (err) - goto done; - - err = os9_set_file_size(image, &file_info, 64); - if (err) - goto done; - - /* 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); - - err = os9_write_lsn(image, file_info.sector_map[0].lsn, 0, dir_data, sizeof(dir_data)); - if (err) - goto done; - -done: - return err; -} - - - -static imgtoolerr_t os9_diskimage_deletedir(imgtool_partition *partition, const char *path) -{ - return os9_diskimage_delete(partition, path, 1); -} - - - -void os9_get_info(const imgtool_class *imgclass, UINT32 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_IMAGE_EXTRA_BYTES: info->i = sizeof(os9_diskinfo); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(struct os9_direnum); break; - case IMGTOOLINFO_INT_PATH_SEPARATOR: info->i = '/'; break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "os9"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "OS-9 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_FLOPPY_CREATE: info->create = os9_diskimage_create; break; - case IMGTOOLINFO_PTR_FLOPPY_OPEN: info->open = os9_diskimage_open; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = os9_diskimage_beginenum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = os9_diskimage_nextenum; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = os9_diskimage_freespace; break; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = os9_diskimage_readfile; break; - case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = os9_diskimage_writefile; break; - case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = os9_diskimage_deletefile; break; - case IMGTOOLINFO_PTR_CREATE_DIR: info->create_dir = os9_diskimage_createdir; break; - case IMGTOOLINFO_PTR_DELETE_DIR: info->delete_dir = os9_diskimage_deletedir; break; - case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_coco; break; - } -} diff --git a/src/mess/tools/imgtool/modules/pc_flop.c b/src/mess/tools/imgtool/modules/pc_flop.c deleted file mode 100644 index 916cf873c46..00000000000 --- a/src/mess/tools/imgtool/modules/pc_flop.c +++ /dev/null @@ -1,173 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/**************************************************************************** - - pc_flop.c - - PC floppies - -****************************************************************************/ - -#include "imgtool.h" -#include "formats/imageutl.h" -#include "formats/pc_dsk.h" -#include "fat.h" -#include "iflopimg.h" - -#define FAT_SECLEN 512 - - -static imgtoolerr_t fat_image_create(imgtool_image *image, imgtool_stream *stream, option_resolution *opts) -{ - imgtoolerr_t err; - UINT32 tracks, heads, sectors; - UINT8 buffer[FAT_SECLEN]; - imgtool_class imgclass = { fat_get_info }; - imgtoolerr_t (*fat_partition_create)(imgtool_image *image, UINT64 first_block, UINT64 block_count); - - tracks = option_resolution_lookup_int(opts, 'T'); - heads = option_resolution_lookup_int(opts, 'H'); - sectors = option_resolution_lookup_int(opts, 'S'); - - /* 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) (((UINT64) tracks * heads * sectors) >> 0)); - place_integer_le(buffer, 32, 4, (UINT16) (((UINT64) tracks * heads * sectors) >> 16)); - err = imgtool_image_write_block(image, 0, buffer); - if (err) - goto done; - - /* load fat_partition_create */ - fat_partition_create = (imgtoolerr_t (*)(imgtool_image *, UINT64, UINT64)) - imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_CREATE_PARTITION); - - /* actually create the partition */ - err = fat_partition_create(image, 0, ((UINT64) tracks) * heads * sectors); - if (err) - goto done; - -done: - return err; -} - - - -static imgtoolerr_t fat_image_get_geometry(imgtool_image *image, UINT32 *tracks, UINT32 *heads, UINT32 *sectors) -{ - imgtoolerr_t err; - UINT64 total_sectors; - UINT8 buffer[FAT_SECLEN]; - - err = imgtool_image_read_block(image, 0, buffer); - if (err) - return err; - - total_sectors = pick_integer_le(buffer, 19, 2) - | (pick_integer_le(buffer, 32, 4) << 16); - - *sectors = pick_integer_le(buffer, 24, 2); - *heads = pick_integer_le(buffer, 26, 2); - *tracks = total_sectors / *heads / *sectors; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_get_sector_position(imgtool_image *image, UINT32 sector_index, - UINT32 *track, UINT32 *head, UINT32 *sector) -{ - imgtoolerr_t err; - UINT32 tracks, heads, sectors; - - if (sector_index == 0) - { - /* special case */ - *head = 0; - *track = 0; - *sector = 1; - } - else - { - err = imgtool_image_get_geometry(image, &tracks, &heads, §ors); - if (err) - return err; - - *track = sector_index / sectors / heads; - *head = (sector_index / sectors) % heads; - *sector = 1 + (sector_index % sectors); - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_image_readblock(imgtool_image *image, void *buffer, UINT64 block) -{ - imgtoolerr_t err; - floperr_t ferr; - UINT32 track, head, sector; - UINT32 block_size; - - err = imgtool_image_get_block_size(image, &block_size); - if (err) - return err; - - err = fat_get_sector_position(image, block, &track, &head, §or); - if (err) - return err; - - ferr = floppy_read_sector(imgtool_floppy(image), head, track, sector, 0, buffer, block_size); - if (ferr) - return imgtool_floppy_error(ferr); - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t fat_image_writeblock(imgtool_image *image, const void *buffer, UINT64 block) -{ - imgtoolerr_t err; - floperr_t ferr; - UINT32 track, head, sector; - UINT32 block_size; - - err = imgtool_image_get_block_size(image, &block_size); - if (err) - return err; - - err = fat_get_sector_position(image, block, &track, &head, §or); - if (err) - return err; - - ferr = floppy_write_sector(imgtool_floppy(image), head, track, sector, 0, buffer, block_size, 0); /* TODO: pass ddam argument from imgtool */ - if (ferr) - return imgtool_floppy_error(ferr); - return IMGTOOLERR_SUCCESS; -} - - - -void pc_floppy_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info) -{ - switch(state) - { - /* --- the following bits of info are returned as 64-bit signed integers --- */ - case IMGTOOLINFO_INT_BLOCK_SIZE: info->i = FAT_SECLEN; break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "fat"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "FAT format"); 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 = fat_image_create; break; - case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_pc; break; - case IMGTOOLINFO_PTR_READ_BLOCK: info->read_block = fat_image_readblock; break; - case IMGTOOLINFO_PTR_WRITE_BLOCK: info->write_block = fat_image_writeblock; break; - case IMGTOOLINFO_PTR_GET_GEOMETRY: info->get_geometry = fat_image_get_geometry; break; - - default: fat_get_info(imgclass, state, info); break; - } -} diff --git a/src/mess/tools/imgtool/modules/pc_hard.c b/src/mess/tools/imgtool/modules/pc_hard.c deleted file mode 100644 index 915032932c7..00000000000 --- a/src/mess/tools/imgtool/modules/pc_hard.c +++ /dev/null @@ -1,470 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/**************************************************************************** - - pc_hard.c - - PC hard drives - -***************************************************************************** - - Master boot record format: - - Offset Length Description - ------ ------ ----------- - 0 446 Boot machine code - 446 16 Partion #1 info - 462 16 Partion #2 info - 478 16 Partion #3 info - 494 16 Partion #4 info - 510 2 Magic bytes (0x55 0xAA) - - - Partition info format: - - Offset Length Description - ------ ------ ----------- - 0 1 Bootable (0x80=bootable 0x00=not bootable) - 1 1 Starting head - 2 1 Starting sector (bits 5-0) and high bits of starting track (bits 6-5) - 3 1 Low bits of starting track - 4 1 Partition type: - 0x00 Unused - 0x?1 FAT12 (0-15 MB) - 0x?2 XENIX - 0x?4 FAT16 (16-32 MB) - 0x?6 FAT16` (32 MB-2 GB) - 0x?7 HPFS or NTFS - 0x?A Boot Manager - 0x?B FAT32 (512 MB-2 TB) - 0x?C FAT32 (512 MB-2 TB LBA) - 0x1? OS/2 Boot manager/Win95 hidden - 0xC? DR-DOS secured partition - 0xD? Multiuser DOS secured partition - 0xE? SpeedStor extended partition - 5 1 Ending head - 6 1 Ending sector (bits 5-0) and high bits of ending track (bits 6-5) - 7 1 Low bits of ending track - 8 4 Sector index of beginning of partition - 12 4 Total sectors in partition - -****************************************************************************/ -#include "imgtool.h" -#include "formats/imageutl.h" -#include "imghd.h" - -#define FAT_SECLEN 512 - -static OPTION_GUIDE_START( pc_chd_create_optionguide ) - OPTION_INT('T', "cylinders", "Cylinders" ) - OPTION_INT('H', "heads", "Heads" ) - OPTION_INT('S', "sectors", "Sectors" ) -OPTION_GUIDE_END - -static const char pc_chd_create_optionspec[] = "H1-[16]S1-[32]-63T10/20/30/40/50/60/70/80/90/[100]/110/120/130/140/150/160/170/180/190/200"; - -static const char fat8_string[8] = { 'F', 'A', 'T', ' ', ' ', ' ', ' ', ' ' }; -static const char fat12_string[8] = { 'F', 'A', 'T', '1', '2', ' ', ' ', ' ' }; -static const char fat16_string[8] = { 'F', 'A', 'T', '1', '6', ' ', ' ', ' ' }; -//static const char fat32_string[8] = { 'F', 'A', 'T', '3', '2', ' ', ' ', ' ' }; - -/* imports from fat.c */ -extern void fat_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info); - - -struct pc_chd_image_info -{ - struct mess_hard_disk_file hard_disk; - - struct - { - unsigned int corrupt : 1; - UINT8 partition_type; - UINT32 fat_bits; - UINT32 starting_track; - UINT32 starting_head; - UINT32 starting_sector; - UINT32 ending_track; - UINT32 ending_head; - UINT32 ending_sector; - UINT32 sector_index; - UINT32 total_sectors; - } partitions[4]; -}; - - - -static pc_chd_image_info *pc_chd_get_image_info(imgtool_image *image) -{ - return (pc_chd_image_info *) imgtool_image_extra_bytes(image); -} - - - -static void pc_chd_locate_block(imgtool_image *image, UINT64 block, UINT32 *cylinder, UINT32 *head, UINT32 *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); - - *sector = block % hd_info->sectors; - *head = (block / hd_info->sectors) % hd_info->heads; - *cylinder = block / hd_info->sectors / hd_info->heads; -} - - - -static imgtoolerr_t pc_chd_partition_create(imgtool_image *image, int partition_index, UINT64 first_block, UINT64 block_count) -{ - imgtoolerr_t err; - UINT8 header_block[FAT_SECLEN]; - UINT8 partition_block[FAT_SECLEN]; - UINT8 partition_type; - UINT8 *fat_type; - UINT8 *partition_entry; - UINT32 first_cylinder, first_head, first_sector; - UINT32 last_cylinder, last_head, last_sector; - imgtool_class imgclass = { fat_get_info }; - imgtoolerr_t (*fat_partition_create)(imgtool_image *image, UINT64 first_block, UINT64 block_count); - - /* sanity checks */ - assert((partition_index >= 0) && (partition_index <= 3)); - - /* compute geometry */ - pc_chd_locate_block(image, first_block, &first_cylinder, &first_head, &first_sector); - pc_chd_locate_block(image, first_block + block_count - 1, &last_cylinder, &last_head, &last_sector); - - /* load fat_partition_create */ - fat_partition_create = (imgtoolerr_t (*)(imgtool_image *, UINT64, UINT64)) - imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_CREATE_PARTITION); - - /* first create the actual partition */ - err = fat_partition_create(image, first_block, block_count); - if (err) - goto done; - - /* read the first block of the partition, to determine the type of FAT */ - err = imgtool_image_read_block(image, first_block, partition_block); - if (err) - goto done; - fat_type = &partition_block[54]; - if (!memcmp(fat_type, fat8_string, sizeof(fat8_string))) - partition_type = 0x01; - else if (!memcmp(fat_type, fat12_string, sizeof(fat12_string))) - partition_type = 0x01; - else if ((!memcmp(fat_type, fat16_string, sizeof(fat16_string))) && (block_count < 32*1024*1024/FAT_SECLEN)) - partition_type = 0x04; - else if ((!memcmp(fat_type, fat16_string, sizeof(fat16_string))) && (block_count >= 32*1024*1024/FAT_SECLEN)) - partition_type = 0x06; - else - partition_type = 0x0B; - - /* read the partition header */ - err = imgtool_image_read_block(image, 0, header_block); - if (err) - goto done; - - /* 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); - - /* write the partition header */ - err = imgtool_image_write_block(image, 0, header_block); - if (err) - goto done; - -done: - return err; -} - - - -static imgtoolerr_t pc_chd_read_partition_header(imgtool_image *image) -{ - imgtoolerr_t err; - int i; - const UINT8 *partition_info; - pc_chd_image_info *info; - UINT8 buffer[FAT_SECLEN]; - - info = pc_chd_get_image_info(image); - - /* read the initial block */ - err = imgtool_image_read_block(image, 0, buffer); - if (err) - return err; - - /* magic bytes present? */ - if ((buffer[510] != 0x55) || (buffer[511] != 0xAA)) - return IMGTOOLERR_CORRUPTIMAGE; - - for (i = 0; i < ARRAY_LENGTH(info->partitions); i++) - { - partition_info = &buffer[446 + i * 16]; - - info->partitions[i].partition_type = partition_info[4]; - info->partitions[i].starting_head = partition_info[1]; - info->partitions[i].starting_track = ((partition_info[2] << 2) & 0xFF00) | partition_info[3]; - info->partitions[i].starting_sector = partition_info[2] & 0x3F; - info->partitions[i].ending_head = partition_info[5]; - 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); - - if (info->partitions[i].starting_track > info->partitions[i].ending_track) - return IMGTOOLERR_CORRUPTIMAGE; - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t pc_chd_image_create(imgtool_image *image, imgtool_stream *f, option_resolution *opts) -{ - imgtoolerr_t err; - UINT32 cylinders, heads, sectors; - pc_chd_image_info *info; - UINT8 header_block[FAT_SECLEN]; - - cylinders = option_resolution_lookup_int(opts, 'T'); - heads = option_resolution_lookup_int(opts, 'H'); - sectors = option_resolution_lookup_int(opts, 'S'); - - info = pc_chd_get_image_info(image); - - /* create the hard disk image */ - err = imghd_create(f, 0, cylinders, heads, sectors, FAT_SECLEN); - if (err) - goto done; - - err = imghd_open(f, &info->hard_disk); - if (err) - goto done; - - /* set up partition header block */ - memset(header_block, 0, sizeof(header_block)); - header_block[510] = 0x55; - header_block[511] = 0xAA; - err = imgtool_image_write_block(image, 0, header_block); - if (err) - goto done; - - err = pc_chd_partition_create(image, 0, 1, cylinders * heads * sectors - 1); - if (err) - goto done; - - err = pc_chd_read_partition_header(image); - if (err) - goto done; - -done: - if (err) - imghd_close(&info->hard_disk); - return err; -} - - - -static imgtoolerr_t pc_chd_image_open(imgtool_image *image, imgtool_stream *stream) -{ - imgtoolerr_t err; - pc_chd_image_info *info; - - info = pc_chd_get_image_info(image); - - /* open the hard drive */ - err = imghd_open(stream, &info->hard_disk); - if (err) - return err; - - err = pc_chd_read_partition_header(image); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -static void pc_chd_image_close(imgtool_image *image) -{ - pc_chd_image_info *info; - info = pc_chd_get_image_info(image); - imghd_close(&info->hard_disk); -} - - - -static imgtoolerr_t pc_chd_image_get_geometry(imgtool_image *image, UINT32 *tracks, UINT32 *heads, UINT32 *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); - - *tracks = hd_info->cylinders; - *heads = hd_info->heads; - *sectors = hd_info->sectors; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t pc_chd_image_getsectorsize(imgtool_image *image, UINT32 track, UINT32 head, UINT32 sector, UINT32 *sector_size) -{ - pc_chd_image_info *info; - info = pc_chd_get_image_info(image); - *sector_size = imghd_get_header(&info->hard_disk)->sectorbytes; - return IMGTOOLERR_SUCCESS; -} - - - -static UINT32 pc_chd_calc_lbasector(pc_chd_image_info *info, UINT32 track, UINT32 head, UINT32 sector) -{ - UINT32 lbasector; - const hard_disk_info *hd_info; - - hd_info = imghd_get_header(&info->hard_disk); - lbasector = track; - lbasector *= hd_info->heads; - lbasector += head; - lbasector *= hd_info->sectors; - lbasector += sector; - return lbasector; -} - - - -static imgtoolerr_t pc_chd_image_readsector(imgtool_image *image, UINT32 track, UINT32 head, UINT32 sector, void *buffer, size_t len) -{ - pc_chd_image_info *info; - info = pc_chd_get_image_info(image); - return imghd_read(&info->hard_disk, - pc_chd_calc_lbasector(info, track, head, sector), - buffer); -} - - - -static imgtoolerr_t pc_chd_image_writesector(imgtool_image *image, UINT32 track, UINT32 head, UINT32 sector, const void *buffer, size_t len, int ddam) -{ - pc_chd_image_info *info; - info = pc_chd_get_image_info(image); - return imghd_write(&info->hard_disk, - pc_chd_calc_lbasector(info, track, head, sector), - buffer); -} - - - -static imgtoolerr_t pc_chd_image_readblock(imgtool_image *image, void *buffer, UINT64 block) -{ - pc_chd_image_info *info; - info = pc_chd_get_image_info(image); - return imghd_read(&info->hard_disk, block, buffer); -} - - - -static imgtoolerr_t pc_chd_image_writeblock(imgtool_image *image, const void *buffer, UINT64 block) -{ - pc_chd_image_info *info; - info = pc_chd_get_image_info(image); - return imghd_write(&info->hard_disk, block, buffer); -} - - - -static imgtoolerr_t pc_chd_list_partitions(imgtool_image *image, imgtool_partition_info *partitions, size_t len) -{ - pc_chd_image_info *info; - size_t i; - - info = pc_chd_get_image_info(image); - - for (i = 0; i < MIN(4, len); i++) - { - partitions[i].base_block = info->partitions[i].sector_index; - partitions[i].block_count = info->partitions[i].total_sectors; - - switch(info->partitions[i].partition_type) - { - case 0x00: /* Empty Partition */ - partitions[i].get_info = NULL; - break; - - case 0x01: /* FAT12 */ - case 0x04: /* FAT16 (-32 MB) */ - case 0x06: /* FAT16 (32+ MB) */ - case 0x0B: /* FAT32 */ - case 0x0C: /* FAT32 (LBA Mapped) */ - case 0x0E: /* FAT16 (LBA Mapped) */ - case 0x11: /* OS/2 FAT12 */ - case 0x14: /* OS/2 FAT16 (-32 MB) */ - case 0x16: /* OS/2 FAT16 (32+ MB) */ - case 0x1B: /* Hidden Win95 FAT32 */ - case 0x1C: /* Hidden Win95 FAT32 (LBA Mapped) */ - case 0x1D: /* Hidden Win95 FAT16 (LBA Mapped) */ - case 0xC1: /* DR-DOS FAT12 */ - case 0xC4: /* DR-DOS FAT16 (-32 MB) */ - case 0xC6: /* DR-DOS FAT16 (32+ MB) */ - case 0xD1: /* Old Multiuser DOS FAT12 */ - case 0xD4: /* Old Multiuser DOS FAT16 (-32 MB) */ - case 0xD6: /* Old Multiuser DOS FAT16 (32+ MB) */ - partitions[i].get_info = fat_get_info; - break; - - default: - partitions[i].get_info = unknown_partition_get_info; - break; - } - } - return IMGTOOLERR_SUCCESS; -} - - - -void pc_chd_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info) -{ - switch(state) - { - /* --- the following bits of info are returned as 64-bit signed integers --- */ - case IMGTOOLINFO_INT_BLOCK_SIZE: info->i = FAT_SECLEN; break; - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: info->i = sizeof(pc_chd_image_info); break; - case IMGTOOLINFO_INT_TRACKS_ARE_CALLED_CYLINDERS: info->i = 1; break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "pc_chd"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "PC CHD disk image"); break; - case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "chd"); break; - case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), pc_chd_create_optionspec); break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case IMGTOOLINFO_PTR_CREATE: info->create = pc_chd_image_create; break; - case IMGTOOLINFO_PTR_OPEN: info->open = pc_chd_image_open; break; - case IMGTOOLINFO_PTR_CLOSE: info->close = pc_chd_image_close; break; - case IMGTOOLINFO_PTR_READ_SECTOR: info->read_sector = pc_chd_image_readsector; break; - case IMGTOOLINFO_PTR_WRITE_SECTOR: info->write_sector = pc_chd_image_writesector; break; - case IMGTOOLINFO_PTR_READ_BLOCK: info->read_block = pc_chd_image_readblock; break; - case IMGTOOLINFO_PTR_WRITE_BLOCK: info->write_block = pc_chd_image_writeblock; break; - case IMGTOOLINFO_PTR_GET_SECTOR_SIZE: info->get_sector_size = pc_chd_image_getsectorsize; break; - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = pc_chd_create_optionguide; break; - case IMGTOOLINFO_PTR_GET_GEOMETRY: info->get_geometry = pc_chd_image_get_geometry; break; - case IMGTOOLINFO_PTR_LIST_PARTITIONS: info->list_partitions = pc_chd_list_partitions; break; - } -} diff --git a/src/mess/tools/imgtool/modules/prodos.c b/src/mess/tools/imgtool/modules/prodos.c deleted file mode 100644 index 5800e2bf9f3..00000000000 --- a/src/mess/tools/imgtool/modules/prodos.c +++ /dev/null @@ -1,2282 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/**************************************************************************** - - prodos.c - - 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 dirent_size; - UINT8 dirents_per_block; - UINT16 volume_bitmap_block; - UINT16 total_blocks; -}; - -struct prodos_direnum -{ - UINT32 block; - UINT32 index; - UINT8 block_data[BLOCK_SIZE]; -}; - -struct prodos_dirent -{ - char filename[16]; - UINT8 storage_type; - UINT16 extkey_pointer; - UINT16 key_pointer[2]; - UINT32 filesize[2]; - int depth[2]; - UINT32 lastmodified_time; - UINT32 creation_time; - - /* FInfo */ - UINT32 file_type; - UINT32 file_creator; - UINT16 finder_flags; - UINT16 coord_x; - UINT16 coord_y; - UINT16 finder_folder; - - /* xFInfo */ - UINT16 icon_id; - UINT8 script_code; - UINT8 extended_flags; - UINT16 comment_id; - UINT32 putaway_directory; -}; - -enum creation_policy_t -{ - CREATE_NONE, - CREATE_FILE, - CREATE_DIR -}; - - - -static time_t prodos_crack_time(UINT32 prodos_time) -{ - struct tm t; - time_t now; - - time(&now); - t = *localtime(&now); - - t.tm_sec = 0; - t.tm_min = (prodos_time >> 16) & 0x3F; - t.tm_hour = (prodos_time >> 24) & 0x1F; - t.tm_mday = (prodos_time >> 0) & 0x1F; - t.tm_mon = (prodos_time >> 5) & 0x0F; - t.tm_year = (prodos_time >> 9) & 0x7F; - - if (t.tm_year <= 49) - t.tm_year += 100; - return mktime(&t); -} - - - -static UINT32 prodos_setup_time(time_t ansi_time) -{ - struct tm t; - UINT32 result = 0; - - t = *localtime(&ansi_time); - if ((t.tm_year >= 100) && (t.tm_year <= 149)) - t.tm_year -= 100; - - result |= (((UINT32) t.tm_min) & 0x003F) << 16; - result |= (((UINT32) t.tm_hour) & 0x001F) << 24; - result |= (((UINT32) t.tm_mday) & 0x001F) << 0; - result |= (((UINT32) t.tm_mon) & 0x000F) << 5; - result |= (((UINT32) t.tm_year) & 0x007F) << 9; - return result; -} - - - -static UINT32 prodos_time_now(void) -{ - time_t now; - time(&now); - return prodos_setup_time(now); -} - - - -static int is_file_storagetype(UINT8 storage_type) -{ - return ((storage_type >= 0x10) && (storage_type <= 0x3F)) - || ((storage_type >= 0x50) && (storage_type <= 0x5F)); -} - - - -static int is_normalfile_storagetype(UINT8 storage_type) -{ - return ((storage_type >= 0x10) && (storage_type <= 0x3F)); -} - - - -static int is_extendedfile_storagetype(UINT8 storage_type) -{ - return ((storage_type >= 0x50) && (storage_type <= 0x5F)); -} - - - -static int is_dir_storagetype(UINT8 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 *track, UINT32 *head, UINT32 *sector1, UINT32 *sector2) -{ - static const UINT8 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 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 *) 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 *) 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 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 *) 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 *) 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 *track, UINT32 *head, UINT32 *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 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 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 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 buffer[BLOCK_SIZE]; - prodos_diskinfo *di; - const UINT8 *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 *stream) -{ - prodos_setprocs_525(image); - return prodos_diskimage_open(image); -} - - - -static imgtoolerr_t prodos_diskimage_open_35(imgtool_image *image, imgtool_stream *stream) -{ - prodos_setprocs_35(image); - return prodos_diskimage_open(image); -} - - - -/* ----------------------------------------------------------------------- */ - -static imgtoolerr_t prodos_load_volume_bitmap(imgtool_image *image, UINT8 **bitmap) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - UINT8 *alloc_bitmap; - UINT32 bitmap_blocks, i; - - di = get_prodos_info(image); - - bitmap_blocks = (di->total_blocks + (BLOCK_SIZE * 8) - 1) / (BLOCK_SIZE * 8); - alloc_bitmap = (UINT8*)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 *bitmap) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - UINT32 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 *buffer, UINT16 block, int value) -{ - UINT8 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 *buffer, UINT16 block) -{ - UINT8 mask; - buffer += block / 8; - mask = 1 << (7 - (block % 8)); - return (*buffer & mask) ? 1 : 0; -} - - - -static imgtoolerr_t prodos_alloc_block(imgtool_image *image, UINT8 *bitmap, - UINT16 *block) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - prodos_diskinfo *di; - UINT16 bitmap_blocks, i; - UINT8 *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, option_resolution *opts) -{ - imgtoolerr_t err; - UINT32 heads, tracks, sectors, sector_bytes; - UINT32 dirent_size, volume_bitmap_block, i; - UINT32 volume_bitmap_block_count, total_blocks; - UINT8 buffer[BLOCK_SIZE]; - - heads = option_resolution_lookup_int(opts, 'H'); - tracks = option_resolution_lookup_int(opts, 'T'); - sectors = option_resolution_lookup_int(opts, 'S'); - sector_bytes = option_resolution_lookup_int(opts, '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 *stream, 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 *stream, 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 block, UINT32 index) -{ - imgtoolerr_t err; - UINT8 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 *next_info_block(UINT8 *buffer, size_t *position) -{ - size_t side = *position & 0x100; - size_t subpos = *position & 0x0FF; - UINT8 *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 *alloc_info_block(UINT8 *buffer, size_t block_size, UINT8 block_type) -{ - size_t position = 0; - size_t side; - size_t subpos; - UINT8 *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) 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 next_block, next_index; - UINT32 offset; - UINT8 buffer[BLOCK_SIZE]; - const UINT8 *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 *bitmap, prodos_dirent *ent) -{ - imgtoolerr_t err; - UINT16 new_block; - UINT8 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 offset; - size_t finfo_offset; - UINT8 buffer[BLOCK_SIZE]; - int fork_num; - int needs_finfo = FALSE; - int needs_xfinfo = FALSE; - UINT8 *info_ptr; - UINT8 *finfo; - UINT8 *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 block = ROOTDIR_BLOCK; - const char *old_path; - UINT16 this_block; - UINT32 this_index; - UINT16 free_block = 0; - UINT32 free_index = 0; - UINT16 new_file_block; - UINT8 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 *bitmap, - UINT16 key_block, int key_block_allocated, - int depth, UINT32 blockcount, UINT32 block_index) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - int dirty; - int sub_block_allocated; - UINT16 i, sub_block, new_sub_block; - UINT8 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 *bitmap, int fork_num, UINT32 new_blockcount) -{ - imgtoolerr_t err; - int depth, new_depth, i; - UINT16 new_block, block; - UINT8 buffer[BLOCK_SIZE]; - UINT16 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) (key_pointer >> 0); - buffer[256] = (UINT8) (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 new_size) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - UINT32 blockcount, new_blockcount; - UINT8 *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 prodos_get_storagetype_maxfilesize(UINT8 storage_type) -{ - UINT32 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; - prodos_direnum *appleenum; - prodos_dirent ent; - UINT16 block = ROOTDIR_BLOCK; - - image = imgtool_directory_image(enumeration); - appleenum = (prodos_direnum *) imgtool_directory_extrabytes(enumeration); - - /* 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; - prodos_direnum *appleenum; - prodos_dirent pd_ent; - UINT32 max_filesize; - - image = imgtool_directory_image(enumeration); - appleenum = (prodos_direnum *) imgtool_directory_extrabytes(enumeration); - - 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 *filesize, - UINT32 block, int nest_level, imgtool_stream *destf) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - UINT8 buffer[BLOCK_SIZE]; - UINT16 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 = MIN(*filesize, sizeof(buffer)); - stream_write(destf, buffer, bytes_to_write); - *filesize -= bytes_to_write; - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_write_file_tree(imgtool_image *image, UINT32 *filesize, - UINT32 block, int nest_level, imgtool_stream *sourcef) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - UINT8 buffer[BLOCK_SIZE]; - UINT16 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 = MIN(*filesize, sizeof(buffer)); - stream_read(sourcef, 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 *size) -{ - imgtoolerr_t err; - imgtool_image *image = imgtool_partition_image(partition); - prodos_diskinfo *di; - UINT8 *bitmap = NULL; - UINT16 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 = imgtool_partition_image(partition); - prodos_dirent ent; - UINT16 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) - stream_fill(destf, 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, option_resolution *opts) -{ - imgtoolerr_t err; - imgtool_image *image = imgtool_partition_image(partition); - prodos_dirent ent; - prodos_direnum direnum; - UINT64 file_size; - mac_fork_t fork_num; - - file_size = stream_size(sourcef); - - 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 = imgtool_partition_image(partition); - 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, imgtool_forkent *ents, size_t len) -{ - imgtoolerr_t err; - imgtool_image *image = imgtool_partition_image(partition); - prodos_dirent ent; - prodos_direnum direnum; - int fork_num = 0; - - 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 */ - ents[fork_num].type = FORK_DATA; - ents[fork_num].forkname[0] = '\0'; - ents[fork_num].size = ent.filesize[0]; - fork_num++; - - if (is_extendedfile_storagetype(ent.storage_type)) - { - /* specify the resource fork */ - ents[fork_num].type = FORK_RESOURCE; - strcpy(ents[fork_num].forkname, "RESOURCE_FORK"); - ents[fork_num].size = ent.filesize[1]; - fork_num++; - } - - ents[fork_num].type = FORK_END; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_createdir(imgtool_partition *partition, const char *path) -{ - imgtoolerr_t err; - imgtool_image *image = imgtool_partition_image(partition); - 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 *volume_bitmap, UINT16 key_pointer) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - int i; - UINT16 next_block; - UINT32 offset; - UINT8 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 = imgtool_partition_image(partition); - prodos_dirent ent; - prodos_direnum direnum; - UINT8 *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 block, UINT8 total_depth, UINT8 cur_depth) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - int i; - UINT16 sub_block; - UINT8 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 *attrs, imgtool_attribute *values) -{ - imgtoolerr_t err; - imgtool_image *image = imgtool_partition_image(partition); - 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); - break; - case IMGTOOLATTR_TIME_LASTMODIFIED: - values[i].t = prodos_crack_time(ent.lastmodified_time); - break; - } - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_setattrs(imgtool_partition *partition, const char *path, const UINT32 *attrs, const imgtool_attribute *values) -{ - imgtoolerr_t err; - imgtool_image *image = imgtool_partition_image(partition); - 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 = imgtool_partition_image(partition); - 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 = imgtool_partition_image(partition); - 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 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 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 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/mess/tools/imgtool/modules/psion.c b/src/mess/tools/imgtool/modules/psion.c deleted file mode 100644 index d343dde5c6a..00000000000 --- a/src/mess/tools/imgtool/modules/psion.c +++ /dev/null @@ -1,683 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Sandro Ronco -/*************************************************************************** - - Psion Organiser II Datapack - - 08/18/2010 Sandro Ronco - - Known file types: - 0x00 invalid record - 0x01 - 0x7e deleted record - 0x7f invalid deleted record - 0x80 long record - 0x81 file name - 0x82 diary - 0x83 OPL/OB3 procedure - 0x84 RS232 setup - 0x85 - 0x8f reserved - 0x90 MAIN Record - 0x91 - 0xfe data records from files - 0xff invalid record - -****************************************************************************/ - -#include "imgtool.h" - -#define MAXFILES 256 - -struct psion_file -{ - char filename[9]; - UINT8 type; - UINT8 id; - - UINT16 name_rec; - UINT16 data_rec; -}; - -struct psion_pack -{ - imgtool_stream *stream; - - UINT16 eop; - struct psion_file pack_index[MAXFILES]; -}; - -struct psion_iter -{ - UINT16 index; -}; - -UINT16 head_checksum(UINT8* data) -{ - UINT16 checksum = 0; - - for (int i=0; i<6; i+=2) - checksum += (data[i]<<8 | data[i+1]); - - return checksum; -} - -UINT16 get_long_rec_size(imgtool_stream *stream) -{ - UINT8 size_h, size_l; - - stream_read(stream, &size_h, 1); - stream_read(stream, &size_l, 1); - - return (size_h<<8) | size_l; -} - -UINT32 update_pack_index(psion_pack *pack) -{ - UINT8 data, type; - UINT16 size; - UINT16 index = 0; - - memset(pack->pack_index, 0, sizeof(psion_file) * MAXFILES); - - // start at the first record - stream_seek(pack->stream, 0x10, SEEK_SET); - - do - { - stream_read(pack->stream, &data, 1); - - if(data == 0xff) - { - pack->eop = stream_tell(pack->stream) - 1; - return TRUE; - } - else if (data == 0x02) - { - // long record without name are ignored - stream_read(pack->stream, &data, 1); - size = get_long_rec_size(pack->stream); - stream_seek(pack->stream, size, SEEK_CUR); - } - else - { - stream_read(pack->stream, &type, 1); - - // deleted record are not listed - if (type < 0x90 && (type & 0x80)) - { - pack->pack_index[index].type = type; - stream_read(pack->stream, &pack->pack_index[index].filename, 8); - stream_read(pack->stream, &pack->pack_index[index].id, 1); - pack->pack_index[index].name_rec = stream_tell(pack->stream) - 11; - - //check for data record - stream_read(pack->stream, &data, 1); - if (data == 0x02) - pack->pack_index[index].data_rec = stream_tell(pack->stream) - 1; - - stream_seek(pack->stream, -1, SEEK_CUR); - - index++; - } - else - stream_seek(pack->stream, data, SEEK_CUR); - } - - } while (stream_size(pack->stream) > stream_tell(pack->stream)); - - // corrupted image - return FALSE; -} - -int seek_next_record(imgtool_stream *stream, UINT8 id) -{ - UINT8 data, rec_id; - UINT16 size; - - do - { - stream_read(stream, &data, 1); - - if(data == 0xff) - break; - - if (data == 2) - { - stream_read(stream, &rec_id, 1); - size = get_long_rec_size(stream); - - } - else - { - stream_read(stream, &rec_id, 1); - if (id == rec_id) - { - stream_seek(stream, -2, SEEK_CUR); - return TRUE; - } - size = data; - } - - // next record - stream_seek(stream, size, SEEK_CUR); - - } while (stream_size(stream) > stream_tell(stream)); - - return FALSE; -} - -// if there are multiple files with the same name, only the first is found -int seek_file_name(psion_pack *pack, const char *filename) -{ - UINT16 index = 0; - - while (pack->pack_index[index].name_rec) - { - if (!strncmp(filename, pack->pack_index[index].filename, strlen(filename))) - return index; - index++; - } - - // filename not found - return -1; -} - -UINT8 get_free_file_id(psion_pack *pack) -{ - for (UINT8 file_id=0x91; file_id<0xff; file_id++) - { - int index = 0; - - while (pack->pack_index[index].id != file_id) - if (pack->pack_index[index++].name_rec == 0) - return file_id; - } - - return 0xff; -} - -void put_name_record(imgtool_stream *stream, const char* filename, UINT8 record_type, UINT8 record_id) -{ - char data[0x10]; - int i = 0; - - data[i++] = 0x09; - data[i++] = record_type; - - // filename is 8 char long space filled - for (int j=0; j<8; j++) - if (j < strlen(filename)) - data[i++] = filename[j]; - else - data[i++] = 0x20; - - data[i++] = record_id; - - stream_write(stream, data, i); -} - -void update_opk_head(imgtool_stream *stream) -{ - UINT16 size = stream_size(stream) - 6; - - stream_seek(stream, 4, SEEK_SET); - stream_putc(stream, (size>>8) & 0xff); - stream_putc(stream, size & 0xff); -} - -char *stream_getline(imgtool_stream *source, UINT16 max_len) -{ - UINT16 pos = 0; - char data; - char *line = (char*)malloc(max_len); - memset(line, 0, max_len); - - while (pos < max_len && stream_size(source) > stream_tell(source)) - { - stream_read(source, &data, 1); - - switch(data) - { - case '\r': - stream_read(source, &data, 1); - if (data != '\n') - stream_seek(source, -1, SEEK_CUR); - case '\n': - return line; - default: - line[pos++] = data; - break; - } - } - - if (pos) - return line; - - free(line); - return NULL; -} - -UINT16 put_odb(imgtool_stream *instream, imgtool_stream *outstream, UINT8 file_id) -{ - char *line; - UINT16 out_size = 0; - - // reset stream - stream_seek(instream, 0, SEEK_SET); - - while ((line = stream_getline(instream, 256))) - { - UINT16 len = strlen(line); - - stream_putc(outstream, (UINT8)len); - stream_putc(outstream, file_id); - stream_write(outstream, line, len); - - out_size += (len + 1); - - free(line); - } - - // end of pack - stream_fill(outstream, 0xff, 2); - - return out_size + 4; -} - -UINT16 put_ob3(imgtool_stream *instream, imgtool_stream *outstream) -{ - UINT16 size = stream_size(instream) - 6; - dynamic_buffer buffer(size); - - stream_seek(instream, 6, SEEK_SET); - stream_read(instream, &buffer[0], size); - - stream_write(outstream, &buffer[0], size); - - // end of pack - stream_fill(outstream, 0xff, 2); - - return size; -} - -UINT16 put_opl(imgtool_stream *instream, imgtool_stream *outstream) -{ - UINT16 out_size = 0; - UINT32 rec_start = stream_tell(outstream); - char *line; - - // reset stream - stream_seek(instream, 0, SEEK_SET); - - stream_fill(outstream, 0x00, 4); - - // replace all eol with 0x00 - while ((line = stream_getline(instream, 256))) - { - // replace tab with space - for (int i=0; i<strlen(line); i++) - if (line[i] == '\t') line[i] = ' '; - - stream_write(outstream, line, strlen(line)); - stream_putc(outstream, 0x00); - out_size += strlen(line) + 1; - free(line); - } - - // end of pack - stream_fill(outstream, 0xff, 2); - - // update the size in the head - stream_seek(outstream, rec_start + 2, SEEK_SET); - stream_putc(outstream, (out_size>>8) & 0xff); - stream_putc(outstream, out_size & 0xff); - - return out_size + 4; -} - -UINT16 get_odb(imgtool_stream *instream, imgtool_stream *outstream, UINT8 type, UINT8 file_id) -{ - UINT8 data, *buffer; - UINT16 out_size = 0; - - if (file_id >= 0x90) - while (seek_next_record(instream, file_id)) - { - stream_read(instream, &data, 1); - stream_seek(instream, 1, SEEK_CUR); - buffer = (UINT8*)malloc(data); - stream_read(instream, buffer, data); - stream_write(outstream, buffer, data); - stream_putc(outstream, '\r'); - stream_putc(outstream, '\n'); - free (buffer); - out_size += data; - } - - return out_size; -} - -UINT16 get_ob3(imgtool_stream *instream, imgtool_stream *outstream, UINT8 type, UINT8 file_id) -{ - UINT8 data, *buffer = NULL; - UINT16 size = 0; - static const char ob3_magic[3] = {'O', 'R', 'G'}; - - stream_read(instream, &data, 1); - - if (data == 0x02) - { - stream_seek(instream, 1, SEEK_CUR); - size = get_long_rec_size(instream); - buffer = (UINT8*)malloc(size); - stream_read(instream, buffer, size); - } - - stream_write(outstream, ob3_magic, 3); - stream_putc(outstream, (size>>8) & 0xff); - stream_putc(outstream, size & 0xff); - stream_putc(outstream, type | 0x80); - - if (buffer) - { - stream_write(outstream, buffer, size); - free (buffer); - } - - return size; -} - -static imgtoolerr_t datapack_open( imgtool_image *image, imgtool_stream *stream) -{ - psion_pack *pack = (psion_pack*)imgtool_image_extra_bytes(image); - char opk_magic[4]; - - stream_read(stream, opk_magic, 4); - - if(strcmp(opk_magic, "OPK\0")) - return IMGTOOLERR_UNEXPECTED; - - pack->stream = stream; - - if (update_pack_index(pack)) - return IMGTOOLERR_SUCCESS; - else - return IMGTOOLERR_CORRUPTIMAGE; -} - -static imgtoolerr_t datapack_create( imgtool_image *image, imgtool_stream *stream, option_resolution *opts) -{ - psion_pack *pack = (psion_pack*)imgtool_image_extra_bytes(image); - static const UINT8 opk_magic[4] = {'O', 'P', 'K', 0x00}; - UINT8 pack_head[8] = {0x40, 0x00, 0x59, 0x01, 0x01, 0x01, 0x00, 0x00}; - UINT16 checksum; - - pack_head[0] |= (option_resolution_lookup_int(opts, 'R')) ? 0x00 : 0x02; - pack_head[0] |= (option_resolution_lookup_int(opts, 'P')) ? 0x04 : 0x00; - pack_head[0] |= (option_resolution_lookup_int(opts, 'W')) ? 0x00 : 0x08; - pack_head[0] |= (option_resolution_lookup_int(opts, 'B')) ? 0x00 : 0x10; - pack_head[0] |= (option_resolution_lookup_int(opts, 'C')) ? 0x20 : 0x00; - pack_head[1] = option_resolution_lookup_int(opts, 'S'); - - checksum = head_checksum(pack_head); - - stream_write(stream, opk_magic, 4); - stream_fill(stream, 0x00, 2); - stream_write(stream, pack_head, 8); - - stream_putc(stream, (checksum>>8) & 0xff); - stream_putc(stream, checksum & 0xff); - - put_name_record(stream, "MAIN", 0x81, 0x90); - - stream_fill(stream, 0xff, 2); - - update_opk_head(stream); - - pack->stream = stream; - - if (update_pack_index(pack)) - return IMGTOOLERR_SUCCESS; - else - return IMGTOOLERR_CORRUPTIMAGE; -} - -static void datapack_close( imgtool_image *image) -{ - psion_pack *pack = (psion_pack*)imgtool_image_extra_bytes(image); - - stream_close( pack->stream ); -} - -static imgtoolerr_t datapack_begin_enum(imgtool_directory *enumeration, const char *path) -{ - psion_iter *iter = (psion_iter*)imgtool_directory_extrabytes(enumeration); - iter->index = 0; - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t datapack_next_enum(imgtool_directory *enumeration, imgtool_dirent *ent) -{ - imgtool_image *image = imgtool_directory_image(enumeration); - psion_pack *pack = (psion_pack*)imgtool_image_extra_bytes(image); - psion_iter *iter = (psion_iter*)imgtool_directory_extrabytes(enumeration); - UINT8 data = 0; - - if (!pack->pack_index[iter->index].name_rec) - { - ent->eof = 1; - 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); - - if (pack->pack_index[iter->index].data_rec) - { - stream_seek(pack->stream, pack->pack_index[iter->index].data_rec + 2, SEEK_SET); - ent->filesize = get_long_rec_size(pack->stream); - } - - // seek all file's records - if (pack->pack_index[iter->index].id >= 0x90) - { - stream_seek(pack->stream, 0x10, SEEK_SET); - while (seek_next_record(pack->stream, pack->pack_index[iter->index].id)) - { - stream_read(pack->stream, &data, 1); - stream_seek(pack->stream, data + 1, SEEK_CUR); - ent->filesize +=data; - } - } - - iter->index++; - return IMGTOOLERR_SUCCESS; -} - -static void datapack_close_enum( imgtool_directory *enumeration) -{ -} - -static imgtoolerr_t datapack_free_space( imgtool_partition *partition, UINT64 *size) -{ - imgtool_image *image = imgtool_partition_image( partition); - psion_pack *pack = (psion_pack*)imgtool_image_extra_bytes(image); - UINT32 pack_size = 0; - - stream_seek(pack->stream, 0x07, SEEK_SET); - stream_read(pack->stream, &pack_size, 1); - - if (size) - *size = (pack_size * 0x2000) - pack->eop; - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t datapack_read_file(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf) -{ - imgtool_image *image = imgtool_partition_image(partition); - psion_pack *pack = (psion_pack*)imgtool_image_extra_bytes(image); - int index = seek_file_name(pack, filename); - - if (index >= 0) - { - if ((pack->pack_index[index].type & 0x7f) == 0x01) - { - // ODB files - stream_seek(pack->stream, 0x10, SEEK_SET); - get_odb(pack->stream, destf, pack->pack_index[index].type, pack->pack_index[index].id); - } - else if ((pack->pack_index[index].type & 0x7f) == 0x03) - { - // OB3/OPL files - stream_seek(pack->stream, pack->pack_index[index].data_rec, SEEK_SET); - get_ob3(pack->stream, destf, pack->pack_index[index].type, pack->pack_index[index].id); - } - else - { - // Other files - return IMGTOOLERR_UNIMPLEMENTED; - } - - return IMGTOOLERR_SUCCESS; - } - else - return IMGTOOLERR_FILENOTFOUND; -} - -static imgtoolerr_t datapack_write_file( imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, option_resolution *opts) -{ - imgtool_image *image = imgtool_partition_image(partition); - psion_pack *pack = (psion_pack*)imgtool_image_extra_bytes(image); - static const UINT8 data_head[4] = {0x02, 0x80, 0x00, 0x00}; - UINT8 head[3]; - UINT16 size = 0; - UINT8 type = option_resolution_lookup_int(opts, 'T'); - UINT8 file_id = option_resolution_lookup_int(opts, 'I'); - - if (!pack->eop) - return IMGTOOLERR_CORRUPTIMAGE; - - // if not file_id is specified get the first free (for ODB only) - if (file_id == 0 && type == 3) - { - file_id = get_free_file_id(pack); - - if (file_id == 0xff) - return IMGTOOLERR_NOSPACE; - } - - stream_read(sourcef, head, 3); - stream_seek(pack->stream, pack->eop, SEEK_SET); - - if (type == 0) - type = (!strncmp((char*)head, "ORG", 3)) ? 1 : 2; - - switch (type) - { - case 1: //OB3 file - put_name_record(pack->stream, filename, 0x83, file_id); - stream_write(pack->stream, data_head, 4); - size = put_ob3(sourcef, pack->stream); - break; - case 2: //OPL file - put_name_record(pack->stream, filename, 0x83, file_id); - stream_write(pack->stream, data_head, 4); - size = put_opl(sourcef, pack->stream); - break; - case 3: //ODB file - put_name_record(pack->stream, filename, 0x81, file_id); - size = put_odb(sourcef, pack->stream, file_id); - break; - } - - if (type != 3) - { - // update the OB3/OPL long record size - stream_seek(pack->stream, pack->eop + 13, SEEK_SET); - stream_putc(pack->stream, (size>>8) & 0xff); - stream_putc(pack->stream, size & 0xff); - } - - update_opk_head(pack->stream); - - if (update_pack_index(pack)) - return IMGTOOLERR_SUCCESS; - else - return IMGTOOLERR_CORRUPTIMAGE; -} - -static imgtoolerr_t datapack_delete_file( imgtool_partition *partition, const char *filename) -{ - imgtool_image *image = imgtool_partition_image(partition); - psion_pack *pack = (psion_pack*)imgtool_image_extra_bytes(image); - int index = seek_file_name(pack, filename); - - if (index >= 0) - { - // clear the bit 7 of the file type to mark the file as deleted - stream_seek(pack->stream, pack->pack_index[index].name_rec + 1, SEEK_SET); - stream_putc(pack->stream, pack->pack_index[index].type & 0x7f); - - if (update_pack_index(pack)) - return IMGTOOLERR_SUCCESS; - else - return IMGTOOLERR_CORRUPTIMAGE; - } - else - return IMGTOOLERR_FILENOTFOUND; -} - -static OPTION_GUIDE_START( psion_create_optguide ) - OPTION_ENUM_START( 'S', "size", "datapack size" ) - OPTION_ENUM( 1, "8k", "8 kbyte" ) - OPTION_ENUM( 2, "16k", "16 kbyts" ) - OPTION_ENUM( 4, "32k", "32 kbyte" ) - OPTION_ENUM( 8, "64k", "64 kbyte" ) - OPTION_ENUM( 16, "128k", "128 kbyte" ) // only paged datapacks can have this size - OPTION_ENUM_END - OPTION_INT('R', "ram", "EPROM/RAM datapack" ) - OPTION_INT('P', "paged", "linear/paged datapack" ) - OPTION_INT('W', "protect", "write-protected datapack" ) - OPTION_INT('B', "boot", "bootable datapack" ) - OPTION_INT('C', "copy", "copyable datapack" ) -OPTION_GUIDE_END - -static OPTION_GUIDE_START( psion_write_optguide ) - OPTION_ENUM_START( 'T', "type", "file type" ) - OPTION_ENUM( 1, "OB3", "OB3 files" ) - OPTION_ENUM( 2, "OPL", "OPL files" ) - OPTION_ENUM( 3, "ODB", "ODB or text files" ) - OPTION_ENUM_END - OPTION_INT( 'I', "id", "File ID" ) -OPTION_GUIDE_END - -void psion_get_info( const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info) -{ - switch (state) - { - // --- the following bits of info are returned as 64-bit signed integers --- - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES : info->i = sizeof(psion_pack); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES : info->i = sizeof(psion_iter); break; - - // --- the following bits of info are returned as pointers to data or functions --- - case IMGTOOLINFO_PTR_OPEN : info->open = datapack_open; break; - case IMGTOOLINFO_PTR_CREATE : info->create = datapack_create; break; - case IMGTOOLINFO_PTR_CLOSE : info->close = datapack_close; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM : info->begin_enum = datapack_begin_enum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM : info->next_enum = datapack_next_enum; break; - case IMGTOOLINFO_PTR_CLOSE_ENUM : info->close_enum = datapack_close_enum; break; - case IMGTOOLINFO_PTR_FREE_SPACE : info->free_space = datapack_free_space; break; - case IMGTOOLINFO_PTR_READ_FILE : info->read_file = datapack_read_file; break; - case IMGTOOLINFO_PTR_WRITE_FILE : info->write_file = datapack_write_file; break; - case IMGTOOLINFO_PTR_DELETE_FILE : info->delete_file = datapack_delete_file; break; - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE : info->createimage_optguide = psion_create_optguide; break; - case IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE : info->createimage_optguide = psion_write_optguide; break; - - // --- the following bits of info are returned as NULL-terminated strings --- - case IMGTOOLINFO_STR_NAME : strcpy( info->s = imgtool_temp_str(), "psionpack"); break; - case IMGTOOLINFO_STR_DESCRIPTION : strcpy( info->s = imgtool_temp_str(), "Psion Organiser II Datapack"); break; - case IMGTOOLINFO_STR_FILE : strcpy( info->s = imgtool_temp_str(), __FILE__); break; - case IMGTOOLINFO_STR_FILE_EXTENSIONS : strcpy( info->s = imgtool_temp_str(), "opk"); break; - case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC : strcpy( info->s = imgtool_temp_str(), "S1/2/[4]/8/16;R[0]/1;P[0]/1;W0/[1];B[0]/1;C0/[1]"); break; - case IMGTOOLINFO_STR_WRITEFILE_OPTSPEC : strcpy( info->s = imgtool_temp_str(), "T[1]/2/3;I[0]/145-255"); break; - } -} diff --git a/src/mess/tools/imgtool/modules/rsdos.c b/src/mess/tools/imgtool/modules/rsdos.c deleted file mode 100644 index 8323574b001..00000000000 --- a/src/mess/tools/imgtool/modules/rsdos.c +++ /dev/null @@ -1,623 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/**************************************************************************** - - rsdos.c - - CoCo RS-DOS disk images - -****************************************************************************/ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include "imgtool.h" -#include "formats/coco_dsk.h" -#include "iflopimg.h" - -/* this structure mirrors the structure of an RS-DOS directory entry on disk */ -struct rsdos_dirent -{ - char fname[8]; - char fext[3]; - char ftype; - char asciiflag; - unsigned char first_granule; - unsigned char lastsectorbytes_msb; - unsigned char lastsectorbytes_lsb; - unsigned char unused[16]; -}; - -struct rsdos_direnum -{ - int index; - int eof; -}; - -#define RSDOS_OPTIONS_FTYPE 'T' -#define RSDOS_OPTIONS_ASCII 'M' - - - -/********************************************************************* - Imgtool module code -*********************************************************************/ - -#define MAX_DIRENTS ((18-2)*(256/32)) -static floperr_t get_rsdos_dirent(imgtool_image *f, int index_loc, struct rsdos_dirent *ent) -{ - return floppy_read_sector(imgtool_floppy(f), 0, 17, 3, index_loc * 32, (void *) ent, sizeof(*ent)); -} - - - -static floperr_t put_rsdos_dirent(imgtool_image *f, int index_loc, const struct rsdos_dirent *ent) -{ - if (index_loc >= MAX_DIRENTS) - return (floperr_t)IMGTOOLERR_FILENOTFOUND; - return floppy_write_sector(imgtool_floppy(f), 0, 17, 3, index_loc * 32, (void *) ent, sizeof(*ent), 0); /* TODO: pass ddam argument from imgtool */ -} - - - -/* fnamebuf must have at least 13 bytes */ -static void get_dirent_fname(char *fnamebuf, const struct rsdos_dirent *ent) -{ - char *s; - - memset(fnamebuf, 0, 13); - memcpy(fnamebuf, ent->fname, sizeof(ent->fname)); - rtrim(fnamebuf); - s = fnamebuf + strlen(fnamebuf); - *(s++) = '.'; - memcpy(s, ent->fext, sizeof(ent->fext)); - rtrim(s); - - /* If no extension, remove period */ - if (*s == '\0') - s[-1] = '\0'; -} - - - -static imgtoolerr_t lookup_rsdos_file(imgtool_image *f, const char *fname, struct rsdos_dirent *ent, int *position) -{ - int i; - floperr_t ferr; - char fnamebuf[13]; - - i = 0; - fnamebuf[0] = '\0'; - - do - { - do - { - ferr = get_rsdos_dirent(f, i++, ent); - if (ferr) - return imgtool_floppy_error(ferr); - } - while(ent->fname[0] == '\0'); - - - if (ent->fname[0] != -1) - get_dirent_fname(fnamebuf, ent); - } - while((ent->fname[0] != -1) && core_stricmp(fnamebuf, fname)); - - if (ent->fname[0] == -1) - return IMGTOOLERR_FILENOTFOUND; - - if (position) - *position = i - 1; - return (imgtoolerr_t)0; -} - - - -static UINT8 get_granule_count(imgtool_image *img) -{ - UINT16 tracks; - UINT16 granules; - - tracks = floppy_get_tracks_per_disk(imgtool_floppy(img)); - granules = (tracks - 1) * 2; - return (granules > 255) ? 255 : (UINT8) granules; -} - -#define MAX_GRANULEMAP_SIZE 256 - -/* granule_map must be an array of MAX_GRANULEMAP_SIZE bytes */ -static floperr_t get_granule_map(imgtool_image *img, UINT8 *granule_map, UINT8 *granule_count) -{ - UINT8 count; - - count = get_granule_count(img); - if (granule_count) - *granule_count = count; - - return floppy_read_sector(imgtool_floppy(img), 0, 17, 2, 0, granule_map, count); -} - - - -static floperr_t put_granule_map(imgtool_image *img, const UINT8 *granule_map, UINT8 granule_count) -{ - return floppy_write_sector(imgtool_floppy(img), 0, 17, 2, 0, granule_map, granule_count, 0); /* TODO: pass ddam argument from imgtool */ -} - - - - -static imgtoolerr_t transfer_granule(imgtool_image *img, UINT8 granule, int length, imgtool_stream *f, imgtoolerr_t (*proc)(imgtool_image *, int, int, int, int, size_t, imgtool_stream *)) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - UINT8 track, sector; - - track = granule / 2; - if (track >= 17) - track++; - - sector = (granule % 2) ? 10 : 1; - - if (length > 0) - err = proc(img, 0, track, sector, 0, length, f); - return err; -} - - - -static imgtoolerr_t transfer_from_granule(imgtool_image *img, UINT8 granule, int length, imgtool_stream *destf) -{ - return transfer_granule(img, granule, length, destf, imgtool_floppy_read_sector_to_stream); -} - - - -static imgtoolerr_t transfer_to_granule(imgtool_image *img, UINT8 granule, int length, imgtool_stream *sourcef) -{ - return transfer_granule(img, granule, length, sourcef, imgtool_floppy_write_sector_from_stream); -} - - - -static imgtoolerr_t process_rsdos_file(struct rsdos_dirent *ent, imgtool_image *img, imgtool_stream *destf, size_t *size) -{ - floperr_t ferr; - size_t s, lastgransize; - UINT8 granule_count; - unsigned char i = 0, granule; - UINT8 usedmap[MAX_GRANULEMAP_SIZE]; /* Used to detect infinite loops */ - UINT8 granule_map[MAX_GRANULEMAP_SIZE]; - - ferr = get_granule_map(img, granule_map, &granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - memset(usedmap, 0, granule_count); - - lastgransize = ent->lastsectorbytes_lsb + (((int) ent->lastsectorbytes_msb) << 8); - s = 0; - granule = ent->first_granule; - - while(!usedmap[granule] && ((i = granule_map[granule]) < granule_count)) - { - usedmap[granule] = 1; - if (destf) - transfer_from_granule(img, granule, 9*256, destf); - - /* i is the next granule */ - s += (256 * 9); - granule = i; - } - - if ((i < 0xc0) || (i > 0xc9)) - return IMGTOOLERR_CORRUPTIMAGE; - - if (lastgransize) - i--; - lastgransize += (256 * (i - 0xc0)); - - if (destf) - transfer_from_granule(img, granule, lastgransize, destf); - - if (size) - *size = s + lastgransize; - return IMGTOOLERR_SUCCESS; -} - - - -/* create a new directory entry with a specified name */ -static imgtoolerr_t prepare_dirent(struct rsdos_dirent *ent, const char *fname) -{ - const char *fname_end; - const char *fname_ext; - int fname_ext_len; - - memset(ent, '\0', sizeof(*ent)); - memset(ent->fname, ' ', sizeof(ent->fname)); - memset(ent->fext, ' ', sizeof(ent->fext)); - - 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->fname, fname, fname_end - fname); - memcpy(ent->fext, fname_ext, fname_ext_len); - - /* For now, all files are type 2 binary files */ - ent->ftype = 2; - ent->asciiflag = 0; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t rsdos_diskimage_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent) -{ - floperr_t ferr; - imgtoolerr_t err; - size_t filesize; - struct rsdos_direnum *rsenum; - struct rsdos_dirent rsent; - char fname[13]; - imgtool_image *image; - - image = imgtool_directory_image(enumeration); - rsenum = (struct rsdos_direnum *) imgtool_directory_extrabytes(enumeration); - - /* Did we hit the end of file before? */ - if (rsenum->eof) - goto eof; - - do - { - if (rsenum->index >= MAX_DIRENTS) - goto eof; - - ferr = get_rsdos_dirent(image, rsenum->index++, &rsent); - if (ferr) - return imgtool_floppy_error(ferr); - } - while(rsent.fname[0] == '\0'); - - /* Now are we at the eof point? */ - if (rsent.fname[0] == -1) - { - rsenum->eof = 1; -eof: - ent->eof = 1; - } - else - { - /* Not the end of file */ - err = process_rsdos_file(&rsent, image, NULL, &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; - - 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')); - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t rsdos_diskimage_freespace(imgtool_partition *partition, UINT64 *size) -{ - floperr_t ferr; - UINT8 i; - size_t s = 0; - UINT8 granule_count; - UINT8 granule_map[MAX_GRANULEMAP_SIZE]; - imgtool_image *image = imgtool_partition_image(partition); - - ferr = get_granule_map(image, granule_map, &granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - for (i = 0; i < granule_count; i++) - { - if (granule_map[i] == 0xff) - s += (9 * 256); - } - *size = s; - return (imgtoolerr_t)FLOPPY_ERROR_SUCCESS; -} - - - -static imgtoolerr_t delete_entry(imgtool_image *img, struct rsdos_dirent *ent, int pos) -{ - floperr_t ferr; - unsigned char g, i; - UINT8 granule_count; - UINT8 granule_map[MAX_GRANULEMAP_SIZE]; - - /* Write a NUL in the filename, marking it deleted */ - ent->fname[0] = 0; - ferr = put_rsdos_dirent(img, pos, ent); - if (ferr) - return imgtool_floppy_error(ferr); - - ferr = get_granule_map(img, granule_map, &granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - /* Now free up the granules */ - g = ent->first_granule; - while (g < granule_count) - { - i = granule_map[g]; - granule_map[g] = 0xff; - g = i; - } - - ferr = put_granule_map(img, granule_map, granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t rsdos_diskimage_readfile(imgtool_partition *partition, const char *fname, const char *fork, imgtool_stream *destf) -{ - imgtoolerr_t err; - struct rsdos_dirent ent; - size_t size; - imgtool_image *img = imgtool_partition_image(partition); - - err = lookup_rsdos_file(img, fname, &ent, NULL); - if (err) - return err; - - err = process_rsdos_file(&ent, img, destf, &size); - if (err) - return err; - - if (size == (size_t) -1) - return IMGTOOLERR_CORRUPTIMAGE; - - return (imgtoolerr_t)0; -} - - - -static imgtoolerr_t rsdos_diskimage_writefile(imgtool_partition *partition, const char *fname, const char *fork, imgtool_stream *sourcef, option_resolution *writeoptions) -{ - floperr_t ferr; - imgtoolerr_t err; - imgtool_image *img = imgtool_partition_image(partition); - struct rsdos_dirent ent, ent2; - size_t i; - UINT64 sz; - UINT64 freespace = 0; - unsigned char g; - unsigned char *gptr; - UINT8 granule_count; - UINT8 granule_map[MAX_GRANULEMAP_SIZE]; - - /* can we write to this image? */ - if (floppy_is_read_only(imgtool_floppy(img))) - return IMGTOOLERR_READONLY; - - err = rsdos_diskimage_freespace(partition, &freespace); - if (err) - return err; - - /* is there enough space? */ - sz = stream_size(sourcef); - if (sz > freespace) - return IMGTOOLERR_NOSPACE; - - /* setup our directory entry */ - err = prepare_dirent(&ent, fname); - if (err) - return err; - - ent.ftype = option_resolution_lookup_int(writeoptions, RSDOS_OPTIONS_FTYPE); - ent.asciiflag = ((UINT8) option_resolution_lookup_int(writeoptions, RSDOS_OPTIONS_ASCII)) - 1; - ent.lastsectorbytes_lsb = sz % 256; - ent.lastsectorbytes_msb = (((sz % 256) == 0) && (sz > 0)) ? 1 : 0; - gptr = &ent.first_granule; - - ferr = get_granule_map(img, granule_map, &granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - g = 0x00; - - do - { - while (granule_map[g] != 0xff) - { - g++; - if ((g >= granule_count) || (g == 0)) - return IMGTOOLERR_UNEXPECTED; /* We should have already verified that there is enough space */ - } - *gptr = g; - gptr = &granule_map[g]; - - - i = MIN(sz, (9*256)); - err = transfer_to_granule(img, g, i, sourcef); - if (err) - return err; - - sz -= i; - - /* Go to next granule */ - g++; - } - while(sz > 0); - - /* Now that we are done with the file, we need to specify the final entry - * in the file allocation table - */ - *gptr = 0xc0 + ((i + 255) / 256); - - /* Now we need to find an empty directory entry */ - i = -1; - do - { - ferr = get_rsdos_dirent(img, ++i, &ent2); - if (ferr) - return imgtool_floppy_error(ferr); - } - while((ent2.fname[0] != '\0') && strcmp(ent.fname, ent2.fname) && (ent2.fname[0] != -1)); - - /* delete file if it already exists */ - if (ent2.fname[0] && (ent2.fname[0] != -1)) - { - err = delete_entry(img, &ent2, i); - if (err) - return err; - } - - ferr = put_rsdos_dirent(img, i, &ent); - if (ferr) - return imgtool_floppy_error(ferr); - - /* write the granule map back out */ - ferr = put_granule_map(img, granule_map, granule_count); - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t rsdos_diskimage_deletefile(imgtool_partition *partition, const char *fname) -{ - imgtoolerr_t err; - imgtool_image *image = imgtool_partition_image(partition); - int pos; - struct rsdos_dirent ent; - - err = lookup_rsdos_file(image, fname, &ent, &pos); - if (err) - return err; - - return delete_entry(image, &ent, pos); -} - - - -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 = imgtool_partition_image(partition); - struct rsdos_dirent ent; - int pos; - - if (fname) - { - err = lookup_rsdos_file(image, fname, &ent, &pos); - if (err) - return err; - - if (ent.asciiflag == (char) 0xFF) - { - /* ASCII file */ - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = filter_eoln_getinfo; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = NULL; - } - else if (ent.ftype == 0) - { - /* tokenized BASIC file */ - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = filter_cocobas_getinfo; - } - } - else - { - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = filter_eoln_getinfo; - suggestions[2].viability = SUGGESTION_POSSIBLE; - suggestions[2].filter = filter_cocobas_getinfo; - } - - return IMGTOOLERR_SUCCESS; -} - - - -/********************************************************************* - Imgtool module declaration -*********************************************************************/ - -static OPTION_GUIDE_START( coco_rsdos_writefile_optionguide ) - OPTION_ENUM_START( RSDOS_OPTIONS_FTYPE, "ftype", "File type" ) - OPTION_ENUM( 0, "basic", "Basic" ) - OPTION_ENUM( 1, "data", "Data" ) - OPTION_ENUM( 2, "binary", "Binary" ) - OPTION_ENUM( 3, "assembler", "Assembler Source" ) - OPTION_ENUM_END - OPTION_ENUM_START( RSDOS_OPTIONS_ASCII, "ascii", "Ascii flag" ) - OPTION_ENUM( 0, "ascii", "Ascii" ) - OPTION_ENUM( 1, "binary", "Binary" ) - OPTION_ENUM_END -OPTION_GUIDE_END - - - -void rsdos_get_info(const imgtool_class *imgclass, UINT32 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 rsdos_direnum); break; - - /* --- the following bits of info are returned as NULL-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; - case IMGTOOLINFO_STR_EOLN: strcpy(info->s = imgtool_temp_str(), "\r"); break; - case IMGTOOLINFO_STR_WRITEFILE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), "T0-[2]-3;M0-[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_NEXT_ENUM: info->next_enum = rsdos_diskimage_nextenum; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = rsdos_diskimage_freespace; break; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = rsdos_diskimage_readfile; break; - case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = rsdos_diskimage_writefile; break; - case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = rsdos_diskimage_deletefile; break; - case IMGTOOLINFO_PTR_SUGGEST_TRANSFER: info->suggest_transfer = rsdos_diskimage_suggesttransfer; break; - case IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE: info->writefile_optguide = coco_rsdos_writefile_optionguide; break; - case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_coco; break; - } -} diff --git a/src/mess/tools/imgtool/modules/thomson.c b/src/mess/tools/imgtool/modules/thomson.c deleted file mode 100644 index 43684bc0aea..00000000000 --- a/src/mess/tools/imgtool/modules/thomson.c +++ /dev/null @@ -1,1681 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Antoine Mine -/**************************************************************************** - - Copyright (C) Antoine Mine' 2006 - - Thomson 8-bit micro-computers. - - Handles SAP, QD and FD floppy formats with a BASIC-DOS filesystem - (most floppies except some games and demo). - -*****************************************************************************/ - -/* TODO: - - improve two-sided floppy support - - check & correct BASIC read filter - - implement BASIC write filter - - handle accented letters - */ - - -/* Thomson floppy geometry are: - - 5"1/4 single density: 40 tracks, 16 sectors/track, 128 bytes/sector - - 5"1/4 double density: 40 tracks, 16 sectors/track, 256 bytes/sector - - 3"1/2 double density: 80 tracks, 16 sectors/track, 256 bytes/sector - - 2"8: 25 logical tracks, 16 logical sectors/track, 128 bytes/sector - - Notes: - - - 2"8 QDD actually contain a single spiraling track, with 400 128-byte - sectors; however, the filesystem considers it has 25 virtual tracks of - 16 sectors => we do the same in imgtool (but thomflop.c uses a 400-sector - addressing to emulate the device hardware) - - - tracks always have 16 sectors, this is requred by the filesystem - - - two-sided floppies are handled as two one-sided floppies in two - logical floppy drives on the original Thomsons; each has its own - independent FAT and directory. - In imgtool, we handle two-sided images as two partitions. - For now, only 3"1/2 .fd and QDD .qd files can be two-sided. - - - it seems possible to create 3"1/2 single density floppies on the TO9, - I am not sure this is standard, and we do not support it... - -*/ - - -/* Microsoft BASIC Filesystem. - - The floppy is divided into blocks, with always two blocks / track. - Also, in double density, only the first 255 bytes of each 256-byte - sector is used. Thus, blocks are 1024 bytes in single density, and - 2040 bytes in double density. - Depending on the number of tracks, there can be 50, 80 or 160 blocks. - - Filesystem data always occupy track 20, whatever the floppy geometry. - - * sector 1: - - bytes 0-7: floppy name - - remaining bytes: undocumented, seem unused - - * sector 2: FAT, 1 byte info per block - - byte 0: always 0 - - byte 1: block 0 - ... - - byte i: block i-1 - ... - - byte 160: block 159 - - remaining bytes: undocumented, seem unused - - The byte has the following meaning: - - ff: block is free - - fb: block is reserved - - 00-bf: block allocated, points to then next file block - - c1-c8: last block in file, (value & 15) is the number of sectors - actually allocated to the file - - Note: in single density, we can reference only 127 blocks. This is not - a problem because single density floppies can only have 50 or 80 blocks, - never 160. - - * sector 3-16: directory - - no subdirectories - - each file entry occupies 32 bytes: - - bytes 00-07: filename, padded with whitespaces - - bytes 08-0A: file extension, padedd with whitespaces - - byte 0B: file type - . 0 = BASIC, ASCII or binary program (B) - . 1 = BASIC or ASCII data (D) - . 2 = machine code (M) - . 3 = ASCII assembler file (A) - - byte 0C: format flag - . 00 = binary (tokenized) - . ff = ASCII - - byte 0D: first block - - bytes 0E-0F: bytes used in the last sector - - bytes 10-17: comment - - byte 18: day (of month) - - byte 19: month - - byte 1A: year (two last digits) - - bytes 1B-1f: unknown - - Note that byte 0 has a special significance: - - 00: free directory entry - - 20-7F: actual directory entry, value is the first character ini filename - - ff: end of directory - - There can be 56 files in single density, 112 in double density. - */ - -#include "imgtool.h" -#include "iflopimg.h" - -#include <time.h> - - -#define MAXSIZE 80*16*256*2 /* room for two faces, double-density, 80 tracks */ - -struct thom_floppy { - imgtool_stream *stream; - - UINT16 sector_size; /* 128 or 256 */ - UINT16 sectuse_size; /* bytes used in sector: 128 or 255 */ - UINT8 tracks; /* 25, 40, or 80 */ - UINT8 heads; /* 1 or 2 */ - UINT8 data[MAXSIZE]; /* image data */ - - int modified; /* data need to be copied back to image file */ - -}; - - -enum thom_dirent_type { - THOM_DIRENT_END, - THOM_DIRENT_FREE, - THOM_DIRENT_FILE, - THOM_DIRENT_INVALID, - -}; - - -struct thom_dirent { - thom_dirent_type type; - int index; - - char name[9]; - char ext[4]; - char comment[9]; - UINT8 ftype; - UINT8 format; - UINT8 firstblock; - UINT16 lastsectsize; - UINT8 day; - UINT8 month; - UINT8 year; - -}; - - -static void thom_basic_get_info(const imgtool_class *clas, UINT32 param, - union imgtoolinfo *info); - -static UINT8* thom_get_sector(thom_floppy* f, unsigned head, - unsigned track, unsigned sector); - - -/*********************** .fd / .qd format ************************/ - -/* .fd and .qd formats are very simple: the sectors are simply put one after - another, starting at sector 1 of track 0 to sector 16 track 0, then - starting again at sector 1 of track 1, and so on. - There is no image or sector header, and no gap between sectors. - The number of tracks and sector size are determined by the extension - (.fd have 40 or 80 tracks, .qd have 25 tracks) and the file size. -*/ - -static imgtoolerr_t thom_open_fd_qd(imgtool_image *img, imgtool_stream *stream) -{ - thom_floppy* f = (thom_floppy*) imgtool_image_extra_bytes( img ); - int size = stream_size( stream ); - - f->stream = stream; - f->modified = 0; - - /* guess format */ - switch ( size ) { - case 81920: - f->tracks = 40; - f->sector_size = 128; - f->sectuse_size = 128; - f->heads = 1; - break; - - case 163840: - f->tracks = 40; - f->sector_size = 256; - f->sectuse_size = 255; - f->heads = 1; - /* could also be: sector_size=128, heads=2 */ - /* maight even be: tracks=80, sector_size=128 */ - break; - - case 327680: - f->tracks = 80; - f->sector_size = 256; - f->sectuse_size = 255; - f->heads = 1; - /* could also be: tracks=40, heads=2 */ - break; - - case 655360: - f->tracks = 80; - f->sector_size = 256; - f->sectuse_size = 255; - f->heads = 2; - break; - - case 51200: - f->tracks = 25; - f->sector_size = 128; - f->sectuse_size = 128; - f->heads = 1; - break; - - case 62400: - f->tracks = 25; - f->sector_size = 128; - f->sectuse_size = 128; - f->heads = 2; - break; - - default: - return IMGTOOLERR_CORRUPTIMAGE; - } - - assert( size == f->heads * f->tracks * 16 * f->sector_size ); - - stream_seek( stream, 0, SEEK_SET ); - if ( stream_read( stream, f->data, size ) < size ) - return IMGTOOLERR_READERROR; - - return IMGTOOLERR_SUCCESS; -} - -static void thom_close_fd_qd(imgtool_image *img) -{ - thom_floppy* f = (thom_floppy*) imgtool_image_extra_bytes( img ); - - /* save image */ - if ( f->modified ) { - int size = f->heads * f->tracks * 16 * f->sector_size; - stream_seek( f->stream, 0, SEEK_SET ); - if ( stream_write( f->stream, f->data, size ) < size ) - { - /* logerror( "thom_diskimage_close_fd_qd: write error\n" ); */ - } - } - - stream_close( f->stream ); -} - - -/*********************** .sap format ************************/ - -/* SAP format, Copyright 1998 by Alexandre Pukall - - image is composed of: - - byte 0: version (0 or 1) - - bytes 1..65: signature - - bytes 66..end: sectors - - each sector is composed of - - a 4-byte header: - . byte 0: format - 0 3"1/2 double density - 1 5"1/4 low density - . byte 1: protection (?) - . byte 2: track index, in 0..79 - . byte 3: sector index, in 1..16 - - sector data, XOR 0xB3 - - 2-byte CRC of header + data, high byte first - - there is no provision for two-sided images in sap - */ - -static const int sap_magic_num = 0xB3; /* simple XOR crypt */ - -static const char sap_header[]= - "\001SYSTEME D'ARCHIVAGE PUKALL S.A.P. " - "(c) Alexandre PUKALL Avril 1998"; - -static const UINT16 sap_crc[] = { - 0x0000, 0x1081, 0x2102, 0x3183, 0x4204, 0x5285, 0x6306, 0x7387, - 0x8408, 0x9489, 0xa50a, 0xb58b, 0xc60c, 0xd68d, 0xe70e, 0xf78f, -}; - -static UINT16 thom_sap_crc( UINT8* data, int size ) -{ - int i; - UINT16 crc = 0xffff, crc2; - for ( i = 0; i < size; i++ ) { - crc2 = ( crc >> 4 ) ^ sap_crc[ ( crc ^ data[i] ) & 15 ]; - crc = ( crc2 >> 4 ) ^ sap_crc[ ( crc2 ^ (data[i] >> 4) ) & 15 ]; - } - return crc; -} - -static imgtoolerr_t thom_open_sap(imgtool_image *img, imgtool_stream *stream) -{ - thom_floppy* f = (thom_floppy*) imgtool_image_extra_bytes( img ); - UINT8 buf[262]; - - f->stream = stream; - f->modified = 0; - - /* check image header */ - stream_seek( stream, 0, SEEK_SET ); - stream_read( stream, buf, 66 ); - if ( memcmp( buf+1, sap_header+1, 65 ) ) return IMGTOOLERR_CORRUPTIMAGE; - - /* guess format */ - stream_read( stream, buf, 1 ); - switch ( buf[0] ) { - case 1: - case 3: - f->heads = 1; - f->tracks = 40; - f->sector_size = 128; - f->sectuse_size = 128; - break; - case 0: - case 2: - case 4: - f->heads = 1; - f->tracks = 80; - f->sector_size = 256; - f->sectuse_size = 255; - break; - default: return IMGTOOLERR_CORRUPTIMAGE; - } - - stream_seek( stream, 66, SEEK_SET ); - while ( 1) { - int i, sector, track; - UINT16 crc; - - /* load sector */ - if ( stream_read( stream, buf, 6 + f->sector_size ) < 6 + f->sector_size ) - break; - - /* parse sector header */ - track = buf[2]; - sector = buf[3]; - if ( sector < 1 || sector > 16 || track >= f->tracks ) - return IMGTOOLERR_CORRUPTIMAGE; - - /* decrypt */ - for ( i = 0; i < f->sector_size; i++ ) buf[ i + 4 ] ^= sap_magic_num; - memcpy( thom_get_sector( f, 0, track, sector ), buf + 4, f->sector_size ); - - /* check CRC */ - crc = thom_sap_crc( buf, f->sector_size + 4 ); - if ( ( (crc >> 8) != buf[ f->sector_size + 4 ] ) || - ( (crc & 0xff) != buf[ f->sector_size + 5 ] ) ) - return IMGTOOLERR_CORRUPTIMAGE; - } - - return IMGTOOLERR_SUCCESS; -} - -static void thom_close_sap(imgtool_image *img) -{ - thom_floppy* f = (thom_floppy*) imgtool_image_extra_bytes( img ); - - if ( f->modified ) { - int i, sector, track; - UINT8 buf[262]; - UINT16 crc; - - /* rewind */ - stream_seek( f->stream, 0, SEEK_SET ); - - /* image header */ - if ( stream_write( f->stream, sap_header, 66 ) < 66 ) { - /* logerror( "thom_diskimage_close_sap: write error\n" ); */ - return; - } - - for ( track = 0; track < f->tracks; track++ ) - for ( sector = 1; sector <= 16; sector++ ) { - /* sector header & data */ - buf[0] = ( f->tracks == 80 ) ? 2 : 1; - buf[1] = 0; - buf[2] = track; - buf[3] = sector; - memcpy( buf + 4, - thom_get_sector( f, 0, track, sector), f->sector_size ); - - /* compute crc */ - crc = thom_sap_crc( buf, f->sector_size + 4 ); - buf[ f->sector_size + 4 ] = crc >> 8; - buf[ f->sector_size + 5 ] = crc & 0xff; - - /* crypt */ - for ( i = 0; i < f->sector_size; i++ ) buf[ i + 4 ] ^= sap_magic_num; - - /* save */ - if ( stream_write( f->stream, buf, f->sector_size + 6 ) < - f->sector_size + 6 ) { - /* logerror( "thom_diskimage_close_sap: write error\n" ); */ - return; - } - } - } - - stream_close( f->stream ); -} - - -/*********************** low-level functions *********************/ - -static UINT8* thom_get_sector(thom_floppy* f, unsigned head, - unsigned track, unsigned sector) -{ - assert( head < f->heads); - assert( track < f->tracks ); - assert( sector > 0 && sector <= 16 ); - return & f->data[ ( (head * f->tracks + track) * 16 + (sector-1) ) * - f->sector_size ]; -} - -static int thom_nb_blocks(thom_floppy* f) -{ - int n1 = f->tracks * 2; /* 2 blocks per track */ - int n2 = f->sector_size - 1; /* FAT entries */ - return (n1 < n2) ? n1 : n2; -} - -static int thom_max_dirent(thom_floppy* f) -{ - return 14 * f->sector_size / 32; -} - -/* remove trailing spaces */ -static void thom_stringify(char* str) -{ - char* s = str + strlen(str) - 1; - while ( s >= str && *s == ' ' ) { *s = 0; s--; } - for ( s = str; *s; s++ ) - if ( (UINT8)*s == 0xff ) *s = 0; - else if ( *s < ' ' || *s >= 127 ) *s = '?'; -} - -/* pad with spaces until the length is nb */ -static void thom_unstringity(char* str, int nb) -{ - char* s = str; - while ( s < str + nb && *s ) s++; - while ( s < str + nb ) { *s = ' '; s++; } -} - -/* get filename and extension & truncate them to 8 + 3 */ -static void thom_conv_filename(const char* s, char name[9], char ext[4]) -{ - int i; - memset( name, 0, 9 ); - memset( ext, 0, 4 ); - for ( i = 0; i < 8 && *s && *s != '.'; i++, s++ ) name[i] = *s; - while ( *s && *s != '.' ) s++; - if ( *s == '.' ) { - s++; - for ( i = 0; i < 3 && *s; i++, s++ ) ext[i] = *s; - } -} - -static time_t thom_crack_time(thom_dirent* d) -{ - struct tm t; - time_t now; - - /* check */ - if ( d->day < 1 || d->day > 31 || d->month < 1 || d->month > 12 ) return 0; - - /* converts */ - time( &now ); - t = *localtime( &now ); - t.tm_sec = 0; - t.tm_min = 0; - t.tm_hour = 0; - t.tm_mday = d->day; - t.tm_mon = d->month - 1; - t.tm_year = (d->year < 65 ) ? d->year + 100 : d->year; - return mktime(&t); -} - -static void thom_make_time(thom_dirent* d, time_t time) -{ - if ( ! time ) { - d->day = d->month = d->year = 0; - } - else { - struct tm t = *localtime( &time ); - d->day = t.tm_mday; - d->month = t.tm_mon + 1; - d->year = t.tm_year % 100; - } -} - -static void thom_make_time_now(thom_dirent* d) -{ - time_t now; - time( &now ); - thom_make_time( d, now ); -} - -static void thom_get_dirent(thom_floppy* f, unsigned head, - unsigned n, thom_dirent* d) -{ - UINT8* base = thom_get_sector( f, head, 20, 3 ) + n * 32; - memset( d, 0, sizeof(*d) ); - d->index = n; - if ( n >= thom_max_dirent( f ) ) - d->type = THOM_DIRENT_END; - else if ( *base == 0xff ) - d->type = THOM_DIRENT_END; - else if ( *base == 0 ) - d->type = THOM_DIRENT_FREE; - else { - int i; - /* fill regular entry */ - d->type = THOM_DIRENT_FILE; - memcpy( d->name, base, 8 ); - memcpy( d->ext, base + 8, 3 ); - memcpy( d->comment, base + 16, 8 ); - thom_stringify( d->name ); - thom_stringify( d->ext ); - thom_stringify( d->comment ); - d->ftype = base[11]; - d->format = base[12]; - d->firstblock = base[13]; - d->lastsectsize = ((int)base[14] << 8) + base[15]; - d->day = base[24]; - d->month = base[25]; - d->year = base[26]; - /* sanity check */ - for ( i = 0; i < 11; i++ ) - if ( base[i] < ' ' || base[i] > 127 ) d->type = THOM_DIRENT_INVALID; - } -} - -static void thom_set_dirent(thom_floppy* f, unsigned head, - unsigned n, thom_dirent* d) -{ - UINT8* base = thom_get_sector( f, head, 20, 3 ) + n * 32; - if ( n >= thom_max_dirent( f ) ) return; - memset( base, 0, 32 ); - if ( d->type == THOM_DIRENT_END ) base[ 0 ] = 0xff; - else if ( d->type == THOM_DIRENT_FREE ) base[ 0 ] = 0; - else { - memcpy( base, d->name, 8 ); - memcpy( base + 8, d->ext, 3 ); - memcpy( base + 16, d->comment, 8 ); - thom_unstringity( (char*)base, 8 ); - thom_unstringity( (char*)base + 8, 3 ); - if ( base[16] ) thom_unstringity( (char*)base + 16, 8 ); - base[11] = d->ftype; - base[12] = d->format; - base[13] = d->firstblock; - base[14] = d->lastsectsize >> 8; - base[15] = d->lastsectsize & 0xff; - base[24] = d->day; - base[25] = d->month; - base[26] = d->year; - } - f->modified = 1; -} - -/* returns 1 if file found, 0 if not */ -static int thom_find_dirent(thom_floppy* f, unsigned head, - const char* name, thom_dirent* d) -{ - 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++; - } -} - -/* returns 1 if free entry found, 0 if none available */ -static int thom_find_free_dirent(thom_floppy* f, unsigned head, thom_dirent* d) -{ - int n = 0; - while ( 1 ) { - thom_get_dirent( f, head, n, d ); - if ( d->type == THOM_DIRENT_FREE ) return 1; - if ( d->type == THOM_DIRENT_END ) break; - n++; - } - if ( n + 1 >= thom_max_dirent( f ) ) return 0; - thom_set_dirent( f, head, n+1, d ); - d->type = THOM_DIRENT_FREE; - return 1; -} - -/* returns the file size in bytes, or -1 if error */ -static int thom_get_file_size(thom_floppy* f, unsigned head, thom_dirent* d) -{ - UINT8* fat = thom_get_sector( f, head, 20, 2 ); - int nbblocks = thom_nb_blocks(f); - int block = d->firstblock; - int size = 0; - int timeout = nbblocks; - if ( d->type != THOM_DIRENT_FILE ) return -1; - if ( block >= nbblocks ) return -1; - block = fat[ block + 1 ]; - while ( 1 ) { - if ( block < nbblocks ) { - /* full block */ - size += 8 * f->sectuse_size; - block = fat[ block + 1 ]; - } - else if ( block >= 0xc1 && block <= 0xc8 ) { - /* last block in file */ - size += (block-0xc1) * f->sectuse_size; - size += d->lastsectsize; - return size; - } - else return -1; - timeout--; - if ( timeout < 0 ) return -1; - } -} - -/* number of blocks used by file */ -static int thom_get_file_blocks(thom_floppy* f, unsigned head, thom_dirent* d) -{ - UINT8* fat = thom_get_sector( f, head, 20, 2 ); - int nbblocks = thom_nb_blocks(f); - int block = d->firstblock; - int nb = 0; - if ( d->type != THOM_DIRENT_FILE ) return 0; - if ( block >= nbblocks ) return 0; - block = fat[ block + 1 ]; - while ( 1 ) { - if ( block < nbblocks ) { - /* full block */ - nb++; - block = fat[ block + 1 ]; - } - else if ( block >= 0xc1 && block <= 0xc8 ) { - /* last block in file */ - nb++; - return nb; - } - else return nb; - } -} - -/* number of free blocks */ -static int thom_get_free_blocks(thom_floppy* f, unsigned head) -{ - UINT8* fat = thom_get_sector( f, head, 20, 2 ); - int nbblocks = thom_nb_blocks(f); - int i, nb = 0; - for ( i = 1; i <= nbblocks; i++ ) - if ( fat[i] == 0xff ) nb++; - return nb; -} - -/* dump file contents into dst */ -static void thom_get_file(thom_floppy* f, unsigned head, - thom_dirent* d, imgtool_stream *dst) -{ - UINT8* fat = thom_get_sector( f, head, 20, 2 ); - int nbblocks = thom_nb_blocks(f); - int block = d->firstblock; - if ( block >= nbblocks ) return; - while ( 1 ) { - int nextblock = fat[ block + 1 ]; - int track = block / 2; - int firstsect = (block % 2) ? 9 : 1; - if ( nextblock < nbblocks ) { - /* full block */ - int i; - for ( i = 0; i < 8; i++ ) { - UINT8* data = thom_get_sector( f, head, track, firstsect + i ); - stream_write( dst, data, f->sectuse_size ); - } - block = fat[ block + 1 ]; - } - else if ( nextblock >= 0xc1 && nextblock <= 0xc8 ) { - /* last block in file */ - int i; - UINT8* data; - for ( i = 0; i < nextblock - 0xc1; i++ ) { - data = thom_get_sector( f, head, track, firstsect + i ); - stream_write( dst, data, f->sectuse_size ); - } - data = thom_get_sector( f, head, track, firstsect + i ); - stream_write( dst, data, d->lastsectsize ); - return; - } - else { - /* invalid, assume last block */ - UINT8* data = thom_get_sector( f, head, track, firstsect ); - stream_write( dst, data, d->lastsectsize ); - return; - } - block = nextblock; - } -} - -static void thom_del_file(thom_floppy* f, unsigned head, thom_dirent* d) -{ - UINT8* fat = thom_get_sector( f, head, 20, 2 ); - int nbblocks = thom_nb_blocks(f); - int block = d->firstblock; - if ( d->type != THOM_DIRENT_FILE ) return; - if ( block >= nbblocks ) return; - while ( 1 ) { - int nextblock = fat[ block + 1 ]; - fat[ block ] = 0xff; - if ( nextblock < nbblocks ) block = fat[ block + 1 ]; - else break; - } - d->type = THOM_DIRENT_FREE; - thom_set_dirent( f, head, d->index, d ); - f->modified = 1; -} - -/* create a new file or overwrite an old one, with the contents of src */ -static void thom_put_file(thom_floppy* f, unsigned head, - thom_dirent* d, imgtool_stream *src) -{ - int size = stream_size( src ); - UINT8* fat = thom_get_sector( f, head, 20, 2 ); - int nbblocks = thom_nb_blocks(f); - int block; - - /* find first free block */ - for ( block = 0; block < nbblocks && fat[ block + 1 ] != 0xff; block++ ); - if ( block >= nbblocks ) return; - d->firstblock = block; - - /* store file */ - while (1) { - int track = block / 2; - int firstsect = (block % 2) ? 9 : 1; - int i; - - /* store data, full sectors */ - for ( i = 0; i < 8 && size > f->sectuse_size; i++ ) { - UINT8* dst = thom_get_sector( f, head, track, firstsect + i ); - stream_read( src, dst, f->sectuse_size ); - size -= f->sectuse_size; - } - - /* store data, last sector */ - if ( i < 8 ) { - UINT8* dst = thom_get_sector( f, head, track, firstsect + i ); - stream_read( src, dst, size ); - fat[ block + 1 ] = 0xc1 + i; - d->lastsectsize = size; - break; - } - - /* find next free block & update fat */ - i = block; - for ( block++; block < nbblocks && fat[ block + 1 ] != 0xff; block++ ); - if ( block >= nbblocks ) { - /* out of memory! */ - fat[ i + 1 ] = 0; - d->lastsectsize = 0; - break; - } - fat[ i + 1 ] = block; - } - - d->type = THOM_DIRENT_FILE; - thom_set_dirent( f, head, d->index, d ); - f->modified = 1; -} - - -/********************** module functions ***********************/ - -static imgtoolerr_t thom_get_sector_size(imgtool_image* img, UINT32 track, - UINT32 head, UINT32 sector, - UINT32 *sector_size) -{ - thom_floppy* f = (thom_floppy*) imgtool_image_extra_bytes( img ); - - if ( head >= f->heads || sector < 1 || sector > 16 || track >= f->tracks ) { - if ( sector_size ) *sector_size = 0; - return IMGTOOLERR_SEEKERROR; - } - if ( sector_size ) *sector_size = f->sector_size; - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_get_geometry(imgtool_image* img, UINT32* tracks, - UINT32* heads, UINT32* sectors) -{ - thom_floppy* f = (thom_floppy*) imgtool_image_extra_bytes( img ); - if ( tracks ) *tracks = f->tracks; - if ( heads ) *heads = f->heads; - if ( sectors ) *sectors = 16; - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_read_sector(imgtool_image* img, UINT32 track, - UINT32 head, UINT32 sector, void *buf, - size_t len) -{ - thom_floppy* f = (thom_floppy*) imgtool_image_extra_bytes( img ); - if ( head >= f->heads || sector < 1 || sector > 16 || track >= f->tracks ) - return IMGTOOLERR_SEEKERROR; - if ( len > f->sector_size) return IMGTOOLERR_READERROR; - memcpy( buf, thom_get_sector( f, head, track, sector ), len ); - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_write_sector(imgtool_image *img, UINT32 track, - UINT32 head, UINT32 sector, - const void *buf, size_t len, int ddam) -{ - thom_floppy* f = (thom_floppy*) imgtool_image_extra_bytes( img ); - if ( stream_isreadonly( f->stream ) ) return IMGTOOLERR_WRITEERROR; - if ( head >= f->heads || sector < 1 || sector > 16 || track >= f->tracks ) - return IMGTOOLERR_SEEKERROR; - if ( len > f->sector_size) return IMGTOOLERR_WRITEERROR; - f->modified = 1; - memcpy( thom_get_sector( f, head, track, sector ), buf, len ); - return IMGTOOLERR_SUCCESS; -} - -/* returns floopy name */ -/* actually, each side has its own name, but we only return the one on side 0. - */ -static void thom_info(imgtool_image *img, char *string, size_t len) -{ - thom_floppy* f = (thom_floppy*) imgtool_image_extra_bytes( img ); - UINT8* base = thom_get_sector( f, 0, 20, 1 ); - char buf[9]; - memcpy( buf, base, 8 ); - buf[8] = 0; - thom_stringify( buf ); - strncpy( string, buf, len ); -} - -/* each side of a floppy has its own filesystem, we treat them as'partitions' - */ -static imgtoolerr_t thom_list_partitions(imgtool_image *img, - imgtool_partition_info *partitions, - size_t len) -{ - thom_floppy* f = (thom_floppy*) imgtool_image_extra_bytes( img ); - if ( len >= 1 ) { - partitions[0].get_info = thom_basic_get_info; - partitions[0].base_block = 0; - partitions[0].block_count = 1; - } - if ( len >= 2 && f->heads >= 2 ) { - partitions[1].get_info = thom_basic_get_info; - partitions[1].base_block = 1; - partitions[1].block_count = 1; - } - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_open_partition(imgtool_partition *part, - UINT64 first_block, UINT64 block_count) -{ - imgtool_image* img = imgtool_partition_image( part ); - thom_floppy* f = (thom_floppy*) imgtool_image_extra_bytes( img ); - if ( first_block >= f->heads ) - return IMGTOOLERR_INVALIDPARTITION; - * ( (int*) imgtool_partition_extra_bytes( part ) ) = first_block; - return IMGTOOLERR_SUCCESS; -} - - -static imgtoolerr_t thom_begin_enum(imgtool_directory *enumeration, - const char *path) -{ - int* n = (int*) imgtool_directory_extrabytes( enumeration ); - *n = 0; - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_next_enum(imgtool_directory *enumeration, - imgtool_dirent *ent) -{ - imgtool_partition *part = imgtool_directory_partition( enumeration); - int head = *( (int*) imgtool_partition_extra_bytes( part ) ); - imgtool_image* img = imgtool_partition_image( part ); - thom_floppy* f = (thom_floppy*) imgtool_image_extra_bytes( img ); - int* n = (int*) imgtool_directory_extrabytes( enumeration ); - thom_dirent d; - - do { - thom_get_dirent( f, head, *n, &d ); - (*n) ++; - } - while ( d.type == THOM_DIRENT_FREE ); - if ( d.type == THOM_DIRENT_END ) ent->eof = 1; - else if ( d.type == THOM_DIRENT_INVALID ) { - ent->corrupt = 1; - } - else { - int size; - snprintf( ent->filename, sizeof(ent->filename), "%s.%s", d.name, d.ext ); - snprintf( ent->attr, sizeof(ent->attr), "%c %c %s", - (d.ftype == 0) ? 'B' : (d.ftype == 1) ? 'D' : - (d.ftype == 2) ? 'M' : (d.ftype == 3) ? 'A' : '?', - (d.format == 0) ? 'B' : (d.format == 0xff) ? 'A' : '?', - d.comment ); - ent->creation_time = thom_crack_time( &d ); - size = thom_get_file_size( f, head, &d ); - if ( size >= 0 ) ent->filesize = size; - else { - ent->filesize = 0; - ent->corrupt = 1; - } - } - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_free_space(imgtool_partition *part, UINT64 *size) -{ - int head = *( (int*) imgtool_partition_extra_bytes( part ) ); - imgtool_image* img = imgtool_partition_image( part ); - thom_floppy* f = (thom_floppy*) imgtool_image_extra_bytes( img ); - int nb = thom_get_free_blocks( f, head ); - (*size) = nb * f->sectuse_size * 8; - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_read_file(imgtool_partition *part, - const char *filename, - const char *fork, - imgtool_stream *destf) -{ - int head = *( (int*) imgtool_partition_extra_bytes( part ) ); - imgtool_image* img = imgtool_partition_image( part ); - thom_floppy* f = (thom_floppy*) imgtool_image_extra_bytes( img ); - thom_dirent d; - char name[9], ext[4], fname[14]; - int size; - - /* convert filename */ - thom_conv_filename( filename, name, ext ); - sprintf( fname, "%s.%s", name, ext ); - - if ( ! thom_find_dirent( f, head, fname, &d ) ) - return IMGTOOLERR_FILENOTFOUND; - size = thom_get_file_size( f, head, &d ); - if ( size < 0 ) return IMGTOOLERR_CORRUPTFILE; - thom_get_file( f, head, &d, destf ); - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_delete_file(imgtool_partition *part, - const char *filename) -{ - int head = *( (int*) imgtool_partition_extra_bytes( part ) ); - imgtool_image* img = imgtool_partition_image( part ); - thom_floppy* f = (thom_floppy*) imgtool_image_extra_bytes( img ); - thom_dirent d; - char name[9], ext[4], fname[14]; - - /* convert filename */ - thom_conv_filename( filename, name, ext ); - sprintf( fname, "%s.%s", name, ext ); - - if ( ! thom_find_dirent( f, head, fname, &d ) ) - return IMGTOOLERR_FILENOTFOUND; - /*if ( thom_get_file_size( f, head, &d ) < 0 ) return IMGTOOLERR_CORRUPTFILE;*/ - if ( stream_isreadonly( f->stream ) ) return IMGTOOLERR_WRITEERROR; - thom_del_file( f, head, &d ); - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_write_file(imgtool_partition *part, - const char *filename, - const char *fork, - imgtool_stream *sourcef, - option_resolution *opts) -{ - int head = *( (int*) imgtool_partition_extra_bytes( part ) ); - imgtool_image* img = imgtool_partition_image( part ); - thom_floppy* f = (thom_floppy*) imgtool_image_extra_bytes( img ); - thom_dirent d; - int size = stream_size( sourcef ); - int blocks = thom_get_free_blocks( f, head ); - char name[9], ext[4], fname[14]; - const char* comment; - int is_new = 1; - - if ( stream_isreadonly( f->stream ) ) return IMGTOOLERR_WRITEERROR; - - /* convert filename */ - thom_conv_filename( filename, name, ext ); - sprintf( fname, "%s.%s", name, ext ); - - /* check available space & find dir entry */ - if ( thom_find_dirent( f, head, fname, &d ) ) { - /* file already exists: delete it */ - if ( thom_get_file_size( f, head, &d ) < 0 ) return IMGTOOLERR_CORRUPTFILE; - blocks += thom_get_file_blocks( f, head, &d ); - if ( blocks * 8 * f->sectuse_size < size ) return IMGTOOLERR_NOSPACE; - thom_del_file( f, head, &d ); - is_new = 0; - } - else { - /* new file, need new dir entry */ - if ( blocks * 8 * f->sectuse_size < size ) return IMGTOOLERR_NOSPACE; - if ( ! thom_find_free_dirent( f, head, &d ) ) return IMGTOOLERR_NOSPACE; - thom_make_time_now( &d ); - } - - /* fill-in dir entry */ - memcpy( d.name, name, 9 ); - memcpy( d.ext, ext, 4 ); - - /* file type */ - switch ( option_resolution_lookup_int( opts, 'T' ) ) { - case 0: - if ( ! is_new ) break; - if ( ! core_stricmp( ext, "BAS" ) ) d.ftype = 0; - else if ( ! core_stricmp( ext, "BAT" ) ) d.ftype = 0; - else if ( ! core_stricmp( ext, "DAT" ) ) d.ftype = 1; - else if ( ! core_stricmp( ext, "ASC" ) ) d.ftype = 1; - else if ( ! core_stricmp( ext, "BIN" ) ) d.ftype = 2; - else if ( ! core_stricmp( ext, "MAP" ) ) d.ftype = 2; - else if ( ! core_stricmp( ext, "CFG" ) ) d.ftype = 2; - else if ( ! core_stricmp( ext, "ASM" ) ) d.ftype = 3; - else d.ftype = 2; - break; - case 1: d.ftype = 0; break; - case 2: d.ftype = 1; break; - case 3: d.ftype = 2; break; - case 4: d.ftype = 3; break; - } - - /* format flag */ - switch ( option_resolution_lookup_int( opts, 'F' ) ) { - case 0: - if ( ! is_new ) break; - if ( ! core_stricmp( ext, "DAT" ) ) d.format = 0xff; - else if ( ! core_stricmp( ext, "ASC" ) ) d.format = 0xff; - else if ( ! core_stricmp( ext, "ASM" ) ) d.format = 0xff; - else d.format = 0; - break; - case 1: d.format = 0; break; - case 2: d.format = 0xff; break; - } - - /* comment */ - comment = option_resolution_lookup_string( opts, 'C' ); - if ( comment && *comment ) - strncpy( d.comment, comment, 8 ); - - /* write file */ - thom_put_file( f, head, &d, sourcef ); - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_suggest_transfer(imgtool_partition *part, - const char *fname, - imgtool_transfer_suggestion *suggestions, - size_t suggestions_length) -{ - int head = *( (int*) imgtool_partition_extra_bytes( part ) ); - imgtool_image* img = imgtool_partition_image( part ); - thom_floppy* f = (thom_floppy*) imgtool_image_extra_bytes( img ); - thom_dirent d; - int is_basic = 0; - - 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 ( 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; - } - } - else { - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - } - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_create(imgtool_image* img, - imgtool_stream *stream, - option_resolution *opts) -{ - thom_floppy* f = (thom_floppy*) imgtool_image_extra_bytes( img ); - int i; - UINT8* buf; - const char* name; - - f->stream = stream; - f->modified = 0; - - /* get parameters */ - f->heads = option_resolution_lookup_int( opts, 'H' ); - f->tracks = option_resolution_lookup_int( opts, 'T' ); - name = option_resolution_lookup_string( opts, 'N' ); - switch ( option_resolution_lookup_int( opts, 'D' ) ) { - case 0: f->sector_size = 128; f->sectuse_size = 128; break; - case 1: f->sector_size = 256; f->sectuse_size = 255; break; - default: return IMGTOOLERR_PARAMCORRUPT; - } - - /* sanity checks */ - switch ( f->tracks ) { - case 25: if ( f->sector_size != 128 ) return IMGTOOLERR_PARAMCORRUPT; break; - case 40: break; - case 80: if ( f->sector_size != 256 ) return IMGTOOLERR_PARAMCORRUPT; break; - default: return IMGTOOLERR_PARAMCORRUPT; - } - - memset( f->data, 0xe5, sizeof( f->data ) ); - - for ( i = 0; i < f->heads; i++ ) { - /* disk info */ - buf = thom_get_sector( f, i, 20, 1 ); - memset( buf, 0xff, f->sector_size ); - if ( name ) { - strncpy( (char*)buf, name, 8 ); - thom_unstringity( (char*)buf, 8 ); - } - else memset( buf, ' ', 8 ); - - /* FAT */ - buf = thom_get_sector( f, i, 20, 2 ); - memset( buf, 0, f->sector_size ); - memset( buf + 1, 0xff, thom_nb_blocks( f ) ); - buf[ 41 ] = buf[ 42 ] = 0xfe; /* reserved for FAT */ - - /* (empty) directory */ - buf = thom_get_sector( f, i, 20, 3 ); - memset( buf, 0xff, 14 * f->sector_size ); - } - - f->modified = 1; - - return IMGTOOLERR_SUCCESS; -} - - -/****************** BASIC tokenization *********************/ - -/* character codes >= 128 are reserved for BASIC keywords */ - -static const char *const thombas7[2][128] = { - { /* statements */ - "END", "FOR", "NEXT", "DATA", "DIM", "READ", "LET", "GO", "RUN", "IF", - "RESTORE", "RETURN", "REM", "'", "STOP", "ELSE", "TRON", "TROFF", "DEFSTR", - "DEFINT", "DEFSNG", "DEFDBL", "ON", "WAIT", "ERROR", "RESUME", "AUTO", - "DELETE", "LOCATE", "CLS", "CONSOLE", "PSET", "MOTOR", "SKIP", "EXEC", - "BEEP", "COLOR", "LINE", "BOX", "UNMASK", "ATTRB", "DEF", "POKE", "PRINT", - "CONT", "LIST", "CLEAR", "WHILE", "WHEN", "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", "@", - ">", "=", "<", - /* DOS specific */ - "DSKINI", "DSKO$", "KILL", "NAME", "FIELD", "LSET", "RSET", - "PUT", "GET", "VERIFY", "DEVICE", "DIR", "FILES", "WRITE", "UNLOAD", - "BACKUP", "COPY", "CIRCLE", "PAINT", "DRAW", "RENUM", "SWAP", "DENSITY", - }, - { /* functions: 0xff prefix */ - "SGN", "INT", "ABS", "FRE", "SQR", "LOG", "EXP", "COS", "SIN", - "TAN", "PEEK", "LEN", "STR$", "VAL", "ASC", "CHR$", "EOF", "CINT", "CSNG", - "CDBL", "FIX", "HEX$", "OCT$", "STICK", "STRIG", "GR$", "LEFT$", "RIGHT$", - "MID$", "INSTR", "VARPTR", "RND", "INKEY$", "INPUT", "CSRLIN", "POINT", - "SCREEN", "POS", "PTRIG", - /* DOS specific */ - "DSKL", "CVI", "CVS", "CVD", "MKI$", "MKS$", "MKD$", "LOC", "LOF", - "SPACE$", "STRING$", "DSKI$", - } -}; - -/* 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", - "RESTORE", "RETURN", "REM", "'", "STOP", "ELSE", "TRON", "TROFF", "DEFSTR", - "DEFINT", "DEFSNG", NULL, "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", - "OPEN", "CLOSE", "INPEN", "PEN", "PLAY", "TAB(", "TO", "SUB", "FN", - "SPC(", "USING", "USR", "ERL", "ERR", "OFF", "THEN", "NOT", "STEP", - "+", "-", "*", "/", "^", "AND", "OR", "XOR", "EQV", "IMP", "MOD", "@", - ">", "=", "<", - /* DOS specific */ - "DSKINI", "DSKO$", "KILL", "NAME", "FIELD", "LSET", "RSET", - "PUT", "GET", "VERIFY", "DEVICE", "DIR", "FILES", "WRITE", "UNLOAD", - "BACKUP","COPY", "CIRCLE", "PAINT", "DRAW", "RENUM", "SWAP", "SEARCH", - "DENSITY", - }, - { /* 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$", - "MID$", "INSTR", "VARPTR", "RND", "INKEY$", "INPUT", "CSRLIN", "POINT", - "SCREEN", "POS", "PTRIG", - /* DOS specific */ - "DSKL", "CVI", "CVS", "CVD", "MKI$", "MKS$", "MKD$", "LOC", "LOF", - "SPACE$", "STRING$", "DSKI$", - } -}; - -/* BASIC 128 has many new keywords */ -/* DENSITY is missing on BASIC 512 & BASIC 128 for MO6 but, otherwise, they - have the same tokens -*/ -static const char *const thombas128[2][128] = { - { /* statements */ - "END", "FOR", "NEXT", "DATA", "DIM", "READ", "LET", "GO", "RUN", "IF", - "RESTORE", "RETURN", "REM", "'", "STOP", "ELSE", "TRON", "TROFF", "DEFSTR", - "DEFINT", "DEFSNG", "DEFDBL", "ON", "WAIT", "ERROR", "RESUME", "AUTO", - "DELETE", "LOCATE", "CLS", "CONSOLE", "PSET", "MOTOR", "SKIP", "EXEC", - "BEEP", "COLOR", "LINE", "BOX", "UNMASK", "ATTRB", "DEF", "POKE", "PRINT", - "CONT", "LIST", "CLEAR", "INTERVAL", "KEY", "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", "@", - ">", "=", "<", - "DSKINI", "DSKO$", "KILL", "NAME", "FIELD", "LSET", "RSET", - "PUT", "GET", "VERIFY", "DEVICE", "DIR", "FILES", "WRITE", "UNLOAD", - "BACKUP", "COPY", "CIRCLE", "PAINT", "RESET", "RENUM", "SWAP", "DENSITY", - "WINDOW", "PATTERN", "DO", "LOOP", "EXIT", "INMOUSE", "MOUSE", "CHAINE", - "COMMON", "SEARCH", "FWD", "TURTLE", - }, - { /* functions: 0xff prefix */ - "SGN", "INT", "ABS", "FRE", "SQR", "LOG", "EXP", "COS", "SIN", - "TAN", "PEEK", "LEN", "STR$", "VAL", "ASC", "CHR$", "EOF", "CINT", "CSNG", - "CDBL", "FIX", "HEX$", "OCT$", "STICK", "STRIG", "GR$", "LEFT$", "RIGHT$", - "MID$", "INSTR", "VARPTR", "RND", "INKEY$", "INPUT", "CSRLIN", "POINT", - "SCREEN", "POS", "PTRIG", - "DSKL", "CVI", "CVS", "CVD", "MKI$", "MKS$", "MKD$", "LOC", "LOF", - "SPACE$", "STRING$", "DSKI$", - "FKEY$", "MIN(", "MAX(", "ATN", "CRUNCH$", "MTRIG", "EVAL", "PALETTE", - "BANK", "HEAD", "ROT", "SHOW", "ZOOM", "TRACE", - } -}; - -/* tables for simple XOR encryption sieve */ -static const UINT8 crypt1[11] = { - 0x80, 0x19, 0x56, 0xAA, 0x80, 0x76, 0x22, 0xF1, 0x82, 0x38, 0xAA -}; - -static const UINT8 crypt2[13] = { - 0x86, 0x1E, 0xD7, 0xBA, 0x87, 0x99, 0x26, 0x64, 0x87, 0x23, 0x34, 0x58, 0x86 -}; - -/* decrypt BASIC protected files */ -static void thom_decrypt(imgtool_stream* out, imgtool_stream* in) -{ - int i1 = 11, i2 = 13; - while ( 1 ) { - UINT8 b; - if ( stream_read( in, &b, 1) < 1 ) break; - b = ( (UINT8)(b - i2) ^ crypt2[i2-1] ^ crypt1[i1-1] ) + i1; - stream_putc( out, b ); - i1--; i2--; - if ( !i1 ) i1 = 11; - if ( !i2 ) i2 = 13; - } -} - -/* encrypt BASIC protected files */ -static void thom_encrypt(imgtool_stream* out, imgtool_stream* in) -{ - int i1 = 11, i2 = 13; - while ( 1 ) { - UINT8 b; - if ( stream_read( in, &b, 1) < 1 ) break; - b = ( (UINT8)(b - i1) ^ crypt2[i2-1] ^ crypt1[i1-1] ) + i2; - stream_putc( out, b ); - i1--; i2--; - if ( !i1 ) i1 = 11; - if ( !i2 ) i2 = 13; - } -} - -static imgtoolerr_t thomcrypt_read_file(imgtool_partition *part, - const char *name, - const char *fork, imgtool_stream *dst) -{ - UINT8 buf[3]; - imgtool_stream *org = stream_open_mem( NULL, 0 ); - imgtoolerr_t err; - if ( !org ) return IMGTOOLERR_OUTOFMEMORY; - - /* read file */ - err = thom_read_file( part, name, fork, org ); - if ( err ) { - stream_close( org ); - return err; - } - - stream_seek( org, 0, SEEK_SET ); - if ( stream_read( org, buf, 3 ) < 3 || buf[0] != 0xfe ) { - /* regular file */ - stream_seek( org, 0, SEEK_SET ); - stream_transfer_all( dst, org ); - } - else { - /* encrypted file */ - stream_putc( dst, '\xff' ); - stream_write( dst, buf+1, 2 ); - thom_decrypt( dst, org ); - } - - stream_close( org ); - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thomcrypt_write_file(imgtool_partition *part, - const char *name, - const char *fork, imgtool_stream *src, - option_resolution *opts) -{ - UINT8 buf[3]; - - if ( stream_read( src, buf, 3 ) < 3 || buf[0] == 0xfe ) { - /* too short or already encrypted file */ - stream_seek( src, 0, SEEK_SET ); - return thom_write_file( part, name, fork, src, opts ); - } - else { - /* regular file */ - imgtool_stream *dst = stream_open_mem( NULL, 0 ); - imgtoolerr_t err; - if ( !dst ) return IMGTOOLERR_OUTOFMEMORY; - stream_putc( dst, '\xfe' ); - stream_write( dst, buf+1, 2 ); - thom_encrypt( dst, src ); - stream_seek( dst, 0, SEEK_SET ); - err = thom_write_file( part, name, fork, dst, opts ); - stream_close( dst); - return err; - } -} - -void filter_thomcrypt_getinfo(UINT32 state, union filterinfo *info) -{ - switch(state) { - case FILTINFO_STR_NAME: - info->s = "thomcrypt"; - break; - case FILTINFO_STR_HUMANNAME: - info->s = "Thomson BASIC, Protected file encryption (no tokenization)"; - break; - case FILTINFO_PTR_READFILE: - info->read_file = thomcrypt_read_file; - break; - case FILTINFO_PTR_WRITEFILE: - info->write_file = thomcrypt_write_file; - break; - } -} - -/* untokenization automatically decrypt protected files */ -static imgtoolerr_t thom_basic_read_file(imgtool_partition *part, - const char *name, - const char *fork, - imgtool_stream *dst, - const char *const table[2][128]) -{ - imgtool_stream *org = stream_open_mem( NULL, 0 ); - imgtoolerr_t err; - UINT8 buf[4]; - int i; - - if ( !org ) return IMGTOOLERR_OUTOFMEMORY; - - err = thomcrypt_read_file( part, name, fork, org ); - if ( err ) { - stream_close( org ); - return err; - } - stream_seek( org, 3, SEEK_SET ); /* skip header */ - - while ( 1 ) { - int in_str = 0, in_fun = 0; - int linelength, linenum; - - /* line header: line length and line number */ - /* I am not sure this is 100% correct but it works in many cases */ - if ( stream_read( org, buf, 2 ) < 2 ) goto end; - linelength = ((int)buf[0] << 8) + (int)buf[1] - 4; - if ( linelength <= 0 ) goto end; - if ( stream_read( org, buf, 2 ) < 2 ) goto end; - linenum = ((int)buf[0] << 8) + buf[1]; - stream_printf( dst, "%u ", linenum ); - - /* process line */ - for ( i = 0; i < linelength; i++ ) { - UINT8 c; - if ( stream_read( org, &c, 1 ) < 1 ) break; - if ( c == 0 ) { - /* Sometimes, linelength seems wrong and we must rely on the fact that - BASIC lines are 0-terminated. - At other times, there are 0 embedded within lines or extra stuff - between the 0 and the following line, and so, we must rely - on linelength to cut the line (!) - */ - if ( linelength > 256 ) break; - } - else if ( c == 0xff && ! in_str ) in_fun = 1; /* function prefix */ - else { - if ( c >= 0x80 && ! in_str ) { - /* token */ - const char* token = table[ in_fun ][ c - 0x80 ]; - if ( token ) stream_puts( dst, token ); - else stream_puts( dst, "???" ); - } - else { - /* regular character */ - if ( c == '"' ) in_str = 1 - in_str; - stream_putc( dst, c ); /* normal letter */ - } - in_fun = 0; - } - } - stream_putc( dst, '\n' ); - } - end: - - stream_close( org ); - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t thom_basic_write_file(imgtool_partition *part, - const char *name, - const char *fork, - imgtool_stream *src, - option_resolution *opts, - const char *const table[2][128]) -{ - return IMGTOOLERR_UNIMPLEMENTED; -} - - -#define FILTER(short,long) \ - static imgtoolerr_t short##_read_file(imgtool_partition *part, \ - const char *name, \ - const char *fork, \ - imgtool_stream *dst) \ - { \ - 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, \ - option_resolution *opts) \ - { \ - return thom_basic_write_file( part, name, fork, src, opts, short ); \ - } \ - void filter_##short##_getinfo(UINT32 state, union filterinfo *info) \ - { \ - switch(state) \ - { \ - case FILTINFO_STR_NAME: \ - info->s = #short; \ - break; \ - case FILTINFO_STR_HUMANNAME: \ - info->s = long; \ - break; \ - case FILTINFO_PTR_READFILE: \ - info->read_file = short##_read_file; \ - break; \ - case FILTINFO_PTR_WRITEFILE: \ - info->write_file = short##_write_file; \ - break; \ - } \ - } - -FILTER( thombas5, - "Thomson MO5 w/ BASIC 1.0, Tokenized Files (read-only, auto-decrypt)" ) -FILTER( thombas7, - "Thomson TO7 w/ BASIC 1.0, Tokenized Files (read-only, auto-decrypt)" ) -FILTER( thombas128, - "Thomson w/ BASIC 128/512, Tokenized Files (read-only, auto-decrypt)" ) - - -/************************* driver ***************************/ - -static OPTION_GUIDE_START( thom_createimage_optguide ) - OPTION_INT( 'H', "heads", "Heads" ) - OPTION_INT( 'T', "tracks", "Tracks" ) - OPTION_ENUM_START( 'D', "density", "Density" ) - OPTION_ENUM( 0, "SD", "Single density (128 bytes)" ) - OPTION_ENUM( 1, "DD", "Double density (256 bytes)" ) - OPTION_ENUM_END - OPTION_STRING( 'N', "name", "Floppy name" ) -OPTION_GUIDE_END - -static OPTION_GUIDE_START( thom_writefile_optguide ) - OPTION_ENUM_START( 'T', "ftype", "File type" ) - OPTION_ENUM( 0, "auto", "Automatic (by extension)" ) - OPTION_ENUM( 1, "B", "Program" ) - OPTION_ENUM( 2, "D", "Data" ) - OPTION_ENUM( 3, "M", "Machine Code" ) - OPTION_ENUM( 4, "A", "Assembler Source" ) - OPTION_ENUM_END - OPTION_ENUM_START( 'F', "format", "Format flag" ) - OPTION_ENUM( 0, "auto", "Automatic (by extension)" ) - OPTION_ENUM( 1, "B", "Binary, Tokenized BASIC" ) - OPTION_ENUM( 2, "A", "ASCII" ) - OPTION_ENUM_END - OPTION_STRING( 'C', "comment", "Comment" ) -OPTION_GUIDE_END - -static void thom_basic_get_info(const imgtool_class *clas, - UINT32 param, - union imgtoolinfo *info) -{ - switch ( param ) { - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: - info->i = sizeof(thom_floppy); break; - case IMGTOOLINFO_INT_PARTITION_EXTRA_BYTES: - info->i = sizeof(int); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: - info->i = sizeof(int); break; - case IMGTOOLINFO_INT_SUPPORTS_CREATION_TIME: - case IMGTOOLINFO_INT_PREFER_UCASE: - info->i = 1; break; - case IMGTOOLINFO_INT_PATH_SEPARATOR: - info->i = 0; break; - case IMGTOOLINFO_STR_FILE: - strcpy( info->s = imgtool_temp_str(), __FILE__ ); break; - case IMGTOOLINFO_STR_NAME: - strcpy( info->s = imgtool_temp_str(), "thom" ); break; - case IMGTOOLINFO_STR_DESCRIPTION: - strcpy( info->s = imgtool_temp_str(), "Thomson BASIC filesystem" ); - break; - case IMGTOOLINFO_PTR_CREATE: - info->create = thom_create; break; - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: - info->createimage_optguide = thom_createimage_optguide; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: - info->begin_enum = thom_begin_enum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: - info->next_enum = thom_next_enum; break; - case IMGTOOLINFO_PTR_READ_FILE: - info->read_file = thom_read_file; break; - case IMGTOOLINFO_PTR_WRITE_FILE: - info->write_file = thom_write_file; break; - case IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE: - 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; - case IMGTOOLINFO_PTR_SUGGEST_TRANSFER: - info->suggest_transfer = thom_suggest_transfer; break; - case IMGTOOLINFO_PTR_DELETE_FILE: - info->delete_file = thom_delete_file; break; - case IMGTOOLINFO_PTR_FREE_SPACE: - info->free_space = thom_free_space; break; - case IMGTOOLINFO_PTR_GET_SECTOR_SIZE: - info->get_sector_size = thom_get_sector_size; break; - case IMGTOOLINFO_PTR_GET_GEOMETRY: - info->get_geometry = thom_get_geometry; break; - case IMGTOOLINFO_PTR_INFO: - info->info = thom_info; break; - case IMGTOOLINFO_PTR_READ_SECTOR: - info->read_sector = thom_read_sector; break; - case IMGTOOLINFO_PTR_WRITE_SECTOR: - info->write_sector = thom_write_sector; break; - case IMGTOOLINFO_PTR_LIST_PARTITIONS: - info->list_partitions = thom_list_partitions; break; - case IMGTOOLINFO_PTR_OPEN_PARTITION: - info->open_partition = thom_open_partition; break; - } -} - -void thom_fd_basic_get_info(const imgtool_class *clas, - UINT32 param, - union imgtoolinfo *info) -{ - switch ( param ) { - case IMGTOOLINFO_STR_NAME: - 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; - case IMGTOOLINFO_STR_FILE_EXTENSIONS: - strcpy( info->s = imgtool_temp_str(), "fd" ); break; - case IMGTOOLINFO_PTR_OPEN: - info->open = thom_open_fd_qd; break; - case IMGTOOLINFO_PTR_CLOSE: - 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; - default: - thom_basic_get_info( clas, param, info ); - } -} - -void thom_qd_basic_get_info(const imgtool_class *clas, - UINT32 param, - union imgtoolinfo *info) -{ - switch ( param ) { - case IMGTOOLINFO_STR_NAME: - 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; - case IMGTOOLINFO_STR_FILE_EXTENSIONS: - strcpy( info->s = imgtool_temp_str(), "qd" ); break; - case IMGTOOLINFO_PTR_OPEN: - info->open = thom_open_fd_qd; break; - case IMGTOOLINFO_PTR_CLOSE: - 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; - default: - thom_basic_get_info( clas, param, info ); - } -} - -void thom_sap_basic_get_info(const imgtool_class *clas, - UINT32 param, - union imgtoolinfo *info) -{ - switch ( param ) { - case IMGTOOLINFO_STR_NAME: - 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; - case IMGTOOLINFO_STR_FILE_EXTENSIONS: - strcpy( info->s = imgtool_temp_str(), "sap" ); break; - case IMGTOOLINFO_PTR_OPEN: - info->open = thom_open_sap; break; - case IMGTOOLINFO_PTR_CLOSE: - 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; - default: - thom_basic_get_info( clas, param, info ); - } -} diff --git a/src/mess/tools/imgtool/modules/ti99.c b/src/mess/tools/imgtool/modules/ti99.c deleted file mode 100644 index 220cbebdb27..00000000000 --- a/src/mess/tools/imgtool/modules/ti99.c +++ /dev/null @@ -1,5360 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/* - Handlers for ti99 disk images - - We support the following types of image: - * floppy disks ("DSK format") in v9t9, pc99 and old mess image format - * hard disks ("WIN format") in MAME harddisk format (256-byte sectors only, - i.e. no SCSI) - Files are extracted in TIFILES format. There is a compile-time option to - extract text files in flat format instead, but I need to re-implement it - properly (using filters comes to mind). - - Raphael Nabet, 2002-2004 - - TODO: - - finish and test hd support ***test sibling FDR support*** - - check allocation bitmap against corruption when an image is opened -*/ - -#include <limits.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <time.h> -#include "imgtool.h" -#include "harddisk.h" -#include "imghd.h" - -/* - Concepts shared by both disk structures: - ---------------------------------------- - - In both formats, the entire disk surface is split into physical records, - each 256-byte-long. For best efficiency, the sector size is usually 256 - bytes so that one sector is equivalent to a physical record (this is true - with floppies and HFDC hard disks). If the sector size is not 256 bytes - (e.g. 512 bytes with SCSI hard disks, possibly 128 bytes on a TI-99 - simulator running on TI-990), sectors are grouped or split to form 256-byte - physical records. Physical records are numbered from 0, with the first - starting on sector 0 track 0. To avoid confusion with physical records in - files, such physical records will be called "absolute physical records", - abbreviated as "absolute physrecs" or "aphysrecs". - - Disk space is allocated in units referred to as AUs. Each AU represents an - integral number of 256-byte physical records. The number of physrecs per - AU varies depending on the disk format and size. AUs are numbered from 0, - with the first starting with absolute physrec 0. - - Absolute physrec 0 contains a 256-byte record with volume information, - which is called "Volume Information Block", abbreviated as "vib". - - To keep track of which areas on the disk are allocated and which are free, - disk managers maintain a bit map of allocated AUs (called "allocation - bitmap", abbreviated as "abm"). Each bit in the allocation bitmap - represents an AU: if a bit is 0, the AU is free; if a bit is 1, the AU is - allocated (or possibly bad if the disk manager can track bad sectors). - Where on the disk the abm is located depends on the disk structure (see - structure-specific description for details). - - Files are implemented as a succession of 256-byte physical records. To - avoid confusion with absolute physical records, these physical records will - be called "file physical records", abbreviated as "file physrecs" or - "fphysrecs". - - Programs do normally not access file physical records directly. They may - call high-level file routines that enable to create either fixed-length - logical records of any size from 1 through 255, or variable-length records - of any size from 0 through 254: logical records are grouped by file - managers into 256-byte physical records. Some disk managers (HFDC and - SCSI) allow programs to create fixed-length records larger than 255 bytes, - too, but few programs use this possibility. Additionally, program files - can be created: program files do not implement any logical record, and can - be seen as a flat byte stream, not unlike files under MSDOS, UNIX and the C - standard library. (Unfortunately, the API for program files lacks - flexibility, and most programs that need to process a flat byte stream - will use fixed-size records of 128 bytes.) - - Fixed-length records (reclen < 256) are grouped like this: - fphysrec 0 fphysrec 1 - _______________ _______________ - |R0 |R1 |R2 |X| |R3 |R4 |R5 |X| - --------------- --------------- - \_/ \_/ - unused unused - (size < reclen) (size < reclen) - - Fixed-length records (reclen > 256) are grouped like this: - fphysrec 0 fphysrec 1 fphysrec 2 fphysrec 3 ... - _________________ _________________ _________________ _________________ - | R0 (#0-255) | | R0 (#256-511) | |R0 (#512-end)|X| | R1 (#0-255) | ... - ----------------- ----------------- ----------------- ----------------- - \_/ - unused - - Variable length records are grouped like this: - fphysrec 0: - byte: - ------------------------------ - 0 |l0 = length of record 0 data| - |----------------------------| - 1 | | - | | - : | record 0 data | - | | - l0 | | - |----------------------------| - l0+1 |l1 = length of record 1 data| - |----------------------------| - l0+2 | | - | | - : | record 1 data | - | | - l0+l1+1 | | - |----------------------------| - : : : - : : : - |----------------------------| - n |lm = length of record m data| - |----------------------------| - n+1 | | - | | - : | record m data | - | | - n+lm | | - |----------------------------| - n+lm+1 |>ff: EOR mark | - |----------------------------| - n+lm+2 | | - | | - : | unused | - : |(we should have size < lm+1)| - | | - 255 | | - ------------------------------ - - fphysrec 1: - byte: - ------------------------------ - 0 |lm+1=length of record 0 data| - |----------------------------| - 1 | | - | | - : | record m+1 data | - | | - lm+1 | | - |----------------------------| - : : : - : : : - - I think the EOR mark is not required if all 256 bytes of a physical - record are used by logical records. - - - All files are associated with a "file descriptor record" ("fdr") that holds - file information (name, format, length) and points to the data AUs. The WIN - disk structure also supports sibling FDRs, in case a file is so fragmented - that all the data pointers cannot fit in one FDR; the DSK disk structure - does not implement any such feature, and you may be unable to append data - to an existing file if it is too fragmented, even though the disk is not - full. - - - DSK disk structure: - ------------------- - - The DSK disk structure is used for floppy disks, and a few RAMDISKs as - well. It supports 1600 AUs and 16 MBytes at most (the 16 MByte value is a - theorical maximum, as I doubt anyone has ever created so big a DSK volume). - - The disk sector size is always 256 bytes (the only potential exceptions are - the SCSI floppy disk units and the TI-99 simulator on TI-990, but I don't - know anything about either). - - For some reason, the number of physrecs per AU is always a power of 2. - Originally, AUs always were one physical record each. However, since the - allocation bitmap cannot support more than 1600 AUs, disks larger than - 400kbytes need to have several physical records per AU. Note that - relatively few disk controllers implement AUs that span multiple physical - records (IIRC, these are Myarc's HFDC, SCSI DSR with floppy disk interface, - and some upgraded Myarc and Corcomp DD floppy controllers). - - The allocation bitmap is located in the VIB. It is 200 bytes long, and - supports 1600 AUs at most. - - Directories are implemented with a "File Descriptor Index Record" (FDIR) - for each directory. The FDIR is array of 0 through 128 words, containing - the aphysrec address of each fdr in the directory, sorted by ascending file - name, terminated with a 0. Note that, while we should be prepared to read - images images with 128 entries, I think (not 100% sure) that we should - write no more than 127 for compatibility with some existing disk managers. - - Originally, the DSK structure only supported one directory level (i.e. the - root directory level). The FDIR record for the root directory is always - located in aphysrec 1. Moreover, Myarc extended the DSK structure to - support up to 3 subdirectories in the root directory (note that there is no - support for more subdirs, or for subdirs located in subdirs). To do so, - they used an unused field of the VIB to hold the 10-char name of each - directory and the aphysrec address of the associated FDIR record. - - aphysrec 0: Volume Information Block (VIB): see below - aphysrec 1: FDIR for root directory - Remaining AUs are used for fdr and data (and subdirectory FDIR if - applicable). There is one FDIR record per directory; the FDIR points to - the FDR for each file in the directory. The FDR (File Descriptor Record) - contains the file information (name, format, length, pointers to data - physrecs/AUs, etc). - - - WIN disk structure: - ------------------- - - The WIN disk structure is used for hard disks. It supports 65535 AUs and - 256 MBytes at most. - - The disk sector size is 256 bytes on HFDC, 512 bytes on SCSI. 512-byte - sectors are split into 256-byte physical records. - - We may have from 1 through 16 physrecs per AUs. Since we cannot have more - than 65535 AUs, we need to have several physical records per AU in disks - larger than 16 Mbytes. - - Contrary to the DSK disk structure, the WIN disk structure supports - hierarchic subdirectories, with a limit of 114 subdirectories and 127 files - per directory. Each directory is associated with both a "Directory - Descriptor Record" (DDR) and a "File Descriptor Index Record" (FDIR). The - only exception is the root directory, which uses the VIB instead of a DDR - (the VIB includes all the important fields of the DDR). The DDR contains - some directory info (name, number of files and subdirectories directly - enclosed in the directory, AU address of the FDIR of the parent directory, - etc), the AU address of the associated FDIR, and the AU address of the DDR - of up to 114 subdirectories, sorted by ascending directory name. The WIN - FDIR is similar to, yet different from, the DSK FDIR: it contains up to 127 - (vs. 128) AU address (vs. aphysrec address) of each fdr in the directory, - sorted by ascending file name. Additionally, it includes the AU address of - the associated DDR. - - When a file has more than 54 data fragments, the disk manager creates - sibling FDRs that hold additional fragments. (Sibling FDRs are called - offspring FDRs in most existing documentation, but I prefer "sibling FDRs" - as "offspring FDRs" wrongly suggests a directory-like hierarchy. - Incidentally, I cannot really figure out why they chose to duplicate the - FDR rather than create a file extension record, but there must be a - reason.) Note that sibling FDRs usually fill unused physrecs in the AU - allocated for the eldest FDR, and a new AU is allocated for new sibling - FDRs only when the first AU is full. - - aphysrec 0: Volume Information Block (VIB): see below - aphysrec 1-n (where n = 1+SUP(number_of_AUs/2048)): Volume bitmap - Remaining AUs are used for ddr, fdir, fdr and data. -*/ - -/* Since string length is encoded with a byte, the maximum length of a string -is 255. Since we need to add a device name (1 char minimum, typically 4 chars) -and a '.' separator, we chose a practical value of 250 (though few applications -will accept paths of such length). */ -#define MAX_PATH_LEN 253 -#define MAX_SAFE_PATH_LEN 250 - -#define MAX_DIR_LEVEL 125 /* We need to put a recursion limit to avoid endless recursion hazard */ - - -#if 0 -#pragma mark MISCELLANEOUS UTILITIES -#endif - -/* - Miscellaneous utilities that are used to handle TI data types -*/ - -struct UINT16BE -{ - UINT8 bytes[2]; -}; - -struct UINT16LE -{ - UINT8 bytes[2]; -}; - -INLINE UINT16 get_UINT16BE(UINT16BE word) -{ - return (word.bytes[0] << 8) | word.bytes[1]; -} - -INLINE void set_UINT16BE(UINT16BE *word, UINT16 data) -{ - word->bytes[0] = (data >> 8) & 0xff; - word->bytes[1] = data & 0xff; -} - -INLINE UINT16 get_UINT16LE(UINT16LE word) -{ - return word.bytes[0] | (word.bytes[1] << 8); -} - -INLINE void set_UINT16LE(UINT16LE *word, UINT16 data) -{ - word->bytes[0] = data & 0xff; - word->bytes[1] = (data >> 8) & 0xff; -} - -/* - Convert a C string to a 10-character file name (padded with spaces if necessary) - - dst (O): destination 10-character array - src (I): source C string -*/ -static void str_to_fname(char dst[10], const char *src) -{ - int i; - - - i = 0; - - /* copy 10 characters at most */ - if (src) - while ((i<10) && (src[i]!='\0')) - { - dst[i] = src[i]; - i++; - } - - /* pad with spaces */ - while (i<10) - { - dst[i] = ' '; - i++; - } -} - -/* - Convert a 10-character file name to a C string (removing trailing spaces if necessary) - - dst (O): destination C string - src (I): source 10-character array - n (I): length of dst buffer (string may be truncated if less than 11) -*/ -static void fname_to_str(char *dst, const char src[10], int n) -{ - int i; - int last_nonspace; - - - /* copy 10 characters at most */ - if (--n > 10) - n = 10; - - /* copy filename */ - i = 0; - last_nonspace = -1; - - while (i<n) - { - dst[i] = src[i]; - if (src[i] != ' ') - last_nonspace = i; - i++; - } - - /* terminate with '\0' */ - dst[last_nonspace+1] = '\0'; -} - -/* - Check a 10-character file name. - - filename (I): 10-character array with file name - - Return non-zero if the file name is invalid. -*/ -static int check_fname(const char filename[10]) -{ - int i; - int space_found_flag; - - - /* check and copy file name */ - space_found_flag = FALSE; - for (i=0; i<10; i++) - { - switch (filename[i]) - { - case '.': - case '\0': - /* illegal characters */ - return 1; - case ' ': - /* illegal in a file name, but file names shorter than 10 - characters are padded with spaces */ - space_found_flag = TRUE; - break; - default: - /* all other characters are legal (though non-ASCII characters, - control characters and even lower-case characters are not - recommended) */ - if (space_found_flag) - return 1; - break; - } - } - - return 0; -} - -/* - Check a file path. - - fpath (I): C string with file path - - Return non-zero if the file path is invalid. -*/ -static int check_fpath(const char *fpath) -{ - const char *element_start, *element_end; - int element_len; - - - /* first check that the path is not too long and that there is no space - character */ - if ((strlen(fpath) > MAX_PATH_LEN) || strchr(fpath, ' ')) - return 1; - - /* check that each path element has an acceptable length */ - element_start = fpath; - do - { - /* find next path element */ - element_end = strchr(element_start, '.'); - element_len = element_end ? (element_end - element_start) : strlen(element_start); - if ((element_len > 10) || (element_len == 0)) - return 1; - - /* iterate */ - if (element_end) - element_start = element_end+1; - else - element_start = NULL; - } - while (element_start); - - return 0; -} - -#if 0 -#pragma mark - -#pragma mark LEVEL 1 DISK ROUTINES -#endif - -/* - Level 1 deals with accessing the disk hardware (in our case, the raw disk - image). - - Higher level routines will only know the disk as a succession of - 256-byte-long physical records addressed by a linear address. -*/ - -/* - Disk geometry -*/ -struct ti99_geometry -{ - int secspertrack; - int cylinders; - int heads; -}; - -/* - Physical sector address -*/ -struct ti99_sector_address -{ - int sector; - int cylinder; - int side; -}; - -/* - Time stamp (used in fdr, and WIN VIB/DDR) -*/ -struct ti99_date_time -{ - UINT8 time_MSB, time_LSB;/* 0-4: hour, 5-10: minutes, 11-15: seconds/2 */ - UINT8 date_MSB, date_LSB;/* 0-6: year, 7-10: month, 11-15: day */ -}; - -/* - Subdirectory descriptor (HFDC only) - - The HFDC supports up to 3 subdirectories. -*/ -struct dsk_subdir -{ - char name[10]; /* subdirectory name (10 characters, pad with spaces) */ - UINT16BE fdir_aphysrec; /* aphysrec address of fdir record for this subdirectory */ -}; - -/* - DSK VIB record - - Most fields in this record are only relevant to level 2 routines, but level - 1 routines need the disk geometry information extracted from the VIB. -*/ -struct dsk_vib -{ - char name[10]; /* disk volume name (10 characters, pad with spaces) */ - UINT16BE totphysrecs; /* total number of physrecs on disk (usually 360, */ - /* 720, 640, 1280 or 1440). (TI originally */ - /* said it should be the total number of AUs, */ - /* but, in practice, DSRs that supports disks */ - /* over 400kbytes (e.g. HFDC) write the total */ - /* number of physrecs.) */ - UINT8 secspertrack; /* sectors per track (usually 9 (FM SD), */ - /* 16 or 18 (MFM DD), or 36 (MFM HD) */ - UINT8 id[3]; /* 'DSK' */ - UINT8 protection; /* 'P' if disk is protected, ' ' otherwise. */ - UINT8 cylinders; /* tracks per side (usually 40) */ - UINT8 heads; /* sides (1 or 2) */ - UINT8 density; /* density: 1 (FM SD), 2 (MFM DD), or 3 (MFM HD) */ - dsk_subdir subdir[3]; /* descriptor for up to 3 subdirectories (HFDC only) */ - /* reserved by TI */ - UINT8 abm[200]; /* allocation bitmap: there is one bit per AU. */ - /* A binary 1 in a bit position indicates that */ - /* the allocation unit associated with that */ - /* bit has been allocated. */ - /* Bits corresponding to system reserved AUs, */ - /* non-existant AUs, and bad AUs, are set to one, too. */ - /* (AU 0 is associated to LSBit of byte 0, */ - /* AU 7 to MSBit of byte 0, AU 8 to LSBit */ - /* of byte 1, etc.) */ -}; - -enum ti99_img_format -{ - if_mess, - if_v9t9, - if_pc99_fm, - if_pc99_mfm, - if_harddisk -}; - -/* - level-1 disk image descriptor -*/ -struct ti99_lvl1_imgref -{ - ti99_img_format img_format; /* tells the image format */ - imgtool_stream *file_handle; /* imgtool file handle */ - struct mess_hard_disk_file harddisk_handle; /* MAME harddisk handle (harddisk format) */ - ti99_geometry geometry; /* geometry */ - unsigned pc99_track_len; /* unformatted track length (pc99 format) */ - UINT32 *pc99_data_offset_array; /* offset for each sector (pc99 format) */ -}; - -/* - calculate CRC for data address marks or sector data - - crc (I/O): current CRC value to be updated (initialize to 0xffff before - calling this function for the first time) - value: new byte of data to update the CRC with -*/ -static void calc_crc(UINT16 *crc, UINT8 value) -{ - UINT8 l, h; - - l = value ^ (*crc >> 8); - *crc = (*crc & 0xff) | (l << 8); - l >>= 4; - l ^= (*crc >> 8); - *crc <<= 8; - *crc = (*crc & 0xff00) | l; - l = (l << 4) | (l >> 4); - h = l; - l = (l << 2) | (l >> 6); - l &= 0x1f; - *crc = *crc ^ (l << 8); - l = h & 0xf0; - *crc = *crc ^ (l << 8); - l = (h << 1) | (h >> 7); - l &= 0xe0; - *crc = *crc ^ l; -} - -/* - Parse a PC99 disk image - - file_handle (I/O): imgtool file handle - fm_format (I): if true, the image is in FM format, otherwise it is in MFM - format - pass (I): 0 for first pass, 1 for second pass - vib (O): buffer where the vib should be stored (first pass) - geometry (O): disk image geometry (second pass) - data_offset_array (O): array of data offset to generate (second pass) - out_track_len (O): track length is returned there - - Return imgtool error code -*/ -#define MAX_TRACK_LEN 6872 -#define DATA_OFFSET_NONE 0xffffffff -static int parse_pc99_image(imgtool_stream *file_handle, int fm_format, int pass, dsk_vib *vib, const ti99_geometry *geometry, UINT32 *data_offset_array, unsigned *out_track_len) -{ - int track_len, num_tracks; /* length of a track in bytes, and number of tracks */ - int phys_track; - int expected_cylinder, expected_head; - int track_start_pos, track_pos; - UINT8 c; - UINT8 cylinder, head, sector; - int seclen; - UINT8 crc1, crc2; - UINT16 crc; - long data_offset; - UINT8 track_buf[MAX_TRACK_LEN]; - int i; - - if (fm_format) - track_len = 3253; - else - track_len = 6872; - - if (out_track_len) - *out_track_len = track_len; - - if (stream_size(file_handle) % track_len) - return IMGTOOLERR_CORRUPTIMAGE; - - num_tracks = stream_size(file_handle) / track_len; - if (num_tracks <= 0) - return IMGTOOLERR_CORRUPTIMAGE; - - /* we only support 40-track-per-side images */ - if ((num_tracks != 40) && (num_tracks != 80)) - return IMGTOOLERR_UNIMPLEMENTED; - - if (pass == 1) - { - /* initialize offset map */ - for (head = 0; head < geometry->heads; head++) - for (cylinder = 0; cylinder < geometry->cylinders; cylinder++) - for (sector = 0; sector < geometry->secspertrack; sector++) - data_offset_array[(head*geometry->cylinders + cylinder)*geometry->secspertrack + sector] = DATA_OFFSET_NONE; - } - /* rewind to start of file */ - stream_seek(file_handle, 0, SEEK_SET); - - /* pass 0 only looks for vib in track 0; pass 1 scans every track */ - for (phys_track=0; phys_track < ((pass == 1) ? num_tracks : 1); phys_track++) - { - if (stream_read(file_handle, track_buf, track_len) != track_len) - return IMGTOOLERR_READERROR; - - /* we only support 40-track-per-side images */ - expected_cylinder = phys_track % 40; - expected_head = phys_track / 40; - - track_start_pos = 0; - - while (track_start_pos < track_len) - { - if (fm_format) - { - do - { - c = track_buf[track_start_pos]; - track_start_pos++; - } while ((c != 0xfe) && (track_start_pos < track_len)); - - if (c != 0xfe) - break; - - track_pos = track_start_pos; - - crc = 0xffff; - calc_crc(& crc, c); - } - else - { - do - { - c = track_buf[track_start_pos]; - track_start_pos++; - } while ((c != 0xa1) && (track_start_pos < track_len)); - - if (c != 0xa1) - break; - - track_pos = track_start_pos; - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - if (c != 0xa1) - continue; - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - if (c != 0xa1) - continue; - - crc = 0xffff; - calc_crc(& crc, c); - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - if (c != 0xfe) - continue; - } - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - cylinder = c; - calc_crc(& crc, c); - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - head = c; - calc_crc(& crc, c); - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - sector = c; - calc_crc(& crc, c); - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - seclen = 128 << c; - calc_crc(& crc, c); - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - crc1 = c; - calc_crc(& crc, c); - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - crc2 = c; - calc_crc(& crc, c); - -#if 0 - /* CRC seems to be completely hosed */ - if (crc) - printf("aargh!"); -#endif - if ((seclen != 256) || (crc1 != 0xf7) || (crc2 != 0xf7) - || (cylinder != expected_cylinder) || (head != expected_head) - || ((pass == 1) && ((cylinder >= geometry->cylinders) - || (head >= geometry->heads) - || (sector >= geometry->secspertrack)))) - continue; - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - while (c == (fm_format ? 0xff : 0x4e)) - { - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - } - - while (c == 0x00) - { - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - } - - if (fm_format) - { - if (c != 0xfb) - continue; - - crc = 0xffff; - calc_crc(& crc, c); - } - else - { - if (c != 0xa1) - continue; - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - if (c != 0xa1) - continue; - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - if (c != 0xa1) - continue; - - crc = 0xffff; - calc_crc(& crc, c); - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - if (c != 0xfb) - continue; - } - data_offset = track_pos; - for (i=0; i<seclen; i++) - { - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - calc_crc(& crc, c); - } - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - crc1 = c; - calc_crc(& crc, c); - - c = track_buf[track_pos]; - track_pos++; - if (track_pos == track_len) - track_pos = 0; - - crc2 = c; - calc_crc(& crc, c); - -#if 0 - /* CRC seems to be completely hosed */ - if (crc) - printf("aargh!"); -#endif - if ((crc1 != 0xf7) || (crc2 != 0xf7)) - continue; - - switch (pass) - { - case 0: - if ((cylinder == 0) && (head == 0) && (sector == 0)) - { - /* return vib */ - if ((data_offset + 256) <= track_len) - memcpy(vib, track_buf + data_offset, 256); - else - { - memcpy((UINT8 *)vib, track_buf + data_offset, track_len-data_offset); - memcpy((UINT8 *)vib + (track_len-data_offset), track_buf, 256-(track_len-data_offset)); - } - return 0; - } - break; - - case 1: - /* set up offset map */ - if (data_offset_array[(head*geometry->cylinders + cylinder)*geometry->secspertrack + sector] != DATA_OFFSET_NONE) - /* error: duplicate sector */ - return IMGTOOLERR_CORRUPTIMAGE; - data_offset_array[(head*geometry->cylinders + cylinder)*geometry->secspertrack + sector] = data_offset; - break; - } - } - } - - if (pass == 0) - return IMGTOOLERR_CORRUPTIMAGE; - - if (pass == 1) - { - /* check offset map */ - for (head = 0; head < geometry->heads; head++) - for (cylinder = 0; cylinder < geometry->cylinders; cylinder++) - for (sector = 0; sector < geometry->secspertrack; sector++) - if (data_offset_array[(head*geometry->cylinders + cylinder)*geometry->secspertrack + sector] == DATA_OFFSET_NONE) - /* error: missing sector */ - return IMGTOOLERR_CORRUPTIMAGE; - } - - return 0; -} - - -/* - Read the volume information block (aphysrec 0) assuming no geometry - information. (Called when an image is opened to figure out the - geometry information.) - - file_handle (I/O): imgtool file handle - img_format (I): image format (MESS, V9T9 or PC99) - dest (O): pointer to 256-byte destination buffer - - Return imgtool error code -*/ -static int read_image_vib_no_geometry(imgtool_stream *file_handle, ti99_img_format img_format, dsk_vib *dest) -{ - int reply; - - switch (img_format) - { - case if_mess: - case if_v9t9: - /* seek to sector */ - reply = stream_seek(file_handle, 0, SEEK_SET); - if (reply) - return IMGTOOLERR_READERROR; - /* read it */ - reply = stream_read(file_handle, dest, 256); - if (reply != 256) - return IMGTOOLERR_READERROR; - return 0; - - case if_pc99_fm: - case if_pc99_mfm: - return parse_pc99_image(file_handle, img_format == if_pc99_fm, 0, dest, NULL, NULL, NULL); - - case if_harddisk: - /* not implemented, because we don't need it */ - break; - } - - return IMGTOOLERR_UNIMPLEMENTED; -} - -/* - Open a disk image at level 1 - - file_handle (I/O): imgtool file handle - img_format (I): image format (MESS, V9T9, PC99, or MAME harddisk) - l1_img (O): level-1 image handle - vib (O): buffer where the vib should be stored (floppy images only) - - Return imgtool error code -*/ -static imgtoolerr_t open_image_lvl1(imgtool_stream *file_handle, ti99_img_format img_format, ti99_lvl1_imgref *l1_img, dsk_vib *vib) -{ - imgtoolerr_t err; - int reply; - UINT16 totphysrecs; - - - l1_img->img_format = img_format; - l1_img->file_handle = file_handle; - - if (img_format == if_harddisk) - { - const hard_disk_info *info; - - err = imghd_open(file_handle, &l1_img->harddisk_handle); - if (err) - return err; - - info = imghd_get_header(&l1_img->harddisk_handle); - l1_img->geometry.cylinders = info->cylinders; - l1_img->geometry.heads = info->heads; - l1_img->geometry.secspertrack = info->sectors; - if (info->sectorbytes != 256) - { - imghd_close(&l1_img->harddisk_handle); - return IMGTOOLERR_CORRUPTIMAGE; /* TODO: support 512-byte sectors */ - } - -#if 0 - /* read vib */ - reply = read_absolute_physrec(l1_img, 0, vib); - if (reply) - return reply; -#endif - } - else - { - /* read vib */ - reply = read_image_vib_no_geometry(file_handle, img_format, vib); - if (reply) - return (imgtoolerr_t)reply; - - /* extract geometry information */ - totphysrecs = get_UINT16BE(vib->totphysrecs); - - l1_img->geometry.secspertrack = vib->secspertrack; - if (l1_img->geometry.secspertrack == 0) - /* Some images might be like this, because the original SSSD TI - controller always assumes 9. */ - l1_img->geometry.secspertrack = 9; - l1_img->geometry.cylinders = vib->cylinders; - if (l1_img->geometry.cylinders == 0) - /* Some images are like this, because the original SSSD TI - controller always assumes 40. */ - l1_img->geometry.cylinders = 40; - l1_img->geometry.heads = vib->heads; - if (l1_img->geometry.heads == 0) - /* Some images are like this, because the original SSSD TI - controller always assumes that tracks beyond 40 are on side 2. */ - l1_img->geometry.heads = totphysrecs / (l1_img->geometry.secspertrack * l1_img->geometry.cylinders); - - /* check information */ - if ((totphysrecs != (l1_img->geometry.secspertrack * l1_img->geometry.cylinders * l1_img->geometry.heads)) - || (totphysrecs < 2) - || memcmp(vib->id, "DSK", 3) || (! strchr(" P", vib->protection)) - || (((img_format == if_mess) || (img_format == if_v9t9)) - && (stream_size(file_handle) != totphysrecs*256U))) - return (imgtoolerr_t)IMGTOOLERR_CORRUPTIMAGE; - - if ((img_format == if_pc99_fm) || (img_format == if_pc99_mfm)) - { - l1_img->pc99_data_offset_array = (UINT32*)malloc(sizeof(*l1_img->pc99_data_offset_array)*totphysrecs); - if (! l1_img->pc99_data_offset_array) - return IMGTOOLERR_OUTOFMEMORY; - reply = parse_pc99_image(file_handle, img_format == if_pc99_fm, 1, NULL, & l1_img->geometry, l1_img->pc99_data_offset_array, &l1_img->pc99_track_len); - if (reply) - { - free(l1_img->pc99_data_offset_array); - return (imgtoolerr_t)reply; - } - } - } - - return (imgtoolerr_t)0; -} - -/* - Close a disk image at level 1 - - l1_img (I/O): level-1 image handle - - Return imgtool error code -*/ -static void close_image_lvl1(ti99_lvl1_imgref *l1_img) -{ - if (l1_img->img_format == if_harddisk) - { - imghd_close(&l1_img->harddisk_handle); - } - - stream_close(l1_img->file_handle); - - if ((l1_img->img_format == if_pc99_fm) || (l1_img->img_format == if_pc99_mfm)) - free(l1_img->pc99_data_offset_array); -} - -/* - Convert physical sector address to offset in disk image (old MESS and V9T9 - formats only) - - l1_img (I/O): level-1 image handle - address (I): physical sector address - - Return offset in image -*/ -INLINE int sector_address_to_image_offset(const ti99_lvl1_imgref *l1_img, const ti99_sector_address *address) -{ - int offset = 0; - - switch (l1_img->img_format) - { - case if_mess: - /* old MESS format */ - offset = (((address->cylinder*l1_img->geometry.heads) + address->side)*l1_img->geometry.secspertrack + address->sector)*256; - break; - - case if_v9t9: - /* V9T9 format */ - if (address->side & 1) - /* on side 1, tracks are stored in the reverse order */ - offset = (((address->side*l1_img->geometry.cylinders) + (l1_img->geometry.cylinders-1 - address->cylinder))*l1_img->geometry.secspertrack + address->sector)*256; - else - offset = (((address->side*l1_img->geometry.cylinders) + address->cylinder)*l1_img->geometry.secspertrack + address->sector)*256; - break; - - case if_pc99_fm: - case if_pc99_mfm: - /* pc99 format */ - case if_harddisk: - /* harddisk format */ - assert(1); /* not implemented */ - break; - } - - return offset; -} - -/* - Read one 256-byte sector from a disk image - - l1_img (I/O): level-1 image handle - address (I): physical sector address - dest (O): pointer to 256-byte destination buffer - - Return non-zero on error -*/ -static int read_sector(ti99_lvl1_imgref *l1_img, const ti99_sector_address *address, void *dest) -{ - int reply; - UINT32 track_len, track_offset, sector_offset; - - switch (l1_img->img_format) - { - case if_mess: - /* old MESS format */ - case if_v9t9: - /* V9T9 format */ - /* seek to sector */ - reply = stream_seek(l1_img->file_handle, sector_address_to_image_offset(l1_img, address), SEEK_SET); - if (reply) - return 1; - /* read it */ - reply = stream_read(l1_img->file_handle, dest, 256); - if (reply != 256) - return 1; - break; - - case if_pc99_fm: - case if_pc99_mfm: - /* pc99 format */ - track_len = l1_img->pc99_track_len; - track_offset = (address->side*l1_img->geometry.cylinders + address->cylinder)*track_len; - sector_offset = l1_img->pc99_data_offset_array[(address->side*l1_img->geometry.cylinders + address->cylinder)*l1_img->geometry.secspertrack + address->sector]; - - if ((sector_offset + 256) <= track_len) - { - /* seek to sector */ - reply = stream_seek(l1_img->file_handle, track_offset+sector_offset, SEEK_SET); - if (reply) - return 1; - /* read it */ - reply = stream_read(l1_img->file_handle, dest, 256); - if (reply != 256) - return 1; - } - else - { - /* seek to sector */ - reply = stream_seek(l1_img->file_handle, track_offset+sector_offset, SEEK_SET); - if (reply) - return 1; - /* read first chunk (until end of track) */ - reply = stream_read(l1_img->file_handle, (UINT8 *)dest, track_len-sector_offset); - if (reply != track_len-sector_offset) - return 1; - - /* wrap to start of track */ - reply = stream_seek(l1_img->file_handle, track_offset, SEEK_SET); - if (reply) - return 1; - /* read remnant of sector */ - reply = stream_read(l1_img->file_handle, (UINT8 *)dest + (track_len-sector_offset), 256-(track_len-sector_offset)); - if (reply != 256-(track_len-sector_offset)) - return 1; - } - break; - - case if_harddisk: - /* not implemented */ - assert(1); - /*return imghd_read(l1_img->harddisk_handle, ((address->cylinder*l1_img->geometry.heads) + address->side)*l1_img->geometry.secspertrack + address->sector, 1, dest) != 1;*/ - break; - } - - return 0; -} - -/* - Write one 256-byte sector to a disk image - - l1_img (I/O): level-1 image handle - address (I): physical sector address - src (I): pointer to 256-byte source buffer - - Return non-zero on error -*/ -static int write_sector(ti99_lvl1_imgref *l1_img, const ti99_sector_address *address, const void *src) -{ - int reply; - UINT32 track_len, track_offset, sector_offset; - - switch (l1_img->img_format) - { - case if_mess: - /* old MESS format */ - case if_v9t9: - /* V9T9 format */ - /* seek to sector */ - reply = stream_seek(l1_img->file_handle, sector_address_to_image_offset(l1_img, address), SEEK_SET); - if (reply) - return 1; - /* write it */ - reply = stream_write(l1_img->file_handle, src, 256); - if (reply != 256) - return 1; - break; - - case if_pc99_fm: - case if_pc99_mfm: - /* pc99 format */ - track_len = l1_img->pc99_track_len; - track_offset = (address->side*l1_img->geometry.cylinders + address->cylinder)*track_len; - sector_offset = l1_img->pc99_data_offset_array[(address->side*l1_img->geometry.cylinders + address->cylinder)*l1_img->geometry.secspertrack + address->sector]; - - if ((sector_offset + 256) <= track_len) - { - /* seek to sector */ - reply = stream_seek(l1_img->file_handle, track_offset+sector_offset, SEEK_SET); - if (reply) - return 1; - /* write it */ - reply = stream_write(l1_img->file_handle, src, 256); - if (reply != 256) - return 1; - } - else - { - /* seek to sector */ - reply = stream_seek(l1_img->file_handle, track_offset+sector_offset, SEEK_SET); - if (reply) - return 1; - /* write first chunk (until end of track) */ - reply = stream_write(l1_img->file_handle, (UINT8 *)src, track_len-sector_offset); - if (reply != track_len-sector_offset) - return 1; - - /* wrap to start of track */ - reply = stream_seek(l1_img->file_handle, track_offset, SEEK_SET); - if (reply) - return 1; - /* write remnant of sector */ - reply = stream_write(l1_img->file_handle, (UINT8 *)src + (track_len-sector_offset), 256-(track_len-sector_offset)); - if (reply != 256-(track_len-sector_offset)) - return 1; - } - break; - - case if_harddisk: - /* not implemented */ - assert(1); - /*return imghd_write(l1_img->harddisk_handle, ((address->cylinder*l1_img->geometry.heads) + address->side)*l1_img->geometry.secspertrack + address->sector, 1, src) != 1;*/ - break; - } - - return 0; -} - -/* - Convert physical record address to sector address (DSK format) - - aphysrec (I): absolute physrec address - geometry (I): disk image geometry - address (O): physical sector address -*/ -static void dsk_aphysrec_to_sector_address(int aphysrec, const ti99_geometry *geometry, ti99_sector_address *address) -{ - address->sector = aphysrec % geometry->secspertrack; - aphysrec /= geometry->secspertrack; - address->cylinder = aphysrec % geometry->cylinders; - address->side = aphysrec / geometry->cylinders; - if (address->side & 1) - /* on side 1, tracks are stored in the reverse order */ - address->cylinder = geometry->cylinders-1 - address->cylinder; -} - -/* - Convert physical record address to sector address (WIN format for HFDC) - - Note that physical address translation makes sense for HFDC, but not SCSI. - - aphysrec (I): absolute physrec address - geometry (I): disk image geometry - address (O): physical sector address -*/ -#ifdef UNUSED_FUNCTION -static void win_aphysrec_to_sector_address(int aphysrec, const ti99_geometry *geometry, ti99_sector_address *address) -{ - address.sector = aphysrec % l1_img->geometry.secspertrack; - aphysrec /= l1_img->geometry.secspertrack; - address.side = aphysrec % l1_img->geometry.heads; - address.cylinder = aphysrec / l1_img->geometry.heads; -} -#endif - -/* - Read one 256-byte physical record from a disk image - - l1_img (I/O): level-1 image handle - aphysrec (I): absolute physrec address - dest (O): pointer to 256-byte destination buffer - - Return non-zero on error -*/ -static int read_absolute_physrec(ti99_lvl1_imgref *l1_img, unsigned aphysrec, void *dest) -{ - ti99_sector_address address; - - - if (l1_img->img_format == if_harddisk) - { -#if 0 - win_aphysrec_to_sector_address(aphysrec, & l1_img->geometry, & address); - return read_sector(l1_img, & address, dest); -#endif - - return imghd_read(&l1_img->harddisk_handle, aphysrec, dest) != IMGTOOLERR_SUCCESS; - } - else - { - dsk_aphysrec_to_sector_address(aphysrec, & l1_img->geometry, & address); - - return read_sector(l1_img, & address, dest); - } -} - -/* - Write one 256-byte physical record to a disk image - - l1_img (I/O): level-1 image handle - aphysrec (I): absolute physrec address - src (I): pointer to 256-byte source buffer - - Return non-zero on error -*/ -static int write_absolute_physrec(ti99_lvl1_imgref *l1_img, unsigned aphysrec, const void *src) -{ - ti99_sector_address address; - - - if (l1_img->img_format == if_harddisk) - { -#if 0 - win_aphysrec_to_sector_address(aphysrec, & l1_img->geometry, & address); - return write_sector(l1_img, & address, dest); -#endif - - return imghd_write(&l1_img->harddisk_handle, aphysrec, src) != IMGTOOLERR_SUCCESS; - } - else - { - dsk_aphysrec_to_sector_address(aphysrec, & l1_img->geometry, & address); - - return write_sector(l1_img, & address, src); - } -} - -#if 0 -#pragma mark - -#pragma mark LEVEL 2 DISK ROUTINES -#endif - -/* - Level 2 implements files as a succession of 256-byte-long physical records. - - Level 2 implements allocation bitmap (and AU), disk catalog, etc. -*/ - -/* - WIN VIB/DDR record -*/ -struct win_vib_ddr -{ - char name[10]; /* disk volume name (10 characters, pad with spaces) */ - UINT16BE totAUs; /* total number of AUs */ - UINT8 secspertrack; /* HFDC: sectors per track (typically 32) */ - /* SCSI: reserved */ - union - { - struct - { - UINT8 id[3]; /* V1 VIB: 'WIN' */ - } vib_v1; - - struct /* V2 VIB: extra params */ - { - UINT8 res_AUs; /* # AUs reserved for vib, bitmap, ddr, fdir and fdr, divided by 64 */ - UINT8 step_spd; /* HFDC: step speed (0-7) */ - /* SCSI: reserved */ - UINT8 red_w_cur;/* HFDC: reduced write current cylinder, divided by 8 */ - /* SCSI: reserved */ - } vib_v2; - - struct - { - UINT8 id[3]; /* DDR: 'DIR' */ - } ddr; - } u; - UINT16BE params; /* bits 0-3: sectors/AU - 1 */ - /* HFDC: */ - /* bits 4-7: # heads - 1 */ - /* bit 8: V1: buffered head stepping flag */ - /* V2: reserved */ - /* bit 9-15: write precompensation track, divided by 16 */ - /* SCSI: */ - /* bits 4-15: reserved */ - ti99_date_time creation;/* date and time of creation */ - UINT8 num_files; /* number of files in directory */ - UINT8 num_subdirs; /* number of subdirectories in directory */ - UINT16BE fdir_AU; /* points to root directory fdir */ - union - { - struct - { - UINT16BE dsk1_AU; /* HFDC: points to current dsk1 emulation image (0 if none) */ - /* SCSI: reserved */ - } vib; - - struct - { - UINT16BE parent_ddr_AU; /* points to parent directory DDR */ - } ddr; - } u2; - UINT16BE subdir_AU[114];/* points to all subdirectory DDRs */ -}; - -/* - AU format -*/ -struct ti99_AUformat -{ - int totAUs; /* total number of AUs */ - int physrecsperAU; /* number of 256-byte physical records per AU */ -}; - -/* - DSK directory reference: 0 for root, 1 for 1st subdir, 2 for 2nd subdir, 3 - for 3rd subdir -*/ -/*typedef int dir_ref;*/ - -/* - catalog entry (used for in-memory catalog) -*/ -struct dir_entry -{ - UINT16 dir_ptr; /* DSK: unused */ - /* WIN: AU address of the DDR for this directory */ - char name[10]; /* name of this directory (copied from the VIB for DSK, DDR for WIN) */ -}; - -struct file_entry -{ - UINT16 fdr_ptr; /* DSK: aphysrec address of the FDR for this file */ - /* WIN: AU address of the FDR for this file */ - char name[10]; /* name of this file (copied from FDR) */ -}; - -struct ti99_catalog -{ - int num_subdirs; /* number of subdirectories */ - int num_files; /* number of files */ - dir_entry subdirs[114]; /* description of each subdir */ - file_entry files[128]; /* description of each file */ -}; - -/* - level-2 disk image descriptor -*/ -struct ti99_lvl2_imgref_dsk -{ - UINT16 totphysrecs; /* total number of aphysrecs (extracted from vib record in aphysrec 0) */ - ti99_catalog catalogs[4]; /* catalog of root directory and up to 3 subdirectories */ - UINT16 fdir_aphysrec[4]; /* fdir aphysrec address for root directory - and up to 3 subdirectories */ -}; - -enum win_vib_t -{ - win_vib_v1, - win_vib_v2 -}; -struct ti99_lvl2_imgref_win -{ - win_vib_t vib_version; /* version of the vib record in aphysrec 0 (see win_vib_ddr) */ -}; - -enum l2i_t -{ - L2I_DSK, - L2I_WIN -}; - -struct ti99_lvl2_imgref -{ - ti99_lvl1_imgref l1_img;/* image format, imgtool image handle, image geometry */ - ti99_AUformat AUformat; /* AU format */ - int data_offset; /* In order to reduce seek times when searching the - disk for a given file name, fdr (and ddr, and - fdir) records are preferentially allocated in - AUs n to data_offset, whereas data records are - preferentially allocated in AUs starting at - data_offset. */ - /* With the DSK disk structure, n is always 2 (if 1 - physrec per AU) or 1 (if 2 physrecs per AU or - more), and data_offset is arbitrarily chosen as - 34. */ - /* With the WIN disk structure, n depends on the - size of the volume bitmap, which itself depends - on the number of AUs on disk (we always have n - <= 33), and data_offset is read from the vib - record (except with the obsolete v1 VIB, where - we use a default value of 64). */ - char vol_name[10]; /* cached volume name (extracted from vib record in aphysrec 0) */ - - UINT8 abm[8192]; /* allocation bitmap */ - - l2i_t type; /* structure format */ - - union - { - ti99_lvl2_imgref_dsk dsk; - ti99_lvl2_imgref_win win; - }; /* structure-specific info */ -}; - -/* - file flags found in fdr (and tifiles) -*/ -enum -{ - fdr99_f_program = 0x01, /* set for program files */ - fdr99_f_int = 0x02, /* set for binary files */ - fdr99_f_wp = 0x08, /* set if file is write-protected */ - /*fdr99_f_backup = 0x10,*/ /* set if file has been modified since last backup */ - /*fdr99_f_dskimg = 0x20,*/ /* set if file is a DSK image (HFDC HD only) */ - fdr99_f_var = 0x80 /* set if file uses variable-length records*/ -}; - -/* - DSK FDR record -*/ -struct dsk_fdr -{ - char name[10]; /* file name (10 characters, pad with spaces) */ - UINT16BE xreclen; /* extended record len: if record len is >= 256, */ - /* reclen is set to 0 and the actual reclen is */ - /* stored here (Myarc HFDC only). TI reserved */ - /* this field for data chain pointer extension, */ - /* but this was never implemented. */ - UINT8 flags; /* file status flags (see enum above) */ - UINT8 recsperphysrec; /* logical records per physrec */ - /* ignored for variable length record files and */ - /* program files */ - UINT16BE fphysrecs; /* file length in physrecs */ - /* Note that the HFDC defines this field as the */ - /* number of allocated physrecs in the cluster */ - /* chain (i.e. rounded on the next AU */ - /* boundary), so level-3 routines should use */ - /* the fixrecs field instead to determine the */ - /* logical length of field. IIRC, the HFDC */ - /* implementation is regarded as a bug because */ - /* program files do not define the fixrecs field */ - /* field, so program field saved by the HFDC */ - /* DSR may be larger whan they should. */ - UINT8 eof; /* EOF offset in last physrec for variable length */ - /* record files and program files (0->256)*/ - UINT8 reclen; /* logical record size in bytes ([1,255] 0->256) */ - /* Maximum allowable record size for variable */ - /* length record files. Reserved for program */ - /* files (set to 0). Set to 0 if reclen >=256 */ - /* (HFDC only). */ - UINT16LE fixrecs; /* file length in logical records */ - /* For variable length record files, number of */ - /* 256-byte records actually used. */ - ti99_date_time creation;/* date and time of creation (HFDC and BwG only; */ - /* reserved in TI) */ - ti99_date_time update; /* date and time of last write to file (HFDC and */ - /* BwG only; reserved in TI) */ - UINT8 clusters[76][3]; /* data cluster table: 0 through 76 entries (3 */ - /* bytes each), one entry for each file cluster. */ - /* 12 bits: address of first AU of cluster */ - /* 12 bits: offset of last 256-byte record in cluster */ -}; - -/* - WIN FDR record -*/ -struct win_fdr -{ - char name[10]; /* file name (10 characters, pad with spaces) */ - UINT16BE xreclen; /* extended record len: if record len is >= 256, */ - /* reclen is set to 0 and the actual reclen is */ - /* stored here (Myarc HFDC only). TI reserved */ - /* this field for data chain pointer extension, */ - /* but this was never implemented. */ - UINT8 flags; /* file status flags (see enum above) */ - UINT8 recsperphysrec; /* logical records per physrec */ - /* ignored for variable length record files and */ - /* program files */ - UINT16BE fphysrecs_LSW; /* eldest FDR: file length in physrecs */ - /* Note that the HFDC defines this field as the */ - /* number of allocated physrecs in the cluster */ - /* chain (i.e. rounded on the next AU */ - /* boundary), so level-3 routines should use */ - /* the fixrecs field instead to determine the */ - /* logical length of field. IIRC, the HFDC */ - /* implementation is regarded as a bug because */ - /* program files do not define the fixrecs field */ - /* field, so program field saved by the HFDC */ - /* DSR may be larger whan they should. */ - /* other sibling FDRs: index of the first file */ - /* physrec in this particular sibling FDR */ - UINT8 eof; /* EOF offset in last physrec for variable length */ - /* record files and program files (0->256)*/ - UINT8 reclen; /* logical record size in bytes ([1,255]) */ - /* Maximum allowable record size for variable */ - /* length record files. Reserved for program */ - /* files (set to 0). Set to 0 if reclen >=256 */ - /* (HFDC only). */ - UINT16LE fixrecs_LSW; /* file length in logical records */ - /* For variable length record files, number of */ - /* 256-byte records actually used. */ - ti99_date_time creation;/* date and time of creation */ - ti99_date_time update; /* date and time of last write to file */ - - char id[2]; /* 'FI' */ - UINT16BE prevsibFDR_AU; /* address of the AU where previous sibling FDR is */ - /* (see also xinfo_LSB) */ - UINT16BE nextsibFDR_AU; /* address of the AU where next sibling FDR is */ - /* (see also xinfo_LSB) */ - UINT16BE sibFDR_AUlen; /* total number of data AUs allocated in this particular sibling FDR */ - UINT16BE parent_FDIR_AU;/* FDIR the file is listed in */ - UINT8 xinfo_MSB; /* extended information (MSByte) */ - /* bits 0-3: MSN of fphysrecs */ - /* bits 4-7: MSN of fixrecs */ - UINT8 xinfo_LSB; /* extended information (LSByte) */ - /* bits 8-11: physrec offset within AU for */ - /* previous sibling FDR (see prevsibFDR_AU) */ - /* bits 12-15: physrec offset within AU for */ - /* next sibling FDR (see nextsibFDR_AU) */ - UINT16BE clusters[54][2];/* data cluster table: 0 through 54 entries (4 */ - /* bytes each), one entry for each file cluster. */ - /* 16 bits: address of first AU of cluster */ - /* 16 bits: address of last AU of cluster */ -}; - -/* - tifile header: stand-alone file -*/ -struct tifile_header -{ - char tifiles[8]; /* always '\7TIFILES' */ - UINT16BE fphysrecs; /* file length in physrecs */ - UINT8 flags; /* see enum above */ - UINT8 recsperphysrec; /* records per physrec */ - UINT8 eof; /* current position of eof in last physrec (0->255)*/ - UINT8 reclen; /* bytes per record ([1,255] 0->256) */ - UINT16BE fixrecs; /* file length in records */ - UINT8 res[128-16]; /* reserved */ - /* * variant a: */ - /* 112 chars: 0xCA53 repeated 56 times */ - /* * variant b: */ - /* 4 chars: unknown */ - /* 108 chars: 0xCA53 repeated 54 times */ - /* * variant c: */ - /* 10 chars: original TI file name filed with spaces */ - /* 102 chars: spaces */ - /* * variant d: */ - /* 10 chars: original TI file name filed with spaces */ - /* 2 chars: CR+LF */ - /* 98 chars: spaces */ - /* 2 chars: CR+LF */ - /* * variant e: */ - /* 10 chars: original TI file name */ - /* 4 bytes: unknown */ - /* 4 bytes: time & date of creation */ - /* 4 bytes: time & date of last update */ - /* 90 chars: spaces */ - /* * variant f: */ - /* 6 bytes: 'MYTERM' */ - /* 4 bytes: time & date of creation */ - /* 4 bytes: time & date of last update */ - /* 2 bytes: unknown (always >0000) */ - /* 96 chars: 0xCA53 repeated 56 times */ -}; - -/* - level-2 file descriptor -*/ -struct ti99_lvl2_fileref_dsk -{ - struct ti99_lvl2_imgref *l2_img; - int fdr_aphysrec; - dsk_fdr fdr; -}; - -struct ti99_lvl2_fileref_win -{ - struct ti99_lvl2_imgref *l2_img; - unsigned fphysrecs; /* copy of field in the eldest FDR */ - unsigned eldestfdr_aphysrec; /* aphysrec address of the eldest FDR */ - unsigned curfdr_aphysrec; /* aphysrec address of the currently open sibling FDR */ - win_fdr curfdr; /* buffer with currently open sibling FDR */ -}; - -struct ti99_lvl2_fileref_tifiles -{ - imgtool_stream *file_handle; - tifile_header hdr; -}; - -enum l2f_type_t -{ - L2F_DSK, - L2F_WIN, - L2F_TIFILES -}; - -struct ti99_lvl2_fileref -{ - l2f_type_t type; - union - { - ti99_lvl2_fileref_dsk dsk; - ti99_lvl2_fileref_win win; - ti99_lvl2_fileref_tifiles tifiles; - }; -}; - -/* - Compare two (possibly empty) catalog entry for qsort -*/ -static int cat_file_compare_qsort(const void *p1, const void *p2) -{ - const file_entry *entry1 = (const file_entry *)p1; - const file_entry *entry2 = (const file_entry *)p2; - - if ((entry1->fdr_ptr == 0) && (entry2->fdr_ptr == 0)) - return 0; - else if (entry1->fdr_ptr == 0) - return +1; - else if (entry2->fdr_ptr == 0) - return -1; - else - return memcmp(entry1->name, entry2->name, 10); -} - -static int cat_dir_compare_qsort(const void *p1, const void *p2) -{ - const dir_entry *entry1 = (const dir_entry *)p1; - const dir_entry *entry2 = (const dir_entry *)p2; - - if ((entry1->dir_ptr == 0) && (entry2->dir_ptr == 0)) - return 0; - else if (entry1->dir_ptr == 0) - return +1; - else if (entry2->dir_ptr == 0) - return -1; - else - return memcmp(entry1->name, entry2->name, 10); -} - -/* - Read a directory catalog from disk image - - l2_img: image reference - aphysrec: physical record address of the FDIR - dest: pointer to the destination buffer where the catalog should be written - - Return an error code if there was an error, 0 otherwise. -*/ -static int dsk_read_catalog(struct ti99_lvl2_imgref *l2_img, int aphysrec, ti99_catalog *dest) -{ - int totphysrecs = l2_img->dsk.totphysrecs; - UINT16BE fdir_buf[128]; - dsk_fdr fdr; - int i; - int reply; - - - /* Read FDIR record */ - reply = read_absolute_physrec(& l2_img->l1_img, aphysrec, fdir_buf); - if (reply) - return IMGTOOLERR_READERROR; - - /* Copy FDIR info to catalog structure */ - for (i=0; i<128; i++) - dest->files[i].fdr_ptr = get_UINT16BE(fdir_buf[i]); - - /* Check FDIR pointers and check and extract file names from DDRs */ - for (i=0; i<128; i++) - { - if (dest->files[i].fdr_ptr >= totphysrecs) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - else if (dest->files[i].fdr_ptr) - { - reply = read_absolute_physrec(& l2_img->l1_img, dest->files[i].fdr_ptr, &fdr); - if (reply) - return IMGTOOLERR_READERROR; - - /* check and copy file name */ - if (check_fname(fdr.name)) - return IMGTOOLERR_CORRUPTIMAGE; - memcpy(dest->files[i].name, fdr.name, 10); - } - } - - /* Check catalog */ - for (i=0; i<127; i++) - { - if (((! dest->files[i].fdr_ptr) && dest->files[i+1].fdr_ptr) - || ((dest->files[i].fdr_ptr && dest->files[i+1].fdr_ptr) && (memcmp(dest->files[i].name, dest->files[i+1].name, 10) >= 0))) - { - /* if the catalog is not sorted, we repair it */ - qsort(dest->files, ARRAY_LENGTH(dest->files), sizeof(dest->files[0]), - cat_file_compare_qsort); - break; - } - } - - /* Set file count */ - for (i=0; (i<128) && (dest->files[i].fdr_ptr != 0); i++) - ; - dest->num_files = i; - - /* Set subdir count to 0 (subdirs are loaded elsewhere) */ - dest->num_subdirs = 0; - - return 0; -} - -/* - Read a directory catalog from disk image - - l2_img: image reference - DDR_AU: AU address of the VIB/DDR - dest: pointer to the destination buffer where the catalog should be written - - Return an error code if there was an error, 0 otherwise. -*/ -static int win_read_catalog(struct ti99_lvl2_imgref *l2_img, int DDR_AU, ti99_catalog *dest) -{ - win_vib_ddr ddr_buf; - UINT16BE fdir_buf[128]; - win_fdr fdr_buf; - int i; - int reply; - - - /* Read DDR record */ - reply = read_absolute_physrec(& l2_img->l1_img, DDR_AU*l2_img->AUformat.physrecsperAU, &ddr_buf); - if (reply) - return IMGTOOLERR_READERROR; - - /* sanity checks */ - if ((ddr_buf.num_files > 127) || (ddr_buf.num_subdirs > 114) || (get_UINT16BE(ddr_buf.fdir_AU) > l2_img->AUformat.totAUs)) - return IMGTOOLERR_CORRUPTIMAGE; - - /* set file count and subdir count */ - dest->num_files = ddr_buf.num_files; - dest->num_subdirs = ddr_buf.num_subdirs; - - /* Copy DDR info to catalog structure */ - for (i=0; i<ddr_buf.num_subdirs; i++) - dest->subdirs[i].dir_ptr = get_UINT16BE(ddr_buf.subdir_AU[i]); - - /* Read FDIR record */ - reply = read_absolute_physrec(& l2_img->l1_img, get_UINT16BE(ddr_buf.fdir_AU)*l2_img->AUformat.physrecsperAU, fdir_buf); - if (reply) - return IMGTOOLERR_READERROR; - - /* Copy FDIR info to catalog structure */ - for (i=0; i<dest->num_files; i++) - dest->files[i].fdr_ptr = get_UINT16BE(fdir_buf[i]); - - /* Check DDR pointers and check and extract file names from FDRs */ - for (i=0; i<dest->num_subdirs; i++) - { - if (dest->subdirs[i].dir_ptr >= l2_img->AUformat.totAUs) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - else if (dest->subdirs[i].dir_ptr) - { - reply = read_absolute_physrec(& l2_img->l1_img, dest->subdirs[i].dir_ptr*l2_img->AUformat.physrecsperAU, &ddr_buf); - if (reply) - return IMGTOOLERR_READERROR; - - /* check and copy file name */ - if (check_fname(ddr_buf.name)) - return IMGTOOLERR_CORRUPTIMAGE; - memcpy(dest->subdirs[i].name, ddr_buf.name, 10); - } - } - - /* Check FDIR pointers and check and extract file names from FDRs */ - for (i=0; i<dest->num_files; i++) - { - if (dest->files[i].fdr_ptr >= l2_img->AUformat.totAUs) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - else if (dest->files[i].fdr_ptr) - { - reply = read_absolute_physrec(& l2_img->l1_img, dest->files[i].fdr_ptr*l2_img->AUformat.physrecsperAU, &fdr_buf); - if (reply) - return IMGTOOLERR_READERROR; - - /* check and copy file name */ - if (check_fname(fdr_buf.name)) - return IMGTOOLERR_CORRUPTIMAGE; - memcpy(dest->files[i].name, fdr_buf.name, 10); - } - } - - /* Check catalog */ - - /* Check subdir order */ - for (i=0; i<dest->num_subdirs-1; i++) - { - if (((! dest->subdirs[i].dir_ptr) && dest->subdirs[i+1].dir_ptr) - || ((dest->subdirs[i].dir_ptr && dest->subdirs[i+1].dir_ptr) && (memcmp(dest->subdirs[i].name, dest->subdirs[i+1].name, 10) >= 0))) - { - /* if the subdir catalog is not sorted, we repair it */ - qsort(dest->subdirs, dest->num_subdirs, sizeof(dest->subdirs[0]), cat_dir_compare_qsort); - break; - } - } - - /* Fix subdir count */ - while (dest->num_subdirs && (dest->subdirs[dest->num_subdirs-1].dir_ptr == 0)) - dest->num_subdirs--; - - /* Check file order */ - for (i=0; i<dest->num_files-1; i++) - { - if (((! dest->files[i].fdr_ptr) && dest->files[i+1].fdr_ptr) - || ((dest->files[i].fdr_ptr && dest->files[i+1].fdr_ptr) && (memcmp(dest->files[i].name, dest->files[i+1].name, 10) >= 0))) - { - /* if the file catalog is not sorted, we repair it */ - qsort(dest->files, dest->num_files, sizeof(dest->files[0]), cat_file_compare_qsort); - break; - } - } - - /* Fix file count */ - while (dest->num_files && (dest->files[dest->num_files-1].fdr_ptr == 0)) - dest->num_files--; - - return 0; -} - -/* - Search for a file path on a floppy image - - l2_img: image reference - fpath: path of the file to search - parent_ref_valid: set to TRUE if either the file was found or the file was - not found but its parent dir was - parent_ref: reference to parent dir (0 for root) - out_is_dir: TRUE if element is a directory - catalog_index: on output, index of file catalog entry (may be NULL) -*/ -static int dsk_find_catalog_entry(struct ti99_lvl2_imgref *l2_img, const char *fpath, int *parent_ref_valid, int *parent_ref, int *out_is_dir, int *catalog_index) -{ - int i; - const ti99_catalog *cur_catalog; - const char *element_start, *element_end; - int element_len; - char element[10]; - int is_dir = FALSE; - - - cur_catalog = & l2_img->dsk.catalogs[0]; - if (parent_ref_valid) - (* parent_ref_valid) = FALSE; - if (parent_ref) - *parent_ref = 0; - - element_start = fpath; - do - { - /* find next path element */ - element_end = strchr(element_start, '.'); - element_len = element_end ? (element_end - element_start) : strlen(element_start); - if ((element_len > 10) || (element_len == 0)) - return IMGTOOLERR_BADFILENAME; - /* last path element */ - if ((!element_end) && parent_ref_valid) - (* parent_ref_valid) = TRUE; - - /* generate file name */ - memcpy(element, element_start, element_len); - memset(element+element_len, ' ', 10-element_len); - - /* search entry in subdirectories */ - for (i = 0; i<cur_catalog->num_subdirs; i++) - { - if (! memcmp(element, cur_catalog->subdirs[i].name, 10)) - { - is_dir = TRUE; - break; - } - } - - /* if it failed, search entry in files */ - if (i == cur_catalog->num_subdirs) - { - for (i = 0; i<cur_catalog->num_files; i++) - { - if (! memcmp(element, cur_catalog->files[i].name, 10)) - { - is_dir = FALSE; - break; - } - } - /* exit if not found */ - if (i == cur_catalog->num_files) - { - return IMGTOOLERR_FILENOTFOUND; - } - } - - /* iterate */ - if (element_end) - { - element_start = element_end+1; - - if (! is_dir) - /* this is not a directory */ - return IMGTOOLERR_BADFILENAME; - - /* initialize cur_catalog */ - cur_catalog = & l2_img->dsk.catalogs[i+1]; - if (parent_ref) - *parent_ref = i+1; - } - else - element_start = NULL; - } - while (element_start); - - if (out_is_dir) - *out_is_dir = is_dir; - - if (catalog_index) - *catalog_index = i; - - return 0; -} - -/* - Search for a file path on a harddisk image - - l2_img: image reference - fpath: path of the file to search - parent_ref_valid: set to TRUE if either the file was found or the file was - not found but its parent dir was - parent_ddr_AU: parent DDR AU address (0 for root) - parent_catalog: catalog of parent dir (cannot be NULL) - out_is_dir: TRUE if element is a directory - catalog_index: on output, index of file catalog entry (may be NULL) -*/ -static int win_find_catalog_entry(struct ti99_lvl2_imgref *l2_img, const char *fpath, - int *parent_ref_valid, int *parent_ddr_AU, ti99_catalog *parent_catalog, - int *out_is_dir, int *catalog_index) -{ - int i; - const char *element_start, *element_end; - int element_len; - char element[10]; - int is_dir = FALSE; - int errorcode; - - if (parent_ref_valid) - (* parent_ref_valid) = FALSE; - if (parent_ddr_AU) - *parent_ddr_AU = 0; - - errorcode = win_read_catalog(l2_img, 0, parent_catalog); - if (errorcode) - return errorcode; - - element_start = fpath; - do - { - /* find next path element */ - element_end = strchr(element_start, '.'); - element_len = element_end ? (element_end - element_start) : strlen(element_start); - if ((element_len > 10) || (element_len == 0)) - return IMGTOOLERR_BADFILENAME; - /* last path element */ - if ((!element_end) && parent_ref_valid) - (* parent_ref_valid) = TRUE; - - /* generate file name */ - memcpy(element, element_start, element_len); - memset(element+element_len, ' ', 10-element_len); - - /* search entry in subdirectories */ - for (i = 0; i<parent_catalog->num_subdirs; i++) - { - if (! memcmp(element, parent_catalog->subdirs[i].name, 10)) - { - is_dir = TRUE; - break; - } - } - - /* if it failed, search entry in files */ - if (i == parent_catalog->num_subdirs) - { - for (i = 0; i<parent_catalog->num_files; i++) - { - if (! memcmp(element, parent_catalog->files[i].name, 10)) - { - is_dir = FALSE; - break; - } - } - /* exit if not found */ - if (i == parent_catalog->num_files) - { - return IMGTOOLERR_FILENOTFOUND; - } - } - - /* iterate */ - if (element_end) - { - element_start = element_end+1; - - if (! is_dir) - /* this is not a directory */ - return IMGTOOLERR_BADFILENAME; - - if (parent_ddr_AU) - *parent_ddr_AU = parent_catalog->subdirs[i].dir_ptr; - - errorcode = win_read_catalog(l2_img, parent_catalog->subdirs[i].dir_ptr, parent_catalog); - if (errorcode) - return errorcode; - } - else - element_start = NULL; - } - while (element_start); - - if (out_is_dir) - *out_is_dir = is_dir; - - if (catalog_index) - *catalog_index = i; - - return 0; -} - -/* - Allocate one AU on disk, for use as a fdr record - - l2_img: image reference - fdr_AU: on output, address of allocated AU -*/ -static int alloc_fdr_AU(struct ti99_lvl2_imgref *l2_img, unsigned *fdr_AU) -{ - int totAUs = l2_img->AUformat.totAUs; - int i; - - for (i=0; i<totAUs; i++) - { - if (! (l2_img->abm[i >> 3] & (1 << (i & 7)))) - { - *fdr_AU = i; - l2_img->abm[i >> 3] |= 1 << (i & 7); - - return 0; - } - } - - return IMGTOOLERR_NOSPACE; -} - -INLINE int get_dsk_fdr_cluster_baseAU(struct ti99_lvl2_imgref *l2_img, dsk_fdr *fdr, int cluster_index) -{ - int reply; - - /* read base AU/physrec for this cluster */ - reply = ((fdr->clusters[cluster_index][1] & 0xf) << 8) | fdr->clusters[cluster_index][0]; - /* convert to AU address */ - if (l2_img->AUformat.physrecsperAU <= 2) - reply /= l2_img->AUformat.physrecsperAU; - - return reply; -} - -INLINE int get_dsk_fdr_cluster_baseaphysrec(struct ti99_lvl2_imgref *l2_img, dsk_fdr *fdr, int cluster_index) -{ - int reply; - - /* read base AU/physrec for this cluster */ - reply = ((fdr->clusters[cluster_index][1] & 0xf) << 8) | fdr->clusters[cluster_index][0]; - /* convert to physrec address */ - if (l2_img->AUformat.physrecsperAU > 2) - reply *= l2_img->AUformat.physrecsperAU; - - return reply; -} - -INLINE int get_dsk_fdr_cluster_lastfphysrec(dsk_fdr *fdr, int cluster_index) -{ - return (fdr->clusters[cluster_index][2] << 4) | (fdr->clusters[cluster_index][1] >> 4); -} - -INLINE void set_dsk_fdr_cluster_lastfphysrec(dsk_fdr *fdr, int cluster_index, int data) -{ - fdr->clusters[cluster_index][1] = (fdr->clusters[cluster_index][1] & 0x0f) | (data << 4); - fdr->clusters[cluster_index][2] = data >> 4; -} - -INLINE void set_dsk_fdr_cluster(struct ti99_lvl2_imgref *l2_img, dsk_fdr *fdr, int cluster_index, int baseAU, int lastfphysrec) -{ - /* convert AU address to FDR value */ - if (l2_img->AUformat.physrecsperAU <= 2) - baseAU *= l2_img->AUformat.physrecsperAU; - - /* write cluster entry */ - fdr->clusters[cluster_index][0] = baseAU; - fdr->clusters[cluster_index][1] = ((baseAU >> 8) & 0x0f) | (lastfphysrec << 4); - fdr->clusters[cluster_index][2] = lastfphysrec >> 4; -} - -INLINE unsigned get_win_fdr_fphysrecs(win_fdr *fdr) -{ - return (((unsigned) fdr->xinfo_MSB << 12) & 0xf0000) | get_UINT16BE(fdr->fphysrecs_LSW); -} - -INLINE void set_win_fdr_fphysrecs(win_fdr *fdr, unsigned data) -{ - fdr->xinfo_MSB = (fdr->xinfo_MSB & 0x0f) | ((data >> 12) & 0xf0); - set_UINT16BE(&fdr->fphysrecs_LSW, data & 0xffff); -} - -INLINE unsigned get_win_fdr_fixrecs(win_fdr *fdr) -{ - return (((unsigned) fdr->xinfo_MSB << 16) & 0xf0000) | get_UINT16LE(fdr->fixrecs_LSW); -} - -INLINE void set_win_fdr_fixrecs(win_fdr *fdr, unsigned data) -{ - fdr->xinfo_MSB = (fdr->xinfo_MSB & 0xf0) | ((data >> 16) & 0x0f); - set_UINT16LE(&fdr->fixrecs_LSW, data & 0xffff); -} - -INLINE unsigned get_win_fdr_prevsibFDR_aphysrec(struct ti99_lvl2_imgref *l2_img, win_fdr *fdr) -{ - unsigned prevsibFDR_AU = get_UINT16BE(fdr->prevsibFDR_AU); - - return prevsibFDR_AU - ? (prevsibFDR_AU * l2_img->AUformat.physrecsperAU + ((fdr->xinfo_LSB >> 4) & 0xf)) - : 0; -} - -INLINE unsigned get_win_fdr_nextsibFDR_aphysrec(struct ti99_lvl2_imgref *l2_img, win_fdr *fdr) -{ - unsigned nextsibFDR_AU = get_UINT16BE(fdr->nextsibFDR_AU); - - return nextsibFDR_AU - ? (nextsibFDR_AU * l2_img->AUformat.physrecsperAU + (fdr->xinfo_LSB & 0xf)) - : 0; -} - -INLINE unsigned get_win_fdr_cursibFDR_basefphysrec(win_fdr *fdr) -{ - return get_UINT16BE(fdr->prevsibFDR_AU) ? get_win_fdr_fphysrecs(fdr) : 0; -} - -/* - Advance to next sibling FDR -*/ -static int win_goto_next_sibFDR(ti99_lvl2_fileref_win *win_file) -{ - if (get_UINT16BE(win_file->curfdr.nextsibFDR_AU) == 0) - return IMGTOOLERR_UNEXPECTED; - - win_file->curfdr_aphysrec = get_win_fdr_nextsibFDR_aphysrec(win_file->l2_img, &win_file->curfdr); - if (read_absolute_physrec(& win_file->l2_img->l1_img, win_file->curfdr_aphysrec, &win_file->curfdr)) - return IMGTOOLERR_READERROR; - - return 0; -} - -/* - Back to previous sibling FDR -*/ -static int win_goto_prev_sibFDR(ti99_lvl2_fileref_win *win_file) -{ - if (get_UINT16BE(win_file->curfdr.prevsibFDR_AU) == 0) - return IMGTOOLERR_UNEXPECTED; - - win_file->curfdr_aphysrec = get_win_fdr_prevsibFDR_aphysrec(win_file->l2_img, &win_file->curfdr); - if (read_absolute_physrec(& win_file->l2_img->l1_img, win_file->curfdr_aphysrec, &win_file->curfdr)) - return IMGTOOLERR_READERROR; - - return 0; -} - -/* - Append a new sibling FDR at the end of the sibling FDR list, and open it. - - You must have gone to the end of the list. -*/ -static int win_alloc_sibFDR(ti99_lvl2_fileref_win *win_file) -{ - unsigned oldfdr_AU, oldfdr_physrecinAU; - unsigned newfdr_AU, newfdr_physrecinAU; - int allocated = FALSE; - int errorcode; - unsigned cursibFDR_basefphysrec; - - if (get_UINT16BE(win_file->curfdr.nextsibFDR_AU)) - return IMGTOOLERR_UNEXPECTED; - - oldfdr_AU = win_file->curfdr_aphysrec / win_file->l2_img->AUformat.physrecsperAU; - oldfdr_physrecinAU = win_file->curfdr_aphysrec % win_file->l2_img->AUformat.physrecsperAU; - - if (oldfdr_physrecinAU != (win_file->l2_img->AUformat.physrecsperAU - 1)) - { /* current AU is not full */ - newfdr_AU = oldfdr_AU; - newfdr_physrecinAU = oldfdr_physrecinAU + 1; - } - else - { /* current AU is full: allocate another */ - errorcode = alloc_fdr_AU(win_file->l2_img, &newfdr_AU); - if (errorcode) - return errorcode; - newfdr_physrecinAU = 0; - allocated = TRUE; - } - - set_UINT16BE(&win_file->curfdr.nextsibFDR_AU, newfdr_AU); - win_file->curfdr.xinfo_LSB = (win_file->curfdr.xinfo_LSB & 0xf0) | newfdr_physrecinAU; - - /* save current sibling FDR */ - if (write_absolute_physrec(& win_file->l2_img->l1_img, win_file->curfdr_aphysrec, &win_file->curfdr)) - { - /* clear pointer */ - set_UINT16BE(&win_file->curfdr.nextsibFDR_AU, 0); - win_file->curfdr.xinfo_LSB = win_file->curfdr.xinfo_LSB & 0xf0; - if (allocated) - /* free AU */ - win_file->l2_img->abm[newfdr_AU >> 3] |= 1 << (newfdr_AU & 7); - return IMGTOOLERR_WRITEERROR; - } - - /* now update in-memory structure to describe new sibling FDR */ - cursibFDR_basefphysrec = get_win_fdr_cursibFDR_basefphysrec(&win_file->curfdr) - + get_UINT16BE(win_file->curfdr.sibFDR_AUlen) * win_file->l2_img->AUformat.physrecsperAU; - - set_UINT16BE(&win_file->curfdr.nextsibFDR_AU, 0); - set_UINT16BE(&win_file->curfdr.prevsibFDR_AU, oldfdr_AU); - win_file->curfdr.xinfo_LSB = oldfdr_physrecinAU << 4; - - win_file->curfdr_aphysrec = newfdr_AU * win_file->l2_img->AUformat.physrecsperAU + newfdr_physrecinAU; - - set_win_fdr_fphysrecs(&win_file->curfdr, cursibFDR_basefphysrec); - set_UINT16BE(&win_file->curfdr.sibFDR_AUlen, 0); - memset(win_file->curfdr.clusters, 0, sizeof(win_file->curfdr.clusters)); - - return 0; -} - -/* - Extend a file with nb_alloc_physrecs extra physrecs - - dsk_file: file reference - nb_alloc_physrecs: number of physical records to allocate -*/ -static int dsk_alloc_file_physrecs(ti99_lvl2_fileref_dsk *dsk_file, int nb_alloc_physrecs) -{ - int totAUs = dsk_file->l2_img->AUformat.totAUs; - int free_physrecs; - int fphysrecs; - int i; - int cluster_index; - int last_sec, p_last_sec = 0; - int cur_block_seclen; - int cluster_baseAU, cluster_AUlen; - int first_best_block_baseAU = 0, first_best_block_seclen; - int second_best_block_baseAU = 0, second_best_block_seclen; - int search_start; - - /* compute free space */ - free_physrecs = 0; - for (i=0; i<totAUs; i++) - { - if (! (dsk_file->l2_img->abm[i >> 3] & (1 << (i & 7)))) - free_physrecs += dsk_file->l2_img->AUformat.physrecsperAU; - } - - /* check we have enough free space */ - if (free_physrecs < nb_alloc_physrecs) - return IMGTOOLERR_NOSPACE; - - /* current number of data physrecs in file */ - fphysrecs = get_UINT16BE(dsk_file->fdr.fphysrecs); - - if (fphysrecs == 0) - { /* cluster array must be empty */ - cluster_index = 0; - } - else - { /* try to extend last block */ - last_sec = -1; - for (cluster_index=0; cluster_index<76; cluster_index++) - { - p_last_sec = last_sec; - last_sec = get_dsk_fdr_cluster_lastfphysrec(&dsk_file->fdr, cluster_index); - if (last_sec >= (fphysrecs-1)) - break; - } - if (cluster_index == 76) - /* that sucks */ - return IMGTOOLERR_CORRUPTIMAGE; - - if (last_sec > (fphysrecs-1)) - { /* some extra space has already been allocated */ - cur_block_seclen = last_sec - (fphysrecs-1); - if (cur_block_seclen > nb_alloc_physrecs) - cur_block_seclen = nb_alloc_physrecs; - - fphysrecs += cur_block_seclen; - set_UINT16BE(& dsk_file->fdr.fphysrecs, fphysrecs); - nb_alloc_physrecs -= cur_block_seclen; - if (! nb_alloc_physrecs) - return 0; /* done */ - } - - /* round up to next AU boundary */ - last_sec = last_sec + dsk_file->l2_img->AUformat.physrecsperAU - (last_sec % dsk_file->l2_img->AUformat.physrecsperAU) - 1; - - if (last_sec > (fphysrecs-1)) - { /* some extra space has already been allocated */ - cur_block_seclen = last_sec - (fphysrecs-1); - if (cur_block_seclen > nb_alloc_physrecs) - cur_block_seclen = nb_alloc_physrecs; - - fphysrecs += cur_block_seclen; - set_UINT16BE(& dsk_file->fdr.fphysrecs, fphysrecs); - set_dsk_fdr_cluster_lastfphysrec(&dsk_file->fdr, cluster_index, fphysrecs-1); - nb_alloc_physrecs -= cur_block_seclen; - if (! nb_alloc_physrecs) - return 0; /* done */ - } - - /* read base AU address for this cluster */ - cluster_baseAU = get_dsk_fdr_cluster_baseAU(dsk_file->l2_img, &dsk_file->fdr, cluster_index); - /* point past cluster end */ - cluster_baseAU += (last_sec-p_last_sec/*+file->l2_img->AUformat.physrecsperAU-1*/) / dsk_file->l2_img->AUformat.physrecsperAU; - /* count free physrecs after last block */ - cur_block_seclen = 0; - for (i=cluster_baseAU; (! (dsk_file->l2_img->abm[i >> 3] & (1 << (i & 7)))) && (cur_block_seclen < nb_alloc_physrecs) && (i < totAUs); i++) - cur_block_seclen += dsk_file->l2_img->AUformat.physrecsperAU; - if (cur_block_seclen) - { /* extend last block */ - if (cur_block_seclen > nb_alloc_physrecs) - cur_block_seclen = nb_alloc_physrecs; - - fphysrecs += cur_block_seclen; - set_UINT16BE(& dsk_file->fdr.fphysrecs, fphysrecs); - last_sec += cur_block_seclen; - nb_alloc_physrecs -= cur_block_seclen; - set_dsk_fdr_cluster_lastfphysrec(&dsk_file->fdr, cluster_index, last_sec); - cluster_AUlen = (cur_block_seclen + dsk_file->l2_img->AUformat.physrecsperAU - 1) / dsk_file->l2_img->AUformat.physrecsperAU; - for (i=0; i<cluster_AUlen; i++) - dsk_file->l2_img->abm[(i+cluster_baseAU) >> 3] |= 1 << ((i+cluster_baseAU) & 7); - if (! nb_alloc_physrecs) - return 0; /* done */ - } - cluster_index++; - if (cluster_index == 76) - /* that sucks */ - return IMGTOOLERR_NOSPACE; - } - - search_start = dsk_file->l2_img->data_offset; /* initially, search for free space only in data space */ - while (nb_alloc_physrecs) - { - /* find smallest data block at least nb_alloc_physrecs in length, and largest data block less than nb_alloc_physrecs in length */ - first_best_block_seclen = INT_MAX; - second_best_block_seclen = 0; - for (i=search_start; i<totAUs; i++) - { - if (! (dsk_file->l2_img->abm[i >> 3] & (1 << (i & 7)))) - { /* found one free block */ - /* compute its length */ - cluster_baseAU = i; - cur_block_seclen = 0; - while ((i<totAUs) && (! (dsk_file->l2_img->abm[i >> 3] & (1 << (i & 7))))) - { - cur_block_seclen += dsk_file->l2_img->AUformat.physrecsperAU; - i++; - } - /* compare to previous best and second-best blocks */ - if ((cur_block_seclen < first_best_block_seclen) && (cur_block_seclen >= nb_alloc_physrecs)) - { - first_best_block_baseAU = cluster_baseAU; - first_best_block_seclen = cur_block_seclen; - if (cur_block_seclen == nb_alloc_physrecs) - /* no need to search further */ - break; - } - else if ((cur_block_seclen > second_best_block_seclen) && (cur_block_seclen < nb_alloc_physrecs)) - { - second_best_block_baseAU = cluster_baseAU; - second_best_block_seclen = cur_block_seclen; - } - } - } - - if (first_best_block_seclen != INT_MAX) - { /* found one contiguous block which can hold it all */ - fphysrecs += nb_alloc_physrecs; - set_UINT16BE(& dsk_file->fdr.fphysrecs, fphysrecs); - - set_dsk_fdr_cluster(dsk_file->l2_img, &dsk_file->fdr, cluster_index, first_best_block_baseAU, fphysrecs-1); - cluster_AUlen = (nb_alloc_physrecs + dsk_file->l2_img->AUformat.physrecsperAU - 1) / dsk_file->l2_img->AUformat.physrecsperAU; - for (i=0; i<cluster_AUlen; i++) - dsk_file->l2_img->abm[(i+first_best_block_baseAU) >> 3] |= 1 << ((i+first_best_block_baseAU) & 7); - - nb_alloc_physrecs = 0; - } - else if (second_best_block_seclen != 0) - { /* jeez, we need to fragment it. We use the largest smaller block to limit fragmentation. */ - fphysrecs += second_best_block_seclen; - set_UINT16BE(& dsk_file->fdr.fphysrecs, fphysrecs); - - set_dsk_fdr_cluster(dsk_file->l2_img, &dsk_file->fdr, cluster_index, second_best_block_baseAU, fphysrecs-1); - cluster_AUlen = (second_best_block_seclen + dsk_file->l2_img->AUformat.physrecsperAU - 1) / dsk_file->l2_img->AUformat.physrecsperAU; - for (i=0; i<cluster_AUlen; i++) - dsk_file->l2_img->abm[(i+second_best_block_baseAU) >> 3] |= 1 << ((i+second_best_block_baseAU) & 7); - - nb_alloc_physrecs -= second_best_block_seclen; - - cluster_index++; - if (cluster_index == 76) - /* that sucks */ - return IMGTOOLERR_NOSPACE; - } - else if (search_start != 0) - { /* we did not find any free physrec in the data section of the disk */ - search_start = 0; /* time to fall back to fdr space */ - } - else - return IMGTOOLERR_NOSPACE; /* This should never happen, as we pre-check that there is enough free space */ - } - - return 0; -} - -/* - Extend a file with nb_alloc_physrecs extra physrecs - - win_file: file reference - nb_alloc_physrecs: number of physical records to allocate -*/ -static int win_alloc_file_physrecs(ti99_lvl2_fileref_win *win_file, int nb_alloc_physrecs) -{ - int totAUs = win_file->l2_img->AUformat.totAUs; - int free_physrecs; - int fphysrecs; - int i; - int cluster_index; - int num_fphysrec; - int cur_block_seclen; - int cluster_baseAU, cluster_AUlen; - int first_best_block_baseAU = 0, first_best_block_seclen; - int second_best_block_baseAU = 0, second_best_block_seclen; - int search_start; - int errorcode; - - /* compute free space */ - free_physrecs = 0; - for (i=0; i<totAUs; i++) - { - if (! (win_file->l2_img->abm[i >> 3] & (1 << (i & 7)))) - free_physrecs += win_file->l2_img->AUformat.physrecsperAU; - } - - /* check we have enough free space */ - if (free_physrecs < nb_alloc_physrecs) - return IMGTOOLERR_NOSPACE; - - /* move to last sibling non-empty FDR */ - while ((get_UINT16BE(win_file->curfdr.nextsibFDR_AU) != 0) && - (get_UINT16BE(win_file->curfdr.clusters[53][0]) != 0)) - { - errorcode = win_goto_next_sibFDR(win_file); - if (errorcode) - return errorcode; - } - if ((get_UINT16BE(win_file->curfdr.clusters[0][0]) == 0) && (get_UINT16BE(win_file->curfdr.prevsibFDR_AU) != 0)) - { /* this is annoying: we have found a sibling FDR filled with 0s: rewind - to last non-empty sibling if applicable */ - errorcode = win_goto_prev_sibFDR(win_file); - if (errorcode) - return errorcode; - } - - /* current number of data physrecs in file */ - fphysrecs = win_file->fphysrecs; - - /* current number of allocated physrecs */ - num_fphysrec = get_win_fdr_cursibFDR_basefphysrec(&win_file->curfdr) - + get_UINT16BE(win_file->curfdr.sibFDR_AUlen) * win_file->l2_img->AUformat.physrecsperAU; - - if (num_fphysrec > fphysrecs) - { /* some extra space has already been allocated */ - cur_block_seclen = num_fphysrec - fphysrecs; - if (cur_block_seclen > nb_alloc_physrecs) - cur_block_seclen = nb_alloc_physrecs; - - fphysrecs += cur_block_seclen; - win_file->fphysrecs = fphysrecs; - /* TODO: update eldest FDR fphysrecs field */ - /*set_win_fdr_fphysrecs(& win_file->rootfdr.fphysrecs, fphysrecs);*/ - nb_alloc_physrecs -= cur_block_seclen; - if (! nb_alloc_physrecs) - return 0; /* done */ - } - - /* find last non-empty cluster */ - for (cluster_index=0; (cluster_index<54) && (get_UINT16BE(win_file->curfdr.clusters[cluster_index][0]) != 0); cluster_index++) - ; - /* if we are dealing with an empty file, we will have (cluster_index == 0)... */ - if (cluster_index != 0) - { - cluster_index--; - /* try to extend last cluster */ - /* point past cluster end */ - cluster_baseAU = get_UINT16BE(win_file->curfdr.clusters[cluster_index][1]) + 1; - /* count free physrecs after last block */ - cur_block_seclen = 0; - for (i=cluster_baseAU; (! (win_file->l2_img->abm[i >> 3] & (1 << (i & 7)))) && (cur_block_seclen < nb_alloc_physrecs) && (i < totAUs); i++) - cur_block_seclen += win_file->l2_img->AUformat.physrecsperAU; - if (cur_block_seclen) - { /* extend last block */ - if (cur_block_seclen > nb_alloc_physrecs) - cur_block_seclen = nb_alloc_physrecs; - - fphysrecs += cur_block_seclen; - cluster_AUlen = (cur_block_seclen + win_file->l2_img->AUformat.physrecsperAU - 1) / win_file->l2_img->AUformat.physrecsperAU; - win_file->fphysrecs = fphysrecs; - /* TODO: update eldest FDR fphysrecs field */ - /*set_win_fdr_fphysrecs(& win_file->rootfdr.fphysrecs, fphysrecs);*/ - set_UINT16BE(&win_file->curfdr.sibFDR_AUlen, - get_UINT16BE(win_file->curfdr.sibFDR_AUlen)+cluster_AUlen); - set_UINT16BE(&win_file->curfdr.clusters[cluster_index][1], - get_UINT16BE(win_file->curfdr.clusters[cluster_index][1])+cluster_AUlen); - for (i=0; i<cluster_AUlen; i++) - win_file->l2_img->abm[(i+cluster_baseAU) >> 3] |= 1 << ((i+cluster_baseAU) & 7); - nb_alloc_physrecs -= cur_block_seclen; - if (! nb_alloc_physrecs) - return 0; /* done */ - } - /* now point to first free entry in cluster table */ - cluster_index++; - } - - search_start = win_file->l2_img->data_offset; /* initially, search for free space only in data space */ - while (nb_alloc_physrecs) - { - /* find smallest data block at least nb_alloc_physrecs in length, and largest data block less than nb_alloc_physrecs in length */ - first_best_block_seclen = INT_MAX; - second_best_block_seclen = 0; - for (i=search_start; i<totAUs; i++) - { - if (! (win_file->l2_img->abm[i >> 3] & (1 << (i & 7)))) - { /* found one free block */ - /* compute its length */ - cluster_baseAU = i; - cur_block_seclen = 0; - while ((i<totAUs) && (! (win_file->l2_img->abm[i >> 3] & (1 << (i & 7))))) - { - cur_block_seclen += win_file->l2_img->AUformat.physrecsperAU; - i++; - } - /* compare to previous best and second-best blocks */ - if ((cur_block_seclen < first_best_block_seclen) && (cur_block_seclen >= nb_alloc_physrecs)) - { - first_best_block_baseAU = cluster_baseAU; - first_best_block_seclen = cur_block_seclen; - if (cur_block_seclen == nb_alloc_physrecs) - /* no need to search further */ - break; - } - else if ((cur_block_seclen > second_best_block_seclen) && (cur_block_seclen < nb_alloc_physrecs)) - { - second_best_block_baseAU = cluster_baseAU; - second_best_block_seclen = cur_block_seclen; - } - } - } - - if ((first_best_block_seclen != INT_MAX) || (second_best_block_seclen != 0)) - { - if (cluster_index == 54) - { - /* end of cluster list: go to next sibling FDR */ - if (write_absolute_physrec(& win_file->l2_img->l1_img, win_file->curfdr_aphysrec, &win_file->curfdr)) - return IMGTOOLERR_WRITEERROR; - if (get_UINT16BE(win_file->curfdr.nextsibFDR_AU) != 0) - { /* read next sibling FDR */ - errorcode = win_goto_next_sibFDR(win_file); - if (errorcode) - return errorcode; - } - else - { /* allocate new sibling FDR */ - errorcode = win_alloc_sibFDR(win_file); - if (errorcode) - return errorcode; - } - cluster_index = 0; - } - } - - if (first_best_block_seclen != INT_MAX) - { /* found one contiguous block which can hold it all */ - fphysrecs += nb_alloc_physrecs; - cluster_AUlen = (nb_alloc_physrecs + win_file->l2_img->AUformat.physrecsperAU - 1) / win_file->l2_img->AUformat.physrecsperAU; - win_file->fphysrecs = fphysrecs; - /* TODO: update eldest FDR fphysrecs field */ - /*set_win_fdr_fphysrecs(& win_file->rootfdr.fphysrecs, fphysrecs);*/ - set_UINT16BE(&win_file->curfdr.sibFDR_AUlen, - get_UINT16BE(win_file->curfdr.sibFDR_AUlen)+cluster_AUlen); - set_UINT16BE(&win_file->curfdr.clusters[cluster_index][0], first_best_block_baseAU); - set_UINT16BE(&win_file->curfdr.clusters[cluster_index][1], - first_best_block_baseAU+cluster_AUlen-1); - - for (i=0; i<cluster_AUlen; i++) - win_file->l2_img->abm[(i+first_best_block_baseAU) >> 3] |= 1 << ((i+first_best_block_baseAU) & 7); - - nb_alloc_physrecs = 0; - } - else if (second_best_block_seclen != 0) - { /* jeez, we need to fragment it. We use the largest smaller block to limit fragmentation. */ - fphysrecs += second_best_block_seclen; - cluster_AUlen = (second_best_block_seclen + win_file->l2_img->AUformat.physrecsperAU - 1) / win_file->l2_img->AUformat.physrecsperAU; - win_file->fphysrecs = fphysrecs; - /* TODO: update eldest FDR fphysrecs field */ - /*set_win_fdr_fphysrecs(& win_file->rootfdr.fphysrecs, fphysrecs);*/ - set_UINT16BE(&win_file->curfdr.sibFDR_AUlen, - get_UINT16BE(win_file->curfdr.sibFDR_AUlen)+cluster_AUlen); - set_UINT16BE(&win_file->curfdr.clusters[cluster_index][0], second_best_block_baseAU); - set_UINT16BE(&win_file->curfdr.clusters[cluster_index][1], - second_best_block_baseAU+cluster_AUlen-1); - - for (i=0; i<cluster_AUlen; i++) - win_file->l2_img->abm[(i+second_best_block_baseAU) >> 3] |= 1 << ((i+second_best_block_baseAU) & 7); - - nb_alloc_physrecs -= second_best_block_seclen; - - /* now point to first free entry in cluster table */ - cluster_index++; - } - else if (search_start != 0) - { /* we did not find any free physrec in the data section of the disk */ - search_start = 0; /* time to fall back to fdr space */ - } - else - return IMGTOOLERR_NOSPACE; /* This should never happen, as we pre-check that there is enough free space */ - } - - return 0; -} - -/* - Allocate a new (empty) file -*/ -static int new_file_lvl2_dsk(struct ti99_lvl2_imgref *l2_img, int parent_ref, char filename[10], struct ti99_lvl2_fileref *l2_file) -{ - ti99_catalog *catalog = &l2_img->dsk.catalogs[parent_ref]; - unsigned fdr_AU, fdr_aphysrec; - int catalog_index, i; - int reply = 0; - int errorcode; - - - if (catalog->num_files >= 127) - /* if num_files == 128, catalog is full */ - /* if num_files == 127, catalog is not full, but we don't want to write - a 128th entry for compatibility with some existing DSRs that detect the - end of the FDIR array with a 0 entry (and do not check that the index - has not reached 128) */ - return IMGTOOLERR_NOSPACE; - - /* find insertion point in catalog */ - for (i=0; (i < catalog->num_files) && ((reply = memcmp(catalog->files[i].name, filename, 10)) < 0); i++) - ; - - if ((i<catalog->num_files) && (reply == 0)) - /* file already exists */ - return IMGTOOLERR_BADFILENAME; - else - { - /* otherwise insert new entry */ - catalog_index = i; - errorcode = alloc_fdr_AU(l2_img, &fdr_AU); - if (errorcode) - return errorcode; - fdr_aphysrec = fdr_AU * l2_img->AUformat.physrecsperAU; - - /* shift catalog entries until the insertion point */ - for (i=catalog->num_files; i>catalog_index; i--) - catalog->files[i] = catalog->files[i-1]; - - /* write new catalog entry */ - catalog->files[catalog_index].fdr_ptr = fdr_aphysrec; - memcpy(catalog->files[catalog_index].name, filename, 10); - - /* update catalog len */ - catalog->num_files++; - } - - /* set up file handle */ - l2_file->type = L2F_DSK; - l2_file->dsk.l2_img = l2_img; - l2_file->dsk.fdr_aphysrec = fdr_aphysrec; - memset(&l2_file->dsk.fdr, 0, sizeof(l2_file->dsk.fdr)); - memcpy(l2_file->dsk.fdr.name, filename, 10); - - return 0; -} - -/* - Allocate a new (empty) file -*/ -static int new_file_lvl2_win(struct ti99_lvl2_imgref *l2_img, ti99_catalog *parent_catalog, char filename[10], struct ti99_lvl2_fileref *l2_file) -{ - unsigned fdr_AU; - int catalog_index, i; - int reply = 0; - int errorcode; - - - if (parent_catalog->num_files >= 127) - /* if num_files == 127, catalog is full */ - return IMGTOOLERR_NOSPACE; - - /* find insertion point in catalog */ - for (i=0; (i < parent_catalog->num_files) && ((reply = memcmp(parent_catalog->files[i].name, filename, 10)) < 0); i++) - ; - - if ((i<parent_catalog->num_files) && (reply == 0)) - /* file already exists */ - return IMGTOOLERR_BADFILENAME; - else - { - /* otherwise insert new entry */ - catalog_index = i; - errorcode = alloc_fdr_AU(l2_img, &fdr_AU); - if (errorcode) - return errorcode; - - /* shift catalog entries until the insertion point */ - for (i=parent_catalog->num_files; i>catalog_index; i--) - parent_catalog->files[i] = parent_catalog->files[i-1]; - - /* write new catalog entry */ - parent_catalog->files[catalog_index].fdr_ptr = fdr_AU; - memcpy(parent_catalog->files[catalog_index].name, filename, 10); - - /* update catalog len */ - parent_catalog->num_files++; - } - - /* set up file handle */ - l2_file->type = L2F_WIN; - l2_file->win.l2_img = l2_img; - l2_file->win.fphysrecs = 0; - l2_file->win.eldestfdr_aphysrec = fdr_AU * l2_img->AUformat.physrecsperAU; - l2_file->win.curfdr_aphysrec = l2_file->win.eldestfdr_aphysrec; - memset(&l2_file->win.curfdr, 0, sizeof(l2_file->win.curfdr)); - memcpy(l2_file->win.curfdr.name, filename, 10); - - return 0; -} - -/* - Allocate a new (empty) file -*/ -static int new_file_lvl2_tifiles(imgtool_stream *file_handle, struct ti99_lvl2_fileref *l2_file) -{ - /* set up file handle */ - l2_file->type = L2F_TIFILES; - l2_file->tifiles.file_handle = file_handle; - memset(&l2_file->tifiles.hdr, 0, sizeof(l2_file->tifiles.hdr)); - l2_file->tifiles.hdr.tifiles[0] = '\7'; - l2_file->tifiles.hdr.tifiles[1] = 'T'; - l2_file->tifiles.hdr.tifiles[2] = 'I'; - l2_file->tifiles.hdr.tifiles[3] = 'F'; - l2_file->tifiles.hdr.tifiles[4] = 'I'; - l2_file->tifiles.hdr.tifiles[5] = 'L'; - l2_file->tifiles.hdr.tifiles[6] = 'E'; - l2_file->tifiles.hdr.tifiles[7] = 'S'; - - return 0; -} - -/* - Open an existing file on a floppy image - - l2_img: level 2 image the file is located on - fpath: access path to the file - file: set up if open is successful -*/ -static int open_file_lvl2_dsk(struct ti99_lvl2_imgref *l2_img, const char *fpath, struct ti99_lvl2_fileref *l2_file) -{ - int parent_ref, is_dir, catalog_index; - int reply; - - - reply = dsk_find_catalog_entry(l2_img, fpath, NULL, &parent_ref, &is_dir, &catalog_index); - if (reply) - return reply; - - if (is_dir) - /* this is not a file */ - return IMGTOOLERR_BADFILENAME; - - l2_file->type = L2F_DSK; - l2_file->dsk.l2_img = l2_img; - l2_file->dsk.fdr_aphysrec = l2_img->dsk.catalogs[parent_ref].files[catalog_index].fdr_ptr; - if (read_absolute_physrec(& l2_img->l1_img, l2_file->dsk.fdr_aphysrec, &l2_file->dsk.fdr)) - return IMGTOOLERR_READERROR; - - return 0; -} - -/* - Open an existing file on a harddisk image - - l2_img: level 2 image the file is located on - fpath: access path to the file - file: set up if open is successful -*/ -static int open_file_lvl2_win(struct ti99_lvl2_imgref *l2_img, const char *fpath, struct ti99_lvl2_fileref *l2_file) -{ - int parent_ref, is_dir, catalog_index; - ti99_catalog catalog; - int reply; - - reply = win_find_catalog_entry(l2_img, fpath, NULL, &parent_ref, &catalog, &is_dir, &catalog_index); - if (reply) - return reply; - - if (is_dir) - /* this is not a file */ - return IMGTOOLERR_BADFILENAME; - - l2_file->type = L2F_WIN; - l2_file->win.l2_img = l2_img; - l2_file->win.eldestfdr_aphysrec = catalog.files[catalog_index].fdr_ptr * l2_img->AUformat.physrecsperAU; - l2_file->win.curfdr_aphysrec = l2_file->win.eldestfdr_aphysrec; - if (read_absolute_physrec(& l2_img->l1_img, l2_file->win.curfdr_aphysrec, &l2_file->win.curfdr)) - return IMGTOOLERR_READERROR; - l2_file->win.fphysrecs = get_win_fdr_fphysrecs(&l2_file->win.curfdr); - - /* check integrity of FDR sibling chain */ - /* note that as we check that the back chain is consistent with the forward - chain, we will also detect any cycle in the sibling chain, so we do not - need to check against them explicitely */ - if (get_UINT16BE(l2_file->win.curfdr.prevsibFDR_AU) != 0) - return IMGTOOLERR_CORRUPTIMAGE; - - { - int i, pastendoflist_flag; - unsigned cur_fphysrec, sibFDR_AUlen; - win_fdr *cur_fdr, fdr_buf; - unsigned curfdr_aphysrec, prevfdr_aphysrec; - - cur_fphysrec = 0; - pastendoflist_flag = 0; - cur_fdr = &l2_file->win.curfdr; - curfdr_aphysrec = l2_file->win.eldestfdr_aphysrec; - - while (1) - { - sibFDR_AUlen = 0; - i=0; - if (! pastendoflist_flag) - { - /* compute number of allocated AUs and check number of AUs */ - for (; i<54; i++) - { - if (get_UINT16BE(cur_fdr->clusters[i][0]) == 0) - { - pastendoflist_flag = TRUE; - break; - } - sibFDR_AUlen += get_UINT16BE(cur_fdr->clusters[i][1]) - - get_UINT16BE(cur_fdr->clusters[i][0]) - + 1; - } - } - /* clear remainder of cluster table */ - for (; i<54; i++) - { -#if 0 - set_UINT16BE(&cur_fdr->clusters[i][0], 0); - set_UINT16BE(&cur_fdr->clusters[i][1], 0); -#endif - if ((get_UINT16BE(cur_fdr->clusters[i][0]) != 0) || (get_UINT16BE(cur_fdr->clusters[i][1]) != 0)) - return IMGTOOLERR_CORRUPTIMAGE; - } - - /* check sibFDR_AUlen field */ - if (get_UINT16BE(cur_fdr->sibFDR_AUlen) != sibFDR_AUlen) - return IMGTOOLERR_CORRUPTIMAGE; - - /* update current file physrec position to point to end of sibling FDR */ - cur_fphysrec += sibFDR_AUlen * l2_file->win.l2_img->AUformat.physrecsperAU; - - /* exit loop if end of sibling chain */ - if (! get_UINT16BE(cur_fdr->nextsibFDR_AU)) - break; - - /* otherwise read next FDR */ - if (get_UINT16BE(cur_fdr->nextsibFDR_AU) >= l2_file->win.l2_img->AUformat.totAUs) - return IMGTOOLERR_CORRUPTIMAGE; - - prevfdr_aphysrec = curfdr_aphysrec; - curfdr_aphysrec = get_win_fdr_nextsibFDR_aphysrec(l2_file->win.l2_img, cur_fdr); - if (read_absolute_physrec(& l2_file->win.l2_img->l1_img, curfdr_aphysrec, &fdr_buf)) - return IMGTOOLERR_READERROR; - cur_fdr = &fdr_buf; - - /* check that back chaining is consistent with forward chaining */ - if (get_win_fdr_prevsibFDR_aphysrec(l2_file->win.l2_img, &fdr_buf) != prevfdr_aphysrec) - return IMGTOOLERR_CORRUPTIMAGE; - /* check fphysrecs field */ - if (get_win_fdr_fphysrecs(&fdr_buf) != cur_fphysrec) - return IMGTOOLERR_CORRUPTIMAGE; - - /* check consistency of informative fields (name, record format, flags, etc) */ - if (memcmp(fdr_buf.name, l2_file->win.curfdr.name, 10) - || (get_UINT16BE(fdr_buf.xreclen) != get_UINT16BE(l2_file->win.curfdr.xreclen)) - || (fdr_buf.flags != l2_file->win.curfdr.flags) - || (fdr_buf.recsperphysrec != l2_file->win.curfdr.recsperphysrec) - || (fdr_buf.eof != l2_file->win.curfdr.eof) - || (fdr_buf.reclen != l2_file->win.curfdr.reclen) - || (get_UINT16LE(fdr_buf.fixrecs_LSW) != get_UINT16LE(l2_file->win.curfdr.fixrecs_LSW)) - || memcmp(&fdr_buf.creation, &l2_file->win.curfdr.creation, 4) - || memcmp(&fdr_buf.update, &l2_file->win.curfdr.update, 4) - /*|| memcmp(fdr_buf.id, l2_file->win.curfdr.id, 2)*/ - || (get_UINT16BE(fdr_buf.parent_FDIR_AU) != get_UINT16BE(l2_file->win.curfdr.parent_FDIR_AU)) - || ((fdr_buf.xinfo_MSB & 0xf) != (l2_file->win.curfdr.xinfo_MSB & 0xf))) - return IMGTOOLERR_CORRUPTIMAGE; - } - if (cur_fphysrec < l2_file->win.fphysrecs) - return IMGTOOLERR_CORRUPTIMAGE; - } - - return 0; -} - -/* - Open an existing file in TIFILES format -*/ -static int open_file_lvl2_tifiles(imgtool_stream *file_handle, struct ti99_lvl2_fileref *l2_file) -{ - /* set up file handle */ - l2_file->type = L2F_TIFILES; - l2_file->tifiles.file_handle = file_handle; - - /* seek to header */ - if (stream_seek(l2_file->tifiles.file_handle, 0, SEEK_SET)) - return IMGTOOLERR_READERROR; - /* read it */ - if (stream_read(l2_file->tifiles.file_handle, &l2_file->tifiles.hdr, sizeof(l2_file->tifiles.hdr)) != sizeof(l2_file->tifiles.hdr)) - return IMGTOOLERR_READERROR; - - return 0; -} - -/* - compute the aphysrec address for a given file physical record (fphysrec) - - l2_img: image where the file is located -*/ -static int dsk_fphysrec_to_aphysrec(ti99_lvl2_fileref_dsk *dsk_file, unsigned fphysrec, unsigned *aphysrec) -{ - int cluster_index; - int cluster_firstfphysrec, cluster_lastfphysrec; - int cluster_baseaphysrec; - - - /* check parameter */ - if (fphysrec >= get_UINT16BE(dsk_file->fdr.fphysrecs)) - return IMGTOOLERR_UNEXPECTED; - - - /* search for the cluster in the data chain pointers array */ - cluster_firstfphysrec = 0; - for (cluster_index=0; cluster_index<76; cluster_index++) - { - /* read curent file block table entry */ - cluster_lastfphysrec = get_dsk_fdr_cluster_lastfphysrec(&dsk_file->fdr, cluster_index); - if (cluster_lastfphysrec >= fphysrec) - break; - cluster_firstfphysrec = cluster_lastfphysrec+1; - } - if (cluster_index == 76) - /* if not found, the file is corrupt */ - return IMGTOOLERR_CORRUPTIMAGE; - - /* read base aphysrec address for this cluster */ - cluster_baseaphysrec = get_dsk_fdr_cluster_baseaphysrec(dsk_file->l2_img, &dsk_file->fdr, cluster_index); - /* return absolute physrec address */ - *aphysrec = cluster_baseaphysrec + (fphysrec - cluster_firstfphysrec); - return 0; -} - -/* - compute the aphysrec address for a given file physical record (fphysrec) - - l2_img: image where the file is located -*/ -static int win_fphysrec_to_aphysrec(ti99_lvl2_fileref_win *win_file, unsigned fphysrec, unsigned *aphysrec) -{ - int cluster_index; - int cluster_firstfphysrec, cluster_lastfphysrec; - int cluster_baseaphysrec; - int errorcode; - - - /* check parameter */ - if (fphysrec >= win_file->fphysrecs) - return IMGTOOLERR_UNEXPECTED; - - /* look for correct sibling */ - if (fphysrec < get_win_fdr_cursibFDR_basefphysrec(& win_file->curfdr)) - { - while (fphysrec < get_win_fdr_cursibFDR_basefphysrec(& win_file->curfdr)) - { - if (get_UINT16BE(win_file->curfdr.prevsibFDR_AU) == 0) - return IMGTOOLERR_CORRUPTIMAGE; - errorcode = win_goto_prev_sibFDR(win_file); - if (errorcode) - return errorcode; - } - } - else /*if (fphysrec >= get_win_fdr_cursibFDR_basefphysrec(& dsk_file->curfdr))*/ - { - while (fphysrec >= (get_win_fdr_cursibFDR_basefphysrec(& win_file->curfdr) - + get_UINT16BE(win_file->curfdr.sibFDR_AUlen) * win_file->l2_img->AUformat.physrecsperAU)) - { - if (get_UINT16BE(win_file->curfdr.nextsibFDR_AU) == 0) - return IMGTOOLERR_CORRUPTIMAGE; - errorcode = win_goto_next_sibFDR(win_file); - if (errorcode) - return errorcode; - } - } - - - /* search for the cluster in the data chain pointers array */ - cluster_firstfphysrec = get_win_fdr_cursibFDR_basefphysrec(& win_file->curfdr); - for (cluster_index = 0; cluster_index<54; cluster_index++) - { - cluster_lastfphysrec = cluster_firstfphysrec - + (get_UINT16BE(win_file->curfdr.clusters[cluster_index][1]) - - get_UINT16BE(win_file->curfdr.clusters[cluster_index][0]) - + 1) - * win_file->l2_img->AUformat.physrecsperAU; - if (fphysrec < cluster_lastfphysrec) - break; - - cluster_firstfphysrec = cluster_lastfphysrec; - } - - if (cluster_index == 54) - return IMGTOOLERR_CORRUPTIMAGE; - - - /* read base aphysrec address for this cluster */ - cluster_baseaphysrec = get_UINT16BE(win_file->curfdr.clusters[cluster_index][0]) * win_file->l2_img->AUformat.physrecsperAU; - /* return absolute physrec address */ - *aphysrec = cluster_baseaphysrec + (fphysrec - cluster_firstfphysrec); - return 0; -} - -/* - read a 256-byte physical record from a file -*/ -static int read_file_physrec(struct ti99_lvl2_fileref *l2_file, unsigned fphysrec, void *dest) -{ - int errorcode; - unsigned aphysrec; - - switch (l2_file->type) - { - case L2F_DSK: - /* compute absolute physrec address */ - errorcode = dsk_fphysrec_to_aphysrec(&l2_file->dsk, fphysrec, &aphysrec); - if (errorcode) - return errorcode; - /* read physrec */ - if (read_absolute_physrec(& l2_file->dsk.l2_img->l1_img, aphysrec, dest)) - return IMGTOOLERR_READERROR; - break; - - case L2F_WIN: - /* compute absolute physrec address */ - errorcode = win_fphysrec_to_aphysrec(&l2_file->win, fphysrec, &aphysrec); - if (errorcode) - return errorcode; - /* read physrec */ - if (read_absolute_physrec(& l2_file->win.l2_img->l1_img, aphysrec, dest)) - return IMGTOOLERR_READERROR; - break; - - case L2F_TIFILES: - /* seek to physrec */ - if (stream_seek(l2_file->tifiles.file_handle, 128+256*fphysrec, SEEK_SET)) - return IMGTOOLERR_READERROR; - /* read it */ - if (stream_read(l2_file->tifiles.file_handle, dest, 256) != 256) - return IMGTOOLERR_READERROR; - break; - } - - return 0; -} - -/* - read a 256-byte physical record from a file -*/ -static int write_file_physrec(struct ti99_lvl2_fileref *l2_file, unsigned fphysrec, const void *src) -{ - int errorcode; - unsigned aphysrec; - - switch (l2_file->type) - { - case L2F_DSK: - /* compute absolute physrec address */ - errorcode = dsk_fphysrec_to_aphysrec(&l2_file->dsk, fphysrec, &aphysrec); - if (errorcode) - return errorcode; - /* write physrec */ - if (write_absolute_physrec(& l2_file->dsk.l2_img->l1_img, aphysrec, src)) - return IMGTOOLERR_WRITEERROR; - break; - - case L2F_WIN: - /* compute absolute physrec address */ - errorcode = win_fphysrec_to_aphysrec(&l2_file->win, fphysrec, &aphysrec); - if (errorcode) - return errorcode; - /* write physrec */ - if (write_absolute_physrec(& l2_file->win.l2_img->l1_img, aphysrec, src)) - return IMGTOOLERR_WRITEERROR; - break; - - case L2F_TIFILES: - /* seek to physrec */ - if (stream_seek(l2_file->tifiles.file_handle, 128+256*fphysrec, SEEK_SET)) - return IMGTOOLERR_WRITEERROR; - /* write it */ - if (stream_write(l2_file->tifiles.file_handle, src, 256) != 256) - return IMGTOOLERR_WRITEERROR; - break; - } - - return 0; -} - -/* - Write a field in every fdr record associated to a file -*/ -#ifdef UNUSED_FUNCTION -static int set_win_fdr_field(struct ti99_lvl2_fileref *l2_file, size_t offset, size_t size, void *data) -{ - win_fdr fdr_buf; - unsigned fdr_aphysrec; - int errorcode = 0; - - for (fdr_aphysrec = l2_file->win.eldestfdr_aphysrec; - fdr_aphysrec && ((errorcode = (read_absolute_physrec(&l2_file->win.l2_img->l1_img, fdr_aphysrec, &fdr_buf) ? IMGTOOLERR_READERROR : 0)) == 0); - fdr_aphysrec = get_win_fdr_nextsibFDR_physrec(l2_file->win.l2_img, &fdr_buf)) - { - memcpy(((UINT8 *) &fdr_buf) + offset, data, size); - if (write_absolute_physrec(&l2_file->win.l2_img->l1_img, fdr_aphysrec, &fdr_buf)) - { - errorcode = IMGTOOLERR_WRITEERROR; - break; - } - } - - return errorcode; -} -#endif - -static UINT8 get_file_flags(struct ti99_lvl2_fileref *l2_file) -{ - int reply = 0; - - switch (l2_file->type) - { - case L2F_DSK: - reply = l2_file->dsk.fdr.flags; - break; - - case L2F_WIN: - reply = l2_file->win.curfdr.flags; - break; - - case L2F_TIFILES: - reply = l2_file->tifiles.hdr.flags; - break; - } - - return reply; -} - -static void set_file_flags(struct ti99_lvl2_fileref *l2_file, UINT8 data) -{ - switch (l2_file->type) - { - case L2F_DSK: - l2_file->dsk.fdr.flags = data; - break; - - case L2F_WIN: - l2_file->win.curfdr.flags = data; - break; - - case L2F_TIFILES: - l2_file->tifiles.hdr.flags = data; - break; - } -} - -static UINT8 get_file_recsperphysrec(struct ti99_lvl2_fileref *l2_file) -{ - int reply = 0; - - switch (l2_file->type) - { - case L2F_DSK: - reply = l2_file->dsk.fdr.recsperphysrec; - break; - - case L2F_WIN: - reply = l2_file->win.curfdr.recsperphysrec; - break; - - case L2F_TIFILES: - reply = l2_file->tifiles.hdr.recsperphysrec; - break; - } - - return reply; -} - -static void set_file_recsperphysrec(struct ti99_lvl2_fileref *l2_file, UINT8 data) -{ - switch (l2_file->type) - { - case L2F_DSK: - l2_file->dsk.fdr.recsperphysrec = data; - break; - - case L2F_WIN: - l2_file->win.curfdr.recsperphysrec = data; - break; - - case L2F_TIFILES: - l2_file->tifiles.hdr.recsperphysrec = data; - break; - } -} - -static unsigned get_file_fphysrecs(struct ti99_lvl2_fileref *l2_file) -{ - int reply = 0; - - switch (l2_file->type) - { - case L2F_DSK: - reply = get_UINT16BE(l2_file->dsk.fdr.fphysrecs); - break; - - case L2F_WIN: - reply = l2_file->win.fphysrecs; - break; - - case L2F_TIFILES: - reply = get_UINT16BE(l2_file->tifiles.hdr.fphysrecs); - break; - } - - return reply; -} - -static int set_file_fphysrecs(struct ti99_lvl2_fileref *l2_file, unsigned data) -{ - switch (l2_file->type) - { - case L2F_DSK: - if (data >= 65536) - return IMGTOOLERR_UNIMPLEMENTED; - set_UINT16BE(&l2_file->dsk.fdr.fphysrecs, data); - break; - - case L2F_WIN: - l2_file->win.fphysrecs = data; - break; - - case L2F_TIFILES: - if (data >= 65536) - return IMGTOOLERR_UNIMPLEMENTED; - set_UINT16BE(&l2_file->tifiles.hdr.fphysrecs, data); - break; - } - - return 0; -} - -static UINT8 get_file_eof(struct ti99_lvl2_fileref *l2_file) -{ - int reply = 0; - - switch (l2_file->type) - { - case L2F_DSK: - reply = l2_file->dsk.fdr.eof; - break; - - case L2F_WIN: - reply = l2_file->win.curfdr.eof; - break; - - case L2F_TIFILES: - reply = l2_file->tifiles.hdr.eof; - break; - } - - return reply; -} - -static void set_file_eof(struct ti99_lvl2_fileref *l2_file, UINT8 data) -{ - switch (l2_file->type) - { - case L2F_DSK: - l2_file->dsk.fdr.eof = data; - break; - - case L2F_WIN: - l2_file->win.curfdr.eof = data; - break; - - case L2F_TIFILES: - l2_file->tifiles.hdr.eof = data; - break; - } -} - -static UINT16 get_file_reclen(struct ti99_lvl2_fileref *l2_file) -{ - int reply = 0; - - switch (l2_file->type) - { - case L2F_DSK: - reply = l2_file->dsk.fdr.reclen; - if ((reply == 0) && (! (l2_file->dsk.fdr.flags & (fdr99_f_program /*| fdr99_f_var*/)))) - reply = get_UINT16BE(l2_file->dsk.fdr.xreclen); - break; - - case L2F_WIN: - reply = l2_file->win.curfdr.reclen; - if ((reply == 0) && (! (l2_file->win.curfdr.flags & (fdr99_f_program /*| fdr99_f_var*/)))) - reply = get_UINT16BE(l2_file->win.curfdr.xreclen); - break; - - case L2F_TIFILES: - reply = l2_file->tifiles.hdr.reclen; - break; - } - - return reply; -} - -static int set_file_reclen(struct ti99_lvl2_fileref *l2_file, UINT16 data) -{ - switch (l2_file->type) - { - case L2F_DSK: - if (data < 256) - { - l2_file->dsk.fdr.reclen = data; - set_UINT16BE(&l2_file->dsk.fdr.xreclen, 0); - } - else - { - l2_file->dsk.fdr.reclen = 0; - set_UINT16BE(&l2_file->dsk.fdr.xreclen, data); - } - break; - - case L2F_WIN: - if (data < 256) - { - l2_file->win.curfdr.reclen = data; - set_UINT16BE(&l2_file->win.curfdr.xreclen, 0); - } - else - { - l2_file->win.curfdr.reclen = 0; - set_UINT16BE(&l2_file->win.curfdr.xreclen, data); - } - break; - - case L2F_TIFILES: - if (data >= 256) - return IMGTOOLERR_UNIMPLEMENTED; - l2_file->tifiles.hdr.reclen = data; - break; - } - - return 0; -} - -static unsigned get_file_fixrecs(struct ti99_lvl2_fileref *l2_file) -{ - int reply = 0; - - switch (l2_file->type) - { - case L2F_DSK: - reply = get_UINT16LE(l2_file->dsk.fdr.fixrecs); - break; - - case L2F_WIN: - reply = get_win_fdr_fixrecs(&l2_file->win.curfdr); - break; - - case L2F_TIFILES: - reply = get_UINT16BE(l2_file->tifiles.hdr.fixrecs); - break; - } - - return reply; -} - -static int set_file_fixrecs(struct ti99_lvl2_fileref *l2_file, unsigned data) -{ - switch (l2_file->type) - { - case L2F_DSK: - if (data >= 65536) - return IMGTOOLERR_UNIMPLEMENTED; - set_UINT16LE(&l2_file->dsk.fdr.fixrecs, data); - break; - - case L2F_WIN: - set_win_fdr_fixrecs(&l2_file->win.curfdr, data); - break; - - case L2F_TIFILES: - if (data >= 65536) - return IMGTOOLERR_UNIMPLEMENTED; - set_UINT16BE(&l2_file->tifiles.hdr.fixrecs, data); - break; - } - - return 0; -} - -static void get_file_creation_date(struct ti99_lvl2_fileref *l2_file, ti99_date_time *reply) -{ - switch (l2_file->type) - { - case L2F_DSK: - *reply = l2_file->dsk.fdr.creation; - break; - - case L2F_WIN: - *reply = l2_file->win.curfdr.creation; - break; - - case L2F_TIFILES: - memset(reply, 0, sizeof(*reply)); - break; - } -} - -static void set_file_creation_date(struct ti99_lvl2_fileref *l2_file, ti99_date_time data) -{ - switch (l2_file->type) - { - case L2F_DSK: - l2_file->dsk.fdr.creation = data; - break; - - case L2F_WIN: - l2_file->win.curfdr.creation = data; - break; - - case L2F_TIFILES: - break; - } -} - -static void get_file_update_date(struct ti99_lvl2_fileref *l2_file, ti99_date_time *reply) -{ - switch (l2_file->type) - { - case L2F_DSK: - *reply = l2_file->dsk.fdr.update; - break; - - case L2F_WIN: - *reply = l2_file->win.curfdr.update; - break; - - case L2F_TIFILES: - memset(reply, 0, sizeof(*reply)); - break; - } -} - -static void set_file_update_date(struct ti99_lvl2_fileref *l2_file, ti99_date_time data) -{ - switch (l2_file->type) - { - case L2F_DSK: - l2_file->dsk.fdr.update = data; - break; - - case L2F_WIN: - l2_file->win.curfdr.update = data; - break; - - case L2F_TIFILES: - break; - } -} - -#ifdef UNUSED_FUNCTION -static void current_date_time(ti99_date_time *reply) -{ - /* All these functions should be ANSI */ - time_t cur_time = time(NULL); - struct tm expanded_time = *localtime(& cur_time); - - reply->time_MSB = (expanded_time.tm_hour << 3) | (expanded_time.tm_min >> 3); - reply->time_LSB = (expanded_time.tm_min << 5) | (expanded_time.tm_sec >> 1); - reply->date_MSB = ((expanded_time.tm_year % 100) << 1) | ((expanded_time.tm_mon+1) >> 3); - reply->date_LSB = ((expanded_time.tm_mon+1) << 5) | expanded_time.tm_mday; -} -#endif - -#if 0 -#pragma mark - -#pragma mark LEVEL 3 DISK ROUTINES -#endif - -/* - Level 3 implements files as a succession of logical records. - - There are three types of files: - * program files that are not implemented at level 3 (no logical record) - * files with fixed-size records (random-access files) - * files with variable-size records (sequential-access) -*/ - -struct ti99_lvl3_fileref -{ - ti99_lvl2_fileref l2_file; - - int cur_log_rec; - int cur_phys_rec; - int cur_pos_in_phys_rec; -}; - -#ifdef UNUSED_FUNCTION -/* - Open a file on level 3. - - To open a file on level 3, you must open (or create) the file on level 2, - then pass the file reference to open_file_lvl3. -*/ -static int open_file_lvl3(ti99_lvl3_fileref *l3_file) -{ - l3_file->cur_log_rec = 0; - l3_file->cur_phys_rec = 0; - l3_file->cur_pos_in_phys_rec = 0; - - /*if ()*/ - - return 0; -} - -/* - Test a file for EOF -*/ -static int is_eof(ti99_lvl3_fileref *l3_file) -{ - int flags = get_file_flags(&l3_file->l2_file); - int fphysrecs = get_file_fphysrecs(&l3_file->l2_file); - int fdr_eof = get_file_eof(&l3_file->l2_file); - - if (flags & fdr99_f_var) - { - return (l3_file->cur_phys_rec >= fphysrecs); - } - else - { - return ((l3_file->cur_phys_rec >= fphysrecs) - || ((l3_file->cur_phys_rec == (fphysrecs-1)) - && (l3_file->cur_pos_in_phys_rec >= (fdr_eof ? fdr_eof : 256)))); - } -} - -/* - Read next record from a file -*/ -static int read_next_record(ti99_lvl3_fileref *l3_file, void *dest, int *out_reclen) -{ - int errorcode; - UINT8 physrec_buf[256]; - int reclen; - int flags = get_file_flags(&l3_file->l2_file); - int fphysrecs = get_file_fphysrecs(&l3_file->l2_file); - int fdr_eof = get_file_eof(&l3_file->l2_file); - - if (flags & fdr99_f_program) - { - /* program files have no level-3 record */ - return IMGTOOLERR_UNEXPECTED; - } - else if (flags & fdr99_f_var) - { - /* variable-length records */ - if (is_eof(l3_file)) - return IMGTOOLERR_UNEXPECTED; - errorcode = read_file_physrec(&l3_file->l2_file, l3_file->cur_phys_rec, physrec_buf); - if (errorcode) - return errorcode; - /* read reclen */ - reclen = physrec_buf[l3_file->cur_pos_in_phys_rec]; - /* check integrity */ - if ((reclen == 0xff) || (reclen > get_file_reclen(&l3_file->l2_file)) - || ((l3_file->cur_pos_in_phys_rec + 1 + reclen) > 256)) - return IMGTOOLERR_CORRUPTIMAGE; - /* copy to buffer */ - memcpy(dest, physrec_buf + l3_file->cur_pos_in_phys_rec + 1, reclen); - l3_file->cur_pos_in_phys_rec += reclen + 1; - /* skip to next physrec if needed */ - if ((l3_file->cur_pos_in_phys_rec == 256) - || (physrec_buf[l3_file->cur_pos_in_phys_rec] == 0xff)) - { - l3_file->cur_pos_in_phys_rec = 0; - l3_file->cur_phys_rec++; - } - (* out_reclen) = reclen; - } - else - { - /* fixed len records */ - reclen = get_file_reclen(&l3_file->l2_file); - if (is_eof(l3_file)) - return IMGTOOLERR_UNEXPECTED; - if ((l3_file->cur_pos_in_phys_rec + reclen) > 256) - { - l3_file->cur_pos_in_phys_rec = 0; - l3_file->cur_phys_rec++; - } - if ((l3_file->cur_phys_rec >= fphysrecs) - || ((l3_file->cur_phys_rec == (fphysrecs-1)) - && ((l3_file->cur_pos_in_phys_rec + reclen) >= (fdr_eof ? fdr_eof : 256)))) - return IMGTOOLERR_CORRUPTIMAGE; - errorcode = read_file_physrec(&l3_file->l2_file, l3_file->cur_phys_rec, physrec_buf); - if (errorcode) - return errorcode; - memcpy(dest, physrec_buf + l3_file->cur_pos_in_phys_rec, reclen); - l3_file->cur_pos_in_phys_rec += reclen; - if (l3_file->cur_pos_in_phys_rec == 256) - { - l3_file->cur_pos_in_phys_rec = 0; - l3_file->cur_phys_rec++; - } - (* out_reclen) = reclen; - } - - return 0; -} -#endif - -#if 0 -#pragma mark - -#pragma mark IMGTOOL MODULE IMPLEMENTATION -#endif - -/* - ti99 catalog iterator, used when imgtool reads the catalog -*/ -struct dsk_iterator -{ - struct ti99_lvl2_imgref *image; - int level; - int listing_subdirs; /* true if we are listing subdirectories at current level */ - int index[2]; /* current index in the disk catalog */ - ti99_catalog *cur_catalog; /* current catalog */ -}; - -struct win_iterator -{ - struct ti99_lvl2_imgref *image; - int level; - int listing_subdirs; /* true if we are listing subdirectories at current level */ - int index[MAX_DIR_LEVEL]; /* current index in the disk catalog */ - ti99_catalog catalog[MAX_DIR_LEVEL]; /* current catalog */ -}; - - -static imgtoolerr_t dsk_image_init_mess(imgtool_image *image, imgtool_stream *f); -static imgtoolerr_t dsk_image_init_v9t9(imgtool_image *image, imgtool_stream *f); -static imgtoolerr_t dsk_image_init_pc99_fm(imgtool_image *image, imgtool_stream *f); -static imgtoolerr_t dsk_image_init_pc99_mfm(imgtool_image *image, imgtool_stream *f); -static imgtoolerr_t win_image_init(imgtool_image *image, imgtool_stream *f); -static void ti99_image_exit(imgtool_image *img); -static void ti99_image_info(imgtool_image *img, char *string, size_t len); -static imgtoolerr_t dsk_image_beginenum(imgtool_directory *enumeration, const char *path); -static imgtoolerr_t dsk_image_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent); -static imgtoolerr_t win_image_beginenum(imgtool_directory *enumeration, const char *path); -static imgtoolerr_t win_image_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent); -static imgtoolerr_t ti99_image_freespace(imgtool_partition *partition, UINT64 *size); -static imgtoolerr_t ti99_image_readfile(imgtool_partition *partition, const char *fpath, const char *fork, imgtool_stream *destf); -static imgtoolerr_t ti99_image_writefile(imgtool_partition *partition, const char *fpath, const char *fork, imgtool_stream *sourcef, option_resolution *writeoptions); -static imgtoolerr_t dsk_image_deletefile(imgtool_partition *partition, const char *fpath); -static imgtoolerr_t win_image_deletefile(imgtool_partition *partition, const char *fpath); -static imgtoolerr_t dsk_image_create_mess(imgtool_image *image, imgtool_stream *f, option_resolution *createoptions); -static imgtoolerr_t dsk_image_create_v9t9(imgtool_image *image, imgtool_stream *f, option_resolution *createoptions); - -enum -{ - dsk_createopts_volname = 'A', - dsk_createopts_sides = 'B', - dsk_createopts_tracks = 'C', - dsk_createopts_sectors = 'D', - dsk_createopts_protection = 'E', - dsk_createopts_density = 'F' -}; - -static OPTION_GUIDE_START( dsk_create_optionguide ) - OPTION_STRING(dsk_createopts_volname, "label", "Volume name" ) - OPTION_INT(dsk_createopts_sides, "sides", "Sides" ) - OPTION_INT(dsk_createopts_tracks, "tracks", "Tracks" ) - OPTION_INT(dsk_createopts_sectors, "sectors", "Sectors (1->9 for SD, 1->18 for DD, 1->36 for HD)" ) - OPTION_INT(dsk_createopts_protection, "protection", "Protection (0 for normal, 1 for protected)" ) - OPTION_ENUM_START(dsk_createopts_density, "density", "Density" ) - OPTION_ENUM( 0, "Auto", "Auto" ) - OPTION_ENUM( 1, "SD", "Single Density" ) - OPTION_ENUM( 2, "DD", "Double Density" ) - OPTION_ENUM( 3, "HD", "High Density" ) - OPTION_ENUM_END -OPTION_GUIDE_END - -#define dsk_create_optionspecs "B1-[2];C1-[40]-80;D1-[18]-36;E[0]-1;F[0]-3" - -static void ti99_getinfo(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info) -{ - switch(state) - { - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: info->i = sizeof(ti99_lvl2_imgref); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(dsk_iterator); break; - - case IMGTOOLINFO_STR_EOLN: strcpy(info->s = imgtool_temp_str(), "\r"); break; - case IMGTOOLINFO_PTR_CLOSE: info->close = ti99_image_exit; break; - case IMGTOOLINFO_PTR_INFO: info->info = ti99_image_info; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = ti99_image_freespace; break; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = ti99_image_readfile; break; - case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = ti99_image_writefile; break; - } -} - -static void ti99_dsk_getinfo(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info) -{ - switch(state) - { - case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "dsk"); break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = dsk_image_beginenum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = dsk_image_nextenum; break; - case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = dsk_image_deletefile; break; - default: ti99_getinfo(imgclass, state, info); - } -} - -void ti99_old_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info) -{ - switch(state) - { - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "ti99_old"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "TI99 Diskette (old MESS format)"); break; - case IMGTOOLINFO_PTR_OPEN: info->open = dsk_image_init_mess; break; - case IMGTOOLINFO_PTR_CREATE: info->create = dsk_image_create_mess; break; - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = dsk_create_optionguide; break; - case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), dsk_create_optionspecs); break; - default: ti99_dsk_getinfo(imgclass, state, info); break; - } -} - -void ti99_v9t9_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info) -{ - switch(state) - { - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "v9t9"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "TI99 Diskette (V9T9 format)"); break; - case IMGTOOLINFO_PTR_OPEN: info->open = dsk_image_init_v9t9; break; - case IMGTOOLINFO_PTR_CREATE: info->create = dsk_image_create_v9t9; break; - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = dsk_create_optionguide; break; - case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), dsk_create_optionspecs); break; - default: ti99_dsk_getinfo(imgclass, state, info); break; - } -} - -void ti99_pc99fm_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info) -{ - switch(state) - { - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "pc99fm"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "TI99 Diskette (PC99 FM format)"); break; - case IMGTOOLINFO_PTR_OPEN: info->open = dsk_image_init_pc99_fm; break; - case IMGTOOLINFO_PTR_CREATE: /* info->create = dsk_image_create_pc99fm; */ break; - default: ti99_dsk_getinfo(imgclass, state, info); break; - } -} - -void ti99_pc99mfm_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info) -{ - switch(state) - { - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "pc99mfm"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "TI99 Diskette (PC99 MFM format)"); break; - case IMGTOOLINFO_PTR_OPEN: info->open = dsk_image_init_pc99_mfm; break; - case IMGTOOLINFO_PTR_CREATE: /* info->create = dsk_image_create_pc99mfm; */ break; - default: ti99_dsk_getinfo(imgclass, state, info); break; - } -} - -void ti99_ti99hd_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info) -{ - switch(state) - { - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "ti99hd"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "TI99 Harddisk"); break; - case IMGTOOLINFO_PTR_OPEN: info->open = win_image_init; break; - case IMGTOOLINFO_PTR_CREATE: /* info->create = hd_image_create; */ break; - - case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "hd"); break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = win_image_beginenum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = win_image_nextenum; break; - case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = win_image_deletefile; break; - default: ti99_getinfo(imgclass, state, info); - } -} - - - -/* - Open a file as a ti99_image (common code). -*/ -static int dsk_image_init(imgtool_image *img, imgtool_stream *f, ti99_img_format img_format) -{ - struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(img); - dsk_vib vib; - int reply; - int totphysrecs; - unsigned fdir_aphysrec; - int i; - - /* open disk image at level 1 */ - reply = open_image_lvl1(f, img_format, &image->l1_img, &vib); - if (reply) - return reply; - - /* open disk image at level 2 */ - image->type = L2I_DSK; - - /* @BN@ */ - /* Copy in the allocation bit map! */ - memcpy(image->abm, vib.abm, 200); - /* first compute AU size and number of AUs */ - totphysrecs = get_UINT16BE(vib.totphysrecs); - - image->AUformat.physrecsperAU = (totphysrecs + 1599) / 1600; - /* round to next larger power of 2 */ - for (i = 1; i < image->AUformat.physrecsperAU; i <<= 1) - ; - image->AUformat.physrecsperAU = i; - image->AUformat.totAUs = totphysrecs / image->AUformat.physrecsperAU; - - /* extract number of physrecs */ - image->dsk.totphysrecs = get_UINT16BE(vib.totphysrecs); - - /* read and check main volume catalog */ - reply = dsk_read_catalog(image, 1, &image->dsk.catalogs[0]); - if (reply) - return reply; - - image->dsk.fdir_aphysrec[0] = 1; - - /* read and check subdirectory catalogs */ - /* Note that the reserved areas used for HFDC subdirs may be used for other - purposes by other FDRs, so, if we get any error, we will assume there is no - subdir after all... */ - image->dsk.catalogs[0].num_subdirs = 0; - for (i=0; i<3; i++) - { - fdir_aphysrec = get_UINT16BE(vib.subdir[i].fdir_aphysrec); - if ((! memcmp(vib.subdir[i].name, "\0\0\0\0\0\0\0\0\0\0", 10)) - || (! memcmp(vib.subdir[i].name, " ", 10))) - { - /* name is empty: fine with us unless there is a fdir pointer */ - if (fdir_aphysrec != 0) - { - image->dsk.catalogs[0].num_subdirs = 0; - break; - } - } - else if (check_fname(vib.subdir[i].name)) - { - /* name is invalid: this is not an HFDC format floppy */ - image->dsk.catalogs[0].num_subdirs = 0; - break; - } - else - { - /* there is a non-empty name */ - if ((fdir_aphysrec == 0) || (fdir_aphysrec >= totphysrecs)) - { - /* error: fdir pointer is invalid or NULL */ - image->dsk.catalogs[0].num_subdirs = 0; - break; - } - /* fill in descriptor fields */ - image->dsk.fdir_aphysrec[image->dsk.catalogs[0].num_subdirs+1] = fdir_aphysrec; - /*image->dsk.catalogs[0].subdirs[image->dsk.catalogs[0].num_subdirs].dir_ptr = fdir_aphysrec;*/ - memcpy(image->dsk.catalogs[0].subdirs[image->dsk.catalogs[0].num_subdirs].name, vib.subdir[i].name, 10); - reply = dsk_read_catalog(image, fdir_aphysrec, &image->dsk.catalogs[image->dsk.catalogs[0].num_subdirs+1]); - if (reply) - { - /* error: invalid fdir */ - image->dsk.catalogs[0].num_subdirs = 0; - break; - } - /* found valid subdirectory: increment subdir count */ - image->dsk.catalogs[0].num_subdirs++; - } - } - - /* extract volume name */ - memcpy(image->vol_name, vib.name, 10); - - /* initialize default data_offset */ - image->data_offset = 32+2; - - return 0; -} - -/* - Open a file as a ti99_image (MESS format). -*/ -static imgtoolerr_t dsk_image_init_mess(imgtool_image *image, imgtool_stream *f) -{ - return (imgtoolerr_t)dsk_image_init(image, f, if_mess); -} - -/* - Open a file as a ti99_image (V9T9 format). -*/ -static imgtoolerr_t dsk_image_init_v9t9(imgtool_image *image, imgtool_stream *f) -{ - return (imgtoolerr_t)dsk_image_init(image, f, if_v9t9); -} - -/* - Open a file as a ti99_image (PC99 FM format). -*/ -static imgtoolerr_t dsk_image_init_pc99_fm(imgtool_image *image, imgtool_stream *f) -{ - return (imgtoolerr_t)dsk_image_init(image, f, if_pc99_fm); -} - -/* - Open a file as a ti99_image (PC99 MFM format). -*/ -static imgtoolerr_t dsk_image_init_pc99_mfm(imgtool_image *image, imgtool_stream *f) -{ - return (imgtoolerr_t)dsk_image_init(image, f, if_pc99_mfm); -} - -/* - Open a file as a ti99_image (harddisk format). -*/ -static imgtoolerr_t win_image_init(imgtool_image *img, imgtool_stream *f) -{ - struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(img); - win_vib_ddr vib; - int reply; - int i; - - /* open disk image at level 1 */ - reply = open_image_lvl1(f, if_harddisk, & image->l1_img, NULL); - if (reply) - return (imgtoolerr_t)reply; - - /* open disk image at level 2 */ - image->type = L2I_WIN; - - /* read VIB */ - reply = read_absolute_physrec(&image->l1_img, 0, &vib); - if (reply) - return (imgtoolerr_t)reply; - - /* guess VIB version */ - image->win.vib_version = memcmp(vib.u.vib_v1.id, "WIN", 3) ? win_vib_v2 : win_vib_v1; - - /* extract AU size and number of AUs */ - image->AUformat.physrecsperAU = ((get_UINT16BE(vib.params) >> 12) & 0xf) + 1; - image->AUformat.totAUs = get_UINT16BE(vib.totAUs); - - /* extract volume name */ - memcpy(image->vol_name, vib.name, 10); - - /* extract data_offset */ - switch (image->win.vib_version) - { - case win_vib_v1: - image->data_offset = 64; - break; - - case win_vib_v2: - image->data_offset = vib.u.vib_v2.res_AUs * 64; - break; - } - - /* read allocation bitmap (aphysrecs 1 through n, n<=33) */ - for (i=0; i < (image->AUformat.totAUs+2047)/2048; i++) - { - reply = read_absolute_physrec(&image->l1_img, i+1, image->abm+i*256); - if (reply) - return (imgtoolerr_t)reply; - } - - return (imgtoolerr_t)0; -} - -/* - close a ti99_image -*/ -static void ti99_image_exit(imgtool_image *img) -{ - struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(img); - - close_image_lvl1(&image->l1_img); -} - -/* - get basic information on a ti99_image - - Currently returns the volume name -*/ -static void ti99_image_info(imgtool_image *img, char *string, size_t len) -{ - struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(img); - char vol_name[11]; - - fname_to_str(vol_name, image->vol_name, 11); - - snprintf(string, len, "%s", vol_name); -} - -/* - Open the disk catalog for enumeration -*/ -static imgtoolerr_t dsk_image_beginenum(imgtool_directory *enumeration, const char *path) -{ - struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(imgtool_directory_image(enumeration)); - dsk_iterator *iter = (dsk_iterator *) imgtool_directory_extrabytes(enumeration); - - iter->image = image; - iter->level = 0; - iter->listing_subdirs = 1; - iter->index[0] = 0; - iter->cur_catalog = &iter->image->dsk.catalogs[0]; - - return (imgtoolerr_t)0; -} - -/* - Enumerate disk catalog next entry -*/ -static imgtoolerr_t dsk_image_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent) -{ - dsk_iterator *iter = (dsk_iterator*) imgtool_directory_extrabytes(enumeration); - dsk_fdr fdr; - int reply; - unsigned fdr_aphysrec; - - - ent->corrupt = 0; - ent->eof = 0; - - /* iterate through catalogs to next file or dir entry */ - while ((iter->level >= 0) - && (iter->index[iter->level] >= (iter->listing_subdirs - ? iter->cur_catalog->num_subdirs - : iter->cur_catalog->num_files))) - { - if (iter->listing_subdirs) - { - iter->listing_subdirs = 0; - iter->index[iter->level] = 0; - } - else - { - iter->listing_subdirs = 1; - if (! iter->level) - iter->level = -1; - else - { - iter->level = 0; - iter->index[0]++; - iter->cur_catalog = &iter->image->dsk.catalogs[0]; - } - } - } - - if (iter->level < 0) - { - ent->eof = 1; - } - else - { - if (iter->listing_subdirs) - { - fname_to_str(ent->filename, iter->image->dsk.catalogs[0].subdirs[iter->index[iter->level]].name, ARRAY_LENGTH(ent->filename)); - - /* set type of DIR */ - snprintf(ent->attr, ARRAY_LENGTH(ent->attr), "DIR"); - - /* len in physrecs */ - /* @BN@ return length in bytes */ - /* ent->filesize = 1; */ - ent->filesize = 256; - - /* recurse subdirectory */ - iter->listing_subdirs = 0; /* no need to list subdirs as only the - root dir has subdirs in DSK format */ - iter->level = 1; - iter->cur_catalog = &iter->image->dsk.catalogs[iter->index[0]+1]; - iter->index[iter->level] = 0; - } - else - { - fdr_aphysrec = iter->cur_catalog->files[iter->index[iter->level]].fdr_ptr; - reply = read_absolute_physrec(& iter->image->l1_img, fdr_aphysrec, & fdr); - if (reply) - return IMGTOOLERR_READERROR; -#if 0 - fname_to_str(ent->filename, fdr.name, ARRAY_LENGTH(ent->filename)); -#else - { - char buf[11]; - - ent->filename[0] = '\0'; - if (iter->level) - { - fname_to_str(ent->filename, iter->image->dsk.catalogs[0].subdirs[iter->index[0]].name, ARRAY_LENGTH(ent->filename)); - strncat(ent->filename, ".", ARRAY_LENGTH(ent->filename) - 1); - } - fname_to_str(buf, fdr.name, 11); - strncat(ent->filename, buf, ARRAY_LENGTH(ent->filename) - 1); - } -#endif - /* parse flags */ - if (fdr.flags & fdr99_f_program) - snprintf(ent->attr, ARRAY_LENGTH(ent->attr), "PGM%s", - (fdr.flags & fdr99_f_wp) ? " R/O" : ""); - else - snprintf(ent->attr, ARRAY_LENGTH(ent->attr), "%c/%c %d%s", - (fdr.flags & fdr99_f_int) ? 'I' : 'D', - (fdr.flags & fdr99_f_var) ? 'V' : 'F', - fdr.reclen, - (fdr.flags & fdr99_f_wp) ? " R/O" : ""); - /* len in physrecs */ - /* @BN@ return length in bytes */ - /* ent->filesize = get_UINT16BE(fdr.fphysrecs); */ - ent->filesize = (get_UINT16BE(fdr.fphysrecs)+1)*256; - - iter->index[iter->level]++; - } - } - - return (imgtoolerr_t)0; -} - -/* - Open the disk catalog for enumeration -*/ -static imgtoolerr_t win_image_beginenum(imgtool_directory *enumeration, const char *path) -{ - struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(imgtool_directory_image(enumeration)); - win_iterator *iter = (win_iterator *) imgtool_directory_extrabytes(enumeration); - imgtoolerr_t errorcode; - - iter->image = image; - iter->level = 0; - iter->listing_subdirs = 1; - iter->index[0] = 0; - errorcode = (imgtoolerr_t)win_read_catalog(image, 0, &iter->catalog[0]); - if (errorcode) - return errorcode; - - return (imgtoolerr_t)0; -} - -/* - Enumerate disk catalog next entry -*/ -static imgtoolerr_t win_image_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent) -{ - win_iterator *iter = (win_iterator *) imgtool_directory_extrabytes(enumeration); - unsigned fdr_aphysrec; - win_fdr fdr; - int reply; - int i; - - - ent->corrupt = 0; - ent->eof = 0; - - /* iterate through catalogs to next file or dir entry */ - while ((iter->level >= 0) - && (iter->index[iter->level] >= (iter->listing_subdirs - ? iter->catalog[iter->level].num_subdirs - : iter->catalog[iter->level].num_files))) - { - if (iter->listing_subdirs) - { - iter->listing_subdirs = 0; - iter->index[iter->level] = 0; - } - else - { - iter->listing_subdirs = 1; - iter->level--; - iter->index[iter->level]++; - } - } - - if (iter->level < 0) - { - ent->eof = 1; - } - else - { - if (iter->listing_subdirs) - { -#if 0 - fname_to_str(ent->filename, iter->catalog[iter->level].subdirs[iter->index[iter->level]].name, ARRAY_LENGTH(ent->filename)); -#else - { - char buf[11]; - - ent->filename[0] = '\0'; - for (i=0; i<iter->level; i++) - { - fname_to_str(buf, iter->catalog[i].subdirs[iter->index[i]].name, 11); - strncat(ent->filename, buf, ARRAY_LENGTH(ent->filename) - 1); - strncat(ent->filename, ".", ARRAY_LENGTH(ent->filename) - 1); - } - fname_to_str(buf, iter->catalog[iter->level].subdirs[iter->index[iter->level]].name, 11); - strncat(ent->filename, buf, ARRAY_LENGTH(ent->filename) - 1); - } -#endif - - /* set type of DIR */ - snprintf(ent->attr, ARRAY_LENGTH(ent->attr), "DIR"); - - /* len in physrecs */ - /* @BN@ return length in bytes */ - /* ent->filesize = 2; */ - ent->filesize = 512; - - /* recurse subdirectory */ - /*iter->listing_subdirs = 1;*/ - iter->level++; - iter->index[iter->level] = 0; - reply = win_read_catalog(iter->image, iter->catalog[iter->level-1].subdirs[iter->index[iter->level-1]].dir_ptr, &iter->catalog[iter->level]); - if (reply) - { - ent->corrupt = 1; - return (imgtoolerr_t)reply; - } - } - else - { - fdr_aphysrec = iter->catalog[iter->level].files[iter->index[iter->level]].fdr_ptr*iter->image->AUformat.physrecsperAU; - reply = read_absolute_physrec(& iter->image->l1_img, fdr_aphysrec, & fdr); - if (reply) - return IMGTOOLERR_READERROR; -#if 0 - fname_to_str(ent->filename, iter->catalog[iter->level].files[iter->index[iter->level]].name, ARRAY_LENGTH(ent->filename)); -#else - { - char buf[11]; - - ent->filename[0] = '\0'; - for (i=0; i<iter->level; i++) - { - fname_to_str(buf, iter->catalog[i].subdirs[iter->index[i]].name, 11); - strncat(ent->filename, buf, ARRAY_LENGTH(ent->filename) - 1); - strncat(ent->filename, ".", ARRAY_LENGTH(ent->filename) - 1); - } - fname_to_str(buf, iter->catalog[iter->level].files[iter->index[iter->level]].name, 11); - strncat(ent->filename, buf, ARRAY_LENGTH(ent->filename) - 1); - } -#endif - /* parse flags */ - if (fdr.flags & fdr99_f_program) - snprintf(ent->attr, ARRAY_LENGTH(ent->attr), "PGM%s", - (fdr.flags & fdr99_f_wp) ? " R/O" : ""); - else - snprintf(ent->attr, ARRAY_LENGTH(ent->attr), "%c/%c %d%s", - (fdr.flags & fdr99_f_int) ? 'I' : 'D', - (fdr.flags & fdr99_f_var) ? 'V' : 'F', - fdr.reclen, - (fdr.flags & fdr99_f_wp) ? " R/O" : ""); - /* len in physrecs */ - /* @BN@ return length in bytes */ - /* ent->filesize = get_win_fdr_fphysrecs(&fdr); */ - ent->filesize = (get_win_fdr_fphysrecs(&fdr)+1)*256; - - iter->index[iter->level]++; - } - } - - return (imgtoolerr_t)0; -} - -/* - Compute free space on disk image (in AUs) -*/ -static imgtoolerr_t ti99_image_freespace(imgtool_partition *partition, UINT64 *size) -{ - imgtool_image *img = imgtool_partition_image(partition); - struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(img); - size_t freeAUs; - int i; - - freeAUs = 0; - for (i=0; i<image->AUformat.totAUs; i++) - { - if (! (image->abm[i >> 3] & (1 << (i & 7)))) - freeAUs++; - } - - /* @BN@ return free space in bytes */ - /* *size = freeAUs; */ - *size = freeAUs*256; - - return IMGTOOLERR_SUCCESS; -} - -/* - Extract a file from a ti99_image. The file is saved in tifile format. -*/ -static imgtoolerr_t ti99_image_readfile(imgtool_partition *partition, const char *fpath, const char *fork, imgtool_stream *destf) -{ - imgtool_image *img = imgtool_partition_image(partition); -#if 1 - - /* extract data as TIFILES */ - struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(img); - ti99_lvl2_fileref src_file; - ti99_lvl2_fileref dst_file; - ti99_date_time date_time; - int fphysrecs; - int i; - UINT8 buf[256]; - imgtoolerr_t errorcode; - - - if (check_fpath(fpath)) - return IMGTOOLERR_BADFILENAME; - - /* open file on TI image */ - switch (image->type) - { - case L2I_DSK: - errorcode = (imgtoolerr_t)open_file_lvl2_dsk(image, fpath, &src_file); - break; - - case L2I_WIN: - errorcode = (imgtoolerr_t)open_file_lvl2_win(image, fpath, &src_file); - break; - - default: - errorcode = (imgtoolerr_t)-1; - break; - } - if (errorcode) - return errorcode; - - errorcode = (imgtoolerr_t)new_file_lvl2_tifiles(destf, &dst_file); - if (errorcode) - return errorcode; - - /* write TIFILE header */ - /* set up parameters */ - set_file_flags(&dst_file, get_file_flags(&src_file)); - set_file_recsperphysrec(&dst_file, get_file_recsperphysrec(&src_file)); - errorcode = (imgtoolerr_t)set_file_fphysrecs(&dst_file, get_file_fphysrecs(&src_file)); - if (errorcode) - return errorcode; - set_file_eof(&dst_file, get_file_eof(&src_file)); - errorcode = (imgtoolerr_t)set_file_reclen(&dst_file, get_file_reclen(&src_file)); - if (errorcode) - return errorcode; - errorcode = (imgtoolerr_t)set_file_fixrecs(&dst_file, get_file_fixrecs(&src_file)); - if (errorcode) - return errorcode; - - get_file_creation_date(&src_file, &date_time); -#if 0 - if ((date_time.time_MSB == 0) || (date_time.time_LSB == 0) - || (date_time.date_MSB == 0) || (date_time.date_LSB == 0)) - current_date_time(&date_time); -#endif - set_file_creation_date(&dst_file, date_time); - - get_file_update_date(&src_file, &date_time); -#if 0 - if ((date_time.time_MSB == 0) || (date_time.time_LSB == 0) - || (date_time.date_MSB == 0) || (date_time.date_LSB == 0)) - current_date_time(&date_time); -#endif - set_file_update_date(&dst_file, date_time); - - if (stream_write(destf, & dst_file.tifiles.hdr, 128) != 128) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - - /* copy data to TIFILE */ - fphysrecs = get_file_fphysrecs(&src_file); - - for (i=0; i<fphysrecs; i++) - { - errorcode = (imgtoolerr_t)read_file_physrec(& src_file, i, buf); - if (errorcode) - return errorcode; - - errorcode = (imgtoolerr_t)write_file_physrec(& dst_file, i, buf); - if (errorcode) - return errorcode; - } - - return (imgtoolerr_t)0; - -#else - - struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(img); - ti99_lvl3_fileref src_file; - UINT8 buf[256]; - int reclen; - char lineend = '\r'; - int errorcode; - - - if (check_fpath(fpath)) - return IMGTOOLERR_BADFILENAME; - - /* open file on TI image */ - switch (image->type) - { - case L2I_DSK: - errorcode = open_file_lvl2_dsk(image, fpath, &src_file.l2_file); - break; - - case L2I_WIN: - errorcode = open_file_lvl2_win(image, fpath, &src_file.l2_file); - break; - } - if (errorcode) - return errorcode; - - errorcode = open_file_lvl3(& src_file); - if (errorcode) - return errorcode; - - /* write text data */ - while (! is_eof(& src_file)) - { - errorcode = read_next_record(& src_file, buf, & reclen); - if (errorcode) - return errorcode; - if (stream_write(destf, buf, reclen) != reclen) - return IMGTOOLERR_WRITEERROR; - if (stream_write(destf, &lineend, 1) != 1) - return IMGTOOLERR_WRITEERROR; - } - - return 0; - -#endif -} - -/* - Add a file to a ti99_image. The file must be in tifile format. -*/ -static imgtoolerr_t ti99_image_writefile(imgtool_partition *partition, const char *fpath, const char *fork, imgtool_stream *sourcef, option_resolution *writeoptions) -{ - imgtool_image *img = imgtool_partition_image(partition); - struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(img); - const char *filename; - char ti_fname[10]; - ti99_lvl2_fileref src_file; - ti99_lvl2_fileref dst_file; - ti99_date_time date_time; - int i; - int fphysrecs; - UINT8 buf[256]; - imgtoolerr_t errorcode; - int parent_ref_valid, parent_ref = 0; - ti99_catalog *catalog, catalog_buf = {0, }; - - - (void) writeoptions; - - if (check_fpath(fpath)) - return IMGTOOLERR_BADFILENAME; - - switch (image->type) - { - case L2I_DSK: - errorcode = (imgtoolerr_t)dsk_find_catalog_entry(image, fpath, &parent_ref_valid, &parent_ref, NULL, NULL); - if (errorcode == 0) - /* file already exists: causes an error for now */ - return (imgtoolerr_t)IMGTOOLERR_UNEXPECTED; - else if ((! parent_ref_valid) || (errorcode != IMGTOOLERR_FILENOTFOUND)) - return (imgtoolerr_t)errorcode; - break; - - case L2I_WIN: - errorcode = (imgtoolerr_t)win_find_catalog_entry(image, fpath, &parent_ref_valid, &parent_ref, &catalog_buf, NULL, NULL); - if (errorcode == 0) - /* file already exists: causes an error for now */ - return (imgtoolerr_t)IMGTOOLERR_UNEXPECTED; - else if ((! parent_ref_valid) || (errorcode != IMGTOOLERR_FILENOTFOUND)) - return (imgtoolerr_t)errorcode; - break; - } - - errorcode =(imgtoolerr_t) open_file_lvl2_tifiles(sourcef, & src_file); - if (errorcode) - return (imgtoolerr_t)errorcode; - - /* create new file */ - filename = strrchr(fpath, '.'); - if (filename) - filename++; - else - filename = fpath; - str_to_fname(ti_fname, filename); - switch (image->type) - { - case L2I_DSK: - errorcode = (imgtoolerr_t)new_file_lvl2_dsk(image, parent_ref, ti_fname, &dst_file); - if (errorcode) - return (imgtoolerr_t)errorcode; - break; - - case L2I_WIN: - errorcode = (imgtoolerr_t)new_file_lvl2_win(image, &catalog_buf, ti_fname, &dst_file); - if (errorcode) - return (imgtoolerr_t)errorcode; - break; - } - - /* set up parameters */ - set_file_flags(&dst_file, get_file_flags(&src_file)); - set_file_recsperphysrec(&dst_file, get_file_recsperphysrec(&src_file)); - errorcode = (imgtoolerr_t)set_file_fphysrecs(&dst_file, /*get_file_fphysrecs(&src_file)*/0); - if (errorcode) - return (imgtoolerr_t)errorcode; - set_file_eof(&dst_file, get_file_eof(&src_file)); - errorcode = (imgtoolerr_t)set_file_reclen(&dst_file, get_file_reclen(&src_file)); - if (errorcode) - return (imgtoolerr_t)errorcode; - errorcode = (imgtoolerr_t)set_file_fixrecs(&dst_file, get_file_fixrecs(&src_file)); - if (errorcode) - return (imgtoolerr_t)errorcode; - - get_file_creation_date(&src_file, &date_time); -#if 0 - if ((date_time.time_MSB == 0) || (date_time.time_LSB == 0) - || (date_time.date_MSB == 0) || (date_time.date_LSB == 0)) - current_date_time(&date_time); -#endif - set_file_creation_date(&dst_file, date_time); - - get_file_update_date(&src_file, &date_time); -#if 0 - if ((date_time.time_MSB == 0) || (date_time.time_LSB == 0) - || (date_time.date_MSB == 0) || (date_time.date_LSB == 0)) - current_date_time(&date_time); -#endif - set_file_update_date(&dst_file, date_time); - - /* alloc data physrecs */ - fphysrecs = get_file_fphysrecs(&src_file); - switch (dst_file.type) - { - case L2F_DSK: - errorcode = (imgtoolerr_t)dsk_alloc_file_physrecs(&dst_file.dsk, fphysrecs); - if (errorcode) - return (imgtoolerr_t)errorcode; - break; - - case L2F_WIN: - errorcode = (imgtoolerr_t)win_alloc_file_physrecs(&dst_file.win, fphysrecs); - if (errorcode) - return (imgtoolerr_t)errorcode; - break; - - case L2F_TIFILES: - break; - } - - /* copy data */ - for (i=0; i<fphysrecs; i++) - { - if (stream_read(sourcef, buf, 256) != 256) - return (imgtoolerr_t)IMGTOOLERR_READERROR; - - errorcode = (imgtoolerr_t)write_file_physrec(& dst_file, i, buf); - if (errorcode) - return (imgtoolerr_t)errorcode; - } - - /* write fdr */ - switch (image->type) - { - case L2I_DSK: - if (write_absolute_physrec(& image->l1_img, dst_file.dsk.fdr_aphysrec, &dst_file.dsk.fdr)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - break; - - case L2I_WIN: - /* save fphysrecs field as well */ - if (dst_file.win.curfdr_aphysrec == dst_file.win.eldestfdr_aphysrec) - set_win_fdr_fphysrecs(&dst_file.win.curfdr, dst_file.win.fphysrecs); - if (write_absolute_physrec(& image->l1_img, dst_file.win.curfdr_aphysrec, &dst_file.win.curfdr)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - if (dst_file.win.curfdr_aphysrec != dst_file.win.eldestfdr_aphysrec) - { - dst_file.win.curfdr_aphysrec = dst_file.win.eldestfdr_aphysrec; - if (read_absolute_physrec(& image->l1_img, dst_file.win.curfdr_aphysrec, &dst_file.win.curfdr)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - set_win_fdr_fphysrecs(&dst_file.win.curfdr, dst_file.win.fphysrecs); - if (write_absolute_physrec(& image->l1_img, dst_file.win.curfdr_aphysrec, &dst_file.win.curfdr)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - } - break; - } - - /* update catalog */ - switch (image->type) - { - case L2I_DSK: - catalog = &image->dsk.catalogs[parent_ref]; - for (i=0; i<128; i++) - { - buf[2*i] = catalog->files[i].fdr_ptr >> 8; - buf[2*i+1] = catalog->files[i].fdr_ptr & 0xff; - } - if (write_absolute_physrec(& image->l1_img, image->dsk.fdir_aphysrec[parent_ref], buf)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - break; - - case L2I_WIN: - { - win_vib_ddr parent_ddr; - int fdir_AU; - - /* update VIB/DDR and get FDIR AU address */ - if (read_absolute_physrec(& image->l1_img, parent_ref * image->AUformat.physrecsperAU, &parent_ddr)) - return (imgtoolerr_t)IMGTOOLERR_READERROR; - parent_ddr.num_files = catalog_buf.num_files; - if (write_absolute_physrec(& image->l1_img, parent_ref * image->AUformat.physrecsperAU, &parent_ddr)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - fdir_AU = get_UINT16BE(parent_ddr.fdir_AU); - - /* generate FDIR and save it */ - for (i=0; i<127; i++) - { - buf[2*i] = catalog_buf.files[i].fdr_ptr >> 8; - buf[2*i+1] = catalog_buf.files[i].fdr_ptr & 0xff; - } - buf[254] = parent_ref >> 8; - buf[255] = parent_ref & 0xff; - if (write_absolute_physrec(& image->l1_img, fdir_AU * image->AUformat.physrecsperAU, buf)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - } - break; - } - - /* update bitmap */ - switch (image->type) - { - case L2I_DSK: - { - dsk_vib vib; - - if (read_absolute_physrec(& image->l1_img, 0, &vib)) - return (imgtoolerr_t)IMGTOOLERR_READERROR; - memcpy(vib.abm, image->abm, 200); - if (write_absolute_physrec(& image->l1_img, 0, &vib)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - } - break; - - case L2I_WIN: - /* save allocation bitmap (aphysrecs 1 through n, n<=33) */ - for (i=0; i < (image->AUformat.totAUs+2047)/2048; i++) - if (write_absolute_physrec(&image->l1_img, i+1, image->abm+i*256)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - break; - } - - return (imgtoolerr_t)0; -} - -/* - Delete a file from a ti99_image. -*/ -static imgtoolerr_t dsk_image_deletefile(imgtool_partition *partition, const char *fpath) -{ - imgtool_image *img = imgtool_partition_image(partition); - struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(img); - dsk_fdr fdr; - int i, cluster_index; - unsigned cur_AU, cluster_lastfphysrec; -// int fphysrecs; - int parent_ref, is_dir, catalog_index; - imgtoolerr_t errorcode; - UINT8 buf[256]; - ti99_catalog *catalog; - - - if (check_fpath(fpath)) - return IMGTOOLERR_BADFILENAME; - - errorcode = (imgtoolerr_t)dsk_find_catalog_entry(image, fpath, NULL, &parent_ref, &is_dir, &catalog_index); - if (errorcode) - return errorcode; - - if (is_dir) - { - catalog = &image->dsk.catalogs[catalog_index+1]; - - if ((catalog->num_files != 0) || (catalog->num_subdirs != 0)) - return IMGTOOLERR_UNIMPLEMENTED; - - catalog = &image->dsk.catalogs[0]; - - /* free fdir AU */ - cur_AU = image->dsk.fdir_aphysrec[catalog_index+1] / image->AUformat.physrecsperAU; - image->abm[cur_AU >> 3] &= ~ (1 << (cur_AU & 7)); - - /* delete catalog entry */ - for (i=catalog_index; i<2; i++) - { - catalog->subdirs[i] = catalog->subdirs[i+1]; - image->dsk.fdir_aphysrec[i+1] = image->dsk.fdir_aphysrec[i+2]; - } - memset(catalog->subdirs[2].name, 0, 10); - catalog->subdirs[2].dir_ptr = 0; - image->dsk.fdir_aphysrec[3] = 0; - catalog->num_subdirs--; - - /* update directory and bitmap in vib */ - { - dsk_vib vib; - - if (read_absolute_physrec(& image->l1_img, 0, &vib)) - return IMGTOOLERR_READERROR; - - for (i=0; i<3; i++) - { - memcpy(vib.subdir[i].name, catalog->subdirs[i].name, 10); - set_UINT16BE(&vib.subdir[i].fdir_aphysrec, image->dsk.fdir_aphysrec[i+1]); - } - - memcpy(vib.abm, image->abm, 200); - - if (write_absolute_physrec(& image->l1_img, 0, &vib)) - return IMGTOOLERR_WRITEERROR; - } - } - else - { - catalog = &image->dsk.catalogs[parent_ref]; - - if (read_absolute_physrec(& image->l1_img, catalog->files[catalog_index].fdr_ptr, &fdr)) - return IMGTOOLERR_READERROR; - - /* free data AUs */ -// fphysrecs = - get_UINT16BE(fdr.fphysrecs); - - i = 0; - cluster_index = 0; - while (cluster_index < 76) - { - cur_AU = get_dsk_fdr_cluster_baseAU(image, & fdr, cluster_index); - if (cur_AU == 0) - /* end of cluster list */ - break; - cluster_lastfphysrec = get_dsk_fdr_cluster_lastfphysrec(& fdr, cluster_index); - - while (i<=cluster_lastfphysrec) - { - /* the condition below is an error, but it should not prevent - us from deleting the file */ - if (cur_AU >= image->AUformat.totAUs) - /*return IMGTOOLERR_CORRUPTIMAGE;*/ - break; - - image->abm[cur_AU >> 3] &= ~ (1 << (cur_AU & 7)); - - i += image->AUformat.physrecsperAU; - cur_AU++; - } - - cluster_index++; - } - /* the condition below is an error, but it should not prevent us from - deleting the file */ -#if 0 - if (i<fphysrecs) - return IMGTOOLERR_CORRUPTIMAGE; -#endif - - /* free fdr AU */ - cur_AU = catalog->files[catalog_index].fdr_ptr / image->AUformat.physrecsperAU; - image->abm[cur_AU >> 3] &= ~ (1 << (cur_AU & 7)); - - /* delete catalog entry */ - for (i=catalog_index; i<127; i++) - catalog->files[i] = catalog->files[i+1]; - catalog->files[127].fdr_ptr = 0; - catalog->num_files--; - - /* update parent fdir */ - for (i=0; i<128; i++) - { - buf[2*i] = catalog->files[i].fdr_ptr >> 8; - buf[2*i+1] = catalog->files[i].fdr_ptr & 0xff; - } - if (write_absolute_physrec(& image->l1_img, image->dsk.fdir_aphysrec[parent_ref], buf)) - return IMGTOOLERR_WRITEERROR; - - /* update bitmap */ - { - dsk_vib vib; - - if (read_absolute_physrec(& image->l1_img, 0, &vib)) - return IMGTOOLERR_READERROR; - memcpy(vib.abm, image->abm, 200); - if (write_absolute_physrec(& image->l1_img, 0, &vib)) - return IMGTOOLERR_WRITEERROR; - } - } - - return (imgtoolerr_t)0; -} - -static imgtoolerr_t win_image_deletefile(imgtool_partition *partition, const char *fpath) -{ - imgtool_image *img = imgtool_partition_image(partition); - struct ti99_lvl2_imgref *image = (struct ti99_lvl2_imgref *) imgtool_image_extra_bytes(img); - int parent_ddr_AU, is_dir, catalog_index; - win_fdr fdr; - int i; - unsigned cur_AU, end_AU; - unsigned curfdr_aphysrec; - unsigned cursibFDR_index, endsibFDR_index = 0; - int errorcode; - UINT8 buf[256]; - ti99_catalog catalog; - - - if (check_fpath(fpath)) - return (imgtoolerr_t)IMGTOOLERR_BADFILENAME; - - errorcode = win_find_catalog_entry(image, fpath, NULL, &parent_ddr_AU, &catalog, &is_dir, &catalog_index); - if (errorcode) - return (imgtoolerr_t)errorcode; - - if (is_dir) - { - unsigned DDR_AU; - win_vib_ddr ddr_buf; - - /* Read DDR record */ - DDR_AU = catalog.subdirs[catalog_index].dir_ptr; - if (read_absolute_physrec(& image->l1_img, DDR_AU*image->AUformat.physrecsperAU, &ddr_buf)) - return (imgtoolerr_t)IMGTOOLERR_READERROR; - - /* read FDIR AU pointer */ - cur_AU = get_UINT16BE(ddr_buf.fdir_AU); - - /* sanity checks */ - if ((ddr_buf.num_files > 127) || (ddr_buf.num_subdirs > 114) || (cur_AU > image->AUformat.totAUs)) - return (imgtoolerr_t)IMGTOOLERR_CORRUPTIMAGE; - - if ((ddr_buf.num_files != 0) || (ddr_buf.num_subdirs != 0)) - return (imgtoolerr_t)IMGTOOLERR_UNIMPLEMENTED; - - /* free fdir AU */ - image->abm[cur_AU >> 3] &= ~ (1 << (cur_AU & 7)); - - /* free ddr AU */ - image->abm[DDR_AU >> 3] &= ~ (1 << (DDR_AU & 7)); - - /* delete parent catalog entry */ - for (i=catalog_index; i<113; i++) - catalog.subdirs[i] = catalog.subdirs[i+1]; - catalog.subdirs[113].dir_ptr = 0; - catalog.num_subdirs--; - - /* update parent VIB/DDR */ - if (read_absolute_physrec(& image->l1_img, parent_ddr_AU * image->AUformat.physrecsperAU, &ddr_buf)) - return (imgtoolerr_t)IMGTOOLERR_READERROR; - ddr_buf.num_subdirs = catalog.num_subdirs; - for (i=0; i<114; i++) - set_UINT16BE(&ddr_buf.subdir_AU[i], catalog.subdirs[i].dir_ptr); - if (write_absolute_physrec(& image->l1_img, parent_ddr_AU * image->AUformat.physrecsperAU, &ddr_buf)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - - /* save allocation bitmap (aphysrecs 1 through n, n<=33) */ - for (i=0; i < (image->AUformat.totAUs+2047)/2048; i++) - if (write_absolute_physrec(&image->l1_img, i+1, image->abm+i*256)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - } - else - { - /* check integrity of FDR sibling chain, and go to last sibling */ - /* note that as we check that the back chain is consistent with the forward - chain, we will also detect any cycle in the sibling chain, so we do not - need to check against them explicitely */ - { - int pastendoflist_flag; - unsigned prevfdr_aphysrec; - - - pastendoflist_flag = 0; - cursibFDR_index = 0; - curfdr_aphysrec = catalog.files[catalog_index].fdr_ptr * image->AUformat.physrecsperAU; - if (read_absolute_physrec(& image->l1_img, curfdr_aphysrec, &fdr)) - return (imgtoolerr_t)IMGTOOLERR_READERROR; - - if (get_UINT16BE(fdr.prevsibFDR_AU) != 0) - return (imgtoolerr_t)IMGTOOLERR_CORRUPTIMAGE; - - while (1) - { - if (! pastendoflist_flag) - { - /* look for end of list */ - for (i=0; i<54; i++) - { - if (get_UINT16BE(fdr.clusters[i][0]) == 0) - { - endsibFDR_index = cursibFDR_index; - pastendoflist_flag = TRUE; - break; - } - } - } - - /* exit loop if end of sibling chain */ - if (! get_UINT16BE(fdr.nextsibFDR_AU)) - break; - - /* otherwise read next FDR */ - if (get_UINT16BE(fdr.nextsibFDR_AU) >= image->AUformat.totAUs) - return (imgtoolerr_t)IMGTOOLERR_CORRUPTIMAGE; - - prevfdr_aphysrec = curfdr_aphysrec; - curfdr_aphysrec = get_win_fdr_nextsibFDR_aphysrec(image, &fdr); - if (read_absolute_physrec(& image->l1_img, curfdr_aphysrec, &fdr)) - return (imgtoolerr_t)IMGTOOLERR_READERROR; - cursibFDR_index++; - - /* check that back chaining is consistent with forward chaining */ - if (get_win_fdr_prevsibFDR_aphysrec(image, &fdr) != prevfdr_aphysrec) - return (imgtoolerr_t)IMGTOOLERR_CORRUPTIMAGE; - } - if (! pastendoflist_flag) - endsibFDR_index = cursibFDR_index; - } - - - while (1) - { - if (cursibFDR_index <= endsibFDR_index) - { - for (i = 0; i < 54; i++) - { - cur_AU = get_UINT16BE(fdr.clusters[i][0]); - if (cur_AU == 0) - /* end of cluster list */ - break; - end_AU = get_UINT16BE(fdr.clusters[i][1]); - - while (cur_AU<=end_AU) - { - /* the condition below is an error, but it should not prevent - us from deleting the file */ - if (cur_AU >= image->AUformat.totAUs) - /*return IMGTOOLERR_CORRUPTIMAGE;*/ - break; - - image->abm[cur_AU >> 3] &= ~ (1 << (cur_AU & 7)); - - cur_AU++; - } - } - } - - /* free fdr AU if applicable */ - if ((curfdr_aphysrec % image->AUformat.physrecsperAU) == 0) - { - cur_AU = curfdr_aphysrec / image->AUformat.physrecsperAU; - image->abm[cur_AU >> 3] &= ~ (1 << (cur_AU & 7)); - } - - if (cursibFDR_index == 0) - break; - curfdr_aphysrec = get_win_fdr_prevsibFDR_aphysrec(image, &fdr); - if (read_absolute_physrec(& image->l1_img, curfdr_aphysrec, &fdr)) - return (imgtoolerr_t)IMGTOOLERR_READERROR; - cursibFDR_index--; - } - - - /* delete catalog entry */ - for (i=catalog_index; i<127; i++) - catalog.files[i] = catalog.files[i+1]; - catalog.files[127].fdr_ptr = 0; - catalog.num_files--; - - - /* update VIB/DDR and get FDIR AU address */ - { - win_vib_ddr parent_ddr; - - if (read_absolute_physrec(& image->l1_img, parent_ddr_AU * image->AUformat.physrecsperAU, &parent_ddr)) - return (imgtoolerr_t)IMGTOOLERR_READERROR; - parent_ddr.num_files = catalog.num_files; - if (write_absolute_physrec(& image->l1_img, parent_ddr_AU * image->AUformat.physrecsperAU, &parent_ddr)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - cur_AU = get_UINT16BE(parent_ddr.fdir_AU); - } - - /* generate FDIR and save it */ - for (i=0; i<127; i++) - { - buf[2*i] = catalog.files[i].fdr_ptr >> 8; - buf[2*i+1] = catalog.files[i].fdr_ptr & 0xff; - } - buf[254] = parent_ddr_AU >> 8; - buf[255] = parent_ddr_AU & 0xff; - if (write_absolute_physrec(& image->l1_img, cur_AU * image->AUformat.physrecsperAU, buf)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - - /* save allocation bitmap (aphysrecs 1 through n, n<=33) */ - for (i=0; i < (image->AUformat.totAUs+2047)/2048; i++) - if (write_absolute_physrec(&image->l1_img, i+1, image->abm+i*256)) - return (imgtoolerr_t)IMGTOOLERR_WRITEERROR; - } - - return (imgtoolerr_t)0; -} - -/* - Create a blank ti99_image (common code). - - Supports MESS and V9T9 formats only -*/ -static imgtoolerr_t dsk_image_create(imgtool_image *image, imgtool_stream *f, option_resolution *createoptions, ti99_img_format img_format) -{ - const char *volname; - int density; - ti99_lvl1_imgref l1_img; - int protected_var; - - int totphysrecs, physrecsperAU, totAUs; - - dsk_vib vib; - UINT8 empty_sec[256]; - - int i; - - l1_img.img_format = img_format; - l1_img.file_handle = f; - - /* read options */ - volname = option_resolution_lookup_string(createoptions, dsk_createopts_volname); - l1_img.geometry.heads = option_resolution_lookup_int(createoptions, dsk_createopts_sides); - l1_img.geometry.cylinders = option_resolution_lookup_int(createoptions, dsk_createopts_tracks); - l1_img.geometry.secspertrack = option_resolution_lookup_int(createoptions, dsk_createopts_sectors); - protected_var = option_resolution_lookup_int(createoptions, dsk_createopts_protection); - density = option_resolution_lookup_int(createoptions, dsk_createopts_density); - - /* NPW 03-DEC-2003 - Fixes a crash if volname is NULL */ - if (!volname) - volname = ""; - - totphysrecs = l1_img.geometry.secspertrack * l1_img.geometry.cylinders * l1_img.geometry.heads; - physrecsperAU = (totphysrecs + 1599) / 1600; - /* round to next larger power of 2 */ - for (i = 1; i < physrecsperAU; i <<= 1) - ; - physrecsperAU = i; - totAUs = totphysrecs / physrecsperAU; - - /* auto-density */ - if (density == 0) - { - if (l1_img.geometry.secspertrack <= 9) - density = 1; - else if (l1_img.geometry.secspertrack <= 18) - density = 2; - else - density = 3; - } - - /* check volume name */ - if (strchr(volname, '.') || strchr(volname, ' ') || (strlen(volname) > 10)) - return /*IMGTOOLERR_BADFILENAME*/IMGTOOLERR_PARAMCORRUPT; - - /* FM disks can hold fewer sector per track than MFM disks */ - if ((density == 1) && (l1_img.geometry.secspertrack > 9)) - return IMGTOOLERR_PARAMTOOLARGE; - - /* DD disks can hold fewer sector per track than HD disks */ - if ((density == 2) && (l1_img.geometry.secspertrack > 18)) - return IMGTOOLERR_PARAMTOOLARGE; - - /* check total disk size */ - if (totphysrecs < 2) - return IMGTOOLERR_PARAMTOOSMALL; - - /* initialize vib in aphysrec 0 */ - - /* set volume name */ - str_to_fname(vib.name, volname); - - /* set every header field */ - set_UINT16BE(& vib.totphysrecs, totphysrecs); - vib.secspertrack = l1_img.geometry.secspertrack; - vib.id[0] = 'D'; - vib.id[1] = 'S'; - vib.id[2] = 'K'; - vib.protection = protected_var ? 'P' : ' '; - vib.cylinders = l1_img.geometry.cylinders; - vib.heads = l1_img.geometry.heads; - vib.density = density; - for (i=0; i<3; i++) - { - memset(vib.subdir[i].name, '\0', 10); - set_UINT16BE(& vib.subdir[i].fdir_aphysrec, 0); - } - - /* clear bitmap */ - for (i=0; i < (totAUs>>3); i++) - vib.abm[i] = 0; - - if (totAUs & 7) - { - vib.abm[i] = 0xff << (totAUs & 7); - i++; - } - - for (; i < 200; i++) - vib.abm[i] = 0xff; - - /* mark first 2 aphysrecs (vib and fdir) as used */ - vib.abm[0] |= (physrecsperAU == 1) ? 3 : 1; - - /* write aphysrec 0 */ - if (write_absolute_physrec(& l1_img, 0, &vib)) - return IMGTOOLERR_WRITEERROR; - - - /* now clear every other physrecs, including the FDIR record */ - memset(empty_sec, 0, sizeof(empty_sec)); - - for (i=1; i<totphysrecs; i++) - if (write_absolute_physrec(& l1_img, i, empty_sec)) - return IMGTOOLERR_WRITEERROR; - - - return (imgtoolerr_t)dsk_image_init(image, f, img_format); -} - -/* - Create a blank ti99_image (MESS format). -*/ -static imgtoolerr_t dsk_image_create_mess(imgtool_image *image, imgtool_stream *f, option_resolution *createoptions) -{ - return dsk_image_create(image, f, createoptions, if_mess); -} - -/* - Create a blank ti99_image (V9T9 format). -*/ -static imgtoolerr_t dsk_image_create_v9t9(imgtool_image *image, imgtool_stream *f, option_resolution *createoptions) -{ - return dsk_image_create(image, f, createoptions, if_v9t9); -} diff --git a/src/mess/tools/imgtool/modules/ti990hd.c b/src/mess/tools/imgtool/modules/ti990hd.c deleted file mode 100644 index 2c2a6c3a13c..00000000000 --- a/src/mess/tools/imgtool/modules/ti990hd.c +++ /dev/null @@ -1,1818 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/* - Handlers for ti990 disk images - - Disk images are in MESS format. - - Raphael Nabet, 2003 -*/ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <limits.h> -#include "imgtool.h" - -/* 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. */ -/* I chose a limit of 512. No need to use more until someone creates CD-ROMs -for TI990. */ -#define MAX_SECTOR_SIZE 512 -#define MIN_SECTOR_SIZE 256 - -#define MAX_CYLINDERS 2047 -#define MAX_HEADS 31 -#define MAX_SECTORS_PER_TRACK 256 /* 255 for 512-byte-long sector, so that the total number of words that can be recorded on a track may fit in one 16-bit word (store registers command) */ - -/* Max path len in chars: this value is 48 characters in DX10, but since the -path includes at least a leading '.', our value is 47. */ -/* Since path generally include a volume name that can be up to 8 character -long, we should display a warning message when the user wants to create a path -that is longer than 39 characters. */ -#define MAX_PATH_LEN 47 -#define MAX_SAFE_PATH_LEN 39 - -#define MAX_DIR_LEVEL 25 /* We need to put a recursion limit to avoid endless recursion hazard */ - - -struct UINT16BE -{ - UINT8 bytes[2]; -}; - -struct UINT32BE -{ - UINT8 bytes[4]; -}; - -INLINE UINT16 get_UINT16BE(UINT16BE word) -{ - return (word.bytes[0] << 8) | word.bytes[1]; -} - -INLINE void set_UINT16BE(UINT16BE *word, UINT16 data) -{ - word->bytes[0] = (data >> 8) & 0xff; - word->bytes[1] = data & 0xff; -} - -INLINE UINT32 get_UINT32BE(UINT32BE word) -{ - return (word.bytes[0] << 24) | (word.bytes[1] << 16) | (word.bytes[2] << 8) | word.bytes[3]; -} - -INLINE void set_UINT32BE(UINT32BE *word, UINT32 data) -{ - word->bytes[0] = (data >> 24) & 0xff; - word->bytes[1] = (data >> 16) & 0xff; - word->bytes[2] = (data >> 8) & 0xff; - word->bytes[3] = data & 0xff; -} - -/* - disk image header -*/ -struct disk_image_header -{ - UINT32BE cylinders; /* number of cylinders on hard disk (big-endian) */ - UINT32BE heads; /* number of heads on hard disk (big-endian) */ - UINT32BE sectors_per_track; /* number of sectors per track on hard disk (big-endian) */ - UINT32BE bytes_per_sector; /* number of bytes of data per sector on hard disk (big-endian) */ -}; - -enum -{ - header_len = sizeof(disk_image_header) -}; - -/* - Disk structure: - - Track 0 Sector 0: see below - Track 0 Sector 1: list of bad ADU - Track 0 Sector 2 through N: disk allocation bitmap - 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) - Remaining sectors are used for fdr and data. -*/ - -/* - SC0 record (Disk sector 0) -*/ -struct ti990_sc0 -{ - char vnm[8]; /* volume name */ - UINT16BE tna; /* total number of ADUs */ - UINT8 sbm; /* starting sector of bit maps */ - UINT8 tbm; /* total bit maps */ - UINT16BE rl; /* track 01 record length */ - UINT16BE slt; /* system loader track address */ - UINT8 fill00[6]; /* * * RESERVED * * */ - UINT16BE nba; /* total number of bad ADUs on disk */ - UINT16BE sle; /* system loader entry point */ - UINT16BE sll; /* system loader length */ - UINT8 fill01[8]; /* * * RESERVED * * */ - UINT16BE lt1; /* system loader track (copy 2) */ - UINT8 fill02[8]; /* * * RESERVED * * */ - char pi1[8]; /* primary system file name */ - char pi2[8]; /* secondary system file name */ - UINT16BE pif; /* system selector */ - UINT16BE vda; /* volume directory ADU */ - UINT16BE vpl; /* vcatalog physical record length */ - UINT16BE spa; /* sectors per ADU */ - UINT8 dcd[4]; /* disk creation date */ - char pf1[8]; /* primary program file */ - char pf2[8]; /* secondary program file */ - UINT16BE pff; /* program file switch */ - char of1[8]; /* primary overlay file */ - char of2[8]; /* secondary overlay file */ - UINT16BE off; /* overlay file switch */ - char il1[8]; /* primary intermediate loader */ - char il2[8]; /* secondary intermediate loader */ - UINT16BE ilf; /* intermediate loader flag */ - char din[8]; /* diagnostic file name */ - UINT16BE dif; /* diagnostic flag */ - UINT16BE drs; /* default physical record size "DBUILD DETERMINES DEFAULT PRS" (whatever it means) */ - UINT16BE bal; /* starting sector of bad ADU list */ - UINT16BE spr; /* track 0 sectors per record */ - char wf1[8]; /* WCS primary microcode file */ - char wf2[8]; /* WCS secondary microcode file */ - UINT16BE wff; /* WCS flag switch */ - UINT16BE vif; /* track 1 select flag (whatever it means) volume information copied flag */ - UINT16BE sta; /* state of disk: */ - /* 1 = disk surface has not been tested for defects */ - /* 2 = disk surface has been tested, but no file system has been installed */ - /* 3 = a file system has been installed */ - UINT16BE dct; /* disk creation time */ - UINT16BE fsf; /* * * RESERVED * * */ - /* SCOSIZ = >AA */ -}; - -/* - DOR (Directory Overhead Record) -*/ -struct ti990_dor -{ - UINT16BE nrc; /* # records in directory (minus DOR) nrc = nfl + nar (+ tfc???) */ - UINT16BE nfl; /* # files currently in directory */ - UINT16BE nar; /* # of available records */ - UINT16BE tfc; /* number of temporary files */ - char dnm[8]; /* directory file name (VCATALOG for root) */ - UINT16BE lvl; /* level # of directory (0 for root, 1 for children of root, 2 for grandchildren, etc) */ - char pnm[8]; /* name of parent directory (VCATALOG for root, even though it makes little sense) */ - UINT16BE prs; /* "default physical record length (used for file creation)" */ - /* DORSIZ = >1C */ -}; - -/* - file flags found in fdr -*/ -enum -{ - ace_flg_rdf = 0x8000, /* read access flag */ - ace_flg_wrf = 0x4000, /* write access flag */ - ace_flg_dlf = 0x2000, /* delete access flag */ - ace_flg_exf = 0x1000, /* execute access flag */ - ace_flg_ctf = 0x0800, /* control access flag */ - - fdr_fl1_sec = 0x8000, /* file secured flag */ - - fdr_flg_fu = 0xc000, /* file usage bits */ - fdr_flg_fu_shift = 14, - fdr_flg_fmt = 0x3000, /* file format bits */ - fdr_flg_fmt_shift = 12, - fdr_flg_all = 0x0800, /* extendable file flag */ - fdr_flg_ft = 0x0600, /* file type bits */ - fdr_flg_ft_shift = 9, - fdr_flg_wpb = 0x0100, /* write protect bit */ - fdr_flg_dpb = 0x0080, /* delete protect bit */ - fdr_flg_tmp = 0x0040, /* temporary file flag */ - fdr_flg_blb = 0x0020, /* blocked file flag */ - fdr_flg_ali = 0x0010, /* alias flag bit */ - fdr_flg_fwt = 0x0008, /* forced write / partial logging */ - fdr_flg_cdr = 0x0001 /* record is CDR */ -}; - -/* - ACE subrecord found in FDR -*/ -struct ti990_ace -{ - char agn[8]; /* access group name */ - UINT16BE flg; /* flags */ -}; - -/* - FDR record -*/ -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 rsv[2]; /* reserved */ - UINT16BE fl1; /* flags word 1 */ - UINT16BE flg; /* flags word 2 */ - UINT16BE prs; /* physical record size */ - UINT16BE lrs; /* logical record size */ - UINT16BE pas; /* primary allocation size: # of ADUs allocated in primary allocation block? */ - UINT16BE paa; /* primary allocation address: first ADU of primary allocation block? */ - UINT16BE sas; /* secondary allocation size: used to determinate the # of blocks allocated per secondary allocation */ - UINT16BE saa; /* offset of secondary table: ???? "offset into this FDR of the secondary allocation table, if any. No secondary allocation table is denoted by 0. Secondary allocations are present only for unbounded files." */ - UINT16BE rfa; /* record number of first alias */ - UINT32BE eom; /* end of medium record number */ - UINT32BE bkm; /* end of medium block number */ - UINT16BE ofm; /* end of medium offset / */ - /* 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 ud[6]; /* last update date */ - UINT8 cd[6]; /* creation date */ - UINT8 apb; /* ADU's per block */ - UINT8 bpa; /* blocks per ADU */ - UINT16BE mrs; /* minimumu KIF record size */ - UINT8 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 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 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. -*/ -struct ti990_adr -{ - UINT16BE hkc; /* hask key count */ - UINT16BE hkv; /* hask key value */ - char fnm[8]; /* file name */ - char psw[4]; /* "password" (whatever it means) */ - UINT16BE flg; /* flags (same as fdr.flg) */ - UINT16BE fill00; /* *** physical record size */ - UINT16BE fill01; /* *** logical record size */ - UINT16BE fill02; /* *** primary allocation size */ - UINT16BE fill03; /* *** primary allocation address */ - UINT16BE fill04; /* *** secondary allocation size */ - UINT16BE fill05; /* *** secondary allocation address */ - UINT16BE rna; /* record number of next ADR */ - UINT16BE raf; /* record # of actual FDR (from 1 through dor.nrc) */ -}; - -/* - CDR record: variant of FDR for Channel - - The CDR is the permanent record of a channel. It is carried as an alias - of the program file in which the channel owner task resides. -*/ -struct ti990_cdr -{ - UINT16BE hkc; /* hask key count */ - UINT16BE hkv; /* hask key value */ - char fnm[8]; /* file name */ - UINT16BE fill00; /* reserved */ - UINT16BE fill01; /* reserved */ - UINT16BE fdf; /* flags (same as fdr.flg) */ - UINT8 flg; /* channel flzgs */ - UINT8 iid; /* owner task installed ID */ - UINT8 typ; /* default resource type */ - UINT8 tf; /* resource type flags */ - UINT16BE mxl; /* maximum message length */ - UINT8 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 fill05[110]; /* reserved */ - char uid[8]; /* user ID of channel creator */ - UINT16BE psa; /* public security attribute */ - UINT8 scg[94]; /* "SDT with 9 control groups" (whatever it means - and, no, 94 is not dividable by 9) */ - UINT8 fill06[8]; /* reserved */ -}; - -/* - Based on contents of the flags field, catalog entries may be either an FDR, - an ADR or a CDR. - - They may be a KDR, too, but confusion is impossible because the KDR FILL00 - field starts at offset 4, and therefore if we try to interpret a KDR as an - FDR (or ADR, CDR), we will find fnm[0] and assume the FDR is empty. -*/ -union directory_entry -{ - ti990_fdr fdr; - ti990_adr adr; - ti990_cdr cdr; -}; - -#if 0 - -/* - tifile header: stand-alone file -*/ -struct tifile_header -{ - char tifiles[8]; /* always '\7TIFILES' */ - UINT8 secsused_MSB; /* file length in sectors (big-endian) */ - UINT8 secsused_LSB; - UINT8 flags; /* see enum above */ - UINT8 recspersec; /* records per sector */ - UINT8 eof; /* current position of eof in last sector (0->255)*/ - UINT8 reclen; /* bytes per record ([1,255] 0->256) */ - UINT8 fixrecs_MSB; /* file length in records (big-endian) */ - UINT8 fixrecs_LSB; - UINT8 res[128-16]; /* reserved */ -}; - - -/* - catalog entry (used for in-memory catalog) -*/ -struct catalog_entry -{ - UINT16 fdr_secnum; - char filename[10]; -}; - -#endif - -/* - Disk geometry -*/ -struct ti990_geometry -{ - unsigned int cylinders, heads, sectors_per_track, bytes_per_sector; -}; - -/* - Physical sector address -*/ -struct ti990_phys_sec_address -{ - int cylinder; - int head; - int sector; -}; - -/* - ti99 disk image descriptor -*/ -struct ti990_image -{ - imgtool_stream *file_handle; /* imgtool file handle */ - ti990_geometry geometry; /* geometry */ - ti990_sc0 sec0; /* cached copy of sector 0 */ -}; - -/* - ti990 catalog iterator, used when imgtool reads the catalog -*/ -struct ti990_iterator -{ - ti990_image *image; - int level; /* current recursion level */ - int nrc[MAX_DIR_LEVEL]; /* length of disk catalogs in records */ - int index[MAX_DIR_LEVEL]; /* current index in the disk catalog */ - directory_entry xdr[MAX_DIR_LEVEL]; /* fdr records */ -}; - - -static imgtoolerr_t ti990_image_init(imgtool_image *img, imgtool_stream *f); -static void ti990_image_exit(imgtool_image *img); -static void ti990_image_info(imgtool_image *img, char *string, size_t len); -static imgtoolerr_t ti990_image_beginenum(imgtool_directory *enumeration, const char *path); -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 *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, option_resolution *writeoptions); -static imgtoolerr_t ti990_image_deletefile(imgtool_partition *partition, const char *fpath); -#endif -static imgtoolerr_t ti990_image_create(imgtool_image *image, imgtool_stream *f, option_resolution *createoptions); - -enum -{ - /*ti990_createopts_volname = 'A',*/ - ti990_createopts_cylinders = 'B', - ti990_createopts_heads = 'C', - ti990_createopts_sectors = 'D', - ti990_createopts_sectorsize = 'E' -}; - -static OPTION_GUIDE_START( ti990_create_optionguide ) - /*OPTION_STRING(ti990_createopts_volname, "label", "Volume name" )*/ - OPTION_INT(ti990_createopts_cylinders, "cylinders", "Cylinders" ) - OPTION_INT(ti990_createopts_heads, "heads", "Heads" ) - OPTION_INT(ti990_createopts_sectors, "sectors", "Sectors" ) - OPTION_INT(ti990_createopts_sectorsize, "bytes per sector (typically 256)", "Bytes Per Sector" ) -OPTION_GUIDE_END - -#define symb2str2(a) #a -#define symb2str(a) symb2str2(a) -#define ti990_create_optionspecs "B1-[145]-" symb2str(MAX_CYLINDERS)";C1-[4]-" symb2str(MAX_HEADS)";D1-[32]-" symb2str(MAX_SECTORS_PER_TRACK)";E" symb2str(MIN_SECTOR_SIZE)"-[256]-" symb2str(MAX_SECTOR_SIZE)";" - -void ti990_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info) -{ - switch(state) - { - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "ti990hd"); break; - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "TI990 Hard Disk"); break; - case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "hd"); break; - case IMGTOOLINFO_STR_EOLN: /* strcpy(info->s = imgtool_temp_str(), "\r"); */ break; - - case IMGTOOLINFO_PTR_OPEN: info->open = ti990_image_init; break; - case IMGTOOLINFO_PTR_CLOSE: info->close = ti990_image_exit; break; - case IMGTOOLINFO_PTR_INFO: info->info = ti990_image_info; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = ti990_image_beginenum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = ti990_image_nextenum; break; - case IMGTOOLINFO_PTR_CLOSE_ENUM: info->close_enum = ti990_image_closeenum; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = ti990_image_freespace; break; - case IMGTOOLINFO_PTR_READ_FILE: /* info->read_file = ti990_image_readfile; */ break; - case IMGTOOLINFO_PTR_WRITE_FILE: /* info->write_file = ti990_image_writefile; */ break; - case IMGTOOLINFO_PTR_DELETE_FILE: /* info->delete_file = ti990_image_deletefile; */ break; - case IMGTOOLINFO_PTR_CREATE: info->create = ti990_image_create; break; - - case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = ti990_create_optionguide; break; - case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), ti990_create_optionspecs); break; - } -} - -#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) -{ - int i; - - - i = 0; - - /* copy 8 characters at most */ - if (src) - while ((i<8) && (src[i]!='\0')) - { - dst[i] = src[i]; - i++; - } - - /* pad with spaces */ - while (i<8) - { - dst[i] = ' '; - i++; - } -} -#endif - -/* - Convert a 8-character file name to a C string (removing trailing spaces if necessary) -*/ -static void fname_to_str(char *dst, const char src[8], int n) -{ - int i; - int last_nonspace; - - - /* copy 8 characters at most */ - if (--n > 8) - n = 8; - - /* copy filename */ - i = 0; - last_nonspace = -1; - - while (i<n) - { - dst[i] = src[i]; - if (src[i] != ' ') - last_nonspace = i; - i++; - } - - /* terminate with '\0' */ - dst[last_nonspace+1] = '\0'; -} - -#if 0 -#pragma mark - -#pragma mark DISK ROUTINES -#endif - -/* - Convert physical sector address to offset -*/ -static unsigned phys_address_to_offset(const ti990_phys_sec_address *address, const ti990_geometry *geometry) -{ - unsigned offset; - - /* current MESS format */ - offset = (((address->cylinder*geometry->heads) + address->head)*geometry->sectors_per_track + address->sector)*geometry->bytes_per_sector + header_len; - - return offset; -} - -/* - Read one sector from a disk image - - file_handle: imgtool file handle - address: physical sector address - geometry: disk geometry (sectors per track, tracks per side, sides) - dest: pointer to destination buffer - len: length of data to read -*/ -static int read_sector_physical_len(imgtool_stream *file_handle, const ti990_phys_sec_address *address, const ti990_geometry *geometry, void *dest, int len) -{ - int reply; - - if (len > geometry->bytes_per_sector) - return 1; - - /* seek to sector */ - reply = stream_seek(file_handle, phys_address_to_offset(address, geometry), SEEK_SET); - if (reply) - return 1; - /* read it */ - reply = stream_read(file_handle, dest, len); - if (reply != len) - return 1; - - return 0; -} - -#ifdef UNUSED_FUNCTION -/* - Read one sector from a disk image - - file_handle: imgtool file handle - address: physical sector address - 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) -{ - return read_sector_physical_len(file_handle, address, geometry, dest, geometry->bytes_per_sector); -} -#endif - -/* - Write one sector to a disk image - - file_handle: imgtool file handle - address: physical sector address - geometry: disk geometry (sectors per track, tracks per side, sides) - src: pointer to source buffer - len: length of source buffer -*/ -static int write_sector_physical_len(imgtool_stream *file_handle, const ti990_phys_sec_address *address, const ti990_geometry *geometry, const void *src, int len) -{ - int reply; - - if (len > geometry->bytes_per_sector) - return 1; - - /* seek to sector */ - reply = stream_seek(file_handle, phys_address_to_offset(address, geometry), SEEK_SET); - if (reply) - return 1; - /* write it */ - reply = stream_write(file_handle, src, len); - if (reply != len) - return 1; - /* pad with 0s if needed */ - if (len < geometry->bytes_per_sector) - { - reply = stream_fill(file_handle, 0, geometry->bytes_per_sector - len); - - if (reply != geometry->bytes_per_sector - len) - return 1; - } - - return 0; -} - -#ifdef UNUSED_FUNCTION -/* - Write one sector to a disk image - - file_handle: imgtool file handle - address: physical sector address - 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) -{ - return write_sector_physical_len(file_handle, address, geometry, src, geometry->bytes_per_sector); -} -#endif - -/* - Convert logical sector address to physical sector address -*/ -static void log_address_to_phys_address(int secnum, const ti990_geometry *geometry, ti990_phys_sec_address *address) -{ - address->sector = secnum % geometry->sectors_per_track; - secnum /= geometry->sectors_per_track; - address->head = secnum % geometry->heads; - address->cylinder = secnum / geometry->heads; -} - -/* - Read one sector from a disk image - - file_handle: imgtool file handle - secnum: logical sector address - geometry: disk geometry (sectors per track, tracks per side, sides) - dest: pointer to destination buffer - len: length of data to read -*/ -static int read_sector_logical_len(imgtool_stream *file_handle, int secnum, const ti990_geometry *geometry, void *dest, int len) -{ - ti990_phys_sec_address address; - - - log_address_to_phys_address(secnum, geometry, &address); - - return read_sector_physical_len(file_handle, &address, geometry, dest, len); -} - -#ifdef UNUSED_FUNCTION -/* - Read one sector from a disk image - - file_handle: imgtool file handle - secnum: logical sector address - 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) -{ - return read_sector_logical_len(file_handle, secnum, geometry, dest, geometry->bytes_per_sector); -} -#endif - -/* - Write one sector to a disk image - - file_handle: imgtool file handle - secnum: logical sector address - geometry: disk geometry (sectors per track, tracks per side, sides) - src: pointer to source buffer - len: length of source buffer -*/ -static int write_sector_logical_len(imgtool_stream *file_handle, int secnum, const ti990_geometry *geometry, const void *src, int len) -{ - ti990_phys_sec_address address; - - - log_address_to_phys_address(secnum, geometry, &address); - - return write_sector_physical_len(file_handle, &address, geometry, src, len); -} - -/* - Write one sector to a disk image - - file_handle: imgtool file handle - secnum: logical sector address - 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_logical(imgtool_stream *file_handle, int secnum, const ti990_geometry *geometry, const void *src) -{ - return write_sector_logical_len(file_handle, secnum, geometry, src, geometry->bytes_per_sector); -} - -#if 0 -#pragma mark - -#pragma mark CATALOG FILE ROUTINES -#endif - -#ifdef UNUSED_FUNCTION -/* - Find the catalog entry and fdr record associated with a file name - - image: ti990_image image record - fpath: path of the file to search - fdr: pointer to buffer where the fdr record should be stored (may be NULL) - catalog_index: on output, index of file catalog entry (may be NULL) - out_fdr_secnum: on output, sector address of the fdr (may be NULL) - 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) -{ - int fdr_secnum = -1, parent_fdr_secnum; - int i; - const char *element_start, *element_end; - int element_len; - char element[8]; - ti990_dor dor; - directory_entry xdr; - int hash_key; - int nrc; - unsigned base; - int reply; - int flag; - - - base = (unsigned) get_UINT16BE(image->sec0.vda) * get_UINT16BE(image->sec0.spa); - - element_start = fpath; - do - { - /* read directory header */ - reply = read_sector_logical_len(image->file_handle, base, & image->geometry, &dor, sizeof(dor)); - if (reply) - return IMGTOOLERR_READERROR; - - nrc = get_UINT16BE(dor.nrc); - - /* find next path element */ - element_end = strchr(element_start, '.'); - element_len = element_end ? (element_end - element_start) : strlen(element_start); - if ((element_len > 8) || (element_len == 0)) - return IMGTOOLERR_BADFILENAME; - /* generate file name and hash key */ - hash_key = 1; - for (i=0; i<element_len; i++) - { - element[i] = element_start[i]; - hash_key = ((hash_key * (unsigned char) element_start[i]) % nrc) + 1; - } - while (i<8) - { - element[i] = ' '; - i++; - } - - /* search entry in directory */ - i = hash_key; - while (1) - { - reply = read_sector_logical_len(image->file_handle, base + i, & image->geometry, - & xdr, 0x86); - if (reply) - return IMGTOOLERR_READERROR; - if (!memcmp(element, xdr.fdr.fnm, 8)) - { /* found match !!! */ - parent_fdr_secnum = fdr_secnum; - fdr_secnum = base + i; - break; - } - - /* next record */ - if (i != nrc) - i++; - else - i = 1; - - /* exit if we have tested every record */ - if (i == hash_key) - return IMGTOOLERR_FILENOTFOUND; - } - - /* iterate */ - if (element_end) - { - element_start = element_end+1; - /* we need to check that this is a directory */ - /* if it is an alias to a directory, we need to follow it, too. */ - - /* parse flags */ - flag = get_UINT16BE(xdr.fdr.flg); - - if (flag & fdr_flg_ali) - { - /* read original fdr */ - reply = read_sector_logical_len(image->file_handle, base + get_UINT16BE(xdr.adr.raf), - & image->geometry, & xdr, 0x86); - - flag = get_UINT16BE(xdr.fdr.flg); - } - - if (flag & fdr_flg_cdr) - /* This is a channel, not a file */ - return IMGTOOLERR_BADFILENAME; - else if (flag & fdr_flg_ali) - /* WTH??? */ - return IMGTOOLERR_CORRUPTIMAGE; - else if (((flag >> fdr_flg_fu_shift) & 3) != 1) - { - /* This file is not a directory */ - return IMGTOOLERR_BADFILENAME; - } - - /* initialize base */ - base = (unsigned) get_UINT16BE(xdr.fdr.paa) * get_UINT16BE(image->sec0.spa); - } - else - element_start = NULL; - } - while (element_start); - - if (catalog_index) - *catalog_index = i; - - if (out_fdr_secnum) - *out_fdr_secnum = fdr_secnum; - - if (out_parent_fdr_secnum) - *out_parent_fdr_secnum = parent_fdr_secnum; - - return 0; -} -#endif - -#if 0 -/* - Allocate one sector on disk, for use as a fdr record - - image: ti99_image image record - fdr_secnum: on output, logical address of a free sector -*/ -static int alloc_fdr_sector(ti99_image *image, int *fdr_secnum) -{ - int totsecs = (image->sec0.totsecsMSB << 8) | image->sec0.totsecsLSB; - int i; - - - for (i=0; i<totsecs; i++) - { - if (! (image->sec0.abm[i >> 3] & (1 << (i & 7)))) - { - *fdr_secnum = i; - image->sec0.abm[i >> 3] |= 1 << (i & 7); - - return 0; - } - } - - return IMGTOOLERR_NOSPACE; -} - -/* - Extend a file with nb_alloc_sectors extra sectors - - image: ti99_image image record - fdr: file fdr record - nb_alloc_sectors: number of sectors to allocate -*/ -static int alloc_file_sectors(ti99_image *image, ti99_fdr *fdr, int nb_alloc_sectors) -{ - int totsecs = (image->sec0.totsecsMSB << 8) | image->sec0.totsecsLSB; - int free_sectors; - int secsused; - int i; - int lnks_index; - int cur_sec, last_sec, p_last_sec; - int cur_block_len, cur_block_start; - int first_best_block_len, first_best_block_start = 0; - int second_best_block_len, second_best_block_start = 0; - int search_start; - - /* compute free space */ - free_sectors = 0; - for (i=0; i<totsecs; i++) - { - if (! (image->sec0.abm[i >> 3] & (1 << (i & 7)))) - free_sectors++; - } - - /* check we have enough free space */ - if (free_sectors < nb_alloc_sectors) - return IMGTOOLERR_NOSPACE; - - /* current number of data sectors in file */ - secsused = get_fdr_secsused(fdr); - - if (secsused == 0) - { /* links array must be empty */ - lnks_index = 0; - } - else - { /* try to extend last block */ - last_sec = -1; - for (lnks_index=0; lnks_index<76; lnks_index++) - { - p_last_sec = last_sec; - last_sec = (fdr->lnks[lnks_index][2] << 4) | (fdr->lnks[lnks_index][1] >> 4); - if (last_sec >= (secsused-1)) - break; - } - if (lnks_index == 76) - /* that sucks */ - return IMGTOOLERR_CORRUPTIMAGE; - - if (last_sec > (secsused-1)) - { /* some extra space has already been allocated */ - cur_block_len = last_sec - (secsused-1); - if (cur_block_len > nb_alloc_sectors) - cur_block_len = nb_alloc_sectors; - - secsused += cur_block_len; - set_fdr_secsused(fdr, secsused); - nb_alloc_sectors -= cur_block_len; - if (! nb_alloc_sectors) - return 0; /* done */ - } - - /* block base */ - cur_sec = ((fdr->lnks[lnks_index][1] & 0xf) << 8) | fdr->lnks[lnks_index][0]; - /* point past block end */ - cur_sec += last_sec-p_last_sec; - /* count free sectors after last block */ - cur_block_len = 0; - for (i=cur_sec; (! (image->sec0.abm[i >> 3] & (1 << (i & 7)))) && (cur_block_len < nb_alloc_sectors) && (i < totsecs); i++) - cur_block_len++; - if (cur_block_len) - { /* extend last block */ - secsused += cur_block_len; - set_fdr_secsused(fdr, secsused); - last_sec += cur_block_len; - nb_alloc_sectors -= cur_block_len; - fdr->lnks[lnks_index][1] = (fdr->lnks[lnks_index][1] & 0x0f) | (last_sec << 4); - fdr->lnks[lnks_index][2] = last_sec >> 4; - for (i=0; i<cur_block_len; i++) - image->sec0.abm[(i+cur_sec) >> 3] |= 1 << ((i+cur_sec) & 7); - if (! nb_alloc_sectors) - return 0; /* done */ - } - lnks_index++; - if (lnks_index == 76) - /* that sucks */ - return IMGTOOLERR_NOSPACE; - } - - search_start = image->data_offset; /* initially, search for free space only in data space */ - while (nb_alloc_sectors) - { - /* find smallest data block at least nb_alloc_sectors in length, and largest data block less than nb_alloc_sectors in length */ - first_best_block_len = INT_MAX; - second_best_block_len = 0; - for (i=search_start; i<totsecs; i++) - { - if (! (image->sec0.abm[i >> 3] & (1 << (i & 7)))) - { /* found one free block */ - /* compute its length */ - cur_block_start = i; - cur_block_len = 0; - while ((i<totsecs) && (! (image->sec0.abm[i >> 3] & (1 << (i & 7))))) - { - cur_block_len++; - i++; - } - /* compare to previous best and second-best blocks */ - if ((cur_block_len < first_best_block_len) && (cur_block_len >= nb_alloc_sectors)) - { - first_best_block_start = cur_block_start; - first_best_block_len = cur_block_len; - if (cur_block_len == nb_alloc_sectors) - /* no need to search further */ - break; - } - else if ((cur_block_len > second_best_block_len) && (cur_block_len < nb_alloc_sectors)) - { - second_best_block_start = cur_block_start; - second_best_block_len = cur_block_len; - } - } - } - - if (first_best_block_len != INT_MAX) - { /* found one contiguous block which can hold it all */ - secsused += nb_alloc_sectors; - set_fdr_secsused(fdr, secsused); - - fdr->lnks[lnks_index][0] = first_best_block_start; - fdr->lnks[lnks_index][1] = ((first_best_block_start >> 8) & 0x0f) | ((secsused-1) << 4); - fdr->lnks[lnks_index][2] = (secsused-1) >> 4; - for (i=0; i<nb_alloc_sectors; i++) - image->sec0.abm[(i+first_best_block_start) >> 3] |= 1 << ((i+first_best_block_start) & 7); - - nb_alloc_sectors = 0; - } - else if (second_best_block_len != 0) - { /* jeez, we need to fragment it. We use the largest smaller block to limit fragmentation. */ - secsused += second_best_block_len; - set_fdr_secsused(fdr, secsused); - - fdr->lnks[lnks_index][0] = second_best_block_start; - fdr->lnks[lnks_index][1] = ((second_best_block_start >> 8) & 0x0f) | ((secsused-1) << 4); - fdr->lnks[lnks_index][2] = (secsused-1) >> 4; - for (i=0; i<second_best_block_len; i++) - image->sec0.abm[(i+second_best_block_start) >> 3] |= 1 << ((i+second_best_block_start) & 7); - - nb_alloc_sectors -= second_best_block_len; - - lnks_index++; - if (lnks_index == 76) - /* that sucks */ - return IMGTOOLERR_NOSPACE; - } - else if (search_start != 0) - { /* we did not find any free sector in the data section of the disk */ - search_start = 0; /* time to fall back to fdr space */ - } - else - return IMGTOOLERR_NOSPACE; /* This should never happen, as we pre-check that there is enough free space */ - } - - return 0; -} - -/* - Allocate a new (empty) file -*/ -static int new_file(ti99_image *image, char filename[10], int *out_fdr_secnum/*, ti99_fdr *fdr,*/) -{ - int fdr_secnum; - int catalog_index, i; - int reply = 0; - - - /* find insertion point in catalog */ - i = 0; - if ((image->catalog[0].fdr_secnum == 0) && (image->catalog[1].fdr_secnum != 0)) - i = 1; /* skip empty entry 0 (it must be a non-listable catalog) */ - - for (; (i<128) && ((fdr_secnum = image->catalog[i].fdr_secnum) != 0) && ((reply = memcmp(image->catalog[i].filename, filename, 10)) < 0); i++) - ; - - if (i == 128) - /* catalog is full */ - return IMGTOOLERR_NOSPACE; - else if (fdr_secnum && (reply == 0)) - /* file already exists */ - return IMGTOOLERR_BADFILENAME; - else - { - catalog_index = i; - reply = alloc_fdr_sector(image, &fdr_secnum); - if (reply) - return reply; - - /* look for first free entry in catalog */ - for (i=catalog_index; image->catalog[i].fdr_secnum != 0; i++) - ; - - if (i == 128) - /* catalog is full */ - return IMGTOOLERR_NOSPACE; - - /* shift catalog entries until the insertion point */ - for (/*i=127*/; i>catalog_index; i--) - image->catalog[i] = image->catalog[i-1]; - - /* write new catalog entry */ - image->catalog[catalog_index].fdr_secnum = fdr_secnum; - memcpy(image->catalog[catalog_index].filename, filename, 10); - if (out_fdr_secnum) - *out_fdr_secnum = fdr_secnum; - } - - return 0; -} - -/* - Compare two (possibly empty) catalog entry for qsort -*/ -static int qsort_catalog_compare(const void *p1, const void *p2) -{ - const catalog_entry *entry1 = p1; - const catalog_entry *entry2 = p2; - - if ((entry1->fdr_secnum == 0) && (entry2->fdr_secnum == 0)) - return 0; - else if (entry1->fdr_secnum == 0) - return +1; - else if (entry2->fdr_secnum == 0) - return -1; - else - return memcmp(entry1->filename, entry2->filename, 10); -} -#endif - -/* - Open a file as a ti990_image. -*/ -static imgtoolerr_t ti990_image_init(imgtool_image *img, imgtool_stream *f) -{ - ti990_image *image = (ti990_image *) imgtool_image_extra_bytes(img); - disk_image_header header; - int reply; - unsigned totsecs; - - image->file_handle = f; - reply = stream_read(f, &header, sizeof(header)); - if (reply != sizeof(header)) - return IMGTOOLERR_READERROR; - - image->geometry.cylinders = get_UINT32BE(header.cylinders); - image->geometry.heads = get_UINT32BE(header.heads); - image->geometry.sectors_per_track = get_UINT32BE(header.sectors_per_track); - image->geometry.bytes_per_sector = get_UINT32BE(header.bytes_per_sector); - - totsecs = image->geometry.cylinders*image->geometry.heads*image->geometry.sectors_per_track; - - if ((image->geometry.bytes_per_sector < MIN_SECTOR_SIZE) - || (image->geometry.bytes_per_sector > MAX_SECTOR_SIZE) - || (image->geometry.sectors_per_track > MAX_SECTORS_PER_TRACK) - || (image->geometry.heads > MAX_HEADS) - || (image->geometry.cylinders > MAX_CYLINDERS) - || (totsecs < 1) - || (stream_size(f) != header_len + totsecs*image->geometry.bytes_per_sector)) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - - { - ti990_phys_sec_address address = { 0, 0, 0 }; - reply = read_sector_physical_len(f, &address, &image->geometry, & image->sec0, sizeof(image->sec0)); - } - if (reply) - { - return IMGTOOLERR_READERROR; - } - - if ((get_UINT16BE(image->sec0.tna)*get_UINT16BE(image->sec0.spa) > totsecs) - || ((get_UINT16BE(image->sec0.spa) != 1) && (get_UINT16BE(image->sec0.spa) % 3))) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - - if ((get_UINT16BE(image->sec0.vpl) != 0x86) && (get_UINT16BE(image->sec0.vpl) != 0x100)) - { - return IMGTOOLERR_CORRUPTIMAGE; - } - - return IMGTOOLERR_SUCCESS; -} - -/* - close a ti990_image -*/ -static void ti990_image_exit(imgtool_image *img) -{ - ti990_image *image = (ti990_image *) imgtool_image_extra_bytes(img); - stream_close(image->file_handle); -} - -/* - get basic information on a ti990_image - - Currently returns the volume name -*/ -static void ti990_image_info(imgtool_image *img, char *string, size_t len) -{ - ti990_image *image = (ti990_image *) imgtool_image_extra_bytes(img); - char vol_name[9]; - - fname_to_str(vol_name, image->sec0.vnm, 9); - - snprintf(string, len, "%s", vol_name); -} - -/* - Open the disk catalog for enumeration -*/ -static imgtoolerr_t ti990_image_beginenum(imgtool_directory *enumeration, const char *path) -{ - ti990_image *image = (ti990_image *) imgtool_image_extra_bytes(imgtool_directory_image(enumeration)); - ti990_iterator *iter = (ti990_iterator *) imgtool_directory_extrabytes(enumeration); - ti990_dor dor; - int reply; - - iter->image = image; - - reply = read_sector_logical_len(iter->image->file_handle, - (unsigned) get_UINT16BE(iter->image->sec0.vda) * get_UINT16BE(iter->image->sec0.spa), - & iter->image->geometry, &dor, sizeof(dor)); - - if (reply) - return IMGTOOLERR_READERROR; - - iter->level = 0; - iter->nrc[0] = get_UINT16BE(dor.nrc); - iter->index[0] = 0; - - return IMGTOOLERR_SUCCESS; -} - -/* - Enumerate disk catalog next entry -*/ -static imgtoolerr_t ti990_image_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent) -{ - ti990_iterator *iter = (ti990_iterator *) imgtool_directory_extrabytes(enumeration); - int flag; - int reply = 0; - - - ent->corrupt = 0; - ent->eof = 0; - - while ((iter->level >= 0) - && (! (reply = read_sector_logical_len(iter->image->file_handle, - iter->level ? (unsigned) get_UINT16BE(iter->xdr[iter->level-1].fdr.paa) * get_UINT16BE(iter->image->sec0.spa) + (iter->index[iter->level]+1) - : (unsigned) get_UINT16BE(iter->image->sec0.vda) * get_UINT16BE(iter->image->sec0.spa) + (iter->index[iter->level]+1), - & iter->image->geometry, &iter->xdr[iter->level], - iter->level ? get_UINT16BE(iter->xdr[iter->level-1].fdr.prs) - : get_UINT16BE(iter->image->sec0.vpl)))) - && (iter->xdr[iter->level].fdr.fnm[0] == 0)) - { - iter->index[iter->level]++; - while (iter->index[iter->level] >= iter->nrc[iter->level]) - iter->level--; - } - - if (iter->level < 0) - { - ent->eof = 1; - } - else if (reply) - return IMGTOOLERR_READERROR; - else - { -#if 0 - fname_to_str(ent->filename, iter->xdr[iter->level].fdr.fnm, ARRAY_LENGTH(ent->filename)); -#else - { - int i; - char buf[9]; - - ent->filename[0] = '\0'; - 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); - } - fname_to_str(buf, iter->xdr[iter->level].fdr.fnm, 9); - strncat(ent->filename, buf, ARRAY_LENGTH(ent->filename) - 1); - } -#endif - - /* parse flags */ - flag = get_UINT16BE(iter->xdr[iter->level].fdr.flg); - if (flag & fdr_flg_cdr) - { - snprintf(ent->attr, ARRAY_LENGTH(ent->attr), "CHANNEL"); - - ent->filesize = 0; - } - else if (flag & fdr_flg_ali) - { - ti990_fdr target_fdr; - char buf[9]; - - reply = read_sector_logical_len(iter->image->file_handle, - iter->level ? ((unsigned) get_UINT16BE(iter->xdr[iter->level-1].fdr.paa) * get_UINT16BE(iter->image->sec0.spa) + get_UINT16BE(iter->xdr[iter->level].adr.raf)) - : ((unsigned) get_UINT16BE(iter->image->sec0.vda) * get_UINT16BE(iter->image->sec0.spa) + get_UINT16BE(iter->xdr[iter->level].adr.raf)), - & iter->image->geometry, &target_fdr, - iter->level ? get_UINT16BE(iter->xdr[iter->level-1].fdr.prs) - : get_UINT16BE(iter->image->sec0.vpl)); - - fname_to_str(buf, target_fdr.fnm, 9); - - snprintf(ent->attr, ARRAY_LENGTH(ent->attr), "ALIAS OF %s", buf); - - ent->filesize = 0; - } - else - { - const char *fmt, *type; - - switch ((flag >> fdr_flg_fmt_shift) & 3) - { - case 0: - fmt = "NBS"; - break; - case 1: - fmt = "BS "; - break; - default: - fmt = "???"; - break; - } - - switch ((flag >> fdr_flg_fu_shift) & 3) - { - case 1: - type = "DIR"; - break; - case 2: - type = "PRO"; - break; - case 3: - type = "IMG"; - break; - default: - switch ((flag >> fdr_flg_ft_shift) & 3) - { - case 1: - type = "SEQ"; - break; - case 2: - type = "REL"; - break; - case 3: - type = "KIF"; - break; - default: - type = "???"; - break; - } - break; - } - snprintf(ent->attr, ARRAY_LENGTH(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" : "", - (flag & fdr_flg_wpb) ? " WPT" : "", - (flag & fdr_flg_dpb) ? " DPT" : ""); - - /* len in blocks */ - ent->filesize = get_UINT32BE(iter->xdr[iter->level].fdr.bkm); - if ((((flag >> fdr_flg_ft_shift) & 3) == 3) || get_UINT16BE(iter->xdr[iter->level].fdr.ofm)) - ent->filesize++; - - /* convert to ADUs */ - if (iter->xdr[iter->level].fdr.apb > 1) - /* more than one ADU per block */ - ent->filesize *= iter->xdr[iter->level].fdr.apb; - else if (iter->xdr[iter->level].fdr.bpa > 1) - /* more than one block per ADU */ - ent->filesize = (ent->filesize + iter->xdr[iter->level].fdr.bpa - 1) / iter->xdr[iter->level].fdr.bpa; - } - iter->index[iter->level]++; - - if (get_UINT16BE(iter->xdr[iter->level].fdr.saa) != 0) - printf("roupoupou"); - else - { - int i; - for (i=0; i<64; i++) - if (iter->xdr[iter->level].fdr.sat[i]) - { - printf("roupoupou"); - break; - } - } - - /* recurse subdirectory if applicable */ - if ((((flag >> fdr_flg_fu_shift) & 3) == 1) - && (! (flag & fdr_flg_ali)) - && (! (flag & fdr_flg_cdr)) - && (iter->level < MAX_DIR_LEVEL) - && ! ((iter->level == 0) && ! memcmp(iter->xdr[iter->level].fdr.fnm, "VCATALOG", 8))) - { - ti990_dor dor; - - if (get_UINT16BE(iter->xdr[iter->level].fdr.saa) != 0) - printf("ninou"); - - read_sector_logical_len(iter->image->file_handle, - get_UINT16BE(iter->xdr[iter->level].fdr.paa) * get_UINT16BE(iter->image->sec0.spa), - & iter->image->geometry, &dor, sizeof(dor)); - - iter->level++; - iter->nrc[iter->level] = get_UINT16BE(dor.nrc)/*get_UINT32BE(iter->fdr[iter->level-1].eom)-1*/; - iter->index[iter->level] = 0; -#if 0 - if (get_UINT16BE(dor.nrc) != (get_UINT32BE(iter->xdr[iter->level-1].fdr.eom)-1)) - printf("hiha"); -#endif - } - - /* go to upper level if applicable */ - while (iter->index[iter->level] >= iter->nrc[iter->level]) - iter->level--; - } - - return (imgtoolerr_t)0; -} - -/* - Free enumerator -*/ -static void ti990_image_closeenum(imgtool_directory *enumeration) -{ -} - -/* - Compute free space on disk image (in ADUs) -*/ -static imgtoolerr_t ti990_image_freespace(imgtool_partition *partition, UINT64 *size) -{ - imgtool_image *img = imgtool_partition_image(partition); - ti990_image *image = (ti990_image *) imgtool_image_extra_bytes(img); - int totadus = get_UINT16BE(image->sec0.tna); - int adu, record, sub_adu; - char buf[256]; - size_t freeadus = 0; - - if ((totadus+2031)/2032 != image->sec0.tbm) - /*return IMGTOOLERR_CORRUPTIMAGE;*/ - return (imgtoolerr_t)0; - - adu = 0; - record = 0; - sub_adu = 0; - while (adu<totadus) - { - read_sector_logical_len(image->file_handle, image->sec0.sbm + record, &image->geometry, buf, sizeof(buf)); - - while ((adu < totadus) && (sub_adu < 2032)) - { - if (! (buf[(sub_adu >> 3) + 2] & (1 << (sub_adu & 7)))) - freeadus++; - sub_adu++; - adu++; - } - sub_adu = 0; - record++; - } - - * size = freeadus; - - 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 = imgtool_partition_image(partition); - ti990_image *image = (ti990_image *) imgtool_image_extra_bytes(img); - int catalog_index, fdr_secnum, parent_fdr_secnum; - imgtoolerr_t reply; - - - reply = find_fdr(image, fpath, &catalog_index, &fdr_secnum, &parent_fdr_secnum); - if (reply) - return reply; - - /* ... */ - - return 0; - -#if 0 - ti99_image *image = (ti99_image*) img; - int totsecs = (image->sec0.totsecsMSB << 8) | image->sec0.totsecsLSB; - char ti_fname[10]; - ti99_fdr fdr; - tifile_header dst_header; - int i, lnks_index; - int cur_sec, last_sec; - int secsused; - UINT8 buf[256]; - int reply; - - str_to_fname(ti_fname, filename); - - reply = find_fdr(image, ti_fname, &fdr, NULL); - if (reply) - return reply; - - dst_header.tifiles[0] = '\7'; - dst_header.tifiles[1] = 'T'; - dst_header.tifiles[2] = 'I'; - dst_header.tifiles[3] = 'F'; - dst_header.tifiles[4] = 'I'; - dst_header.tifiles[5] = 'L'; - dst_header.tifiles[6] = 'E'; - dst_header.tifiles[7] = 'S'; - dst_header.secsused_MSB = fdr.secsused_MSB; - dst_header.secsused_LSB = fdr.secsused_LSB; - dst_header.flags = fdr.flags; - dst_header.recspersec = fdr.recspersec; - dst_header.eof = fdr.eof; - dst_header.reclen = fdr.reclen; - dst_header.fixrecs_MSB = fdr.fixrecs_MSB; - dst_header.fixrecs_LSB = fdr.fixrecs_LSB; - for (i=0; i<(128-14); i++) - dst_header.res[i] = 0; - - if (stream_write(destf, & dst_header, 128) != 128) - return IMGTOOLERR_WRITEERROR; - - - secsused = get_fdr_secsused(&fdr); - - i = 0; /* file logical sector #0 */ - lnks_index = 0; /* start of file block table */ - while (i<secsused) - { - if (lnks_index == 76) - return IMGTOOLERR_CORRUPTIMAGE; - - /* read curent file block table entry */ - cur_sec = ((fdr.lnks[lnks_index][1] & 0xf) << 8) | fdr.lnks[lnks_index][0]; - last_sec = (fdr.lnks[lnks_index][2] << 4) | (fdr.lnks[lnks_index][1] >> 4); - - /* copy current file block */ - while ((i<=last_sec) && (i<secsused)) - { - if (cur_sec >= totsecs) - return IMGTOOLERR_CORRUPTIMAGE; - - if (read_sector_logical(image->file_handle, cur_sec, & image->geometry, buf)) - return IMGTOOLERR_READERROR; - - if (stream_write(destf, buf, 256) != 256) - return IMGTOOLERR_WRITEERROR; - - i++; - cur_sec++; - } - - /* next entry in file block table */ - lnks_index++; - } - - return 0; -#endif -} - -/* - Add a file to a ti990_image. -*/ -static imgtoolerr_t ti990_image_writefile(imgtool_partition *partition, const char *fpath, imgtool_stream *sourcef, option_resolution *writeoptions) -{ - imgtool_image *img = imgtool_partition_image(partition); - ti990_image *image = (ti990_image *) imgtool_image_extra_bytes(img); - int catalog_index, fdr_secnum, parent_fdr_secnum; - imgtoolerr_t reply; - - - /* check that file does not exist */ - reply = find_fdr(image, fpath, &catalog_index, &fdr_secnum, &parent_fdr_secnum); - if ((reply) && (reply != IMGTOOLERR_FILENOTFOUND)) - return reply; - - /* ... */ - - return 0; - -#if 0 - ti99_image *image = (ti99_image*) img; - int totsecs = (image->sec0.totsecsMSB << 8) | image->sec0.totsecsLSB; - char ti_fname[10]; - ti99_fdr fdr; - tifile_header src_header; - int i, lnks_index; - int cur_sec, last_sec; - int secsused; - UINT8 buf[256]; - int reply; - int fdr_secnum; - - str_to_fname(ti_fname, filename); - - reply = find_fdr(image, ti_fname, &fdr, NULL); - if (reply == 0) - { /* file already exists: causes an error for now */ - return IMGTOOLERR_UNEXPECTED; - } - else if (reply != IMGTOOLERR_FILENOTFOUND) - { - return reply; - } - - if (stream_read(sourcef, & src_header, 128) != 128) - return IMGTOOLERR_READERROR; - - /* create new file */ - reply = new_file(image, ti_fname, &fdr_secnum); - if (reply) - return reply; - - memcpy(fdr.name, ti_fname, 10); - fdr.res10[1] = fdr.res10[0] = 0; - fdr.flags = src_header.flags; - fdr.recspersec = src_header.recspersec; - fdr.secsused_MSB = /*src_header.secsused_MSB*/0; - fdr.secsused_LSB = /*src_header.secsused_LSB*/0; - fdr.eof = src_header.eof; - fdr.reclen = src_header.reclen; - fdr.fixrecs_LSB = src_header.fixrecs_LSB; - fdr.fixrecs_MSB = src_header.fixrecs_MSB; - for (i=0; i<8; i++) - fdr.res20[i] = 0; - for (i=0; i<76; i++) - fdr.lnks[i][2] = fdr.lnks[i][1] = fdr.lnks[i][0] = 0; - - /* alloc data sectors */ - secsused = (src_header.secsused_MSB << 8) | src_header.secsused_LSB; - reply = alloc_file_sectors(image, &fdr, secsused); - if (reply) - return reply; - - /* copy data */ - i = 0; - lnks_index = 0; - while (i<secsused) - { - if (lnks_index == 76) - return IMGTOOLERR_CORRUPTIMAGE; - - cur_sec = ((fdr.lnks[lnks_index][1] & 0xf) << 8) | fdr.lnks[lnks_index][0]; - last_sec = (fdr.lnks[lnks_index][2] << 4) | (fdr.lnks[lnks_index][1] >> 4); - - while ((i<secsused) && (i<=last_sec)) - { - if (cur_sec >= totsecs) - return IMGTOOLERR_CORRUPTIMAGE; - - if (stream_read(sourcef, buf, 256) != 256) - return IMGTOOLERR_READERROR; - - if (write_sector_logical(image->file_handle, cur_sec, & image->geometry, buf)) - return IMGTOOLERR_WRITEERROR; - - i++; - cur_sec++; - } - - lnks_index++; - } - - /* write fdr */ - if (write_sector_logical(image->file_handle, fdr_secnum, & image->geometry, &fdr)) - return IMGTOOLERR_WRITEERROR; - - /* update catalog */ - for (i=0; i<128; i++) - { - buf[2*i] = image->catalog[i].fdr_secnum >> 8; - buf[2*i+1] = image->catalog[i].fdr_secnum & 0xff; - } - if (write_sector_logical(image->file_handle, 1, & image->geometry, buf)) - return IMGTOOLERR_WRITEERROR; - - /* update bitmap */ - if (write_sector_logical(image->file_handle, 0, & image->geometry, &image->sec0)) - return IMGTOOLERR_WRITEERROR; - - return 0; -#endif -} - -/* - Delete a file from a ti990_image. -*/ -static imgtoolerr_t ti990_image_deletefile(imgtool_partition *partition, const char *fpath) -{ - imgtool_image *img = imgtool_partition_image(partition); - ti990_image *image = (ti990_image *) imgtool_image_extra_bytes(img); - int catalog_index, fdr_secnum, parent_fdr_secnum; - imgtoolerr_t reply; - - - reply = find_fdr(image, fpath, &catalog_index, &fdr_secnum, &parent_fdr_secnum); - if (reply) - return reply; - - /* ... */ - - return 0; - -#if 0 - ti99_image *image = (ti99_image*) img; - int totsecs = (image->sec0.totsecsMSB << 8) | image->sec0.totsecsLSB; - char ti_fname[10]; - ti99_fdr fdr; - int i, lnks_index; - int cur_sec, last_sec; - int secsused; - int catalog_index; - int reply; - UINT8 buf[256]; - - str_to_fname(ti_fname, filename); - - reply = find_fdr(image, ti_fname, &fdr, &catalog_index); - if (reply) - return reply; - - /* free data sectors */ - secsused = get_fdr_secsused(&fdr); - - i = 0; - lnks_index = 0; - while (i<secsused) - { - if (lnks_index == 76) - return IMGTOOLERR_CORRUPTIMAGE; - - cur_sec = ((fdr.lnks[lnks_index][1] & 0xf) << 8) | fdr.lnks[lnks_index][0]; - last_sec = (fdr.lnks[lnks_index][2] << 4) | (fdr.lnks[lnks_index][1] >> 4); - - while ((i<secsused) && (i<=last_sec)) - { - if (cur_sec >= totsecs) - return IMGTOOLERR_CORRUPTIMAGE; - - image->sec0.abm[cur_sec >> 3] &= ~ (1 << (cur_sec & 7)); - - i++; - cur_sec++; - } - - lnks_index++; - } - - /* free fdr sector */ - image->sec0.abm[image->catalog[catalog_index].fdr_secnum >> 3] &= ~ (1 << (image->catalog[catalog_index].fdr_secnum & 7)); - - /* delete catalog entry */ - for (i=catalog_index; i<127; i++) - image->catalog[i] = image->catalog[i+1]; - image->catalog[127].fdr_secnum = 0; - - /* update catalog */ - for (i=0; i<128; i++) - { - buf[2*i] = image->catalog[i].fdr_secnum >> 8; - buf[2*i+1] = image->catalog[i].fdr_secnum & 0xff; - } - if (write_sector_logical(image->file_handle, 1, & image->geometry, buf)) - return IMGTOOLERR_WRITEERROR; - - /* update bitmap */ - if (write_sector_logical(image->file_handle, 0, & image->geometry, &image->sec0)) - return IMGTOOLERR_WRITEERROR; - - return 0; -#endif -} -#endif - -/* - Create a blank ti990_image. -*/ -static imgtoolerr_t ti990_image_create(imgtool_image *image, imgtool_stream *f, option_resolution *createoptions) -{ - //const char *volname; - ti990_geometry geometry; - unsigned totsecs; - disk_image_header header; - ti990_sc0 sec0; - UINT8 empty_sec[MAX_SECTOR_SIZE]; - int reply; - int i; - - /* read options */ - //volname = option_resolution_lookup_string(createoptions, ti990_createopts_volname); - geometry.cylinders = option_resolution_lookup_int(createoptions, ti990_createopts_cylinders); - geometry.heads = option_resolution_lookup_int(createoptions, ti990_createopts_heads); - geometry.sectors_per_track = option_resolution_lookup_int(createoptions, ti990_createopts_sectors); - geometry.bytes_per_sector = option_resolution_lookup_int(createoptions, ti990_createopts_sectorsize); - - totsecs = geometry.cylinders * geometry.heads * geometry.sectors_per_track; - - /* write header */ - set_UINT32BE(& header.cylinders, geometry.cylinders); - set_UINT32BE(& header.heads, geometry.heads); - set_UINT32BE(& header.sectors_per_track, geometry.sectors_per_track); - set_UINT32BE(& header.bytes_per_sector, geometry.bytes_per_sector); - - reply = stream_write(f, &header, sizeof(header)); - if (reply != sizeof(header)) - { - return IMGTOOLERR_WRITEERROR; - } - - - /* initialize sector 0 */ - /* mark disk as uninitialized */ - set_UINT16BE(& sec0.sta, 2); - - - /* write sector 0 */ - if (write_sector_logical(f, 0, & geometry, &sec0)) - return IMGTOOLERR_WRITEERROR; - - - /* now clear every other sector, including catalog */ - memset(empty_sec, 0, geometry.bytes_per_sector); - - for (i=1; i<totsecs; i++) - if (write_sector_logical(f, i, & geometry, empty_sec)) - return IMGTOOLERR_WRITEERROR; - - return (imgtoolerr_t)0; -} diff --git a/src/mess/tools/imgtool/modules/vzdos.c b/src/mess/tools/imgtool/modules/vzdos.c deleted file mode 100644 index bacaa448ef8..00000000000 --- a/src/mess/tools/imgtool/modules/vzdos.c +++ /dev/null @@ -1,960 +0,0 @@ -// license:GPL-2.0+ -// copyright-holders:Dirk Best -/**************************************************************************** - - vzdos.c - - Laser/VZ disk images - -****************************************************************************/ - -#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 "iflopimg.h" - -/* - -sector format - -| GAP1 | IDAM | GAP2 | DATA | CHECKSUM | ... - -GAP1 = 80 80 80 80 80 00 6 -IDAM = FE E7 18 C3 Track# Sector# Checksum-8 of prev. 2 bytes 7 -GAP2 = 80 80 80 80 80 80 00 C3 18 E7 FE 11 -DATA = 126 bytes actual data 126 - = nextTrack# nextSector# 2 -CHECKSUM = Checksum-16 of the previous 128 bytes 2 - --- - 154 bytes - -sectors 0 to 14 are used for the disk directory. sector 15 is used -as track map, with one bit for each sector used. - -*/ - -#define DATA_SIZE (126) -#define SECTOR_SIZE (0x9b) -#define MAX_DIRENTS (15*8) - -/* vzdos directry entry */ -struct vzdos_dirent -{ - char ftype; - char delimitor; - char fname[8]; - UINT8 start_track; - UINT8 start_sector; - UINT16 start_address; - UINT16 end_address; -}; - -struct vz_iterator -{ - int index; - int eof; -}; - -static const UINT8 sector_order[] = -{ - 0, 3, 6, 9, 12, 15, 2, 5, 8, 11, 14, 1, 4, 7, 10, 13 -}; - -/********************************************************************* - Internal functions -*********************************************************************/ - -/* get length of filename without trailing spaces */ -static int vzdos_get_fname_len(const char *fname) -{ - int len; - - for (len = 7; len > 0; len--) - if (fname[len] != 0x20) - break; - - return len; -} - -/* calculate checksum-16 of buffer */ -static UINT16 chksum16(UINT8 *buffer, int len) -{ - int i; - UINT16 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) -{ - imgtoolerr_t ret; - UINT8 buffer[25]; /* enough to read the sector header */ - - ret = (imgtoolerr_t)floppy_read_sector(imgtool_floppy(img), 0, track, sector_order[sector], 0, &buffer, sizeof(buffer)); - if (ret) return ret; - - /* search for start of data */ - if (memcmp(buffer + 19, "\xC3\x18\xE7\xFE", 4) == 0) - *start = 23; - else if (memcmp(buffer + 20, "\xC3\x18\xE7\xFE", 4) == 0) - *start = 24; - else if (memcmp(buffer + 21, "\xC3\x18\xE7\xFE", 4) == 0) - *start = 25; - else - return IMGTOOLERR_CORRUPTIMAGE; - - return IMGTOOLERR_SUCCESS; -} - -/* return the actual data of a sector */ -static imgtoolerr_t vzdos_read_sector_data(imgtool_image *img, int track, int sector, UINT8 *data) -{ - int ret, data_start; - UINT8 buffer[DATA_SIZE + 4]; /* data + checksum */ - - ret = vzdos_get_data_start(img, track, sector, &data_start); - if (ret) return (imgtoolerr_t)ret; - - ret = floppy_read_sector(imgtool_floppy(img), 0, track, sector_order[sector], data_start, &buffer, sizeof(buffer)); - if (ret) return (imgtoolerr_t)ret; - - /* verify sector checksums */ - if (pick_integer_le(buffer, DATA_SIZE + 2, 2) != chksum16(buffer, DATA_SIZE + 2)) - return IMGTOOLERR_CORRUPTFILE; - - memcpy(data, &buffer, DATA_SIZE + 2); - - return IMGTOOLERR_SUCCESS; -} - -/* write data to sector */ -static imgtoolerr_t vzdos_write_sector_data(imgtool_image *img, int track, int sector, UINT8 *data) -{ - int ret, data_start; - UINT8 buffer[DATA_SIZE + 4]; /* data + checksum */ - - ret = vzdos_get_data_start(img, track, sector, &data_start); - 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)); - - 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; - - return IMGTOOLERR_SUCCESS; -} - -/* write formatted empty sector */ -static imgtoolerr_t vzdos_clear_sector(imgtool_image *img, int track, int sector) -{ - UINT8 data[DATA_SIZE + 2]; - - memset(data, 0x00, sizeof(data)); - - return vzdos_write_sector_data(img, track, sector, data); -} - -/* 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 buffer[DATA_SIZE + 2]; - - ret = vzdos_read_sector_data(img, 0, (int) index / 8, buffer); - if (ret) return (imgtoolerr_t)ret; - - 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); - - if (ent->ftype == 0x00) - return IMGTOOLERR_FILENOTFOUND; - - /* check values */ - if (ent->start_track > 39) - return IMGTOOLERR_CORRUPTFILE; - - if (ent->start_sector > 15) - return IMGTOOLERR_CORRUPTFILE; - - return IMGTOOLERR_SUCCESS; -} - -/* save a directory entry to disk */ -static imgtoolerr_t vzdos_set_dirent(imgtool_image *img, int index, vzdos_dirent ent) -{ - int ret, entry; - UINT8 buffer[DATA_SIZE + 2]; - - /* read current sector with entries */ - ret = vzdos_read_sector_data(img, 0, (int) index / 8, buffer); - if (ret) return (imgtoolerr_t)ret; - - 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); - - /* save new sector */ - ret = vzdos_write_sector_data(img, 0, (int) index / 8, buffer); - if (ret) return (imgtoolerr_t)ret; - - return IMGTOOLERR_SUCCESS; -} - -/* 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; -} - -/* 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]; - - /* check for invalid filenames */ - if (strlen(fname) > 8) - return IMGTOOLERR_BADFILENAME; - - /* TODO: check for invalid characters */ - - *entry = -1; - - for (i = 0; i < MAX_DIRENTS; i++) { - ret = vzdos_get_dirent(image, i, &ent); - if (ret) return (imgtoolerr_t)ret; - - len = vzdos_get_fname_len(ent.fname) + 1; - - if (strlen(fname) != len) - continue; - - memset(filename, 0x00, sizeof(filename)); - memcpy(filename, ent.fname, len); - - if (!core_stricmp(fname, filename)) { - *entry = i; - break; - } - - } - - if (*entry == -1) - return IMGTOOLERR_FILENOTFOUND; - - return IMGTOOLERR_SUCCESS; -} - -/* return a directory entry for a filename */ -static imgtoolerr_t vzdos_get_dirent_fname(imgtool_image *img, const char *fname, vzdos_dirent *ent) -{ - int ret, index; - - ret = vzdos_searchentry(img, fname, &index); - if (ret) return (imgtoolerr_t)ret; - - ret = vzdos_get_dirent(img, index, ent); - if (ret) return (imgtoolerr_t)ret; - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t vzdos_toggle_trackmap(imgtool_image *img, int track, int sector, int clear) -{ - int ret, value, bit; - UINT8 buffer[DATA_SIZE + 2]; - - /* get trackmap from image */ - ret = vzdos_read_sector_data(img, 0, 15, buffer); - if (ret) return (imgtoolerr_t)ret; - - value = (int) (floor(((double)track * 16 + sector) / 8) - 1); - bit = 0x01 << ((track * 16 + sector) % 8); - - if (clear) - buffer[value-1] &= ~bit; - else - buffer[value-1] |= bit; - - ret = vzdos_write_sector_data(img, 0, 15, buffer); - if (ret) return (imgtoolerr_t)ret; - - return IMGTOOLERR_SUCCESS; -} - -/* clear a trackmap entry */ -static imgtoolerr_t vzdos_clear_trackmap(imgtool_image *img, int track, int sector) -{ - return vzdos_toggle_trackmap(img, track, sector, 1); -} - -/* enable a trackmap entry */ -static imgtoolerr_t vzdos_set_trackmap(imgtool_image *img, int track, int sector) -{ - return vzdos_toggle_trackmap(img, track, sector, 0); -} - -/* return the status of a trackmap entry */ -static imgtoolerr_t vzdos_get_trackmap(imgtool_image *img, int track, int sector, int *used) -{ - int ret, value, bit; - UINT8 buffer[DATA_SIZE + 2]; - - /* get trackmap from image */ - ret = vzdos_read_sector_data(img, 0, 15, buffer); - if (ret) return (imgtoolerr_t)ret; - - value = (int) (floor(((double)track * 16 + sector) / 8) - 1); - bit = 0x01 << ((track * 16 + sector) % 8); - - if (buffer[value-1] & bit) - *used = 1; - else - *used = 0; - - return IMGTOOLERR_SUCCESS; -} - -/* return the next free sector */ -static imgtoolerr_t vzdos_free_trackmap(imgtool_image *img, int *track, int *sector) -{ - int ret, used = 0; - - for (*track = 1; *track < 40; (*track)++) { - for (*sector = 0; *sector < 16; (*sector)++) { - ret = vzdos_get_trackmap(img, *track, *sector, &used); - if (ret) return (imgtoolerr_t)ret; - if (!used) return IMGTOOLERR_SUCCESS; - } - } - - return IMGTOOLERR_NOSPACE; -} - -static imgtoolerr_t vzdos_write_formatted_sector(imgtool_image *img, int track, int sector) -{ - int ret; - UINT8 sector_data[DATA_SIZE + 4 + 24]; - - static const UINT8 sector_header[24] = { - 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0xFE, 0xE7, - 0x18, 0xC3, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x00, 0xC3, 0x18, 0xE7, 0xFE - }; - - memset(sector_data, 0x00, sizeof(sector_data)); - memcpy(sector_data, sector_header, sizeof(sector_header)); - - sector_data[10] = (UINT8) track; /* current track */ - sector_data[11] = (UINT8) sector; /* current sector */ - sector_data[12] = (UINT8) 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; - - return IMGTOOLERR_SUCCESS; -} - -/********************************************************************* - Imgtool module code -*********************************************************************/ - -static imgtoolerr_t vzdos_diskimage_beginenum(imgtool_directory *enumeration, const char *path) -{ - vz_iterator *iter; - - iter = (vz_iterator *) imgtool_directory_extrabytes(enumeration); - if (!iter) return IMGTOOLERR_OUTOFMEMORY; - - iter->index = 1; - iter->eof = 0; - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t vzdos_diskimage_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent) -{ - vz_iterator *iter = (vz_iterator *) imgtool_directory_extrabytes(enumeration); - - if (iter->eof == 1 || iter->index > MAX_DIRENTS) { - ent->eof = 1; - - } else { - const char *type; - int ret, len; - vzdos_dirent dirent; - - ret = vzdos_get_dirent(imgtool_directory_image(enumeration), iter->index - 1, &dirent); - - if (ret == IMGTOOLERR_FILENOTFOUND) - { - iter->eof = 1; - ent->eof = 1; - return IMGTOOLERR_SUCCESS; - } - - if (ret == IMGTOOLERR_CORRUPTFILE) - ent->corrupt = 1; - - /* kill trailing spaces */ - for (len = 7; len > 0; len--) { - if (dirent.fname[len] != 0x20) { - break; - } - } - - memcpy(ent->filename, &dirent.fname, len + 1); - ent->filesize = dirent.end_address - dirent.start_address; - - switch (dirent.ftype) - { - case 0x01: type = "Deleted"; break; - case 'T': type = "Basic"; break; - case 'B': type = "Binary"; break; - case 'D': type = "Data"; break; - case 'F': type = "Quickwrite"; break; - case 'A': type = "Assembler"; break; - case 'S': type = "Diskops"; break; - case 'W': type = "Wordpro"; break; - default: type = "Unknown"; - } - - snprintf(ent->attr, ARRAY_LENGTH(ent->attr), "%s", type); - - iter->index++; - } - - return IMGTOOLERR_SUCCESS; -} - -/* TRK 0 sector 15 is used to hold the track map of the disk with one bit - corresponding to a sector used. */ -static imgtoolerr_t vzdos_diskimage_freespace(imgtool_partition *partition, UINT64 *size) -{ - imgtoolerr_t ret; - int i; - imgtool_image *image = imgtool_partition_image(partition); - UINT8 c, v, buffer[DATA_SIZE + 2]; - *size = 0; - - ret = vzdos_read_sector_data(image, 0, 15, buffer); - if (ret) return ret; - - for (i = 0; i < DATA_SIZE; i++) { - v = buffer[i]; - for (c = 0; v; c++) { - v &= v - 1; - } - *size += c * DATA_SIZE; - } - *size = (DATA_SIZE * 16 * 39) - *size; - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t vzdos_diskimage_readfile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf) -{ - imgtoolerr_t ret; - imgtool_image *image = imgtool_partition_image(partition); - int filesize, track, sector; - vzdos_dirent ent; - UINT8 buffer[DATA_SIZE + 2]; - - ret = vzdos_get_dirent_fname(image, filename, &ent); - if (ret) return ret; - - filesize = ent.end_address - ent.start_address; - track = ent.start_track; - sector = ent.start_sector; - - while (filesize > 0) { - int towrite; - - ret = vzdos_read_sector_data(image, track, sector, buffer); - 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))) - 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 0 is invalid */ - if ((track == 0) && (filesize > DATA_SIZE)) - return IMGTOOLERR_CORRUPTIMAGE; - - /* write either DATA_SIZE or the remaining bytes */ - towrite = filesize > DATA_SIZE ? DATA_SIZE : filesize; - - if (stream_write(destf, buffer, towrite) != towrite) - return IMGTOOLERR_WRITEERROR; - - filesize -= DATA_SIZE; - } - - return IMGTOOLERR_SUCCESS; -} - -/* deletes directory entry, clears trackmap entries and sectors */ -static imgtoolerr_t vzdos_diskimage_deletefile(imgtool_partition *partition, const char *fname) -{ - imgtoolerr_t ret; - imgtool_image *img = imgtool_partition_image(partition); - int index, filesize, track, sector, next_track, next_sector; - vzdos_dirent entry, next_entry; - UINT8 buffer[DATA_SIZE + 2]; - - ret = vzdos_get_dirent_fname(img, fname, &entry); - if (ret) return ret; - - ret = (imgtoolerr_t)floppy_read_sector(imgtool_floppy(img), 0, entry.start_track, sector_order[entry.start_sector], 24, &buffer, DATA_SIZE + 2); - if (ret) return ret; - - filesize = entry.end_address - entry.start_address; - track = entry.start_track; - sector = entry.start_sector; - - /* delete directory entry */ - ret = vzdos_searchentry(img, fname, &index); - if (ret) return ret; - - ret = vzdos_get_dirent(img, index + 1, &next_entry); - - if (ret == IMGTOOLERR_FILENOTFOUND) { - /* we are the last directory entry, just delete it */ - ret = vzdos_clear_dirent(img, index); - if (ret) return ret; - - } else if (ret) { - /* an error occurred */ - return ret; - - } else { - ret = vzdos_set_dirent(img, index++, next_entry); - if (ret) return ret; - - while ((ret = vzdos_get_dirent(img, index + 1, &next_entry)) != IMGTOOLERR_FILENOTFOUND) { - if (ret) return ret; - ret = vzdos_set_dirent(img, index++, next_entry); - if (ret) return ret; - } - - ret = vzdos_clear_dirent(img, index); - if (ret) return ret; - - } - - /* clear sectors and trackmap entries */ - while (filesize > 0) { - filesize -= DATA_SIZE; - - /* clear trackmap entry */ - ret = vzdos_clear_trackmap(img, track, sector); - 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); - - /* overwrite sector with default values */ - ret = vzdos_clear_sector(img, track, sector); - if (ret) return ret; - - /* read next sector */ - track = next_track; - sector = next_sector; - - if (filesize > 0) { - ret = (imgtoolerr_t)floppy_read_sector(imgtool_floppy(img), 0, track, sector_order[sector], 24, &buffer, DATA_SIZE + 2); - if (ret) return ret; - } - - } - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t vzdos_writefile(imgtool_partition *partition, int offset, imgtool_stream *sourcef, vzdos_dirent *entry) -{ - imgtoolerr_t ret; - imgtool_image *img = imgtool_partition_image(partition); - int index, track, sector, toread, next_track, next_sector; - vzdos_dirent temp_entry; - UINT64 filesize = 0, freespace = 0; - UINT8 buffer[DATA_SIZE + 2]; - char filename[9]; - - /* is the image writeable? */ - if (floppy_is_read_only(imgtool_floppy(img))) - return IMGTOOLERR_READONLY; - - /* check for already existing filename -> overwrite */ - strcpy(filename, entry->fname); - filename[vzdos_get_fname_len(entry->fname) + 1] = 0x00; - ret = vzdos_get_dirent_fname(img, filename, &temp_entry); - if (!ret) { - /* file already exists, delete it */ - ret = vzdos_diskimage_deletefile(partition, filename); - if (ret) return ret; - } else if (ret != IMGTOOLERR_FILENOTFOUND) { - /* another error occurred, return it */ - return ret; - } - - ret = (imgtoolerr_t)stream_seek(sourcef, offset, SEEK_SET); - if (ret) return ret; - - /* check if there is enough space */ - filesize = stream_size(sourcef) - offset; - - ret = vzdos_diskimage_freespace(partition, &freespace); - if (ret) return ret; - - if (filesize > freespace) - return IMGTOOLERR_NOSPACE; - - /* get next free track and sector */ - ret = vzdos_free_trackmap(img, &track, §or); - if (ret) return ret; - - entry->end_address = entry->start_address + (unsigned int) filesize; - entry->start_track = track; - entry->start_sector = sector; - - /* search for next free directory entry */ - for (index = 0; index < MAX_DIRENTS; index++) { - ret = vzdos_get_dirent(img, index, &temp_entry); - if (ret == IMGTOOLERR_FILENOTFOUND) - break; - else if (ret) - return (ret); - } - - /* write directory entry to disk */ - ret = vzdos_set_dirent(img, index, *entry); - if (ret) return ret; - - next_track = 0; - next_sector = 0; - - /* write data to disk */ - while (filesize > 0) { - toread = filesize > DATA_SIZE ? DATA_SIZE : filesize; - stream_read(sourcef, buffer, toread); - - filesize -= toread; - - /* mark sector as used */ - ret = vzdos_set_trackmap(img, track, sector); - if (ret) return ret; - - /* get track and sector for next sector */ - if (filesize > 0) { - ret = vzdos_free_trackmap(img, &next_track, &next_sector); - if (ret) return ret; - } else { - next_track = 0; - next_sector = 0; - } - buffer[DATA_SIZE] = next_track; - buffer[DATA_SIZE + 1] = next_sector; - - /* write sector to disk */ - ret = vzdos_write_sector_data(img, track, sector, buffer); - if (ret) return ret; - - track = next_track; - sector = next_sector; - } - - return IMGTOOLERR_SUCCESS; - -} - -/* 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, option_resolution *opts) -{ - imgtoolerr_t ret; - int ftype; - vzdos_dirent entry; - - /* TODO: check for leading spaces and strip */ - if (strlen(filename) > 8 || strlen(filename) < 1) - return IMGTOOLERR_BADFILENAME; - - /* prepare directory entry */ - ftype = option_resolution_lookup_int(opts, 'T'); - - switch (ftype) { - case 0: - entry.ftype = 'T'; - entry.start_address = 31465; - break; - case 1: - entry.ftype = 'B'; - entry.start_address = 31465; /* ??? */ - break; - case 2: - entry.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)); - - /* write file to disk */ - ret = vzdos_writefile(partition, 0, sourcef, &entry); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - -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 = imgtool_partition_image(partition); - vzdos_dirent entry; - - if (fname) { - ret = vzdos_get_dirent_fname(image, fname, &entry); - if (ret) return ret; - - switch (entry.ftype) { - case 'B': - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = filter_vzsnapshot_getinfo; - suggestions[0].description = "VZ Snapshot"; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = NULL; - suggestions[1].description = "Raw"; - break; - case 'T': - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = filter_vzsnapshot_getinfo; - suggestions[0].description = "VZ Snapshot"; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = NULL; - suggestions[1].description = "Raw"; - suggestions[2].viability = 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].description = "Raw"; - } - - } else { - suggestions[0].viability = SUGGESTION_RECOMMENDED; - suggestions[0].filter = NULL; - suggestions[0].description = "Raw"; - suggestions[1].viability = SUGGESTION_POSSIBLE; - suggestions[1].filter = filter_vzsnapshot_getinfo; - suggestions[1].description = "VZ Snapshot"; - } - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t vzdos_diskimage_create(imgtool_image *img, imgtool_stream *stream, option_resolution *opts) -{ - imgtoolerr_t ret; - int track, sector; - - for (track = 0; track < 40; track++) { - for (sector = 0; sector < 16; sector++) { - ret = vzdos_write_formatted_sector(img, track, sector); - if (ret) return ret; - } - } - - return IMGTOOLERR_SUCCESS; -} - -/********************************************************************* - Imgtool vz filter code -*********************************************************************/ - -static imgtoolerr_t vzsnapshot_readfile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf) -{ - imgtoolerr_t ret; - imgtool_image *image = imgtool_partition_image(partition); - vzdos_dirent entry; - UINT8 header[24]; - - /* get directory entry from disk */ - ret = vzdos_get_dirent_fname(image, filename, &entry); - if (ret) return ret; - - /* prepare header */ - header[0] = 'V'; - header[1] = 'Z'; - header[2] = 'F'; - - switch (entry.ftype) { - case 'B': - header[3] = '1'; - header[21] = 0xF1; - break; - case 'T': - header[3] = '0'; - header[21] = 0xF0; - break; - default: - memset(header, 0x00, 4); - header[21] = 0x00; - } - - 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); - - /* write header to file */ - stream_write(destf, header, sizeof(header)); - - /* write data to file */ - ret = vzdos_diskimage_readfile(partition, filename, "", destf); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - -static imgtoolerr_t vzsnapshot_writefile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, option_resolution *opts) -{ - imgtoolerr_t ret; - int fnameopt; - vzdos_dirent entry; - UINT8 header[24]; - - /* get header infos from file */ - stream_read(sourcef, header, sizeof(header)); - - /* prepare directory entry */ - entry.ftype = header[21] == 0xF1 ? 'B' : 'T'; - entry.delimitor = ':'; - entry.start_address = pick_integer_le(header, 22, 2); - - /* filename from header or directly? */ - fnameopt = option_resolution_lookup_int(opts, 'F'); - - if (fnameopt == 0) { - memcpy(&entry.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); - } - - /* write file to disk */ - ret = vzdos_writefile(partition, 24, sourcef, &entry); - if (ret) return ret; - - return IMGTOOLERR_SUCCESS; -} - -void filter_vzsnapshot_getinfo(UINT32 state, union filterinfo *info) -{ - switch(state) - { - case FILTINFO_STR_NAME: info->s = "vzsnapshot"; break; - case FILTINFO_STR_HUMANNAME: info->s = "VZ Snapshot"; break; - case FILTINFO_STR_EXTENSION: info->s = "vz"; break; - case FILTINFO_PTR_READFILE: info->read_file = vzsnapshot_readfile; break; - case FILTINFO_PTR_WRITEFILE: info->write_file = vzsnapshot_writefile; break; - } -} - -/********************************************************************* - Imgtool module declaration -*********************************************************************/ - -static OPTION_GUIDE_START(vzdos_writefile_optionguide) - OPTION_ENUM_START( 'T', "ftype", "File type" ) - OPTION_ENUM( 0, "basic", "Basic" ) - OPTION_ENUM( 1, "binary", "Binary" ) - OPTION_ENUM( 2, "data", "Data" ) - OPTION_ENUM_END - OPTION_ENUM_START( 'F', "fname", "Filename" ) - OPTION_ENUM( 0, "intern", "Filename from VZ-Header" ) - OPTION_ENUM( 1, "extern", "Actual filename" ) - OPTION_ENUM_END -OPTION_GUIDE_END - -/* -T Basic Editor File -B Binary File -D Sequential Access Program Data File -F Quickwrite Document -A Russell Harrison's Edit Ass. File -S Dave Mitchell/Mark Hardwood Edit Ass. File Start Addr A280H -S Quickwrite/Diskops System File/Label Except Above -W Edit Ass. with Diskops File Start Addr A813H -W E & F Word Pro with Patch 3.3 File End Addr D000H -W Russell Harrison Word Pro File Except above two -*/ - -void vzdos_get_info(const imgtool_class *imgclass, UINT32 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(vz_iterator); break; - - /* --- the following bits of info are returned as NULL-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; - - /* --- 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_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; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = vzdos_diskimage_readfile; break; - case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = vzdos_diskimage_writefile; break; - case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = vzdos_diskimage_deletefile; break; - case IMGTOOLINFO_PTR_FLOPPY_CREATE: info->create = vzdos_diskimage_create; break; - case IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE: info->writefile_optguide = vzdos_writefile_optionguide; break; - case IMGTOOLINFO_PTR_SUGGEST_TRANSFER: info->suggest_transfer = vzdos_diskimage_suggesttransfer; break; - case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_vz; break; - } -} diff --git a/src/mess/tools/imgtool/stream.c b/src/mess/tools/imgtool/stream.c deleted file mode 100644 index 5c9cf4050c6..00000000000 --- a/src/mess/tools/imgtool/stream.c +++ /dev/null @@ -1,536 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - stream.c - - Code for implementing Imgtool streams - -***************************************************************************/ - -#include <stdio.h> -#include <string.h> -#include <zlib.h> - -#include "unzip.h" -#include "osdcore.h" -#include "imgtool.h" - -enum imgtype_t -{ - IMG_FILE, - IMG_MEM -}; - -struct imgtool_stream -{ - imgtype_t imgtype; - int write_protect; - const char *name; // needed for clear - UINT64 position; - UINT64 filesize; - - union - { - core_file *file; - UINT8 *buffer; - } u; -}; - - - -static imgtool_stream *stream_open_zip(const char *zipname, const char *subname, int read_or_write) -{ - imgtool_stream *imgfile = NULL; -// zip_error ziperr; - zip_file *z = NULL; - const zip_file_header *zipent; - FILE *f; - - if (read_or_write) - goto error; - - /* check to see if the file exists */ - f = fopen(zipname, "r"); - if (!f) - goto error; - fclose(f); - - imgfile = (imgtool_stream *)malloc(sizeof(imgtool_stream)); - if (!imgfile) - goto error; - - memset(imgfile, 0, sizeof(*imgfile)); - imgfile->imgtype = IMG_MEM; - imgfile->write_protect = 1; - imgfile->position = 0; - -// ziperr = - zip_file_open(zipname, &z); - if (!z) - goto error; - - zipent = zip_file_first_file(z); - while(zipent && subname && strcmp(subname, zipent->filename)) - zipent = zip_file_next_file(z); - if (!zipent) - goto error; - - imgfile->filesize = zipent->uncompressed_length; - imgfile->u.buffer = (UINT8*)malloc(zipent->uncompressed_length); - if (!imgfile->u.buffer) - goto error; - - if (zip_file_decompress(z, imgfile->u.buffer, zipent->uncompressed_length)) - goto error; - - zip_file_close(z); - return imgfile; - -error: - if (z) - zip_file_close(z); - if (imgfile) - { - if (imgfile->u.buffer) - free(imgfile->u.buffer); - free(imgfile); - } - return NULL; -} - - - -imgtool_stream *stream_open(const char *fname, int read_or_write) -{ - file_error filerr; - const char *ext; - imgtool_stream *imgfile = NULL; - static const UINT32 write_modes[] = - { - OPEN_FLAG_READ, - OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, - OPEN_FLAG_READ | OPEN_FLAG_WRITE, - OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE - }; - core_file *f = NULL; - char *buf = NULL; - int len, i; - imgtool_stream *s = NULL; - char c; - - /* maybe we are just a ZIP? */ - ext = strrchr(fname, '.'); - if (ext && !core_stricmp(ext, ".zip")) - return stream_open_zip(fname, NULL, read_or_write); - - filerr = core_fopen(fname, write_modes[read_or_write], &f); - if (filerr != FILERR_NONE) - { - if (!read_or_write) - { - len = strlen(fname); - - /* can't open the file; try opening ZIP files with other names */ - buf = (char*)malloc(len + 1); - if (!buf) - goto error; - strcpy(buf, fname); - - for(i = len-1; !s && (i >= 0); i--) - { - if ((buf[i] == '\\') || (buf[i] == '/')) - { - c = buf[i]; - buf[i] = '\0'; - s = stream_open_zip(buf, buf + i + 1, read_or_write); - buf[i] = c; - } - } - free(buf); - buf = NULL; - - if (s) - return s; - } - - /* ah well, it was worth a shot */ - goto error; - } - - imgfile = (imgtool_stream *)malloc(sizeof(imgtool_stream)); - if (!imgfile) - goto error; - - /* Normal file */ - memset(imgfile, 0, sizeof(*imgfile)); - imgfile->imgtype = IMG_FILE; - imgfile->position = 0; - imgfile->filesize = core_fsize(f); - imgfile->write_protect = read_or_write ? 0 : 1; - imgfile->u.file = f; - imgfile->name = fname; - return imgfile; - -error: - if (imgfile != NULL) - free((void *) imgfile); - if (f != NULL) - core_fclose(f); - if (buf) - free(buf); - return (imgtool_stream *) NULL; -} - - - -imgtool_stream *stream_open_write_stream(int size) -{ - imgtool_stream *imgfile; - - imgfile = (imgtool_stream *)malloc(sizeof(imgtool_stream)); - if (!imgfile) - return NULL; - - imgfile->imgtype = IMG_MEM; - imgfile->write_protect = 0; - imgfile->position = 0; - imgfile->filesize = size; - imgfile->u.buffer = (UINT8*)malloc(size); - - if (!imgfile->u.buffer) - { - free(imgfile); - return NULL; - } - - return imgfile; -} - - - -imgtool_stream *stream_open_mem(void *buf, size_t sz) -{ - imgtool_stream *imgfile; - - imgfile = (imgtool_stream *)malloc(sizeof(imgtool_stream)); - if (!imgfile) - return NULL; - - memset(imgfile, 0, sizeof(*imgfile)); - imgfile->imgtype = IMG_MEM; - imgfile->position = 0; - imgfile->write_protect = 0; - - imgfile->filesize = sz; - imgfile->u.buffer = (UINT8*)buf; - return imgfile; -} - - - -void stream_close(imgtool_stream *s) -{ - assert(s != NULL); - - switch(s->imgtype) - { - case IMG_FILE: - if (s->u.file != NULL) - { - core_fclose(s->u.file); - s->u.file = NULL; - } - break; - - case IMG_MEM: - if (s->u.buffer != NULL) - { - free(s->u.buffer); - s->u.buffer = NULL; - } - break; - - default: - assert(0); - break; - } - free((void *) s); -} - - - -core_file *stream_core_file(imgtool_stream *stream) -{ - return (stream->imgtype == IMG_FILE) ? stream->u.file : NULL; -} - - - -UINT32 stream_read(imgtool_stream *stream, void *buf, UINT32 sz) -{ - UINT32 result = 0; - - switch(stream->imgtype) - { - case IMG_FILE: - assert(sz == (UINT32) sz); - core_fseek(stream->u.file, stream->position, SEEK_SET); - result = core_fread(stream->u.file, buf, (UINT32) sz); - break; - - case IMG_MEM: - /* do we have to limit sz? */ - if (sz > (stream->filesize - stream->position)) - sz = (UINT32) (stream->filesize - stream->position); - - memcpy(buf, stream->u.buffer + stream->position, sz); - result = sz; - break; - - default: - assert(0); - break; - } - stream->position += result; - return result; -} - - - -UINT32 stream_write(imgtool_stream *s, const void *buf, UINT32 sz) -{ - void *new_buffer; - UINT32 result = 0; - - switch(s->imgtype) - { - case IMG_MEM: - if (!s->write_protect) - { - /* do we have to expand the buffer? */ - if (s->filesize < s->position + sz) - { - /* try to expand the buffer */ - if (s->u.buffer) free(s->u.buffer); - new_buffer = malloc(s->position + sz); - if (new_buffer) - { - s->u.buffer = (UINT8*)new_buffer; - s->filesize = s->position + sz; - } - } - - /* do we have to limit sz? */ - if (sz > (s->filesize - s->position)) - sz = (UINT32) (s->filesize - s->position); - - memcpy(s->u.buffer + s->position, buf, sz); - result = sz; - } - break; - - case IMG_FILE: - core_fseek(s->u.file, s->position, SEEK_SET); - result = core_fwrite(s->u.file, buf, sz); - break; - - default: - assert(0); - break; - } - - /* advance the file pointer */ - s->position += result; - - /* did we grow the file */ - if (s->position > s->filesize) - s->filesize = s->position; - return result; -} - - - -UINT64 stream_size(imgtool_stream *s) -{ - return s->filesize; -} - - - -void *stream_getptr(imgtool_stream *f) -{ - void *ptr; - - switch(f->imgtype) - { - case IMG_MEM: - ptr = f->u.buffer; - break; - - default: - ptr = NULL; - break; - } - return ptr; -} - - - -int stream_seek(imgtool_stream *s, INT64 pos, int where) -{ - UINT64 size; - - size = stream_size(s); - - switch(where) - { - case SEEK_CUR: - pos += s->position; - break; - case SEEK_END: - pos += size; - break; - } - - if (pos < 0) - s->position = 0; - else - s->position = MIN(size, pos); - - if (s->position < pos) - stream_fill(s, '\0', pos - s->position); - - return 0; -} - - - -UINT64 stream_tell(imgtool_stream *s) -{ - return s->position; -} - - - -UINT64 stream_transfer(imgtool_stream *dest, imgtool_stream *source, UINT64 sz) -{ - UINT64 result = 0; - UINT64 readsz; - char buf[1024]; - - while(sz && (readsz = stream_read(source, buf, MIN(sz, sizeof(buf))))) - { - stream_write(dest, buf, readsz); - sz -= readsz; - result += readsz; - } - return result; -} - - - -UINT64 stream_transfer_all(imgtool_stream *dest, imgtool_stream *source) -{ - return stream_transfer(dest, source, stream_size(source)); -} - - - -int stream_crc(imgtool_stream *s, unsigned long *result) -{ - size_t sz; - void *ptr; - - switch(s->imgtype) - { - case IMG_MEM: - *result = crc32(0, (unsigned char *) s->u.buffer, (size_t) s->filesize); - break; - - default: - sz = stream_size(s); - ptr = malloc(sz); - if (!ptr) - return IMGTOOLERR_OUTOFMEMORY; - stream_seek(s, 0, SEEK_SET); - if (stream_read(s, ptr, sz) != sz) - { - free(ptr); - return IMGTOOLERR_READERROR; - } - *result = crc32(0, (const Bytef*)ptr, sz); - free(ptr); - break; - } - return 0; -} - - - -int file_crc(const char *fname, unsigned long *result) -{ - int err; - imgtool_stream *f; - - f = stream_open(fname, OSD_FOPEN_READ); - if (!f) - return IMGTOOLERR_FILENOTFOUND; - - err = stream_crc(f, result); - stream_close(f); - return err; -} - - - -UINT64 stream_fill(imgtool_stream *f, unsigned char b, UINT64 sz) -{ - UINT64 outsz; - char buf[1024]; - - outsz = 0; - memset(buf, b, MIN(sz, sizeof(buf))); - - while(sz) - { - outsz += stream_write(f, buf, MIN(sz, sizeof(buf))); - sz -= MIN(sz, sizeof(buf)); - } - return outsz; -} - - - -int stream_isreadonly(imgtool_stream *s) -{ - return s->write_protect; -} - - - -UINT32 stream_putc(imgtool_stream *stream, char c) -{ - return stream_write(stream, &c, 1); -} - - - -UINT32 stream_puts(imgtool_stream *stream, const char *s) -{ - return stream_write(stream, s, strlen(s)); -} - - - -UINT32 stream_printf(imgtool_stream *stream, const char *fmt, ...) -{ - va_list va; - char buf[256]; - - va_start(va, fmt); - vsprintf(buf, fmt, va); - va_end(va); - - return stream_puts(stream, buf); -} diff --git a/src/mess/tools/imgtool/stream.h b/src/mess/tools/imgtool/stream.h deleted file mode 100644 index 13e6e0d727f..00000000000 --- a/src/mess/tools/imgtool/stream.h +++ /dev/null @@ -1,48 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/*************************************************************************** - - stream.h - - Code for implementing Imgtool streams - -***************************************************************************/ - -#ifndef STREAM_H -#define STREAM_H - -#include "imgterrs.h" -#include "corefile.h" - -struct imgtool_stream; - -imgtool_stream *stream_open(const char *fname, int read_or_write); /* similar params to mame_fopen */ -imgtool_stream *stream_open_write_stream(int filesize); -imgtool_stream *stream_open_mem(void *buf, size_t sz); -void stream_close(imgtool_stream *stream); -core_file *stream_core_file(imgtool_stream *stream); -UINT32 stream_read(imgtool_stream *stream, void *buf, UINT32 sz); -UINT32 stream_write(imgtool_stream *stream, const void *buf, UINT32 sz); -UINT64 stream_size(imgtool_stream *stream); -int stream_seek(imgtool_stream *stream, INT64 pos, int where); -UINT64 stream_tell(imgtool_stream *stream); -void *stream_getptr(imgtool_stream *stream); -UINT32 stream_putc(imgtool_stream *stream, char c); -UINT32 stream_puts(imgtool_stream *stream, const char *s); -UINT32 stream_printf(imgtool_stream *stream, const char *fmt, ...) ATTR_PRINTF(2,3); - -/* Transfers sz bytes from source to dest */ -UINT64 stream_transfer(imgtool_stream *dest, imgtool_stream *source, UINT64 sz); -UINT64 stream_transfer_all(imgtool_stream *dest, imgtool_stream *source); - -/* Fills sz bytes with b */ -UINT64 stream_fill(imgtool_stream *f, unsigned char b, UINT64 sz); - -/* Returns the CRC of a file */ -int stream_crc(imgtool_stream *f, unsigned long *result); -int file_crc(const char *fname, unsigned long *result); - -/* Returns whether a stream is read only or not */ -int stream_isreadonly(imgtool_stream *f); - -#endif /* STREAM_H */ |