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"
37 #include <SDI_compiler.h>
38 #include "rev/diskimage.device_rev.h"
42 extern struct DiskImagePlugin mds_plugin
;
44 PLUGIN_TABLE(&mds_plugin
)
47 struct MDSTrack
*next
;
62 struct MDSTrack
*tracks
;
69 BOOL
MDS_Init (struct DiskImagePlugin
*Self
, const struct PluginData
*data
);
70 BOOL
MDS_CheckImage (struct DiskImagePlugin
*Self
, BPTR file
, CONST_STRPTR name
, QUAD file_size
,
71 const UBYTE
*test
, LONG testsize
);
72 APTR
MDS_OpenImage (struct DiskImagePlugin
*Self
, APTR unit
, BPTR file
, CONST_STRPTR name
);
73 void MDS_CloseImage (struct DiskImagePlugin
*Self
, APTR image_ptr
);
74 LONG
MDS_Geometry (struct DiskImagePlugin
*Self
, APTR image_ptr
, struct DriveGeometry
*dg
);
75 LONG
MDS_Read (struct DiskImagePlugin
*Self
, APTR image_ptr
, struct IOStdReq
*io
);
76 void MDS_GetCDTracks (struct DiskImagePlugin
*Self
, APTR image_ptr
, struct CDTrack
**tracks
,
78 LONG
MDS_ReadCDDA (struct DiskImagePlugin
*Self
, APTR image_ptr
, APTR buffer_ptr
, ULONG offset
,
81 struct DiskImagePlugin mds_plugin
= {
82 PLUGIN_NODE(0, "MDS"),
101 struct Library
*SysBase
;
102 struct Library
*DOSBase
;
103 static struct Library
*UtilityBase
;
104 static struct DIPluginIFace
*IPlugin
;
106 BOOL
MDS_Init (struct DiskImagePlugin
*Self
, const struct PluginData
*data
) {
107 SysBase
= data
->SysBase
;
108 DOSBase
= data
->DOSBase
;
109 UtilityBase
= data
->UtilityBase
;
110 IPlugin
= data
->IPlugin
;
114 #define MDS_SIGNATURE "MEDIA DESCRIPTOR"
116 BOOL
MDS_CheckImage (struct DiskImagePlugin
*Self
, BPTR file
, CONST_STRPTR name
, QUAD file_size
,
117 const UBYTE
*test
, LONG testsize
)
119 return testsize
>= 16 && !memcmp(test
, MDS_SIGNATURE
, 16);
132 ULONG bca_data_offset
;
134 ULONG disc_structures_offset
;
136 ULONG sessions_blocks_offset
;
137 ULONG dpm_blocks_offset
;
140 #define MDS_MEDIUM_CD 0x00
141 #define MDS_MEDIUM_CD_R 0x01
142 #define MDS_MEDIUM_CD_RW 0x02
143 #define MDS_MEDIUM_DVD 0x10
144 #define MDS_MEDIUM_DVD_MINUS_R 0x12
149 UWORD session_number
;
150 UBYTE num_all_blocks
;
151 UBYTE num_nontrack_blocks
;
155 ULONG tracks_blocks_offset
;
156 } mds_session_block_t
;
173 ULONG number_of_files
;
178 #define MDS_TRACKMODE_UNKNOWN 0x00
179 #define MDS_TRACKMODE_AUDIO 0xA9
180 #define MDS_TRACKMODE_MODE1 0xAA
181 #define MDS_TRACKMODE_MODE2 0xAB
182 #define MDS_TRACKMODE_MODE2_FORM1 0xAC
183 #define MDS_TRACKMODE_MODE2_FORM2 0xAD
185 #define MDS_LEADIN_TRACK_FIRST 0xA0
186 #define MDS_LEADIN_TRACK_LAST 0xA1
187 #define MDS_LEADIN_TRACK_LEADOUT 0xA2
195 ULONG filename_offset
;
196 ULONG widechar_filename
;
202 static LONG
mds_get_mdf_filename (BPTR file
, STRPTR buffer
, LONG size
);
204 APTR
MDS_OpenImage (struct DiskImagePlugin
*Self
, APTR unit
, BPTR file
, CONST_STRPTR name
) {
206 LONG error
= NO_ERROR
;
207 LONG error_string
= NO_ERROR_STRING
;
208 IPTR error_args
[4] = {0};
209 struct MDSImage
*image
= NULL
;
210 struct MDSTrack
*track
= NULL
;
211 mds_header_t mds_header
;
212 mds_session_block_t mds_session
;
213 mds_track_block_t mds_track
;
214 mds_extra_block_t mds_extra
;
215 ULONG track_block_offset
;
216 ULONG extra_block_offset
;
217 BPTR new_lock
= ZERO
, old_lock
= ZERO
;
222 new_lock
= ParentOfFH(file
);
224 old_lock
= CurrentDir(new_lock
);
227 image
= AllocVec(sizeof(*image
), MEMF_CLEAR
);
229 error
= ERROR_NO_FREE_STORE
;
233 error
= mds_get_mdf_filename(file
, filename
, sizeof(filename
));
234 if (error
!= NO_ERROR
) goto error
;
236 image
->file
= Open(filename
, MODE_OLDFILE
);
242 if (Read(file
, &mds_header
, sizeof(mds_header
)) != sizeof(mds_header
) ||
243 !ChangeFilePosition(file
, rle32(&mds_header
.sessions_blocks_offset
), OFFSET_BEGINNING
) ||
244 Read(file
, &mds_session
, sizeof(mds_session
)) != sizeof(mds_session
))
250 if (memcmp(mds_header
.signature
, MDS_SIGNATURE
, sizeof(mds_header
.signature
))) {
251 error
= ERROR_OBJECT_WRONG_TYPE
;
255 image
->num_tracks
= rle16(&mds_session
.num_tracks
);
256 image
->block_size
= 2048;
257 image
->total_blocks
= rle32(&mds_session
.session_end
);
259 track
= (struct MDSTrack
*)&image
->tracks
;
260 track_block_offset
= rle32(&mds_session
.tracks_blocks_offset
);
261 for (i
= 0; i
< mds_session
.num_all_blocks
; i
++) {
262 if (!ChangeFilePosition(file
, track_block_offset
, OFFSET_BEGINNING
) ||
263 Read(file
, &mds_track
, sizeof(mds_track
)) != sizeof(mds_track
))
268 track_block_offset
+= sizeof(mds_track
);
269 mode
= mds_track
.mode
;
270 if (mode
!= MDS_TRACKMODE_UNKNOWN
) {
271 track
= track
->next
= AllocVec(sizeof(*track
), MEMF_ANY
);
273 error
= ERROR_NO_FREE_STORE
;
277 track
->track_num
= mds_track
.track_num
;
278 if (!image
->first_track
|| track
->track_num
< image
->first_track
) {
279 image
->first_track
= track
->track_num
;
281 if (!image
->last_track
|| track
->track_num
> image
->last_track
) {
282 image
->last_track
= track
->track_num
;
284 track
->sector_size
= rle16(&mds_track
.sector_size
);
285 track
->sync_size
= 0;
287 case MDS_TRACKMODE_AUDIO
:
289 if (track
->sector_size
!= 2352) {
290 error
= ERROR_BAD_NUMBER
;
293 case MDS_TRACKMODE_MODE1
:
294 track
->audio
= FALSE
;
295 switch (track
->sector_size
) {
299 track
->sync_size
= 16;
302 error
= ERROR_BAD_NUMBER
;
307 if (error
!= NO_ERROR
) break;
308 track
->offset
= rle64(&mds_track
.start_offset
);
309 extra_block_offset
= rle32(&mds_track
.extra_offset
);
310 if (!extra_block_offset
) {
311 error
= ERROR_REQUIRED_ARG_MISSING
;
314 if (!ChangeFilePosition(file
, extra_block_offset
, OFFSET_BEGINNING
) ||
315 Read(file
, &mds_extra
, sizeof(mds_extra
)) != sizeof(mds_extra
))
320 track
->sectors
= rle32(&mds_extra
.sectors
);
321 track
->length
= track
->sectors
* track
->sector_size
;
324 if (error
!= NO_ERROR
) goto error
;
330 CurrentDir(old_lock
);
335 Plugin_CloseImage(Self
, image
);
337 if (error
== NO_ERROR
) {
338 error
= ERROR_OBJECT_WRONG_TYPE
;
339 error_string
= MSG_EOF
;
341 IPlugin_SetDiskImageErrorA(unit
, error
, error_string
, error_args
);
346 static void strip_file_extension (STRPTR name
, CONST_STRPTR ext
) {
347 LONG len
= strlen(name
) - strlen(ext
);
350 if (!Stricmp(name
, ext
)) {
356 static LONG
mds_get_mdf_filename (BPTR file
, STRPTR buffer
, LONG size
) {
357 struct FileInfoBlock
*fib
;
358 LONG error
= NO_ERROR
;
359 fib
= AllocDosObject(DOS_FIB
, NULL
);
361 if (ExamineFH(file
, fib
)) {
362 Strlcpy(buffer
, fib
->fib_FileName
, size
);
363 strip_file_extension(buffer
, ".mds");
364 Strlcat(buffer
, ".mdf", size
);
368 FreeDosObject(DOS_FIB
, fib
);
370 error
= ERROR_NO_FREE_STORE
;
375 void MDS_CloseImage (struct DiskImagePlugin
*Self
, APTR image_ptr
) {
376 struct MDSImage
*image
= image_ptr
;
378 struct MDSTrack
*track
, *next_track
;
379 track
= image
->tracks
;
381 next_track
= track
->next
;
385 FreeVec(image
->out_buf
);
391 LONG
MDS_Geometry (struct DiskImagePlugin
*Self
, APTR image_ptr
, struct DriveGeometry
*dg
) {
392 struct MDSImage
*image
= image_ptr
;
393 dg
->dg_DeviceType
= DG_CDROM
;
394 dg
->dg_SectorSize
= image
->block_size
;
396 dg
->dg_TrackSectors
=
397 dg
->dg_CylSectors
= 1;
399 dg
->dg_TotalSectors
= image
->total_blocks
;
400 return IOERR_SUCCESS
;
403 LONG
MDS_Read (struct DiskImagePlugin
*Self
, APTR image_ptr
, struct IOStdReq
*io
) {
404 struct MDSImage
*image
= image_ptr
;
405 struct MDSTrack
*track
= image
->tracks
;
406 BPTR file
= image
->file
;
410 UQUAD read_offs
, next_offs
;
411 ULONG to_skip
, to_read
;
415 buffer
= io
->io_Data
;
416 offset
= ((UQUAD
)io
->io_Offset
)|((UQUAD
)io
->io_Actual
<< 32);
417 size
= io
->io_Length
;
420 if (offset
& 0x7ff) return IOERR_BADADDRESS
;
421 if (size
& 0x7ff) return IOERR_BADLENGTH
;
425 if (offset
>= image
->total_blocks
) {
426 return TDERR_SeekError
;
428 read_offs
= next_offs
= 0;
430 next_offs
+= track
->sectors
;
431 if (next_offs
> offset
) break;
432 read_offs
= next_offs
;
434 if (!track
) return TDERR_SeekError
;
437 to_skip
= offset
- read_offs
;
440 return TDERR_NoSecHdr
;
442 to_read
= max((LONG
)min(size
, track
->sectors
- to_skip
), 0);
444 read_pos
= track
->offset
+ ((UQUAD
)to_skip
* track
->sector_size
);
445 if (!ChangeFilePosition(file
, read_pos
, OFFSET_BEGINNING
)) {
446 return TDERR_SeekError
;
448 if (track
->sector_size
== 2048) {
449 read_size
= to_read
<< 11;
450 if (Read(file
, buffer
, read_size
) != read_size
) {
451 return IPlugin_DOS2IOErr(IoErr());
454 io
->io_Actual
+= read_size
;
456 read_size
= track
->sector_size
;
457 if (!(image
->out_buf
= ReAllocBuf(image
->out_buf
, &image
->out_size
, read_size
))) {
458 return ERROR_NO_FREE_STORE
;
461 if (Read(file
, image
->out_buf
, read_size
) != read_size
) {
462 return IPlugin_DOS2IOErr(IoErr());
464 CopyMem(image
->out_buf
+ track
->sync_size
, buffer
, 2048);
466 io
->io_Actual
+= 2048;
472 if (!track
) return IOERR_BADLENGTH
;
475 return IOERR_SUCCESS
;
478 void MDS_GetCDTracks (struct DiskImagePlugin
*Self
, APTR image_ptr
, struct CDTrack
**tracks
,
481 struct MDSImage
*image
= image_ptr
;
482 *tracks
= (struct CDTrack
*)image
->tracks
;
483 *num_tracks
= image
->num_tracks
;
486 LONG
MDS_ReadCDDA (struct DiskImagePlugin
*Self
, APTR image_ptr
, APTR buffer_ptr
, ULONG offset
,
489 struct MDSImage
*image
= image_ptr
;
490 UBYTE
*buffer
= buffer_ptr
;
491 struct MDSTrack
*track
= image
->tracks
;
492 BPTR file
= image
->file
;
493 UQUAD read_offs
, next_offs
;
494 ULONG to_skip
, to_read
;
497 ULONG bytes_read
= 0;
499 if (offset
>= image
->total_blocks
) {
502 read_offs
= next_offs
= 0;
504 next_offs
+= track
->sectors
;
505 if (next_offs
> offset
) break;
506 read_offs
= next_offs
;
508 if (!track
) return bytes_read
;
511 to_skip
= offset
- read_offs
;
513 if (!track
->audio
|| track
->sector_size
!= 2352) {
516 to_read
= max((LONG
)min(size
, track
->sectors
- to_skip
), 0);
518 read_pos
= track
->offset
+ ((UQUAD
)to_skip
* 2352ULL);
519 read_size
= to_read
* 2352;
520 if (!ChangeFilePosition(file
, read_pos
, OFFSET_BEGINNING
) ||
521 Read(file
, buffer
, read_size
) != read_size
)
526 bytes_read
+= read_size
;
529 if (!track
) return bytes_read
;