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, &sector_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