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 <libraries/mpega.h>
34 #include <proto/mpega.h>
37 #include "device_locale.h"
42 #include <SDI_compiler.h>
43 #include "audio/aiff.h"
45 #include "audio/flac.h"
48 #include "audio/mp3_mpg123.h"
50 #include "audio/mp3_mpega.h"
53 #include "audio/vorbis.h"
55 #include "audio/wave.h"
57 #include "audio/wavpack.h"
60 #include "rev/diskimage.device_rev.h"
64 extern struct DiskImagePlugin cue_plugin
;
66 extern struct DiskImagePlugin flac_plugin
;
69 extern struct DiskImagePlugin wavpack_plugin
;
72 #if !defined(USE_FLAC) && !defined(USE_WAVPACK)
73 PLUGIN_TABLE(&cue_plugin
)
75 PLUGIN_TABLE(&cue_plugin
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
,
95 LONG
CUE_ReadCDDA (struct DiskImagePlugin
*Self
, APTR image_ptr
, APTR buffer_ptr
, ULONG offset
,
98 struct DiskImagePlugin cue_plugin
= {
99 PLUGIN_NODE(0, "CUE"),
118 struct Library
*SysBase
;
119 struct Library
*DOSBase
;
120 struct Library
*UtilityBase
;
121 struct DIPluginIFace
*IPlugin
;
123 struct Library
*MPEGABase
;
125 #if defined(USE_MPG123) && defined(__AROS__)
126 struct Library
*StdCBase
;
130 int malloc_init(void);
131 void malloc_exit(void);
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
;
141 StdCBase
= data
->StdCBase
;
143 if (!malloc_init()) {
146 if (mpg123_init() != MPG123_OK
) {
154 void CUE_Exit (struct DiskImagePlugin
*Self
) {
161 BOOL
CUE_CheckImage (struct DiskImagePlugin
*Self
, BPTR file
, CONST_STRPTR name
, QUAD file_size
,
162 const UBYTE
*test
, LONG testsize
)
165 len
= strlen(name
)-4;
168 return !Stricmp(name
, ".cue") && IsText(test
, testsize
);
174 static const MPEGA_CTRL mpa_ctrl
= {
176 { FALSE
, { 1, 2, 44100 }, { 1, 2, 44100 } },
177 { FALSE
, { 1, 2, 44100 }, { 1, 2, 44100 } },
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
,
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
;
200 STRPTR argv
[MAX_ARGS
];
201 LONG track_num
, index_type
;
203 BPTR new_lock
= ZERO
, old_lock
= ZERO
;
205 new_lock
= ParentOfFH(file
);
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
;
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;
223 if (!strcmp(argv
[0], "REM"));
224 else if (!strcmp(argv
[0], "FILE")) {
227 error
= ERROR_REQUIRED_ARG_MISSING
;
231 error
= ERROR_TOO_MANY_ARGS
;
235 cue_file
= image
->files
= AllocVec(sizeof(*cue_file
), MEMF_CLEAR
);
237 cue_file
= cue_file
->next
= AllocVec(sizeof(*cue_file
), MEMF_CLEAR
);
240 error
= ERROR_NO_FREE_STORE
;
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
) {
250 cue_file
->f
.bin
.file_size
= GetFileSize(cue_file
->f
.bin
.file
);
251 if (cue_file
->f
.bin
.file_size
== -1) {
257 if (get_file_header(argv
[1], header
, sizeof(header
)) != sizeof(header
)) {
259 if (error
== NO_ERROR
) {
260 error
= ERROR_OBJECT_WRONG_TYPE
;
261 error_string
= MSG_EOF
;
265 if (AIFF_header(header
)) {
266 cue_file
->type
= FILE_AIFF
;
267 cue_file
->f
.aud
.stream
= (AUDIO_STREAM
*)AIFF_open(argv
[1]);
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
);
274 } else if (VORBIS_header(header
)) {
275 cue_file
->type
= FILE_VORBIS
;
276 cue_file
->f
.aud
.stream
= (AUDIO_STREAM
*)VORBIS_open(argv
[1]);
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]);
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
);
286 } else if (!strcmp(argv
[2], "MP3")) {
287 cue_file
->type
= FILE_MP3
;
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";
299 MPEGABase
= image
->mpegabase
;
301 cue_file
->f
.aud
.stream
= (AUDIO_STREAM
*)MP3_open(argv
[1]);
303 error
= ERROR_OBJECT_WRONG_TYPE
;
304 error_string
= MSG_UNKNCOMPMETHOD
;
307 if (!cue_file
->f
.aud
.stream
) {
309 if (error
== NO_ERROR
) {
310 error
= ERROR_OBJECT_WRONG_TYPE
;
311 error_string
= MSG_EOF
;
316 } else if (!strcmp(argv
[0], "TRACK")) {
318 error
= ERROR_REQUIRED_ARG_MISSING
;
322 error
= ERROR_REQUIRED_ARG_MISSING
;
326 error
= ERROR_TOO_MANY_ARGS
;
329 if (track
&& cue_file
== track
->file
) {
333 track
= image
->tracks
= AllocVec(sizeof(*track
), MEMF_CLEAR
);
335 track
= track
->next
= AllocVec(sizeof(*track
), MEMF_CLEAR
);
338 error
= ERROR_NO_FREE_STORE
;
341 track
->file
= cue_file
;
342 cue_file
->refcount
++;
343 if (StrToLong(argv
[1], &track_num
) == -1) {
344 error
= ERROR_BAD_NUMBER
;
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")) {
368 track
->sector_size
= 2352;
369 track
->sync_size
= 0;
371 error
= ERROR_NOT_IMPLEMENTED
;
377 } else if (!strcmp(argv
[0], "INDEX")) {
379 error
= ERROR_REQUIRED_ARG_MISSING
;
383 error
= ERROR_REQUIRED_ARG_MISSING
;
387 error
= ERROR_TOO_MANY_ARGS
;
390 if (StrToLong(argv
[1], &index_type
) == -1) {
391 error
= ERROR_BAD_NUMBER
;
394 error
= cue_parse_index(argv
[2], &index
);
395 if (error
!= NO_ERROR
) break;
396 switch (index_type
) {
398 if (prev_track
&& prev_track
->index2
== -1) {
399 prev_track
->index2
= index
;
401 track
->index0
= index
;
404 if (prev_track
&& prev_track
->index2
== -1) {
405 prev_track
->index2
= index
;
407 track
->index1
= index
;
413 if (error
!= NO_ERROR
) {
417 if (error
!= NO_ERROR
) {
421 if (!image
->tracks
) {
422 error
= ERROR_REQUIRED_ARG_MISSING
;
426 if ((error
= cue_fix_track_indexes(image
)) != NO_ERROR
) {
431 if (image
->uses_mp3
) {
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
;
446 FreeVec(line_buffer
);
448 CurrentDir(old_lock
);
453 Plugin_CloseImage(Self
, image
);
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
);
472 LONG
cue_parse_args (STRPTR cmd
, STRPTR
*argv
, int *argc_ptr
) {
473 LONG error
= NO_ERROR
;
481 if (c
== 0 || isspace(c
));
482 else if (c
== ';' || c
== '#')
485 if (argc
< MAX_ARGS
) {
486 argv
[argc
++] = cmd
+1;
487 state
= DOUBLE_QUOTED_ARG
;
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
;
496 error
= ERROR_TOO_MANY_ARGS
;
499 if (argc
< MAX_ARGS
) {
501 state
= UNQUOTED_ARG
;
503 error
= ERROR_TOO_MANY_ARGS
;
508 if (c
== 0 || isspace(c
)) {
510 if (argc
== 1 && !strcmp(argv
[0], "REM"))
514 } else if (c
== ';' || c
== '#') {
519 case DOUBLE_QUOTED_ARG
:
521 error
= ERROR_UNMATCHED_QUOTES
;
523 } else if (c
== '"') {
528 case SINGLE_QUOTED_ARG
:
530 error
= ERROR_UNMATCHED_QUOTES
;
532 } else if (c
== '\'') {
541 } while (c
!= 0 && error
== NO_ERROR
&& state
!= COMMENT
);
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
);
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
;
575 if (track
->file
!= cue_file
) {
576 cue_file
= track
->file
;
579 if (track
->index0
== -1) {
580 track
->index0
= track
->index1
;
582 if (track
->index1
== -1) {
583 error
= ERROR_REQUIRED_ARG_MISSING
;
586 offset
+= (track
->index1
- track
->index0
) * track
->sector_size
;
587 if (track
->index2
== -1) {
588 switch (cue_file
->type
) {
591 sectors
= (cue_file
->f
.bin
.file_size
- offset
) / track
->sector_size
;
592 track
->index2
= track
->index1
+ sectors
;
596 sectors
= (cue_file
->f
.aud
.stream
->length
- offset
+ (track
->sector_size
-1)) / track
->sector_size
;
597 track
->index2
= track
->index1
+ sectors
;
601 if (track
->index1
< track
->index0
|| track
->index2
< track
->index1
) {
602 error
= ERROR_BAD_NUMBER
;
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
;
618 static inline LONG
get_file_header (CONST_STRPTR filename
, APTR header
, LONG size
) {
620 file
= Open(filename
, MODE_OLDFILE
);
622 size
= Read(file
, header
, size
);
629 void CUE_CloseImage (struct DiskImagePlugin
*Self
, APTR image_ptr
) {
630 struct CUEImage
*image
= image_ptr
;
632 struct CUEFile
*cue_file
, *next_file
;
633 struct CUETrack
*track
, *next_track
;
635 if (image
->uses_mp3
) {
637 for (i
= 0; i
< MPEGA_MAX_CHANNELS
; i
++) {
638 FreeVec(image
->pcm
[i
]);
642 track
= image
->tracks
;
644 next_track
= track
->next
;
648 cue_file
= image
->files
;
650 next_file
= cue_file
->next
;
651 switch (cue_file
->type
) {
654 Close(cue_file
->f
.bin
.file
);
658 if (cue_file
->f
.aud
.stream
) {
659 AUDIO_close(cue_file
->f
.aud
.stream
);
664 cue_file
= next_file
;
666 FreeVec(image
->out_buf
);
668 if (image
->mpegabase
) CloseLibrary(image
->mpegabase
);
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
;
679 dg
->dg_TrackSectors
=
680 dg
->dg_CylSectors
= 1;
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
;
694 UQUAD read_offs
, next_offs
;
695 ULONG to_skip
, to_read
;
699 buffer
= io
->io_Data
;
700 offset
= ((UQUAD
)io
->io_Offset
)|((UQUAD
)io
->io_Actual
<< 32);
701 size
= io
->io_Length
;
704 if (offset
& 0x7ff) return IOERR_BADADDRESS
;
705 if (size
& 0x7ff) return IOERR_BADLENGTH
;
709 if (offset
>= image
->total_blocks
) {
710 return TDERR_SeekError
;
712 read_offs
= next_offs
= 0;
714 next_offs
+= track
->sectors
;
715 if (next_offs
> offset
) break;
716 read_offs
= next_offs
;
718 if (!track
) return TDERR_SeekError
;
721 to_skip
= offset
- read_offs
;
724 return TDERR_NoSecHdr
;
726 cue_file
= track
->file
;
727 to_read
= max((LONG
)min(size
, track
->sectors
- to_skip
), 0);
729 read_pos
= track
->offset
+ ((uint64
)to_skip
* track
->sector_size
);
730 switch (cue_file
->type
) {
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());
743 io
->io_Actual
+= read_size
;
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
;
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);
755 io
->io_Actual
+= 2048;
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());
767 io
->io_Actual
+= read_size
;
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
;
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);
779 io
->io_Actual
+= 2048;
780 read_pos
+= read_size
;
788 if (!track
) return IOERR_BADLENGTH
;
791 return IOERR_SUCCESS
;
794 void CUE_GetCDTracks (struct DiskImagePlugin
*Self
, APTR image_ptr
, struct CDTrack
**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
,
805 struct CUEImage
*image
= image_ptr
;
806 UBYTE
*buffer
= buffer_ptr
;
807 struct CUETrack
*track
= image
->tracks
;
808 struct CUEFile
*cue_file
;
810 UQUAD read_offs
, next_offs
;
811 ULONG to_skip
, to_read
;
814 ULONG bytes_read
= 0;
816 if (offset
>= image
->total_blocks
) {
819 read_offs
= next_offs
= 0;
821 next_offs
+= track
->sectors
;
822 if (next_offs
> offset
) break;
823 read_offs
= next_offs
;
825 if (!track
) return bytes_read
;
828 to_skip
= offset
- read_offs
;
830 if (!track
->audio
|| track
->sector_size
!= 2352) {
833 cue_file
= track
->file
;
834 to_read
= max((LONG
)min(size
, track
->sectors
- to_skip
), 0);
836 read_pos
= track
->offset
+ ((UQUAD
)to_skip
* 2352ULL);
837 read_size
= to_read
* 2352UL;
838 switch (cue_file
->type
) {
841 file
= cue_file
->f
.bin
.file
;
842 if (!ChangeFilePosition(file
, read_pos
, OFFSET_BEGINNING
) ||
843 Read(file
, buffer
, read_size
) != read_size
)
847 if (cue_file
->type
== FILE_MOTOROLA
) {
848 swab2(buffer
, buffer
, read_size
);
851 bytes_read
+= read_size
;
855 if (AUDIO_read(cue_file
->f
.aud
.stream
, buffer
, read_pos
, read_size
) != read_size
) {
859 bytes_read
+= read_size
;
865 if (!track
) return bytes_read
;