1 // license:BSD-3-Clause
2 // copyright-holders:Nathan Woods, Raphael Nabet
3 /*
4 Code to interface the MESS image code with MAME's harddisk core.
5
6 We do not support diff files as it will involve some changes in the MESS
7 image code.
8
9 Raphael Nabet 2003
10 */
11
12 #include "imgtool.h"
13 #include "harddisk.h"
14 #include "imghd.h"
15
16
map_chd_error(chd_error chderr)17 static imgtoolerr_t map_chd_error(chd_error chderr)
18 {
19 imgtoolerr_t err;
20
21 switch(chderr)
22 {
23 case CHDERR_NONE:
24 err = IMGTOOLERR_SUCCESS;
25 break;
26 case CHDERR_OUT_OF_MEMORY:
27 err = IMGTOOLERR_OUTOFMEMORY;
28 break;
29 case CHDERR_FILE_NOT_WRITEABLE:
30 err = IMGTOOLERR_READONLY;
31 break;
32 case CHDERR_NOT_SUPPORTED:
33 err = IMGTOOLERR_UNIMPLEMENTED;
34 break;
35 default:
36 err = IMGTOOLERR_UNEXPECTED;
37 break;
38 }
39 return err;
40 }
41
42
43
44 /*
45 imghd_create()
46
47 Create a MAME HD image
48 */
imghd_create(imgtool::stream & stream,uint32_t hunksize,uint32_t cylinders,uint32_t heads,uint32_t sectors,uint32_t seclen)49 imgtoolerr_t imghd_create(imgtool::stream &stream, uint32_t hunksize, uint32_t cylinders, uint32_t heads, uint32_t sectors, uint32_t seclen)
50 {
51 imgtoolerr_t err = IMGTOOLERR_SUCCESS;
52 chd_file chd;
53 chd_error rc;
54 chd_codec_type compression[4] = { CHD_CODEC_NONE };
55
56 /* sanity check args -- see parse_hunk_size() in src/lib/util/chd.cpp */
57 if (hunksize > (1024 * 1024))
58 {
59 err = IMGTOOLERR_PARAMCORRUPT;
60 return err;
61 }
62 if (hunksize <= 0)
63 hunksize = 4096; /* default value */
64
65 /* bail if we are read only */
66 if (stream.is_read_only())
67 {
68 err = IMGTOOLERR_READONLY;
69 return err;
70 }
71
72 /* calculations */
73 const uint64_t logicalbytes = (uint64_t)cylinders * heads * sectors * seclen;
74
75 /* create the new hard drive */
76 rc = chd.create(*stream.core_file(), logicalbytes, hunksize, seclen, compression);
77 if (rc != CHDERR_NONE)
78 {
79 err = map_chd_error(rc);
80 return err;
81 }
82
83 /* write the metadata */
84 const std::string metadata = string_format(HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, seclen);
85 err = (imgtoolerr_t)chd.write_metadata(HARD_DISK_METADATA_TAG, 0, metadata);
86 if (rc != CHDERR_NONE)
87 {
88 err = map_chd_error(rc);
89 return err;
90 }
91
92 /* alloc and zero buffer */
93 std::vector<uint8_t> cache;
94 cache.resize(hunksize);
95 memset(&cache[0], 0, hunksize);
96
97 /* zero out every hunk */
98 const int totalhunks = (logicalbytes + hunksize - 1) / hunksize;
99 for (int hunknum = 0; hunknum < totalhunks; hunknum++)
100 {
101 rc = chd.write_units(hunknum, &cache[0]);
102 if (rc)
103 {
104 err = IMGTOOLERR_WRITEERROR;
105 return err;
106 }
107 }
108
109 return err;
110 }
111
112
113
114 /*
115 imghd_open()
116
117 Open stream as a MAME HD image
118 */
imghd_open(imgtool::stream & stream,struct mess_hard_disk_file * hard_disk)119 imgtoolerr_t imghd_open(imgtool::stream &stream, struct mess_hard_disk_file *hard_disk)
120 {
121 chd_error chderr;
122 imgtoolerr_t err = IMGTOOLERR_SUCCESS;
123
124 hard_disk->hard_disk = nullptr;
125
126 chderr = hard_disk->chd.open(*stream.core_file(), !stream.is_read_only());
127 if (chderr)
128 {
129 err = map_chd_error(chderr);
130 goto done;
131 }
132
133 hard_disk->hard_disk = hard_disk_open(&hard_disk->chd);
134 if (!hard_disk->hard_disk)
135 {
136 err = IMGTOOLERR_UNEXPECTED;
137 goto done;
138 }
139 hard_disk->stream = &stream;
140
141 done:
142 if (err)
143 imghd_close(hard_disk);
144 return err;
145 }
146
147
148
149 /*
150 imghd_close()
151
152 Close MAME HD image
153 */
imghd_close(struct mess_hard_disk_file * disk)154 void imghd_close(struct mess_hard_disk_file *disk)
155 {
156 if (disk->hard_disk)
157 {
158 hard_disk_close(disk->hard_disk);
159 disk->hard_disk = nullptr;
160 }
161 if (disk->stream)
162 {
163 delete disk->stream;
164 disk->stream = nullptr;
165 }
166 }
167
168
169
170 /*
171 imghd_read()
172
173 Read sector(s) from MAME HD image
174 */
imghd_read(struct mess_hard_disk_file * disk,uint32_t lbasector,void * buffer)175 imgtoolerr_t imghd_read(struct mess_hard_disk_file *disk, uint32_t lbasector, void *buffer)
176 {
177 uint32_t reply;
178 reply = hard_disk_read(disk->hard_disk, lbasector, buffer);
179 return (imgtoolerr_t)(reply ? IMGTOOLERR_SUCCESS : map_chd_error((chd_error)reply));
180 }
181
182
183
184 /*
185 imghd_write()
186
187 Write sector(s) from MAME HD image
188 */
imghd_write(struct mess_hard_disk_file * disk,uint32_t lbasector,const void * buffer)189 imgtoolerr_t imghd_write(struct mess_hard_disk_file *disk, uint32_t lbasector, const void *buffer)
190 {
191 uint32_t reply;
192 reply = hard_disk_write(disk->hard_disk, lbasector, buffer);
193 return (imgtoolerr_t)(reply ? IMGTOOLERR_SUCCESS : map_chd_error((chd_error)reply));
194 }
195
196
197
198 /*
199 imghd_get_header()
200
201 Return pointer to the header of MAME HD image
202 */
imghd_get_header(struct mess_hard_disk_file * disk)203 const hard_disk_info *imghd_get_header(struct mess_hard_disk_file *disk)
204 {
205 const hard_disk_info *reply;
206 reply = hard_disk_get_info(disk->hard_disk);
207 return reply;
208 }
209
210
211 static imgtoolerr_t mess_hd_image_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *createoptions);
212
213 enum
214 {
215 mess_hd_createopts_blocksize = 'B',
216 mess_hd_createopts_cylinders = 'C',
217 mess_hd_createopts_heads = 'D',
218 mess_hd_createopts_sectors = 'E',
219 mess_hd_createopts_seclen = 'F'
220 };
221
222 OPTION_GUIDE_START( mess_hd_create_optionguide )
223 OPTION_INT(mess_hd_createopts_blocksize, "blocksize", "Sectors Per Block" )
224 OPTION_INT(mess_hd_createopts_cylinders, "cylinders", "Cylinders" )
225 OPTION_INT(mess_hd_createopts_heads, "heads", "Heads" )
226 OPTION_INT(mess_hd_createopts_sectors, "sectors", "Total Sectors" )
227 OPTION_INT(mess_hd_createopts_seclen, "seclen", "Sector Bytes" )
228 OPTION_GUIDE_END
229
230 #define mess_hd_create_optionspecs "B1-[4]-2048;C1-[32]-65536;D1-[8]-64;E1-[128]-4096;F128/256/[512]/1024/2048/4096/8192/16384/32768/65536"
231
232
hd_get_info(const imgtool_class * imgclass,uint32_t state,union imgtoolinfo * info)233 void hd_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info)
234 {
235 switch(state)
236 {
237 case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "mess_hd"); break;
238 case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "MESS hard disk image"); break;
239 case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "hd"); break;
240
241 case IMGTOOLINFO_PTR_CREATE: info->create = mess_hd_image_create; break;
242
243 case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = &mess_hd_create_optionguide; break;
244 case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), mess_hd_create_optionspecs); break;
245 }
246 }
247
248
249
mess_hd_image_create(imgtool::image & image,imgtool::stream::ptr && stream,util::option_resolution * createoptions)250 static imgtoolerr_t mess_hd_image_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *createoptions)
251 {
252 uint32_t blocksize, cylinders, heads, sectors, seclen;
253
254 /* read options */
255 blocksize = createoptions->lookup_int(mess_hd_createopts_blocksize);
256 cylinders = createoptions->lookup_int(mess_hd_createopts_cylinders);
257 heads = createoptions->lookup_int(mess_hd_createopts_heads);
258 sectors = createoptions->lookup_int(mess_hd_createopts_sectors);
259 seclen = createoptions->lookup_int(mess_hd_createopts_seclen);
260
261 return imghd_create(*stream.get(), blocksize * seclen, cylinders, heads, sectors, seclen);
262 }
263