Files
archived-pcsx2/pcsx2/CDVD/IsoFS/IsoFile.cpp
Connor McLaughlin 893b3c629d Everything: Remove a **lot** of wx, and px nonsense
- common has no wx left except for Path.
 - pcsx2core only has it in a few places (memory cards and path related
   stuff).
2022-05-22 13:58:56 +01:00

247 lines
5.4 KiB
C++

/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "common/Assertions.h"
#include "common/Exceptions.h"
#include "IsoFS.h"
#include "IsoFile.h"
#include <cstdio>
IsoFile::IsoFile(SectorSource& reader, const std::string_view& filename)
: internalReader(reader)
, fileEntry(IsoDirectory(reader).FindFile(filename))
{
Init();
}
IsoFile::IsoFile(const IsoDirectory& dir, const std::string_view& filename)
: internalReader(dir.GetReader())
, fileEntry(dir.FindFile(filename))
{
Init();
}
IsoFile::IsoFile(SectorSource& reader, const IsoFileDescriptor& fileEntry)
: internalReader(reader)
, fileEntry(fileEntry)
{
Init();
}
void IsoFile::Init()
{
//pxAssertDev( fileEntry.IsFile(), "IsoFile Error: Filename points to a directory." );
currentSectorNumber = fileEntry.lba;
currentOffset = 0;
sectorOffset = 0;
maxOffset = std::max<u32>(0, fileEntry.size);
if (maxOffset > 0)
internalReader.readSector(currentSector, currentSectorNumber);
}
u32 IsoFile::seek(u32 absoffset)
{
u32 endOffset = absoffset;
int oldSectorNumber = currentSectorNumber;
int newSectorNumber = fileEntry.lba + (int)(endOffset / sectorLength);
if (oldSectorNumber != newSectorNumber)
{
internalReader.readSector(currentSector, newSectorNumber);
}
currentOffset = endOffset;
currentSectorNumber = newSectorNumber;
sectorOffset = (int)(currentOffset % sectorLength);
return currentOffset;
}
// Returns the new offset in the file. Out-of-bounds seeks are automatically truncated at 0
// and fileLength.
u32 IsoFile::seek(s64 offset, int mode)
{
switch (mode)
{
case SEEK_SET:
pxAssertDev(offset >= 0 && offset <= (s64)ULONG_MAX, "Invalid seek position from start.");
return seek(offset);
case SEEK_CUR:
// truncate negative values to zero, and positive values to 4gb
return seek(std::min(std::max<s64>(0, (s64)currentOffset + offset), (s64)ULONG_MAX));
case SEEK_END:
// truncate negative values to zero, and positive values to 4gb
return seek(std::min(std::max<s64>(0, (s64)fileEntry.size + offset), (s64)ULONG_MAX));
jNO_DEFAULT;
}
return 0; // unreachable
}
void IsoFile::reset()
{
seek(0);
}
// Returns the number of bytes actually skipped.
s32 IsoFile::skip(s32 n)
{
s32 oldOffset = currentOffset;
if (n < 0)
return 0;
seek(currentOffset + n);
return currentOffset - oldOffset;
}
u32 IsoFile::getSeekPos() const
{
return currentOffset;
}
bool IsoFile::eof() const
{
return (currentOffset == maxOffset);
}
// loads the current sector index into the CurrentSector buffer.
void IsoFile::makeDataAvailable()
{
if (sectorOffset >= sectorLength)
{
currentSectorNumber++;
internalReader.readSector(currentSector, currentSectorNumber);
sectorOffset -= sectorLength;
}
}
u8 IsoFile::readByte()
{
if (currentOffset >= maxOffset)
throw Exception::EndOfStream();
makeDataAvailable();
currentOffset++;
return currentSector[sectorOffset++];
}
// Reads data from a single sector at a time. Reads cannot cross sector boundaries.
int IsoFile::internalRead(void* dest, int off, int len)
{
if (len > 0)
{
size_t slen = len;
if (slen > (maxOffset - currentOffset))
{
slen = (int)(maxOffset - currentOffset);
}
memcpy((u8*)dest + off, currentSector + sectorOffset, slen);
sectorOffset += slen;
currentOffset += slen;
return slen;
}
return 0;
}
// returns the number of bytes actually read.
s32 IsoFile::read(void* dest, s32 len)
{
pxAssert(dest != NULL);
pxAssert(len >= 0); // should we silent-fail on negative length reads? prolly not...
if (len <= 0)
return 0;
int off = 0;
int totalLength = 0;
int firstSector = internalRead(dest, off, std::min(len, sectorLength - sectorOffset));
off += firstSector;
len -= firstSector;
totalLength += firstSector;
// Read whole sectors
while ((len >= sectorLength) && (currentOffset < maxOffset))
{
makeDataAvailable();
int n = internalRead(dest, off, sectorLength);
off += n;
len -= n;
totalLength += n;
}
// Read remaining, if any
if (len > 0)
{
makeDataAvailable();
int lastSector = internalRead(dest, off, len);
totalLength += lastSector;
}
return totalLength;
}
// Reads data until it reaches a newline character (either \n, \r, or ASCII-Z). The caller is
// responsible for handling files with DOS-style newlines (CR/LF pairs), if needed. The resulting
// string has no newlines.
//
// Read data is unformatted 8 bit / Ascii. If the source file is known to be UTF8, use the fromUTF8()
// conversion helper provided by PCSX2 utility classes.
//
std::string IsoFile::readLine()
{
std::string s;
s.reserve(512);
while (!eof())
{
u8 c = read<u8>();
if ((c == '\n') || (c == '\r') || (c == 0))
break;
s += c;
}
return s;
}
u32 IsoFile::getLength()
{
return maxOffset;
}
const IsoFileDescriptor& IsoFile::getEntry()
{
return fileEntry;
}