1 // license:BSD-3-Clause
2 // copyright-holders:Nathan Woods
3 /*********************************************************************
4
5 iflopimg.c
6
7 Bridge code for Imgtool into the standard floppy code
8
9 *********************************************************************/
10
11 #include "imgtool.h"
12 #include "formats/flopimg.h"
13 #include "library.h"
14 #include "iflopimg.h"
15
imgtool_floppy_error(floperr_t err)16 imgtoolerr_t imgtool_floppy_error(floperr_t err)
17 {
18 switch(err)
19 {
20 case FLOPPY_ERROR_SUCCESS:
21 return IMGTOOLERR_SUCCESS;
22
23 case FLOPPY_ERROR_OUTOFMEMORY:
24 return IMGTOOLERR_OUTOFMEMORY;
25
26 case FLOPPY_ERROR_INVALIDIMAGE:
27 return IMGTOOLERR_CORRUPTIMAGE;
28
29 case FLOPPY_ERROR_SEEKERROR:
30 return IMGTOOLERR_SEEKERROR;
31
32 case FLOPPY_ERROR_UNSUPPORTED:
33 return IMGTOOLERR_UNIMPLEMENTED;
34
35 default:
36 return IMGTOOLERR_UNEXPECTED;
37 }
38 }
39
40
41
42 /*********************************************************************
43 Imgtool ioprocs
44 *********************************************************************/
45
imgtool_floppy_closeproc(void * file)46 static void imgtool_floppy_closeproc(void *file)
47 {
48 delete reinterpret_cast<imgtool::stream *>(file);
49 }
50
imgtool_floppy_seekproc(void * file,int64_t offset,int whence)51 static int imgtool_floppy_seekproc(void *file, int64_t offset, int whence)
52 {
53 reinterpret_cast<imgtool::stream *>(file)->seek(offset, whence);
54 return 0;
55 }
56
imgtool_floppy_readproc(void * file,void * buffer,size_t length)57 static size_t imgtool_floppy_readproc(void *file, void *buffer, size_t length)
58 {
59 return reinterpret_cast<imgtool::stream *>(file)->read(buffer, length);
60 }
61
imgtool_floppy_writeproc(void * file,const void * buffer,size_t length)62 static size_t imgtool_floppy_writeproc(void *file, const void *buffer, size_t length)
63 {
64 reinterpret_cast<imgtool::stream *>(file)->write(buffer, length);
65 return length;
66 }
67
imgtool_floppy_filesizeproc(void * file)68 static uint64_t imgtool_floppy_filesizeproc(void *file)
69 {
70 return reinterpret_cast<imgtool::stream *>(file)->size();
71 }
72
73 static const struct io_procs imgtool_ioprocs =
74 {
75 imgtool_floppy_closeproc,
76 imgtool_floppy_seekproc,
77 imgtool_floppy_readproc,
78 imgtool_floppy_writeproc,
79 imgtool_floppy_filesizeproc
80 };
81
82 static const struct io_procs imgtool_noclose_ioprocs =
83 {
84 nullptr,
85 imgtool_floppy_seekproc,
86 imgtool_floppy_readproc,
87 imgtool_floppy_writeproc,
88 imgtool_floppy_filesizeproc
89 };
90
91
92
93 /*********************************************************************
94 Imgtool handlers
95 *********************************************************************/
96
97 struct imgtool_floppy_image
98 {
99 floppy_image_legacy *floppy;
100 };
101
102
103
104
imgtool_floppy_open_internal(imgtool::image & image,imgtool::stream::ptr && stream,int noclose)105 static imgtoolerr_t imgtool_floppy_open_internal(imgtool::image &image, imgtool::stream::ptr &&stream, int noclose)
106 {
107 floperr_t ferr;
108 imgtoolerr_t err = IMGTOOLERR_SUCCESS;
109 imgtool::stream *f = nullptr;
110 struct imgtool_floppy_image *fimg;
111 const imgtool_class *imgclass;
112 const struct FloppyFormat *format;
113 imgtoolerr_t (*open)(imgtool::image &image, imgtool::stream *f);
114
115 fimg = (struct imgtool_floppy_image *) image.extra_bytes();
116 imgclass = &image.module().imgclass;
117 format = (const struct FloppyFormat *) imgclass->derived_param;
118 open = (imgtoolerr_t (*)(imgtool::image &, imgtool::stream *)) imgtool_get_info_ptr(imgclass, IMGTOOLINFO_PTR_FLOPPY_OPEN);
119
120 // extract the pointer
121 f = stream.release();
122
123 // open up the floppy
124 ferr = floppy_open(f, noclose ? &imgtool_noclose_ioprocs : &imgtool_ioprocs,
125 "", format, FLOPPY_FLAGS_READWRITE, &fimg->floppy);
126 if (ferr)
127 {
128 err = imgtool_floppy_error(ferr);
129 goto done;
130 }
131 f = nullptr; // the floppy object has the stream now
132
133 if (open)
134 {
135 err = open(image, nullptr);
136 if (err)
137 goto done;
138 }
139
140 done:
141 if (f)
142 delete f;
143 if (err && fimg->floppy)
144 {
145 floppy_close(fimg->floppy);
146 fimg->floppy = nullptr;
147 }
148 return err;
149 }
150
151
152
imgtool_floppy_open(imgtool::image & image,imgtool::stream::ptr && stream)153 static imgtoolerr_t imgtool_floppy_open(imgtool::image &image, imgtool::stream::ptr &&stream)
154 {
155 return imgtool_floppy_open_internal(image, std::move(stream), false);
156 }
157
158
159
imgtool_floppy_create(imgtool::image & image,imgtool::stream::ptr && stream,util::option_resolution * opts)160 static imgtoolerr_t imgtool_floppy_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *opts)
161 {
162 floperr_t ferr;
163 imgtoolerr_t err = IMGTOOLERR_SUCCESS;
164 imgtool::stream *f = nullptr;
165 struct imgtool_floppy_image *fimg;
166 const imgtool_class *imgclass;
167 const struct FloppyFormat *format;
168 imgtoolerr_t (*create)(imgtool::image &, imgtool::stream *, util::option_resolution *);
169 imgtoolerr_t (*open)(imgtool::image &, imgtool::stream *f);
170
171 fimg = (struct imgtool_floppy_image *) image.extra_bytes();
172 imgclass = &image.module().imgclass;
173 format = (const struct FloppyFormat *) imgclass->derived_param;
174 create = (imgtoolerr_t (*)(imgtool::image &, imgtool::stream *, util::option_resolution *)) imgtool_get_info_ptr(imgclass, IMGTOOLINFO_PTR_FLOPPY_CREATE);
175 open = (imgtoolerr_t (*)(imgtool::image &, imgtool::stream *)) imgtool_get_info_ptr(imgclass, IMGTOOLINFO_PTR_FLOPPY_OPEN);
176
177 // extract the pointer
178 f = stream.release();
179
180 // open up the floppy
181 ferr = floppy_create(f, &imgtool_ioprocs, format, opts, &fimg->floppy);
182 if (ferr)
183 {
184 err = imgtool_floppy_error(ferr);
185 goto done;
186 }
187 f = nullptr; // the floppy object has the stream now
188
189 // do we have to do extra stuff when creating the image?
190 if (create)
191 {
192 err = create(image, nullptr, opts);
193 if (err)
194 goto done;
195 }
196
197 // do we have to do extra stuff when opening the image?
198 if (open)
199 {
200 err = open(image, nullptr);
201 if (err)
202 goto done;
203 }
204
205 done:
206 if (f)
207 delete f;
208 if (err && fimg->floppy)
209 {
210 floppy_close(fimg->floppy);
211 fimg->floppy = nullptr;
212 }
213 return err;
214 }
215
216
217
imgtool_floppy_close(imgtool::image & img)218 static void imgtool_floppy_close(imgtool::image &img)
219 {
220 floppy_close(imgtool_floppy(img));
221 }
222
223
224
imgtool_floppy_read_sector(imgtool::image & image,uint32_t track,uint32_t head,uint32_t sector,std::vector<uint8_t> & buffer)225 static imgtoolerr_t imgtool_floppy_read_sector(imgtool::image &image, uint32_t track, uint32_t head, uint32_t sector, std::vector<uint8_t> &buffer)
226 {
227 floperr_t ferr;
228 uint32_t sector_size;
229
230 // get the sector length
231 ferr = floppy_get_sector_length(imgtool_floppy(image), head, track, sector, §or_size);
232 if (ferr)
233 return imgtool_floppy_error(ferr);
234
235 // resize the buffer accordingly
236 try { buffer.resize(sector_size); }
237 catch (std::bad_alloc const &) { return IMGTOOLERR_OUTOFMEMORY; }
238
239 // and read the sector
240 ferr = floppy_read_sector(imgtool_floppy(image), head, track, sector, 0, &buffer[0], sector_size);
241 if (ferr)
242 return imgtool_floppy_error(ferr);
243
244 return IMGTOOLERR_SUCCESS;
245 }
246
247
248
imgtool_floppy_write_sector(imgtool::image & image,uint32_t track,uint32_t head,uint32_t sector,const void * buffer,size_t len,int ddam)249 static imgtoolerr_t imgtool_floppy_write_sector(imgtool::image &image, uint32_t track, uint32_t head, uint32_t sector, const void *buffer, size_t len, int ddam)
250 {
251 floperr_t ferr;
252
253 ferr = floppy_write_sector(imgtool_floppy(image), head, track, sector, 0, buffer, len, ddam);
254 if (ferr)
255 return imgtool_floppy_error(ferr);
256
257 return IMGTOOLERR_SUCCESS;
258 }
259
260
261
imgtool_floppy_get_info(const imgtool_class * imgclass,uint32_t state,union imgtoolinfo * info)262 static void imgtool_floppy_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info)
263 {
264 const struct FloppyFormat *format;
265 imgtool_class derived_class;
266
267 format = (const struct FloppyFormat *) imgclass->derived_param;
268 memset(&derived_class, 0, sizeof(derived_class));
269 derived_class.get_info = imgclass->derived_get_info;
270
271 switch(state)
272 {
273 /* --- the following bits of info are returned as 64-bit signed integers --- */
274 case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES:
275 info->i = sizeof(struct imgtool_floppy_image) +
276 imgtool_get_info_int(&derived_class, IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES);
277 break;
278
279 /* --- the following bits of info are returned as NULL-terminated strings --- */
280 case IMGTOOLINFO_STR_NAME:
281 sprintf(info->s = imgtool_temp_str(), "%s_%s", format->name,
282 imgtool_get_info_string(&derived_class, IMGTOOLINFO_STR_NAME));
283 break;
284 case IMGTOOLINFO_STR_DESCRIPTION:
285 sprintf(info->s = imgtool_temp_str(), "%s (%s)", format->description,
286 imgtool_get_info_string(&derived_class, IMGTOOLINFO_STR_DESCRIPTION));
287 break;
288 case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), format->extensions); break;
289 case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: info->p = (void*)format->param_guidelines; break;
290
291 /* --- the following bits of info are returned as pointers to data or functions --- */
292 case IMGTOOLINFO_PTR_OPEN: info->open = imgtool_floppy_open; break;
293 case IMGTOOLINFO_PTR_CREATE: info->create = imgtool_floppy_create; break;
294 case IMGTOOLINFO_PTR_CLOSE: info->close = imgtool_floppy_close; break;
295 case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = format->param_guidelines ? &floppy_option_guide : nullptr; break;
296 case IMGTOOLINFO_PTR_READ_SECTOR: info->read_sector = imgtool_floppy_read_sector; break;
297 case IMGTOOLINFO_PTR_WRITE_SECTOR: info->write_sector = imgtool_floppy_write_sector; break;
298
299 default: imgclass->derived_get_info(imgclass, state, info); break;
300 }
301 }
302
303
304
imgtool_floppy_make_class(int index,imgtool_class * imgclass)305 int imgtool_floppy_make_class(int index, imgtool_class *imgclass)
306 {
307 const struct FloppyFormat *format;
308
309 /* get the format */
310 format = (const struct FloppyFormat *)
311 imgtool_get_info_ptr(imgclass, IMGTOOLINFO_PTR_FLOPPY_FORMAT);
312 assert(format);
313 if (!format[index].construct)
314 return false;
315
316 imgclass->derived_get_info = imgclass->get_info;
317 imgclass->get_info = imgtool_floppy_get_info;
318 imgclass->derived_param = (void *) &format[index];
319 return true;
320 }
321
322
323
imgtool_floppy(imgtool::image & img)324 floppy_image_legacy *imgtool_floppy(imgtool::image &img)
325 {
326 struct imgtool_floppy_image *fimg;
327 fimg = (struct imgtool_floppy_image *) img.extra_bytes();
328 return fimg->floppy;
329 }
330
331
332
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)333 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)
334 {
335 floperr_t err;
336 floppy_image_legacy *floppy;
337 std::vector<uint8_t> buffer;
338
339 floppy = imgtool_floppy(img);
340
341 buffer.resize(length);
342
343 if (direction)
344 {
345 err = floppy_read_sector(floppy, head, track, sector, offset, &buffer[0], length);
346 if (err)
347 goto done;
348 f.write(&buffer[0], length);
349 }
350 else
351 {
352 f.read(&buffer[0], length);
353 err = floppy_write_sector(floppy, head, track, sector, offset, &buffer[0], length, 0); /* TODO: pass ddam argument from imgtool */
354 if (err)
355 goto done;
356 }
357
358 err = FLOPPY_ERROR_SUCCESS;
359
360 done:
361 return imgtool_floppy_error(err);
362 }
363
364
365
imgtool_floppy_read_sector_to_stream(imgtool::image & img,int head,int track,int sector,int offset,size_t length,imgtool::stream & f)366 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)
367 {
368 return imgtool_floppy_transfer_sector_tofrom_stream(img, head, track, sector, offset, length, f, 1);
369 }
370
371
372
imgtool_floppy_write_sector_from_stream(imgtool::image & img,int head,int track,int sector,int offset,size_t length,imgtool::stream & f)373 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)
374 {
375 return imgtool_floppy_transfer_sector_tofrom_stream(img, head, track, sector, offset, length, f, 0);
376 }
377
378
379
imgtool_floppy_extrabytes(imgtool::image & img)380 void *imgtool_floppy_extrabytes(imgtool::image &img)
381 {
382 struct imgtool_floppy_image *fimg;
383 fimg = (struct imgtool_floppy_image *) img.extra_bytes();
384 return fimg + 1;
385 }
386