Check for SYS/GL during library init. Reason is that
[AROS.git] / workbench / devs / diskimage / plugins / cue / cue.c
blob9308db87ed32816e4052ed36d42ec5c84347b3c1
1 /* Copyright 2007-2012 Fredrik Wikstrom. All rights reserved.
2 **
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
5 ** are met:
6 **
7 ** 1. Redistributions of source code must retain the above copyright
8 ** notice, this list of conditions and the following disclaimer.
9 **
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>
32 #ifndef USE_MPG123
33 #include <libraries/mpega.h>
34 #include <proto/mpega.h>
35 #endif
36 #include "endian.h"
37 #include "device_locale.h"
38 #include "scsicmd.h"
39 #include <string.h>
40 #include <ctype.h>
41 #include <stdio.h>
42 #include <SDI_compiler.h>
43 #include "audio/aiff.h"
44 #ifdef USE_FLAC
45 #include "audio/flac.h"
46 #endif
47 #ifdef USE_MPG123
48 #include "audio/mp3_mpg123.h"
49 #else
50 #include "audio/mp3_mpega.h"
51 #endif
52 #ifdef USE_VORBIS
53 #include "audio/vorbis.h"
54 #endif
55 #include "audio/wave.h"
56 #ifdef USE_WAVPACK
57 #include "audio/wavpack.h"
58 #endif
59 #include "cue.h"
60 #include "rev/diskimage.device_rev.h"
62 PLUGIN_VERSTAG("CUE")
64 extern struct DiskImagePlugin cue_plugin;
65 #ifdef USE_FLAC
66 extern struct DiskImagePlugin flac_plugin;
67 #endif
68 #ifdef USE_WAVPACK
69 extern struct DiskImagePlugin wavpack_plugin;
70 #endif
72 #if !defined(USE_FLAC) && !defined(USE_WAVPACK)
73 PLUGIN_TABLE(&cue_plugin)
74 #else
75 PLUGIN_TABLE(&cue_plugin
76 #ifdef USE_FLAC
77 , &flac_plugin
78 #endif
79 #ifdef USE_WAVPACK
80 , &wavpack_plugin
81 #endif
83 #endif
85 BOOL CUE_Init (struct DiskImagePlugin *Self, const struct PluginData *data);
86 void CUE_Exit (struct DiskImagePlugin *Self);
87 BOOL CUE_CheckImage (struct DiskImagePlugin *Self, BPTR file, CONST_STRPTR name, QUAD file_size,
88 const UBYTE *test, LONG testsize);
89 APTR CUE_OpenImage (struct DiskImagePlugin *Self, APTR unit, BPTR file, CONST_STRPTR name);
90 void CUE_CloseImage (struct DiskImagePlugin *Self, APTR image_ptr);
91 LONG CUE_Geometry (struct DiskImagePlugin *Self, APTR image_ptr, struct DriveGeometry *dg);
92 LONG CUE_Read (struct DiskImagePlugin *Self, APTR image_ptr, struct IOStdReq *io);
93 void CUE_GetCDTracks (struct DiskImagePlugin *Self, APTR image_ptr, struct CDTrack **tracks,
94 ULONG *num_tracks);
95 LONG CUE_ReadCDDA (struct DiskImagePlugin *Self, APTR image_ptr, APTR buffer_ptr, ULONG offset,
96 ULONG size);
98 struct DiskImagePlugin cue_plugin = {
99 PLUGIN_NODE(0, "CUE"),
100 PLUGIN_FLAG_M68K,
102 ZERO,
103 NULL,
104 CUE_Init,
105 CUE_Exit,
106 CUE_CheckImage,
107 CUE_OpenImage,
108 CUE_CloseImage,
109 CUE_Geometry,
110 CUE_Read,
111 NULL,
112 NULL,
113 NULL,
114 CUE_GetCDTracks,
115 CUE_ReadCDDA
118 struct Library *SysBase;
119 struct Library *DOSBase;
120 struct Library *UtilityBase;
121 struct DIPluginIFace *IPlugin;
122 #ifndef USE_MPG123
123 struct Library *MPEGABase;
124 #endif
125 #if defined(USE_MPG123) && defined(__AROS__)
126 struct Library *StdCBase;
127 #endif
129 #ifdef USE_MPG123
130 int malloc_init(void);
131 void malloc_exit(void);
132 #endif
134 BOOL CUE_Init (struct DiskImagePlugin *Self, const struct PluginData *data) {
135 SysBase = data->SysBase;
136 DOSBase = data->DOSBase;
137 UtilityBase = data->UtilityBase;
138 IPlugin = data->IPlugin;
139 #ifdef USE_MPG123
140 #ifdef __AROS__
141 StdCBase = data->StdCBase;
142 #endif
143 if (!malloc_init()) {
144 return FALSE;
146 if (mpg123_init() != MPG123_OK) {
147 malloc_exit();
148 return FALSE;
150 #endif
151 return TRUE;
154 void CUE_Exit (struct DiskImagePlugin *Self) {
155 #ifdef USE_MPG123
156 mpg123_exit();
157 malloc_exit();
158 #endif
161 BOOL CUE_CheckImage (struct DiskImagePlugin *Self, BPTR file, CONST_STRPTR name, QUAD file_size,
162 const UBYTE *test, LONG testsize)
164 int len;
165 len = strlen(name)-4;
166 if (len > 0) {
167 name += len;
168 return !Stricmp(name, ".cue") && IsText(test, testsize);
170 return FALSE;
173 #ifndef USE_MPG123
174 static const MPEGA_CTRL mpa_ctrl = {
175 NULL,
176 { FALSE, { 1, 2, 44100 }, { 1, 2, 44100 } },
177 { FALSE, { 1, 2, 44100 }, { 1, 2, 44100 } },
181 #endif
183 LONG cue_parse_args (STRPTR cmd, STRPTR *argv, int *argc_ptr);
184 LONG cue_parse_index (CONST_STRPTR index_str, ULONG *index);
185 LONG cue_fix_track_indexes (struct CUEImage *image);
186 static inline LONG get_file_header (CONST_STRPTR filename, APTR header, LONG size);
188 APTR CUE_OpenImage (struct DiskImagePlugin *Self, APTR unit, BPTR file,
189 CONST_STRPTR name)
191 LONG done = FALSE;
192 LONG error = NO_ERROR;
193 LONG error_string = NO_ERROR_STRING;
194 IPTR error_args[4] = {0};
195 struct CUEImage *image = NULL;
196 struct CUEFile *cue_file;
197 struct CUETrack *track, *prev_track;
198 STRPTR line_buffer;
199 int argc;
200 STRPTR argv[MAX_ARGS];
201 LONG track_num, index_type;
202 ULONG index;
203 BPTR new_lock = ZERO, old_lock = ZERO;
205 new_lock = ParentOfFH(file);
206 if (new_lock) {
207 old_lock = CurrentDir(new_lock);
210 line_buffer = AllocVec(LINE_BUFFER_SIZE, MEMF_ANY);
211 image = AllocVec(sizeof(*image), MEMF_CLEAR);
212 if (!line_buffer || !image) {
213 error = ERROR_NO_FREE_STORE;
214 goto error;
217 cue_file = NULL;
218 track = prev_track = NULL;
219 while (FGets(file, line_buffer, LINE_BUFFER_SIZE)) {
220 error = cue_parse_args(line_buffer, argv, &argc);
221 if (error != NO_ERROR) break;
222 if (argc > 0) {
223 if (!strcmp(argv[0], "REM"));
224 else if (!strcmp(argv[0], "FILE")) {
225 prev_track = NULL;
226 if (argc < 3) {
227 error = ERROR_REQUIRED_ARG_MISSING;
228 break;
230 if (argc > 3) {
231 error = ERROR_TOO_MANY_ARGS;
232 break;
234 if (!cue_file) {
235 cue_file = image->files = AllocVec(sizeof(*cue_file), MEMF_CLEAR);
236 } else {
237 cue_file = cue_file->next = AllocVec(sizeof(*cue_file), MEMF_CLEAR);
239 if (!cue_file) {
240 error = ERROR_NO_FREE_STORE;
241 break;
243 if (!strcmp(argv[2], "BINARY") || !strcmp(argv[2], "MOTOROLA")) {
244 cue_file->type = !strcmp(argv[2], "BINARY") ? FILE_BINARY : FILE_MOTOROLA;
245 cue_file->f.bin.file = Open(argv[1], MODE_OLDFILE);
246 if (!cue_file->f.bin.file) {
247 error = IoErr();
248 break;
250 cue_file->f.bin.file_size = GetFileSize(cue_file->f.bin.file);
251 if (cue_file->f.bin.file_size == -1) {
252 error = IoErr();
253 break;
255 } else {
256 UBYTE header[12];
257 if (get_file_header(argv[1], header, sizeof(header)) != sizeof(header)) {
258 error = IoErr();
259 if (error == NO_ERROR) {
260 error = ERROR_OBJECT_WRONG_TYPE;
261 error_string = MSG_EOF;
263 break;
265 if (AIFF_header(header)) {
266 cue_file->type = FILE_AIFF;
267 cue_file->f.aud.stream = (AUDIO_STREAM *)AIFF_open(argv[1]);
268 #ifdef USE_FLAC
269 } else if (FLAC_header(header)) {
270 cue_file->type = FILE_FLAC;
271 cue_file->f.aud.stream = (AUDIO_STREAM *)FLAC_open(argv[1], FALSE);
272 #endif
273 #ifdef USE_VORBIS
274 } else if (VORBIS_header(header)) {
275 cue_file->type = FILE_VORBIS;
276 cue_file->f.aud.stream = (AUDIO_STREAM *)VORBIS_open(argv[1]);
277 #endif
278 } else if (strcmp(argv[2], "MP3") && WAVE_header(header)) {
279 cue_file->type = FILE_WAVE;
280 cue_file->f.aud.stream = (AUDIO_STREAM *)WAVE_open(argv[1]);
281 #ifdef USE_WAVPACK
282 } else if (WAVPACK_header(header)) {
283 cue_file->type = FILE_WAVPACK;
284 cue_file->f.aud.stream = (AUDIO_STREAM *)WAVPACK_open(argv[1], FALSE);
285 #endif
286 } else if (!strcmp(argv[2], "MP3")) {
287 cue_file->type = FILE_MP3;
288 #ifndef USE_MPG123
289 image->uses_mp3 = TRUE;
290 if (!image->mpegabase) {
291 image->mpegabase = OpenLibrary("mpega.library", 0);
293 if (!image->mpegabase) {
294 error = ERROR_OBJECT_NOT_FOUND;
295 error_string = MSG_REQ;
296 error_args[0] = (IPTR)"mpega.library";
297 break;
299 MPEGABase = image->mpegabase;
300 #endif
301 cue_file->f.aud.stream = (AUDIO_STREAM *)MP3_open(argv[1]);
302 } else {
303 error = ERROR_OBJECT_WRONG_TYPE;
304 error_string = MSG_UNKNCOMPMETHOD;
305 break;
307 if (!cue_file->f.aud.stream) {
308 error = IoErr();
309 if (error == NO_ERROR) {
310 error = ERROR_OBJECT_WRONG_TYPE;
311 error_string = MSG_EOF;
313 break;
316 } else if (!strcmp(argv[0], "TRACK")) {
317 if (!cue_file) {
318 error = ERROR_REQUIRED_ARG_MISSING;
319 break;
321 if (argc < 3) {
322 error = ERROR_REQUIRED_ARG_MISSING;
323 break;
325 if (argc > 3) {
326 error = ERROR_TOO_MANY_ARGS;
327 break;
329 if (track && cue_file == track->file) {
330 prev_track = track;
332 if (!track) {
333 track = image->tracks = AllocVec(sizeof(*track), MEMF_CLEAR);
334 } else {
335 track = track->next = AllocVec(sizeof(*track), MEMF_CLEAR);
337 if (!track) {
338 error = ERROR_NO_FREE_STORE;
339 break;
341 track->file = cue_file;
342 cue_file->refcount++;
343 if (StrToLong(argv[1], &track_num) == -1) {
344 error = ERROR_BAD_NUMBER;
345 break;
347 track->track_num = track_num;
348 if (!image->first_track || track_num < image->first_track) {
349 image->first_track = track_num;
351 if (!image->last_track || track_num > image->last_track) {
352 image->last_track = track_num;
354 if (!strcmp(argv[2], "MODE1/2048")) {
355 track->audio = FALSE;
356 track->sector_size = 2048;
357 track->sync_size = 0;
358 } else if (!strcmp(argv[2], "MODE1/2352")) {
359 track->audio = FALSE;
360 track->sector_size = 2352;
361 track->sync_size = 16;
362 } else if (!strcmp(argv[2], "MODE2/2352")) {
363 track->audio = FALSE;
364 track->sector_size = 2352;
365 track->sync_size = 24;
366 } else if (!strcmp(argv[2], "AUDIO")) {
367 track->audio = TRUE;
368 track->sector_size = 2352;
369 track->sync_size = 0;
370 } else {
371 error = ERROR_NOT_IMPLEMENTED;
372 break;
374 track->index0 = -1;
375 track->index1 = -1;
376 track->index2 = -1;
377 } else if (!strcmp(argv[0], "INDEX")) {
378 if (!track) {
379 error = ERROR_REQUIRED_ARG_MISSING;
380 break;
382 if (argc < 3) {
383 error = ERROR_REQUIRED_ARG_MISSING;
384 break;
386 if (argc > 3) {
387 error = ERROR_TOO_MANY_ARGS;
388 break;
390 if (StrToLong(argv[1], &index_type) == -1) {
391 error = ERROR_BAD_NUMBER;
392 break;
394 error = cue_parse_index(argv[2], &index);
395 if (error != NO_ERROR) break;
396 switch (index_type) {
397 case 0:
398 if (prev_track && prev_track->index2 == -1) {
399 prev_track->index2 = index;
401 track->index0 = index;
402 break;
403 case 1:
404 if (prev_track && prev_track->index2 == -1) {
405 prev_track->index2 = index;
407 track->index1 = index;
408 break;
413 if (error != NO_ERROR) {
414 goto error;
416 error = IoErr();
417 if (error != NO_ERROR) {
418 goto error;
421 if (!image->tracks) {
422 error = ERROR_REQUIRED_ARG_MISSING;
423 goto error;
426 if ((error = cue_fix_track_indexes(image)) != NO_ERROR) {
427 goto error;
430 #ifndef USE_MPG123
431 if (image->uses_mp3) {
432 LONG i;
433 for (i = 0; i < MPEGA_MAX_CHANNELS; i++) {
434 image->pcm[i] = AllocVec(MPEGA_PCM_SIZE * sizeof(WORD), MEMF_ANY);
435 if (!image->pcm[i]) {
436 error = ERROR_NO_FREE_STORE;
437 goto error;
441 #endif
443 done = TRUE;
445 error:
446 FreeVec(line_buffer);
447 if (new_lock) {
448 CurrentDir(old_lock);
449 UnLock(new_lock);
451 Close(file);
452 if (!done) {
453 Plugin_CloseImage(Self, image);
454 image = NULL;
455 if (error == NO_ERROR) {
456 error = ERROR_OBJECT_WRONG_TYPE;
457 error_string = MSG_EOF;
459 IPlugin_SetDiskImageErrorA(unit, error, error_string, error_args);
461 return image;
464 enum {
465 NO_ARG,
466 UNQUOTED_ARG,
467 DOUBLE_QUOTED_ARG,
468 SINGLE_QUOTED_ARG,
469 COMMENT
472 LONG cue_parse_args (STRPTR cmd, STRPTR *argv, int *argc_ptr) {
473 LONG error = NO_ERROR;
474 int argc = 0;
475 int state = NO_ARG;
476 TEXT c;
477 do {
478 c = *cmd;
479 switch (state) {
480 case NO_ARG:
481 if (c == 0 || isspace(c));
482 else if (c == ';' || c == '#')
483 state = COMMENT;
484 else if (c == '"') {
485 if (argc < MAX_ARGS) {
486 argv[argc++] = cmd+1;
487 state = DOUBLE_QUOTED_ARG;
488 } else {
489 error = ERROR_TOO_MANY_ARGS;
491 } else if (c == '\'') {
492 if (argc < MAX_ARGS) {
493 argv[argc++] = cmd+1;
494 state = SINGLE_QUOTED_ARG;
495 } else {
496 error = ERROR_TOO_MANY_ARGS;
498 } else {
499 if (argc < MAX_ARGS) {
500 argv[argc++] = cmd;
501 state = UNQUOTED_ARG;
502 } else {
503 error = ERROR_TOO_MANY_ARGS;
506 break;
507 case UNQUOTED_ARG:
508 if (c == 0 || isspace(c)) {
509 *cmd = 0;
510 if (argc == 1 && !strcmp(argv[0], "REM"))
511 state = COMMENT;
512 else
513 state = NO_ARG;
514 } else if (c == ';' || c == '#') {
515 *cmd = 0;
516 state = COMMENT;
518 break;
519 case DOUBLE_QUOTED_ARG:
520 if (c == 0) {
521 error = ERROR_UNMATCHED_QUOTES;
522 state = NO_ARG;
523 } else if (c == '"') {
524 *cmd = 0;
525 state = NO_ARG;
527 break;
528 case SINGLE_QUOTED_ARG:
529 if (c == 0) {
530 error = ERROR_UNMATCHED_QUOTES;
531 state = NO_ARG;
532 } else if (c == '\'') {
533 *cmd = 0;
534 state = NO_ARG;
536 break;
537 case COMMENT:
538 break;
540 cmd++;
541 } while (c != 0 && error == NO_ERROR && state != COMMENT);
542 *argc_ptr = argc;
543 return error;
546 LONG cue_parse_index (CONST_STRPTR index_str, ULONG *index) {
547 if (strlen(index_str) == 8 &&
548 isdigit(index_str[0]) && isdigit(index_str[1]) && index_str[2] == ':' &&
549 isdigit(index_str[3]) && isdigit(index_str[4]) && index_str[5] == ':' &&
550 isdigit(index_str[6]) && isdigit(index_str[7]))
552 ULONG minute, second, frame;
553 minute = (index_str[0] - '0')*10 + (index_str[1] - '0');
554 second = (index_str[3] - '0')*10 + (index_str[4] - '0');
555 frame = (index_str[6] - '0')*10 + (index_str[7] - '0');
556 if (second < 60 && frame < 75) {
557 *index = MSF2ADDR(minute, second, frame);
558 return NO_ERROR;
561 return ERROR_BAD_NUMBER;
564 LONG cue_fix_track_indexes (struct CUEImage *image) {
565 struct CUETrack *track = image->tracks;
566 struct CUEFile *cue_file = NULL;
567 UQUAD offset = 0, length, sectors;
568 LONG error = NO_ERROR;
570 image->block_size = 2048;
571 image->total_blocks = 0;
572 image->num_tracks = 0;
573 track = image->tracks;
574 while (track) {
575 if (track->file != cue_file) {
576 cue_file = track->file;
577 offset = 0;
579 if (track->index0 == -1) {
580 track->index0 = track->index1;
582 if (track->index1 == -1) {
583 error = ERROR_REQUIRED_ARG_MISSING;
584 break;
586 offset += (track->index1 - track->index0) * track->sector_size;
587 if (track->index2 == -1) {
588 switch (cue_file->type) {
589 case FILE_BINARY:
590 case FILE_MOTOROLA:
591 sectors = (cue_file->f.bin.file_size - offset) / track->sector_size;
592 track->index2 = track->index1 + sectors;
593 break;
595 default:
596 sectors = (cue_file->f.aud.stream->length - offset + (track->sector_size-1)) / track->sector_size;
597 track->index2 = track->index1 + sectors;
598 break;
601 if (track->index1 < track->index0 || track->index2 < track->index1) {
602 error = ERROR_BAD_NUMBER;
603 break;
605 sectors = track->index2 - track->index1;
606 length = sectors * track->sector_size;
607 track->offset = offset;
608 track->sectors = sectors;
609 track->length = length;
610 image->total_blocks += sectors;
611 image->num_tracks++;
612 offset += length;
613 track = track->next;
615 return error;
618 static inline LONG get_file_header (CONST_STRPTR filename, APTR header, LONG size) {
619 BPTR file;
620 file = Open(filename, MODE_OLDFILE);
621 if (file) {
622 size = Read(file, header, size);
623 Close(file);
624 return size;
626 return -1;
629 void CUE_CloseImage (struct DiskImagePlugin *Self, APTR image_ptr) {
630 struct CUEImage *image = image_ptr;
631 if (image) {
632 struct CUEFile *cue_file, *next_file;
633 struct CUETrack *track, *next_track;
634 #ifndef USE_MPG123
635 if (image->uses_mp3) {
636 LONG i;
637 for (i = 0; i < MPEGA_MAX_CHANNELS; i++) {
638 FreeVec(image->pcm[i]);
641 #endif
642 track = image->tracks;
643 while (track) {
644 next_track = track->next;
645 FreeVec(track);
646 track = next_track;
648 cue_file = image->files;
649 while (cue_file) {
650 next_file = cue_file->next;
651 switch (cue_file->type) {
652 case FILE_BINARY:
653 case FILE_MOTOROLA:
654 Close(cue_file->f.bin.file);
655 break;
657 default:
658 if (cue_file->f.aud.stream) {
659 AUDIO_close(cue_file->f.aud.stream);
661 break;
663 FreeVec(cue_file);
664 cue_file = next_file;
666 FreeVec(image->out_buf);
667 #ifndef USE_MPG123
668 if (image->mpegabase) CloseLibrary(image->mpegabase);
669 #endif
670 FreeVec(image);
674 LONG CUE_Geometry (struct DiskImagePlugin *Self, APTR image_ptr, struct DriveGeometry *dg) {
675 struct CUEImage *image = image_ptr;
676 dg->dg_DeviceType = DG_CDROM;
677 dg->dg_SectorSize = image->block_size;
678 dg->dg_Heads =
679 dg->dg_TrackSectors =
680 dg->dg_CylSectors = 1;
681 dg->dg_Cylinders =
682 dg->dg_TotalSectors = image->total_blocks;
683 return IOERR_SUCCESS;
686 LONG CUE_Read (struct DiskImagePlugin *Self, APTR image_ptr, struct IOStdReq *io) {
687 struct CUEImage *image = image_ptr;
688 struct CUETrack *track = image->tracks;
689 struct CUEFile *cue_file;
690 BPTR file;
691 UBYTE *buffer;
692 UQUAD offset;
693 ULONG size;
694 UQUAD read_offs, next_offs;
695 ULONG to_skip, to_read;
696 UQUAD read_pos;
697 ULONG read_size;
699 buffer = io->io_Data;
700 offset = ((UQUAD)io->io_Offset)|((UQUAD)io->io_Actual << 32);
701 size = io->io_Length;
702 io->io_Actual = 0;
704 if (offset & 0x7ff) return IOERR_BADADDRESS;
705 if (size & 0x7ff) return IOERR_BADLENGTH;
707 offset >>= 11;
708 size >>= 11;
709 if (offset >= image->total_blocks) {
710 return TDERR_SeekError;
712 read_offs = next_offs = 0;
713 for (;;) {
714 next_offs += track->sectors;
715 if (next_offs > offset) break;
716 read_offs = next_offs;
717 track = track->next;
718 if (!track) return TDERR_SeekError;
721 to_skip = offset - read_offs;
722 while (size) {
723 if (track->audio) {
724 return TDERR_NoSecHdr;
726 cue_file = track->file;
727 to_read = max((LONG)min(size, track->sectors - to_skip), 0);
728 size -= to_read;
729 read_pos = track->offset + ((uint64)to_skip * track->sector_size);
730 switch (cue_file->type) {
731 case FILE_BINARY:
732 case FILE_MOTOROLA:
733 file = cue_file->f.bin.file;
734 if (!ChangeFilePosition(file, read_pos, OFFSET_BEGINNING)) {
735 return TDERR_SeekError;
737 if (track->sector_size == 2048) {
738 read_size = to_read << 11;
739 if (Read(file, buffer, read_size) != read_size) {
740 return IPlugin_DOS2IOErr(IoErr());
742 buffer += read_size;
743 io->io_Actual += read_size;
744 } else {
745 read_size = track->sector_size;
746 if (!(image->out_buf = ReAllocBuf(image->out_buf, &image->out_size, read_size))) {
747 return ERROR_NO_FREE_STORE;
749 while (to_read--) {
750 if (Read(file, image->out_buf, read_size) != read_size) {
751 return IPlugin_DOS2IOErr(IoErr());
753 CopyMem(image->out_buf + track->sync_size, buffer, 2048);
754 buffer += 2048;
755 io->io_Actual += 2048;
758 break;
760 default:
761 if (track->sector_size == 2048) {
762 read_size = to_read << 11;
763 if (AUDIO_read(cue_file->f.aud.stream, buffer, read_pos, read_size) != read_size) {
764 return IPlugin_DOS2IOErr(IoErr());
766 buffer += read_size;
767 io->io_Actual += read_size;
768 } else {
769 read_size = track->sector_size;
770 if (!(image->out_buf = ReAllocBuf(image->out_buf, &image->out_size, read_size))) {
771 return ERROR_NO_FREE_STORE;
773 while (to_read--) {
774 if (AUDIO_read(cue_file->f.aud.stream, image->out_buf, read_pos, read_size) != read_size) {
775 return IPlugin_DOS2IOErr(IoErr());
777 CopyMem(image->out_buf + track->sync_size, buffer, 2048);
778 buffer += 2048;
779 io->io_Actual += 2048;
780 read_pos += read_size;
783 break;
785 if (size) {
786 to_skip = 0;
787 track = track->next;
788 if (!track) return IOERR_BADLENGTH;
791 return IOERR_SUCCESS;
794 void CUE_GetCDTracks (struct DiskImagePlugin *Self, APTR image_ptr, struct CDTrack **tracks,
795 ULONG *num_tracks)
797 struct CUEImage *image = image_ptr;
798 *tracks = (struct CDTrack *)image->tracks;
799 *num_tracks = image->num_tracks;
802 LONG CUE_ReadCDDA (struct DiskImagePlugin *Self, APTR image_ptr, APTR buffer_ptr, ULONG offset,
803 ULONG size)
805 struct CUEImage *image = image_ptr;
806 UBYTE *buffer = buffer_ptr;
807 struct CUETrack *track = image->tracks;
808 struct CUEFile *cue_file;
809 BPTR file;
810 UQUAD read_offs, next_offs;
811 ULONG to_skip, to_read;
812 UQUAD read_pos;
813 ULONG read_size;
814 ULONG bytes_read = 0;
816 if (offset >= image->total_blocks) {
817 return bytes_read;
819 read_offs = next_offs = 0;
820 for (;;) {
821 next_offs += track->sectors;
822 if (next_offs > offset) break;
823 read_offs = next_offs;
824 track = track->next;
825 if (!track) return bytes_read;
828 to_skip = offset - read_offs;
829 while (size) {
830 if (!track->audio || track->sector_size != 2352) {
831 return bytes_read;
833 cue_file = track->file;
834 to_read = max((LONG)min(size, track->sectors - to_skip), 0);
835 size -= to_read;
836 read_pos = track->offset + ((UQUAD)to_skip * 2352ULL);
837 read_size = to_read * 2352UL;
838 switch (cue_file->type) {
839 case FILE_BINARY:
840 case FILE_MOTOROLA:
841 file = cue_file->f.bin.file;
842 if (!ChangeFilePosition(file, read_pos, OFFSET_BEGINNING) ||
843 Read(file, buffer, read_size) != read_size)
845 return bytes_read;
847 if (cue_file->type == FILE_MOTOROLA) {
848 swab2(buffer, buffer, read_size);
850 buffer += read_size;
851 bytes_read += read_size;
852 break;
854 default:
855 if (AUDIO_read(cue_file->f.aud.stream, buffer, read_pos, read_size) != read_size) {
856 return bytes_read;
858 buffer += read_size;
859 bytes_read += read_size;
860 break;
862 if (size) {
863 to_skip = 0;
864 track = track->next;
865 if (!track) return bytes_read;
868 return bytes_read;