4jcraft/Minecraft.World/IO/Files/FileInputStream.cpp
2026-03-13 17:06:56 -05:00

197 lines
6.1 KiB
C++

#include "../../Platform/stdafx.h"
#include "File.h"
#include "FileInputStream.h"
#include <algorithm>
extern CConsoleMinecraftApp app;
namespace {
__int64 FileTell(std::FILE* file) {
#if defined(_WIN32)
return _ftelli64(file);
#else
return static_cast<__int64>(ftello(file));
#endif
}
bool FileSeek(std::FILE* file, __int64 offset, int origin) {
#if defined(_WIN32)
return _fseeki64(file, offset, origin) == 0;
#else
return fseeko(file, static_cast<off_t>(offset), origin) == 0;
#endif
}
} // namespace
// Creates a FileInputStream by opening a connection to an actual file, the file
// named by the File object file in the file system. A new FileDescriptor object
// is created to represent this file connection. First, if there is a security
// manager, its checkRead method is called with the path represented by the file
// argument as its argument.
//
// If the named file does not exist, is a directory rather than a regular file,
// or for some other reason cannot be opened for reading then a
// FileNotFoundException is thrown.
//
// Parameters:
// file - the file to be opened for reading.
// Throws:
// FileNotFoundException - if the file does not exist, is a directory rather
// than a regular file, or for some other reason cannot be opened for reading.
// SecurityException - if a security manager exists and its checkRead method
// denies read access to the file.
FileInputStream::FileInputStream(const File& file) : m_fileHandle(NULL) {
#if defined(_WIN32)
m_fileHandle = _wfopen(file.getPath().c_str(), L"rb");
#else
const std::string nativePath = wstringtofilename(file.getPath());
m_fileHandle = std::fopen(nativePath.c_str(), "rb");
#endif
if (m_fileHandle == NULL) {
// TODO 4J Stu - Any form of error/exception handling
//__debugbreak();
app.FatalLoadError();
}
}
FileInputStream::~FileInputStream() {
if (m_fileHandle != NULL) {
std::fclose(m_fileHandle);
}
}
// Reads a byte of data from this input stream. This method blocks if no input
// is yet available. Returns: the next byte of data, or -1 if the end of the
// file is reached.
int FileInputStream::read() {
if (m_fileHandle == NULL) {
return -1;
}
std::uint8_t byteRead = static_cast<std::uint8_t>(0);
const size_t numberOfBytesRead = std::fread(&byteRead, 1, 1, m_fileHandle);
if (std::ferror(m_fileHandle) != 0) {
// TODO 4J Stu - Some kind of error handling
app.FatalLoadError();
// return -1;
} else if (numberOfBytesRead == 0) {
// File pointer is past the end of the file
return -1;
}
return static_cast<int>(byteRead);
}
// Reads up to b.length bytes of data from this input stream into an array of
// bytes. This method blocks until some input is available. Parameters: b - the
// buffer into which the data is read. Returns: the total number of bytes read
// into the buffer, or -1 if there is no more data because the end of the file
// has been reached.
int FileInputStream::read(byteArray b) {
if (m_fileHandle == NULL) {
return -1;
}
const size_t numberOfBytesRead =
std::fread(b.data, 1, b.length, m_fileHandle);
if (std::ferror(m_fileHandle) != 0) {
// TODO 4J Stu - Some kind of error handling
app.FatalLoadError();
// return -1;
} else if (numberOfBytesRead == 0) {
// File pointer is past the end of the file
return -1;
}
return numberOfBytesRead;
}
// Reads up to len bytes of data from this input stream into an array of bytes.
// If len is not zero, the method blocks until some input is available;
// otherwise, no bytes are read and 0 is returned. Parameters: b - the buffer
// into which the data is read. off - the start offset in the destination array
// b len - the maximum number of bytes read. Returns: the total number of bytes
// read into the buffer, or -1 if there is no more data because the end of the
// file has been reached.
int FileInputStream::read(byteArray b, unsigned int offset,
unsigned int length) {
// 4J Stu - We don't want to read any more than the array buffer can hold
assert(length <= (b.length - offset));
if (m_fileHandle == NULL) {
return -1;
}
const size_t numberOfBytesRead =
std::fread(&b[offset], 1, length, m_fileHandle);
if (std::ferror(m_fileHandle) != 0) {
// TODO 4J Stu - Some kind of error handling
app.FatalLoadError();
// return -1;
} else if (numberOfBytesRead == 0) {
// File pointer is past the end of the file
return -1;
}
return numberOfBytesRead;
}
// Closes this file input stream and releases any system resources associated
// with the stream. If this stream has an associated channel then the channel is
// closed as well.
void FileInputStream::close() {
if (m_fileHandle == NULL) {
// printf("\n\nFileInputStream::close - TRYING TO CLOSE AN INVALID FILE
// HANDLE\n\n");
return;
}
int result = std::fclose(m_fileHandle);
if (result != 0) {
// TODO 4J Stu - Some kind of error handling
}
// Stop the dtor from trying to close it again
m_fileHandle = NULL;
}
// Skips n bytes of input from this input stream. Fewer bytes might be skipped
// if the end of the input stream is reached. The actual number k of bytes to be
// skipped is equal to the smaller of n and count-pos. The value k is added into
// pos and k is returned. Overrides: skip in class InputStream Parameters: n -
// the number of bytes to be skipped. Returns: the actual number of bytes
// skipped.
__int64 FileInputStream::skip(__int64 n) {
if (m_fileHandle == NULL || n <= 0) {
return 0;
}
const __int64 start = FileTell(m_fileHandle);
if (start < 0) {
return 0;
}
if (!FileSeek(m_fileHandle, 0, SEEK_END)) {
return 0;
}
const __int64 end = FileTell(m_fileHandle);
if (end < 0) {
return 0;
}
const __int64 offset = std::min(n, std::max<__int64>(0, end - start));
const __int64 target = start + offset;
if (!FileSeek(m_fileHandle, target, SEEK_SET)) {
return 0;
}
return offset;
}