#include "../../Platform/stdafx.h" #include "File.h" #include "FileInputStream.h" #include extern CConsoleMinecraftApp app; namespace { int64_t FileTell(std::FILE* file) { #if defined(_WIN32) return _ftelli64(file); #else return static_cast(ftello(file)); #endif } bool FileSeek(std::FILE* file, int64_t offset, int origin) { #if defined(_WIN32) return _fseeki64(file, offset, origin) == 0; #else return fseeko(file, static_cast(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(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(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_t FileInputStream::skip(int64_t n) { if (m_fileHandle == NULL || n <= 0) { return 0; } const int64_t start = FileTell(m_fileHandle); if (start < 0) { return 0; } if (!FileSeek(m_fileHandle, 0, SEEK_END)) { return 0; } const int64_t end = FileTell(m_fileHandle); if (end < 0) { return 0; } const int64_t offset = std::min(n, std::max(0, end - start)); const int64_t target = start + offset; if (!FileSeek(m_fileHandle, target, SEEK_SET)) { return 0; } return offset; }