1 /* Copyright 2007-2012 Fredrik Wikstrom. All rights reserved.
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
7 ** 1. Redistributions of source code must retain the above copyright
8 ** notice, this list of conditions and the following disclaimer.
10 ** 2. Redistributions in binary form must reproduce the above copyright
11 ** notice, this list of conditions and the following disclaimer in the
12 ** documentation and/or other materials provided with the distribution.
14 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
15 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 ** POSSIBILITY OF SUCH DAMAGE.
27 #define USED_PLUGIN_API_VERSION 8
28 #include <devices/diskimage.h>
29 #include <proto/exec.h>
30 #include <proto/dos.h>
31 #include <proto/utility.h>
33 #include "device_locale.h"
38 #include <SDI_compiler.h>
39 #include "rev/diskimage.device_rev.h"
43 extern struct DiskImagePlugin ccd_plugin
;
45 PLUGIN_TABLE(&ccd_plugin
)
47 #define LINE_BUFFER_SIZE 512
50 struct CCDTrack
*next
;
67 struct CCDTrack
*tracks
;
75 BOOL
CCD_Init (struct DiskImagePlugin
*Self
, const struct PluginData
*data
);
76 BOOL
CCD_CheckImage (struct DiskImagePlugin
*Self
, BPTR file
, CONST_STRPTR name
, QUAD file_size
,
77 const UBYTE
*test
, LONG testsize
);
78 APTR
CCD_OpenImage (struct DiskImagePlugin
*Self
, APTR unit
, BPTR file
, CONST_STRPTR name
);
79 void CCD_CloseImage (struct DiskImagePlugin
*Self
, APTR image_ptr
);
80 LONG
CCD_Geometry (struct DiskImagePlugin
*Self
, APTR image_ptr
, struct DriveGeometry
*dg
);
81 LONG
CCD_Read (struct DiskImagePlugin
*Self
, APTR image_ptr
, struct IOStdReq
*io
);
82 void CCD_GetCDTracks (struct DiskImagePlugin
*Self
, APTR image_ptr
, struct CDTrack
**tracks
,
84 LONG
CCD_ReadCDDA (struct DiskImagePlugin
*Self
, APTR image_ptr
, APTR buffer_ptr
, ULONG offset
,
87 struct DiskImagePlugin ccd_plugin
= {
88 PLUGIN_NODE(0, "CCD"),
107 struct Library
*SysBase
;
108 struct Library
*DOSBase
;
109 static struct Library
*UtilityBase
;
110 static struct DIPluginIFace
*IPlugin
;
112 BOOL
CCD_Init (struct DiskImagePlugin
*Self
, const struct PluginData
*data
) {
113 SysBase
= data
->SysBase
;
114 DOSBase
= data
->DOSBase
;
115 UtilityBase
= data
->UtilityBase
;
116 IPlugin
= data
->IPlugin
;
120 BOOL
CCD_CheckImage (struct DiskImagePlugin
*Self
, BPTR file
, CONST_STRPTR name
, QUAD file_size
,
121 const UBYTE
*test
, LONG testsize
)
123 return testsize
>= 9 && !memcmp(test
, "[CloneCD]", 9) && IsText(test
, testsize
);
126 static LONG
ccd_get_img_filename (BPTR file
, STRPTR buffer
, LONG size
);
127 static LONG
ccd_parse_ini_line (STRPTR line
, STRPTR
*section
, STRPTR
*attr
, STRPTR
*value
);
129 APTR
CCD_OpenImage (struct DiskImagePlugin
*Self
, APTR unit
, BPTR file
, CONST_STRPTR name
) {
131 LONG error
= NO_ERROR
;
132 LONG error_string
= NO_ERROR_STRING
;
133 IPTR error_args
[4] = {0};
134 struct CCDImage
*image
= NULL
;
135 struct CCDTrack
*track
, *prev_track
;
137 LONG track_num
, mode
, index
;
138 STRPTR section
, attr
, value
;
139 BPTR new_lock
= ZERO
, old_lock
= ZERO
;
141 UQUAD offset
, length
, sectors
;
143 new_lock
= ParentOfFH(file
);
145 old_lock
= CurrentDir(new_lock
);
148 line_buffer
= AllocVec(LINE_BUFFER_SIZE
, MEMF_ANY
);
149 image
= AllocVec(sizeof(*image
), MEMF_CLEAR
);
150 if (!line_buffer
|| !image
) {
151 error
= ERROR_NO_FREE_STORE
;
154 error
= ccd_get_img_filename(file
, filename
, sizeof(filename
));
155 if (error
!= NO_ERROR
) goto error
;
157 image
->file
= Open(filename
, MODE_OLDFILE
);
163 image
->file_size
= GetFileSize(image
->file
);
164 if (image
->file_size
== -1) {
169 track
= prev_track
= NULL
;
170 while (FGets(file
, line_buffer
, LINE_BUFFER_SIZE
)) {
171 error
= ccd_parse_ini_line(line_buffer
, §ion
, &attr
, &value
);
172 if (error
!= NO_ERROR
) break;
174 if (!strncmp(section
, "TRACK ", 6)) {
175 if (!isdigit(section
[6]) || StrToLong(§ion
[6], &track_num
) == -1) {
176 error
= ERROR_BAD_NUMBER
;
181 track
= image
->tracks
= AllocVec(sizeof(*track
), MEMF_CLEAR
);
183 track
= track
->next
= AllocVec(sizeof(*track
), MEMF_CLEAR
);
186 error
= ERROR_NO_FREE_STORE
;
189 track
->track_num
= track_num
;
190 if (!image
->first_track
|| track_num
< image
->first_track
) {
191 image
->first_track
= track_num
;
193 if (!image
->last_track
|| track_num
> image
->last_track
) {
194 image
->last_track
= track_num
;
196 track
->sector_size
= 2352;
197 if (track_num
== 1) {
198 track
->audio
= FALSE
;
199 track
->sync_size
= 16;
202 track
->sync_size
= 0;
207 if (!strcmp(attr
, "MODE") && value
) {
208 if (StrToLong(value
, &mode
) == -1) {
209 error
= ERROR_BAD_NUMBER
;
215 track
->sync_size
= 0;
218 track
->audio
= FALSE
;
219 track
->sync_size
= 16;
222 track
->audio
= FALSE
;
223 track
->sync_size
= 24;
226 error
= ERROR_NOT_IMPLEMENTED
;
229 if (error
!= NO_ERROR
) break;
230 } else if (!strcmp(attr
, "INDEX 1") && value
) {
231 if (StrToLong(value
, &index
) == -1) {
232 error
= ERROR_BAD_NUMBER
;
235 track
->index1
= index
;
236 if (prev_track
&& !prev_track
->index2
) {
237 prev_track
->index2
= index
;
239 } else if (!strcmp(attr
, "INDEX 2") && value
) {
240 if (StrToLong(value
, &index
) == -1) {
241 error
= ERROR_BAD_NUMBER
;
244 track
->index2
= index
;
249 if (error
!= NO_ERROR
) {
253 if (error
!= NO_ERROR
) {
257 if (!image
->tracks
) {
258 error
= ERROR_REQUIRED_ARG_MISSING
;
262 image
->block_size
= 2048;
263 image
->total_blocks
= 0;
264 image
->num_tracks
= 0;
265 track
= image
->tracks
;
267 offset
= (UQUAD
)track
->index1
* 2352ULL;
268 if (!track
->index2
) {
269 sectors
= (image
->file_size
- offset
) / track
->sector_size
;
270 track
->index2
= track
->index1
+ sectors
;
272 if (track
->index2
< track
->index1
) {
273 error
= ERROR_BAD_NUMBER
;
276 sectors
= track
->index2
- track
->index1
;
277 length
= sectors
* 2352ULL;
278 track
->offset
= offset
;
279 track
->sectors
= sectors
;
280 track
->length
= length
;
281 image
->total_blocks
+= sectors
;
285 if (error
!= NO_ERROR
) {
292 FreeVec(line_buffer
);
294 CurrentDir(old_lock
);
299 Plugin_CloseImage(Self
, image
);
301 if (error
== NO_ERROR
) {
302 error
= ERROR_OBJECT_WRONG_TYPE
;
303 error_string
= MSG_EOF
;
305 IPlugin_SetDiskImageErrorA(unit
, error
, error_string
, error_args
);
310 static void strip_file_extension (STRPTR name
, CONST_STRPTR ext
) {
311 LONG len
= strlen(name
) - strlen(ext
);
314 if (!Stricmp(name
, ext
)) {
320 static LONG
ccd_get_img_filename (BPTR file
, STRPTR buffer
, LONG size
) {
321 struct FileInfoBlock
*fib
;
322 LONG error
= NO_ERROR
;
323 fib
= AllocDosObject(DOS_FIB
, NULL
);
325 if (ExamineFH(file
, fib
)) {
326 Strlcpy(buffer
, fib
->fib_FileName
, size
);
327 strip_file_extension(buffer
, ".ccd");
328 Strlcat(buffer
, ".img", size
);
332 FreeDosObject(DOS_FIB
, fib
);
334 error
= ERROR_NO_FREE_STORE
;
339 static void rtrim (STRPTR string
) {
340 int len
= strlen(string
);
342 for (i
= len
-1; i
>= 0; i
--) {
343 if (isspace(string
[i
])) {
351 static LONG
ccd_parse_ini_line (STRPTR line
, STRPTR
*section
, STRPTR
*attr
, STRPTR
*value
) {
353 *section
= *attr
= *value
= NULL
;
356 if (line
[0] == '[' && line
[len
-1] == ']') {
360 *value
= strchr(*attr
= line
, '=');
361 if (*value
) *(*value
)++ = 0;
366 void CCD_CloseImage (struct DiskImagePlugin
*Self
, APTR image_ptr
) {
367 struct CCDImage
*image
= image_ptr
;
369 struct CCDTrack
*track
, *next_track
;
370 track
= image
->tracks
;
372 next_track
= track
->next
;
376 FreeVec(image
->out_buf
);
382 LONG
CCD_Geometry (struct DiskImagePlugin
*Self
, APTR image_ptr
, struct DriveGeometry
*dg
) {
383 struct CCDImage
*image
= image_ptr
;
384 dg
->dg_DeviceType
= DG_CDROM
;
385 dg
->dg_SectorSize
= image
->block_size
;
387 dg
->dg_TrackSectors
=
388 dg
->dg_CylSectors
= 1;
390 dg
->dg_TotalSectors
= image
->total_blocks
;
391 return IOERR_SUCCESS
;
394 LONG
CCD_Read (struct DiskImagePlugin
*Self
, APTR image_ptr
, struct IOStdReq
*io
) {
395 struct CCDImage
*image
= image_ptr
;
396 struct CCDTrack
*track
= image
->tracks
;
397 BPTR file
= image
->file
;
401 UQUAD read_offs
, next_offs
;
402 ULONG to_skip
, to_read
;
406 buffer
= io
->io_Data
;
407 offset
= ((UQUAD
)io
->io_Offset
)|((UQUAD
)io
->io_Actual
<< 32);
408 size
= io
->io_Length
;
411 if (offset
& 0x7ff) return IOERR_BADADDRESS
;
412 if (size
& 0x7ff) return IOERR_BADLENGTH
;
416 if (offset
>= image
->total_blocks
) {
417 return TDERR_SeekError
;
419 read_offs
= next_offs
= 0;
421 next_offs
+= track
->sectors
;
422 if (next_offs
> offset
) break;
423 read_offs
= next_offs
;
425 if (!track
) return TDERR_SeekError
;
428 to_skip
= offset
- read_offs
;
431 return TDERR_NoSecHdr
;
433 to_read
= max((LONG
)min(size
, track
->sectors
- to_skip
), 0);
435 read_pos
= track
->offset
+ ((UQUAD
)to_skip
* track
->sector_size
);
436 if (!ChangeFilePosition(file
, read_pos
, OFFSET_BEGINNING
)) {
437 return TDERR_SeekError
;
439 if (track
->sector_size
== 2048) {
440 read_size
= to_read
<< 11;
441 if (Read(file
, buffer
, read_size
) != read_size
) {
442 return IPlugin_DOS2IOErr(IoErr());
445 io
->io_Actual
+= read_size
;
447 read_size
= track
->sector_size
;
448 if (!(image
->out_buf
= ReAllocBuf(image
->out_buf
, &image
->out_size
, read_size
))) {
449 return ERROR_NO_FREE_STORE
;
452 if (Read(file
, image
->out_buf
, read_size
) != read_size
) {
453 return IPlugin_DOS2IOErr(IoErr());
455 CopyMem(image
->out_buf
+ track
->sync_size
, buffer
, 2048);
457 io
->io_Actual
+= 2048;
463 if (!track
) return IOERR_BADLENGTH
;
466 return IOERR_SUCCESS
;
469 void CCD_GetCDTracks (struct DiskImagePlugin
*Self
, APTR image_ptr
, struct CDTrack
**tracks
,
472 struct CCDImage
*image
= image_ptr
;
473 *tracks
= (struct CDTrack
*)image
->tracks
;
474 *num_tracks
= image
->num_tracks
;
477 LONG
CCD_ReadCDDA (struct DiskImagePlugin
*Self
, APTR image_ptr
, APTR buffer_ptr
, ULONG offset
,
480 struct CCDImage
*image
= image_ptr
;
481 UBYTE
*buffer
= buffer_ptr
;
482 struct CCDTrack
*track
= image
->tracks
;
483 BPTR file
= image
->file
;
484 UQUAD read_offs
, next_offs
;
485 ULONG to_skip
, to_read
;
488 ULONG bytes_read
= 0;
490 if (offset
>= image
->total_blocks
) {
493 read_offs
= next_offs
= 0;
495 next_offs
+= track
->sectors
;
496 if (next_offs
> offset
) break;
497 read_offs
= next_offs
;
499 if (!track
) return bytes_read
;
502 to_skip
= offset
- read_offs
;
504 if (!track
->audio
|| track
->sector_size
!= 2352) {
507 to_read
= max((LONG
)min(size
, track
->sectors
- to_skip
), 0);
509 read_pos
= track
->offset
+ ((UQUAD
)to_skip
* 2352ULL);
510 read_size
= to_read
* 2352;
511 if (!ChangeFilePosition(file
, read_pos
, OFFSET_BEGINNING
) ||
512 Read(file
, buffer
, read_size
) != read_size
)
517 bytes_read
+= read_size
;
520 if (!track
) return bytes_read
;