1 /******************************************************************************/
2 /* Mednafen - Multi-system Emulator                                           */
3 /******************************************************************************/
4 /* CDInterface.cpp:
5 **  Copyright (C) 2009-2018 Mednafen Team
6 **
7 ** This program is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU General Public License
9 ** as published by the Free Software Foundation; either version 2
10 ** of the License, or (at your option) any later version.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software Foundation, Inc.,
19 ** 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 */
21 
22 #include <mednafen/mednafen.h>
23 #include <mednafen/cdrom/CDInterface.h>
24 #include "CDInterface_MT.h"
25 #include "CDInterface_ST.h"
26 #include "CDAccess.h"
27 
28 namespace Mednafen
29 {
30 
31 using namespace CDUtility;
32 
CDInterface()33 CDInterface::CDInterface() : UnrecoverableError(false)
34 {
35 
36 
37 }
38 
~CDInterface()39 CDInterface::~CDInterface()
40 {
41 
42 
43 }
44 
NonDeterministic_CheckSectorReady(int32 lba)45 bool CDInterface::NonDeterministic_CheckSectorReady(int32 lba)
46 {
47  return true;
48 }
49 
ReadSectors(uint8 * buf,int32 lba,uint32 sector_count)50 uint8 CDInterface::ReadSectors(uint8* buf, int32 lba, uint32 sector_count)
51 {
52  uint8 ret = 0;
53 
54  if(UnrecoverableError)
55   return 0;
56 
57  while(sector_count--)
58  {
59   uint8 rawbuf[2352 + 96];
60   uint8 mode;
61 
62   if(!ReadRawSector(rawbuf, lba))
63   {
64    printf("ReadRawSector() failed in CDInterface::ReadSectors() for LBA=%d.\n", lba);
65    return 0;
66   }
67 
68   mode = rawbuf[12 + 3];
69   if(mode != 0x1 && mode != 0x2)
70    return 0;
71 
72   // Error if mode 2 form 2.
73   if(mode == 0x2 && (rawbuf[12 + 6] & 0x20))
74    return 0;
75 
76   if(!edc_lec_check_and_correct(rawbuf, mode == 2))
77    return false;
78 
79   memcpy(buf, rawbuf + ((mode == 2) ? 24 : 16), 2048);
80   ret = ret ? ret : mode;
81 
82   lba++;
83   buf += 2048;
84  }
85 
86  return ret;
87 }
88 
89 
90 class CDInterface_Stream_Thing : public Stream
91 {
92  public:
93 
94  CDInterface_Stream_Thing(CDInterface *cdintf_arg, uint32 lba_arg, uint32 sector_count_arg);
95  ~CDInterface_Stream_Thing();
96 
97  virtual uint64 attributes(void) override;
98 
99  virtual uint64 read(void *data, uint64 count, bool error_on_eos = true) override;
100  virtual void write(const void *data, uint64 count) override;
101  virtual void truncate(uint64 length) override;
102 
103  virtual void seek(int64 offset, int whence) override;
104  virtual uint64 tell(void) override;
105  virtual uint64 size(void) override;
106  virtual void flush(void) override;
107  virtual void close(void) override;
108 
109  private:
110  CDInterface *cdintf;
111  const uint32 start_lba;
112  const uint32 sector_count;
113  int64 position;
114 };
115 
CDInterface_Stream_Thing(CDInterface * cdintf_arg,uint32 start_lba_arg,uint32 sector_count_arg)116 CDInterface_Stream_Thing::CDInterface_Stream_Thing(CDInterface *cdintf_arg, uint32 start_lba_arg, uint32 sector_count_arg) : cdintf(cdintf_arg), start_lba(start_lba_arg), sector_count(sector_count_arg)
117 {
118 
119 }
120 
~CDInterface_Stream_Thing()121 CDInterface_Stream_Thing::~CDInterface_Stream_Thing()
122 {
123 
124 }
125 
attributes(void)126 uint64 CDInterface_Stream_Thing::attributes(void)
127 {
128  return(ATTRIBUTE_READABLE | ATTRIBUTE_SEEKABLE);
129 }
130 
read(void * data,uint64 count,bool error_on_eos)131 uint64 CDInterface_Stream_Thing::read(void *data, uint64 count, bool error_on_eos)
132 {
133  if(count > (((uint64)sector_count * 2048) - position))
134  {
135   if(error_on_eos)
136   {
137    throw MDFN_Error(0, "EOF");
138   }
139 
140   count = ((uint64)sector_count * 2048) - position;
141  }
142 
143  if(!count)
144   return(0);
145 
146  for(uint64 rp = position; rp < (position + count); rp = (rp &~ 2047) + 2048)
147  {
148   uint8 buf[2048];
149 
150   if(!cdintf->ReadSectors(buf, start_lba + (rp / 2048), 1))
151   {
152    throw MDFN_Error(ErrnoHolder(EIO));
153   }
154 
155   //::printf("Meow: %08llx -- %08llx\n", count, (rp - position) + std::min<uint64>(2048 - (rp & 2047), count - (rp - position)));
156   memcpy((uint8*)data + (rp - position), buf + (rp & 2047), std::min<uint64>(2048 - (rp & 2047), count - (rp - position)));
157  }
158 
159  position += count;
160 
161  return count;
162 }
163 
write(const void * data,uint64 count)164 void CDInterface_Stream_Thing::write(const void *data, uint64 count)
165 {
166  throw MDFN_Error(ErrnoHolder(EBADF));
167 }
168 
truncate(uint64 length)169 void CDInterface_Stream_Thing::truncate(uint64 length)
170 {
171  throw MDFN_Error(ErrnoHolder(EBADF));
172 }
173 
seek(int64 offset,int whence)174 void CDInterface_Stream_Thing::seek(int64 offset, int whence)
175 {
176  int64 new_position;
177 
178  switch(whence)
179  {
180   default:
181 	throw MDFN_Error(ErrnoHolder(EINVAL));
182 	break;
183 
184   case SEEK_SET:
185 	new_position = offset;
186 	break;
187 
188   case SEEK_CUR:
189 	new_position = position + offset;
190 	break;
191 
192   case SEEK_END:
193 	new_position = ((int64)sector_count * 2048) + offset;
194 	break;
195  }
196 
197  if(new_position < 0 || new_position > ((int64)sector_count * 2048))
198   throw MDFN_Error(ErrnoHolder(EINVAL));
199 
200  position = new_position;
201 }
202 
tell(void)203 uint64 CDInterface_Stream_Thing::tell(void)
204 {
205  return position;
206 }
207 
size(void)208 uint64 CDInterface_Stream_Thing::size(void)
209 {
210  return(sector_count * 2048);
211 }
212 
flush(void)213 void CDInterface_Stream_Thing::flush(void)
214 {
215 
216 }
217 
close(void)218 void CDInterface_Stream_Thing::close(void)
219 {
220 
221 }
222 
223 
MakeStream(int32 lba,uint32 sector_count)224 Stream *CDInterface::MakeStream(int32 lba, uint32 sector_count)
225 {
226  return new CDInterface_Stream_Thing(this, lba, sector_count);
227 }
228 
229 
Open(VirtualFS * vfs,const std::string & path,bool image_memcache,const uint64 affinity)230 CDInterface* CDInterface::Open(VirtualFS* vfs, const std::string& path, bool image_memcache, const uint64 affinity)
231 {
232  std::unique_ptr<CDAccess> cda(CDAccess_Open(vfs, path, image_memcache));
233 
234  //
235  // Don't use multithreaded reader if we're using a custom VirtualFS implementation, to avoid
236  // thread safety nightmares.
237  //
238  if(image_memcache || (vfs != &NVFS))
239   return new CDInterface_ST(std::move(cda));
240  else
241   return new CDInterface_MT(std::move(cda), affinity);
242 }
243 
244 }
245