Changeset - r25409:b8a1f662c06f
[Not reviewed]
master
0 1 2
Rubidium - 3 years ago 2021-04-13 19:36:01
rubidium@openttd.org
Add: concept of a RandomAccessFile to replace the FIO slot functions
3 files changed with 216 insertions and 0 deletions:
0 comments (0 inline, 0 general)
src/CMakeLists.txt
Show inline comments
 
@@ -309,6 +309,8 @@ add_files(
 
    rail_gui.h
 
    rail_map.h
 
    rail_type.h
 
    random_access_file.cpp
 
    random_access_file_type.h
 
    rev.h
 
    road.cpp
 
    road.h
src/random_access_file.cpp
Show inline comments
 
new file 100644
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
 /** @file random_access_file.cpp Actual implementation of the RandomAccessFile class. */
 

	
 
#include "stdafx.h"
 
#include "random_access_file_type.h"
 

	
 
#include "debug.h"
 
#include "fileio_func.h"
 
#include "string_func.h"
 

	
 
#include "safeguards.h"
 

	
 
/**
 
 * Create the RandomAccesFile.
 
 * @param filename Name of the file at the disk.
 
 * @param subdir   The sub directory to search this file in.
 
 */
 
RandomAccessFile::RandomAccessFile(const std::string &filename, Subdirectory subdir) : filename(filename)
 
{
 
	this->file_handle = FioFOpenFile(filename, "rb", subdir);
 
	if (this->file_handle == nullptr) usererror("Cannot open file '%s'", filename.c_str());
 

	
 
	/* When files are in a tar-file, the begin of the file might not be at 0. */
 
	long pos = ftell(this->file_handle);
 
	if (pos < 0) usererror("Cannot read file '%s'", filename.c_str());
 

	
 
	/* Store the filename without path and extension */
 
	auto t = filename.rfind(PATHSEPCHAR);
 
	std::string name_without_path = filename.substr(t != std::string::npos ? t + 1 : 0);
 
	this->simplified_filename = name_without_path.substr(0, name_without_path.rfind('.'));
 
	strtolower(this->simplified_filename);
 

	
 
	this->SeekTo((size_t)pos, SEEK_SET);
 
}
 

	
 
/**
 
 * Close the file's file handle.
 
 */
 
RandomAccessFile::~RandomAccessFile()
 
{
 
	fclose(this->file_handle);
 
}
 

	
 
/**
 
 * Get the filename of the opened file with the path from the SubDirectory and the extension.
 
 * @return Name of the file.
 
 */
 
const std::string& RandomAccessFile::GetFilename() const
 
{
 
	return this->filename;
 
}
 

	
 
/**
 
 * Get the simplified filename of the opened file. The simplified filename is the name of the
 
 * file without the SubDirectory or extension in lower case.
 
 * @return Name of the file.
 
 */
 
const std::string& RandomAccessFile::GetSimplifiedFilename() const
 
{
 
	return this->simplified_filename;
 
}
 

	
 
/**
 
 * Get position in the file.
 
 * @return Position in the file.
 
 */
 
size_t RandomAccessFile::GetPos() const
 
{
 
	return this->pos + (this->buffer - this->buffer_end);
 
}
 

	
 
/**
 
 * Seek in the current file.
 
 * @param pos New position.
 
 * @param mode Type of seek (\c SEEK_CUR means \a pos is relative to current position, \c SEEK_SET means \a pos is absolute).
 
 */
 
void RandomAccessFile::SeekTo(size_t pos, int mode)
 
{
 
	if (mode == SEEK_CUR) pos += this->GetPos();
 

	
 
	this->pos = pos;
 
	if (fseek(this->file_handle, this->pos, SEEK_SET) < 0) {
 
		DEBUG(misc, 0, "Seeking in %s failed", this->filename.c_str());
 
	}
 

	
 
	/* Reset the buffer, so the next ReadByte will read bytes from the file. */
 
	this->buffer = this->buffer_end = this->buffer_start;
 
}
 

	
 
/**
 
 * Read a byte from the file.
 
 * @return Read byte.
 
 */
 
byte RandomAccessFile::ReadByte()
 
{
 
	if (this->buffer == this->buffer_end) {
 
		this->buffer = this->buffer_start;
 
		size_t size = fread(this->buffer, 1, RandomAccessFile::BUFFER_SIZE, this->file_handle);
 
		this->pos += size;
 
		this->buffer_end = this->buffer_start + size;
 

	
 
		if (size == 0) return 0;
 
	}
 
	return *this->buffer++;
 
}
 

	
 
/**
 
 * Read a word (16 bits) from the file (in low endian format).
 
 * @return Read word.
 
 */
 
uint16 RandomAccessFile::ReadWord()
 
{
 
	byte b = this->ReadByte();
 
	return (this->ReadByte() << 8) | b;
 
}
 

	
 
/**
 
 * Read a double word (32 bits) from the file (in low endian format).
 
 * @return Read word.
 
 */
 
uint32 RandomAccessFile::ReadDword()
 
{
 
	uint b = this->ReadWord();
 
	return (this->ReadWord() << 16) | b;
 
}
 

	
 
/**
 
 * Read a block.
 
 * @param ptr  Destination buffer.
 
 * @param size Number of bytes to read.
 
 */
 
void RandomAccessFile::ReadBlock(void *ptr, size_t size)
 
{
 
	this->SeekTo(this->GetPos(), SEEK_SET);
 
	this->pos += fread(ptr, 1, size, this->file_handle);
 
}
 

	
 
/**
 
 * Skip \a n bytes ahead in the file.
 
 * @param n Number of bytes to skip reading.
 
 */
 
void RandomAccessFile::SkipBytes(int n)
 
{
 
	int remaining = this->buffer_end - this->buffer;
 
	if (n <= remaining) {
 
		this->buffer += n;
 
	} else {
 
		this->SeekTo(n, SEEK_CUR);
 
	}
 
}
src/random_access_file_type.h
Show inline comments
 
new file 100644
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
 /** @file random_access_file_type.h Class related to random access to files. */
 

	
 
#ifndef RANDOM_ACCESS_FILE_TYPE_H
 
#define RANDOM_ACCESS_FILE_TYPE_H
 

	
 
#include "fileio_type.h"
 
#include <string>
 

	
 
/**
 
 * A file from which bytes, words and double words are read in (potentially) a random order.
 
 *
 
 * This is mostly intended to be used for things that can be read from GRFs when needed, so
 
 * the graphics but also the sounds. This also ties into the spritecache as it uses these
 
 * files to load the sprites from when needed.
 
 */
 
class RandomAccessFile {
 
	/** The number of bytes to allocate for the buffer. */
 
	static constexpr int BUFFER_SIZE = 512;
 

	
 
	std::string filename;            ///< Full name of the file; relative path to subdir plus the extension of the file.
 
	std::string simplified_filename; ///< Simplified lowecase name of the file; only the name, no path or extension.
 

	
 
	FILE *file_handle;               ///< File handle of the open file.
 
	size_t pos;                      ///< Position in the file of the end of the read buffer.
 

	
 
	byte *buffer;                    ///< Current position within the local buffer.
 
	byte *buffer_end;                ///< Last valid byte of buffer.
 
	byte buffer_start[BUFFER_SIZE];  ///< Local buffer when read from file.
 

	
 
public:
 
	RandomAccessFile(const std::string &filename, Subdirectory subdir);
 
	RandomAccessFile(const RandomAccessFile&) = delete;
 
	void operator=(const RandomAccessFile&) = delete;
 

	
 
	virtual ~RandomAccessFile();
 

	
 
	const std::string &GetFilename() const;
 
	const std::string &GetSimplifiedFilename() const;
 

	
 
	size_t GetPos() const;
 
	void SeekTo(size_t pos, int mode);
 

	
 
	byte ReadByte();
 
	uint16 ReadWord();
 
	uint32 ReadDword();
 

	
 
	void ReadBlock(void *ptr, size_t size);
 
	void SkipBytes(int n);
 
};
 

	
 
#endif /* RANDOM_ACCESS_FILE_TYPE_H */
0 comments (0 inline, 0 general)