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"
36 #include <SDI_compiler.h>
37 #include "rev/diskimage.device_rev.h"
41 extern struct DiskImagePlugin nrg_plugin
;
43 PLUGIN_TABLE(&nrg_plugin
)
46 struct NRGTrack
*next
;
62 struct NRGTrack
*tracks
;
70 BOOL
NRG_Init (struct DiskImagePlugin
*Self
, const struct PluginData
*data
);
71 BOOL
NRG_CheckImage (struct DiskImagePlugin
*Self
, BPTR file
, CONST_STRPTR name
, QUAD file_size
,
72 const UBYTE
*test
, LONG testsize
);
73 APTR
NRG_OpenImage (struct DiskImagePlugin
*Self
, APTR unit
, BPTR file
, CONST_STRPTR name
);
74 void NRG_CloseImage (struct DiskImagePlugin
*Self
, APTR image_ptr
);
75 LONG
NRG_Geometry (struct DiskImagePlugin
*Self
, APTR image_ptr
, struct DriveGeometry
*dg
);
76 LONG
NRG_Read (struct DiskImagePlugin
*Self
, APTR image_ptr
, struct IOStdReq
*io
);
77 void NRG_GetCDTracks (struct DiskImagePlugin
*Self
, APTR image_ptr
, struct CDTrack
**tracks
,
79 LONG
NRG_ReadCDDA (struct DiskImagePlugin
*Self
, APTR image_ptr
, APTR buffer_ptr
, ULONG offset
,
82 struct DiskImagePlugin nrg_plugin
= {
83 PLUGIN_NODE(0, "NRG"),
84 PLUGIN_FLAG_FOOTER
|PLUGIN_FLAG_M68K
,
102 struct Library
*SysBase
;
103 struct Library
*DOSBase
;
104 static struct DIPluginIFace
*IPlugin
;
106 BOOL
NRG_Init (struct DiskImagePlugin
*Self
, const struct PluginData
*data
) {
107 SysBase
= data
->SysBase
;
108 DOSBase
= data
->DOSBase
;
109 IPlugin
= data
->IPlugin
;
113 #define ID_NERO MAKE_ID('N','E','R','O') /* v1 */
114 #define ID_NER5 MAKE_ID('N','E','R','5') /* v2 */
115 #define ID_CUES MAKE_ID('C','U','E','S') /* v1 */
116 #define ID_CUEX MAKE_ID('C','U','E','X') /* v2 */
117 #define ID_DAOI MAKE_ID('D','A','O','I') /* v1 */
118 #define ID_DAOX MAKE_ID('D','A','O','X') /* v2 */
119 #define ID_TAOI MAKE_ID('T','A','O','I') /* v1 */
120 #define ID_TAOX MAKE_ID('T','A','O','X') /* v2 */
121 #define ID_CDTX MAKE_ID('C','D','T','X') /* v2 */
122 #define ID_ETNF MAKE_ID('E','T','N','F') /* v1 */
123 #define ID_ETN2 MAKE_ID('E','T','N','2') /* v2 */
124 #define ID_SINF MAKE_ID('S','I','N','F') /* v1 & v2 */
125 #define ID_MTYP MAKE_ID('M','T','Y','P') /* v1 & v2 */
126 #define ID_END MAKE_ID('E','N','D','!') /* v1 & v2 */
128 BOOL
NRG_CheckImage (struct DiskImagePlugin
*Self
, BPTR file
, CONST_STRPTR name
, QUAD file_size
,
129 const UBYTE
*test
, LONG testsize
)
131 return (testsize
>= 8 && rbe32(&test
[testsize
-8]) == ID_NERO
) ||
132 (testsize
>= 12 && rbe32(&test
[testsize
-12]) == ID_NER5
);
158 ULONG index0
; // pre gap
159 ULONG index1
; // start of track
160 ULONG index2
; // end of track + 1
164 ULONG chunk_size
; // chunk size in little-endian format
169 nrg_daoi_track_t tracks
[];
176 UQUAD index0
; // pre gap
177 UQUAD index1
; // start of track
178 UQUAD index2
; // end of track + 1
182 ULONG chunk_size
; // chunk size in little-endian format
187 nrg_daox_track_t tracks
[];
202 static APTR
nrg_read_chunk (BPTR file
, nrg_chunk_t
*chunk
, APTR
*buf
, LONG
*buf_size
);
204 APTR
NRG_OpenImage (struct DiskImagePlugin
*Self
, APTR unit
, BPTR file
,
208 LONG error
= NO_ERROR
;
209 LONG error_string
= NO_ERROR_STRING
;
210 IPTR error_args
[4] = {0};
211 struct NRGImage
*image
= NULL
;
221 struct NRGTrack
*track
;
224 image
= AllocVec(sizeof(*image
), MEMF_CLEAR
);
226 error
= ERROR_NO_FREE_STORE
;
231 if (!ChangeFilePosition(file
, -(int)sizeof(footer
), OFFSET_END
) ||
232 Read(file
, &footer
, sizeof(footer
)) != sizeof(footer
))
238 if (rbe32(&footer
.v1
.id
) == ID_NERO
) {
239 image
->nrg_version
= 1;
240 offset
= rbe32(&footer
.v1
.offset
);
241 } else if (rbe32(&footer
.v2
.id
) == ID_NER5
) {
242 image
->nrg_version
= 2;
243 offset
= rbe64(&footer
.v2
.offset
);
245 error
= ERROR_OBJECT_WRONG_TYPE
;
248 if (!ChangeFilePosition(file
, offset
, OFFSET_BEGINNING
)) {
254 if (Read(file
, &chunk
, sizeof(chunk
)) != sizeof(chunk
)) {
258 wbe32(&chunk
.id
, chunk
.id
);
259 wbe32(&chunk
.size
, chunk
.size
);
263 if (chunk
.size
< (sizeof(nrg_daoi_t
) + sizeof(nrg_daoi_track_t
))) {
264 error
= ERROR_BAD_NUMBER
;
267 if (!(daoi
= nrg_read_chunk(file
, &chunk
, &buf
, &buf_size
))) {
271 track
= (struct NRGTrack
*)&image
->tracks
;
272 image
->first_track
= daoi
->first_track
;
273 image
->last_track
= daoi
->last_track
;
274 image
->num_tracks
= image
->last_track
- image
->first_track
+ 1;
275 for (i
= 0; i
< image
->num_tracks
; i
++) {
276 track
->next
= AllocVec(sizeof(*track
), MEMF_ANY
);
277 if (!(track
= track
->next
)) {
278 error
= ERROR_NO_FREE_STORE
;
282 track
->track_num
= image
->first_track
+i
;
283 track
->sector_size
= rbe32(&daoi
->tracks
[i
].sector_size
);
284 track
->sync_size
= 0;
285 switch (track
->sector_size
) {
287 track
->audio
= FALSE
;
293 error
= ERROR_BAD_NUMBER
;
296 track
->offset
= rbe32(&daoi
->tracks
[i
].index1
);
297 track
->length
= rbe32(&daoi
->tracks
[i
].index2
) - track
->offset
;
298 track
->sectors
= track
->length
/ track
->sector_size
;
299 image
->total_bytes
+= track
->sectors
<< 11;
300 if (track
->sector_size
!= 2048 && track
->sector_size
!= 2352) {
301 error
= ERROR_BAD_NUMBER
;
309 if (chunk
.size
< (sizeof(nrg_daox_t
) + sizeof(nrg_daox_track_t
))) {
310 error
= ERROR_BAD_NUMBER
;
313 if (!(daox
= nrg_read_chunk(file
, &chunk
, &buf
, &buf_size
))) {
317 track
= (struct NRGTrack
*)&image
->tracks
;
318 image
->first_track
= daox
->first_track
;
319 image
->last_track
= daox
->last_track
;
320 image
->num_tracks
= image
->last_track
- image
->first_track
+ 1;
321 for (i
= 0; i
< image
->num_tracks
; i
++) {
322 track
->next
= AllocVec(sizeof(*track
), MEMF_ANY
);
323 if (!(track
= track
->next
)) {
324 error
= ERROR_NO_FREE_STORE
;
328 track
->track_num
= image
->first_track
+i
;
329 track
->sector_size
= rbe32(&daox
->tracks
[i
].sector_size
);
330 track
->sync_size
= 0;
331 switch (track
->sector_size
) {
333 track
->audio
= FALSE
;
339 error
= ERROR_BAD_NUMBER
;
342 track
->offset
= rbe64(&daox
->tracks
[i
].index1
);
343 track
->length
= rbe64(&daox
->tracks
[i
].index2
) - track
->offset
;
344 track
->sectors
= track
->length
/ track
->sector_size
;
345 image
->total_bytes
+= track
->sectors
<< 11;
346 if (track
->sector_size
!= 2048 && track
->sector_size
!= 2352) {
347 error
= ERROR_BAD_NUMBER
;
355 if (chunk
.size
< sizeof(nrg_taoi_t
)) {
356 error
= ERROR_BAD_NUMBER
;
359 if (!(taoi
= nrg_read_chunk(file
, &chunk
, &buf
, &buf_size
))) {
363 image
->first_track
= 1;
364 image
->last_track
= 1;
365 image
->num_tracks
= image
->last_track
- image
->first_track
+ 1;
366 image
->tracks
= AllocVec(sizeof(*track
), MEMF_ANY
);
367 if (!(track
= image
->tracks
)) {
368 error
= ERROR_NO_FREE_STORE
;
372 track
->track_num
= 1;
373 track
->audio
= FALSE
;
374 track
->sector_size
= 2048;
375 track
->sync_size
= 0;
376 track
->offset
= rbe32(&taoi
->track_offset
);
377 track
->length
= rbe32(&taoi
->track_length
);
378 track
->sectors
= track
->length
/ track
->sector_size
;
379 image
->total_bytes
+= track
->sectors
<< 11;
384 if (chunk
.size
< sizeof(nrg_taox_t
)) {
385 error
= ERROR_BAD_NUMBER
;
388 if (!(taox
= nrg_read_chunk(file
, &chunk
, &buf
, &buf_size
))) {
392 image
->first_track
= 1;
393 image
->last_track
= 1;
394 image
->num_tracks
= image
->last_track
- image
->first_track
+ 1;
395 image
->tracks
= AllocVec(sizeof(*track
), MEMF_ANY
);
396 if (!(track
= image
->tracks
)) {
397 error
= ERROR_NO_FREE_STORE
;
401 track
->track_num
= 1;
402 track
->audio
= FALSE
;
403 track
->sector_size
= 2048;
404 track
->sync_size
= 0;
405 track
->offset
= rbe64(&taox
->track_offset
);
406 track
->length
= rbe64(&taox
->track_length
);
407 track
->sectors
= track
->length
/ track
->sector_size
;
408 image
->total_bytes
+= track
->sectors
<< 11;
413 error
= ERROR_OBJECT_NOT_FOUND
;
417 if (!ChangeFilePosition(file
, chunk
.size
, OFFSET_CURRENT
)) {
425 image
->block_size
= 2048;
426 image
->total_blocks
= image
->total_bytes
>> 11;
432 Plugin_CloseImage(Self
, image
);
437 if (error
== NO_ERROR
) {
438 error
= ERROR_OBJECT_WRONG_TYPE
;
439 error_string
= MSG_EOF
;
441 IPlugin_SetDiskImageErrorA(unit
, error
, error_string
, error_args
);
446 static APTR
nrg_read_chunk (BPTR file
, nrg_chunk_t
*chunk
, APTR
*buf
, LONG
*buf_size
) {
447 if (*buf_size
< chunk
->size
) {
449 *buf
= AllocVec(chunk
->size
, MEMF_ANY
);
450 *buf_size
= chunk
->size
;
453 SetIoErr(ERROR_NO_FREE_STORE
);
457 if (Read(file
, *buf
, chunk
->size
) != chunk
->size
) {
463 void NRG_CloseImage (struct DiskImagePlugin
*Self
, APTR image_ptr
) {
464 struct NRGImage
*image
= image_ptr
;
466 struct NRGTrack
*track
, *next_track
;
467 track
= image
->tracks
;
469 next_track
= track
->next
;
473 FreeVec(image
->out_buf
);
479 LONG
NRG_Geometry (struct DiskImagePlugin
*Self
, APTR image_ptr
, struct DriveGeometry
*dg
) {
480 struct NRGImage
*image
= image_ptr
;
481 dg
->dg_DeviceType
= DG_CDROM
;
482 dg
->dg_SectorSize
= image
->block_size
;
484 dg
->dg_TrackSectors
=
485 dg
->dg_CylSectors
= 1;
487 dg
->dg_TotalSectors
= image
->total_blocks
;
488 return IOERR_SUCCESS
;
491 LONG
NRG_Read (struct DiskImagePlugin
*Self
, APTR image_ptr
, struct IOStdReq
*io
) {
492 struct NRGImage
*image
= image_ptr
;
493 struct NRGTrack
*track
= image
->tracks
;
494 BPTR file
= image
->file
;
498 UQUAD read_offs
, next_offs
;
499 ULONG to_skip
, to_read
;
503 buffer
= io
->io_Data
;
504 offset
= ((UQUAD
)io
->io_Offset
)|((UQUAD
)io
->io_Actual
<< 32);
505 size
= io
->io_Length
;
508 if (offset
& 0x7ff) return IOERR_BADADDRESS
;
509 if (size
& 0x7ff) return IOERR_BADLENGTH
;
513 if (offset
>= image
->total_blocks
) {
514 return TDERR_SeekError
;
516 read_offs
= next_offs
= 0;
518 next_offs
+= track
->sectors
;
519 if (next_offs
> offset
) break;
520 read_offs
= next_offs
;
522 if (!track
) return TDERR_SeekError
;
525 to_skip
= offset
- read_offs
;
528 return TDERR_NoSecHdr
;
530 to_read
= max((LONG
)min(size
, track
->sectors
- to_skip
), 0);
532 read_pos
= track
->offset
+ ((UQUAD
)to_skip
* track
->sector_size
);
533 if (!ChangeFilePosition(file
, read_pos
, OFFSET_BEGINNING
)) {
534 return TDERR_SeekError
;
536 if (track
->sector_size
== 2048) {
537 read_size
= to_read
<< 11;
538 if (Read(file
, buffer
, read_size
) != read_size
) {
539 return IPlugin_DOS2IOErr(IoErr());
542 io
->io_Actual
+= read_size
;
544 read_size
= track
->sector_size
;
545 if (!(image
->out_buf
= ReAllocBuf(image
->out_buf
, &image
->out_size
, read_size
))) {
546 return ERROR_NO_FREE_STORE
;
549 if (Read(file
, image
->out_buf
, read_size
) != read_size
) {
550 return IPlugin_DOS2IOErr(IoErr());
552 CopyMem(image
->out_buf
+ track
->sync_size
, buffer
, 2048);
554 io
->io_Actual
+= 2048;
560 if (!track
) return IOERR_BADLENGTH
;
563 return IOERR_SUCCESS
;
566 void NRG_GetCDTracks (struct DiskImagePlugin
*Self
, APTR image_ptr
, struct CDTrack
**tracks
,
569 struct NRGImage
*image
= image_ptr
;
570 *tracks
= (struct CDTrack
*)image
->tracks
;
571 *num_tracks
= image
->num_tracks
;
574 LONG
NRG_ReadCDDA (struct DiskImagePlugin
*Self
, APTR image_ptr
, APTR buffer_ptr
, ULONG offset
,
577 struct NRGImage
*image
= image_ptr
;
578 UBYTE
*buffer
= buffer_ptr
;
579 struct NRGTrack
*track
= image
->tracks
;
580 BPTR file
= image
->file
;
581 UQUAD read_offs
, next_offs
;
582 ULONG to_skip
, to_read
;
585 ULONG bytes_read
= 0;
587 if (offset
>= image
->total_blocks
) {
590 read_offs
= next_offs
= 0;
592 next_offs
+= track
->sectors
;
593 if (next_offs
> offset
) break;
594 read_offs
= next_offs
;
596 if (!track
) return bytes_read
;
599 to_skip
= offset
- read_offs
;
601 if (!track
->audio
|| track
->sector_size
!= 2352) {
604 to_read
= max((LONG
)min(size
, track
->sectors
- to_skip
), 0);
606 read_pos
= track
->offset
+ ((UQUAD
)to_skip
* 2352ULL);
607 read_size
= to_read
* 2352;
608 if (!ChangeFilePosition(file
, read_pos
, OFFSET_BEGINNING
) ||
609 Read(file
, buffer
, read_size
) != read_size
)
614 bytes_read
+= read_size
;
617 if (!track
) return bytes_read
;