Initial commit
This commit is contained in:
516
engines/titanic/support/simple_file.cpp
Normal file
516
engines/titanic/support/simple_file.cpp
Normal file
@@ -0,0 +1,516 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/util.h"
|
||||
#include "titanic/support/simple_file.h"
|
||||
|
||||
namespace Titanic {
|
||||
|
||||
CString readStringFromStream(Common::SeekableReadStream *s) {
|
||||
CString result;
|
||||
char c;
|
||||
while ((c = s->readByte()) != '\0')
|
||||
result += c;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
bool File::open(const Common::Path &filename) {
|
||||
if (!Common::File::open(filename))
|
||||
error("Could not open file - %s", filename.toString(Common::Path::kNativeSeparator).c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
SimpleFile::SimpleFile(): _inStream(nullptr), _outStream(nullptr), _lineCount(1) {
|
||||
}
|
||||
|
||||
SimpleFile::~SimpleFile() {
|
||||
close();
|
||||
}
|
||||
|
||||
void SimpleFile::open(Common::SeekableReadStream *stream) {
|
||||
close();
|
||||
_inStream = stream;
|
||||
}
|
||||
|
||||
void SimpleFile::open(Common::OutSaveFile *stream) {
|
||||
close();
|
||||
_outStream = stream;
|
||||
}
|
||||
|
||||
void SimpleFile::close() {
|
||||
if (_outStream) {
|
||||
_outStream->finalize();
|
||||
delete _outStream;
|
||||
_outStream = nullptr;
|
||||
}
|
||||
|
||||
if (_inStream) {
|
||||
delete _inStream;
|
||||
_inStream = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleFile::safeRead(void *dst, size_t count) {
|
||||
if (unsafeRead(dst, count) != count)
|
||||
error("Could not read %d bytes", (int)count);
|
||||
}
|
||||
|
||||
size_t SimpleFile::unsafeRead(void *dst, size_t count) {
|
||||
assert(_inStream);
|
||||
return _inStream->read(dst, count);
|
||||
}
|
||||
|
||||
size_t SimpleFile::write(const void *src, size_t count) const {
|
||||
assert(_outStream);
|
||||
return _outStream->write(src, count);
|
||||
}
|
||||
|
||||
void SimpleFile::seek(int offset, int origin) {
|
||||
assert(_inStream);
|
||||
_inStream->seek(offset, origin);
|
||||
}
|
||||
|
||||
byte SimpleFile::readByte() {
|
||||
byte b;
|
||||
safeRead(&b, 1);
|
||||
return b;
|
||||
}
|
||||
|
||||
uint SimpleFile::readUint16LE() {
|
||||
uint val;
|
||||
safeRead(&val, 2);
|
||||
return READ_LE_UINT16(&val);
|
||||
}
|
||||
|
||||
uint SimpleFile::readUint32LE() {
|
||||
uint val;
|
||||
safeRead(&val, 4);
|
||||
return READ_LE_UINT32(&val);
|
||||
}
|
||||
|
||||
CString SimpleFile::readString() {
|
||||
char c;
|
||||
CString result;
|
||||
bool backslashFlag = false;
|
||||
|
||||
// First skip any spaces
|
||||
do {
|
||||
safeRead(&c, 1);
|
||||
} while (Common::isSpace(c));
|
||||
|
||||
// Ensure we've found a starting quote for the string
|
||||
if (c != '"')
|
||||
error("Could not find starting quote");
|
||||
|
||||
bool endFlag = false;
|
||||
while (!endFlag) {
|
||||
// Read the next character
|
||||
safeRead(&c, 1);
|
||||
|
||||
if (backslashFlag) {
|
||||
backslashFlag = false;
|
||||
switch (c) {
|
||||
case 'n':
|
||||
result += '\n';
|
||||
break;
|
||||
case 'r':
|
||||
result += '\r';
|
||||
break;
|
||||
case '\t':
|
||||
result += '\t';
|
||||
break;
|
||||
default:
|
||||
result += c;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (c) {
|
||||
case '"':
|
||||
endFlag = true;
|
||||
break;
|
||||
case '\\':
|
||||
backslashFlag = true;
|
||||
break;
|
||||
default:
|
||||
result += c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the string
|
||||
return result;
|
||||
}
|
||||
|
||||
int SimpleFile::readNumber() {
|
||||
char c;
|
||||
int result = 0;
|
||||
bool minusFlag = false;
|
||||
|
||||
// First skip any spaces
|
||||
do {
|
||||
safeRead(&c, 1);
|
||||
} while (Common::isSpace(c));
|
||||
|
||||
// Check for prefix sign
|
||||
if (c == '+' || c == '-') {
|
||||
minusFlag = c == '-';
|
||||
safeRead(&c, 1);
|
||||
}
|
||||
|
||||
// Read in the number
|
||||
if (!Common::isDigit(c))
|
||||
error("Invalid number");
|
||||
|
||||
while (Common::isDigit(c)) {
|
||||
result = result * 10 + (c - '0');
|
||||
safeRead(&c, 1);
|
||||
}
|
||||
|
||||
// Finally, if it's a minus value, then negate it
|
||||
if (minusFlag)
|
||||
result = -result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
double SimpleFile::readFloat() {
|
||||
char c;
|
||||
Common::String result;
|
||||
|
||||
// First skip any spaces
|
||||
do {
|
||||
safeRead(&c, 1);
|
||||
} while (Common::isSpace(c));
|
||||
|
||||
// Check for prefix sign
|
||||
if (c == '+' || c == '-') {
|
||||
result += c;
|
||||
safeRead(&c, 1);
|
||||
}
|
||||
|
||||
// Read in the number
|
||||
if (!Common::isDigit(c))
|
||||
error("Invalid number");
|
||||
|
||||
while (Common::isDigit(c) || c == '.') {
|
||||
result += c;
|
||||
safeRead(&c, 1);
|
||||
}
|
||||
|
||||
// Convert to a float and return it
|
||||
float floatValue;
|
||||
sscanf(result.c_str(), "%f", &floatValue);
|
||||
|
||||
return floatValue;
|
||||
}
|
||||
|
||||
Point SimpleFile::readPoint() {
|
||||
Point pt;
|
||||
pt.x = readNumber();
|
||||
pt.y = readNumber();
|
||||
|
||||
return pt;
|
||||
}
|
||||
|
||||
Rect SimpleFile::readRect() {
|
||||
Rect r;
|
||||
r.left = readNumber();
|
||||
r.top = readNumber();
|
||||
r.right = readNumber();
|
||||
r.bottom = readNumber();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
Rect SimpleFile::readBounds() {
|
||||
Rect r;
|
||||
r.left = readNumber();
|
||||
r.top = readNumber();
|
||||
r.setWidth(readNumber());
|
||||
r.setHeight(readNumber());
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void SimpleFile::readBuffer(char *buffer, size_t count) {
|
||||
CString tempString = readString();
|
||||
if (buffer) {
|
||||
strncpy(buffer, tempString.c_str(), count);
|
||||
buffer[count - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleFile::writeUint16LE(uint val) {
|
||||
byte lo = val & 0xff;
|
||||
byte hi = (val >> 8) & 0xff;
|
||||
write(&lo, 1);
|
||||
write(&hi, 1);
|
||||
}
|
||||
|
||||
void SimpleFile::writeUint32LE(uint val) {
|
||||
uint16 lo = val & 0xffff;
|
||||
uint16 hi = (val >> 16) & 0xff;
|
||||
writeUint16LE(lo);
|
||||
writeUint16LE(hi);
|
||||
}
|
||||
|
||||
void SimpleFile::writeLine(const CString &str) const {
|
||||
write(str.c_str(), str.size());
|
||||
write("\r\n", 2);
|
||||
}
|
||||
|
||||
void SimpleFile::writeString(const CString &str) const {
|
||||
if (str.empty())
|
||||
return;
|
||||
|
||||
const char *msgP = str.c_str();
|
||||
char c;
|
||||
|
||||
while ((c = *msgP++) != '\0') {
|
||||
switch (c) {
|
||||
case '\r':
|
||||
write("\\r", 2);
|
||||
break;
|
||||
case '\n':
|
||||
write("\\n", 2);
|
||||
break;
|
||||
case '\t':
|
||||
write("\\t", 2);
|
||||
break;
|
||||
case '\"':
|
||||
write("\\\"", 2);
|
||||
break;
|
||||
case '\\':
|
||||
write("\\\\", 2);
|
||||
break;
|
||||
case '{':
|
||||
write("\\{", 2);
|
||||
break;
|
||||
case '}':
|
||||
write("\\}", 2);
|
||||
break;
|
||||
default:
|
||||
write(&c, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleFile::writeQuotedString(const CString &str) const {
|
||||
write("\"", 1);
|
||||
writeString(str);
|
||||
write("\" ", 2);
|
||||
}
|
||||
|
||||
void SimpleFile::writeQuotedLine(const CString &str, int indent) const {
|
||||
writeIndent(indent);
|
||||
writeQuotedString(str);
|
||||
write("\n", 1);
|
||||
}
|
||||
|
||||
void SimpleFile::writeNumber(int val) const {
|
||||
CString str = CString::format("%d ", val);
|
||||
write(str.c_str(), str.size());
|
||||
}
|
||||
|
||||
void SimpleFile::writeNumberLine(int val, int indent) const {
|
||||
writeIndent(indent);
|
||||
writeNumber(val);
|
||||
write("\n", 1);
|
||||
}
|
||||
|
||||
void SimpleFile::writeFloat(double val) const {
|
||||
Common::String valStr = Common::String::format("%f ", val);
|
||||
write(valStr.c_str(), valStr.size());
|
||||
}
|
||||
|
||||
void SimpleFile::writeFloatLine(double val, int indent) const {
|
||||
writeIndent(indent);
|
||||
writeFloat(val);
|
||||
write("\n", 1);
|
||||
}
|
||||
|
||||
void SimpleFile::writePoint(const Point &pt, int indent) const {
|
||||
writeIndent(indent);
|
||||
writeNumber(pt.x);
|
||||
writeNumber(pt.y);
|
||||
write("\n", 1);
|
||||
}
|
||||
|
||||
void SimpleFile::writeRect(const Rect &r, int indent) const {
|
||||
writePoint(Point(r.left, r.top), indent);
|
||||
writePoint(Point(r.right, r.bottom), indent);
|
||||
}
|
||||
|
||||
void SimpleFile::writeBounds(const Rect &r, int indent) const {
|
||||
writePoint(Point(r.left, r.top), indent);
|
||||
writePoint(Point(r.width(), r.height()), indent);
|
||||
}
|
||||
|
||||
void SimpleFile::writeFormat(const char *format, ...) const {
|
||||
// Convert the format specifier and params to a string
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
CString line = CString::vformat(format, va);
|
||||
va_end(va);
|
||||
|
||||
// Write out the string
|
||||
write(format, strlen(format));
|
||||
}
|
||||
|
||||
void SimpleFile::writeIndent(uint indent) const {
|
||||
for (uint idx = 0; idx < indent; ++idx)
|
||||
write("\t", 1);
|
||||
}
|
||||
|
||||
bool SimpleFile::isClassStart() {
|
||||
char c;
|
||||
|
||||
do {
|
||||
safeRead(&c, 1);
|
||||
} while (Common::isSpace(c));
|
||||
|
||||
assert(c == '{' || c == '}');
|
||||
return c == '{';
|
||||
}
|
||||
|
||||
void SimpleFile::writeClassStart(const CString &classStr, int indent) {
|
||||
write("\n", 1);
|
||||
writeIndent(indent);
|
||||
write("{\n", 2);
|
||||
writeIndent(indent + 1);
|
||||
writeQuotedString(classStr);
|
||||
write("\n", 1);
|
||||
}
|
||||
|
||||
void SimpleFile::writeClassEnd(int indent) {
|
||||
writeIndent(indent);
|
||||
write("}\n", 2);
|
||||
}
|
||||
|
||||
bool SimpleFile::scanf(const char *format, ...) {
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
char c;
|
||||
|
||||
CString formatStr(format);
|
||||
while (!formatStr.empty()) {
|
||||
if (formatStr.hasPrefix(" ")) {
|
||||
formatStr.deleteChar(0);
|
||||
|
||||
safeRead(&c, 1);
|
||||
if (!Common::isSpace(c)) {
|
||||
va_end(va);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip over whitespaces
|
||||
skipSpaces();
|
||||
} else if (formatStr.hasPrefix("%d")) {
|
||||
// Read in a number
|
||||
formatStr = CString(formatStr.c_str() + 2);
|
||||
int *param = (int *)va_arg(va, int *);
|
||||
*param = readNumber();
|
||||
|
||||
if (!eos())
|
||||
_inStream->seek(-1, SEEK_CUR);
|
||||
} else if (formatStr.hasPrefix("%s")) {
|
||||
// Read in text until the next space
|
||||
formatStr = CString(formatStr.c_str() + 2);
|
||||
CString *str = (CString *)va_arg(va, CString *);
|
||||
str->clear();
|
||||
while (!eos() && !Common::isSpace(c = readByte()))
|
||||
*str += c;
|
||||
|
||||
if (!eos())
|
||||
_inStream->seek(-1, SEEK_CUR);
|
||||
}
|
||||
}
|
||||
|
||||
skipSpaces();
|
||||
va_end(va);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SimpleFile::skipSpaces() {
|
||||
char c = ' ';
|
||||
while (!eos() && Common::isSpace(c))
|
||||
safeRead(&c, 1);
|
||||
|
||||
if (!eos())
|
||||
_inStream->seek(-1, SEEK_CUR);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
bool StdCWadFile::open(const Common::String &filename) {
|
||||
Common::File f;
|
||||
CString name = filename;
|
||||
|
||||
// Check for whether it is indeed a file/resource pair
|
||||
int idx = name.indexOf('#');
|
||||
|
||||
if (idx < 0) {
|
||||
// Nope, so open up file for standard reading
|
||||
assert(!name.empty());
|
||||
if (!f.open(Common::Path(name)))
|
||||
return false;
|
||||
|
||||
SimpleFile::open(f.readStream(f.size()));
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Split up the name and resource, and get the resource index
|
||||
CString fname = name.left(idx) + ".st";
|
||||
int extPos = name.lastIndexOf('.');
|
||||
CString resStr = name.mid(idx + 1, extPos - idx - 1);
|
||||
int resIndex = resStr.readInt();
|
||||
|
||||
// Open up the index for access
|
||||
if (!f.open(Common::Path(fname)))
|
||||
return false;
|
||||
int indexSize = f.readUint32LE() / 4;
|
||||
assert(resIndex < indexSize);
|
||||
|
||||
// Get the specific resource's offset, and size by also
|
||||
// getting the offset of the following resource
|
||||
f.seek(resIndex * 4);
|
||||
uint resOffset = f.readUint32LE();
|
||||
uint nextOffset = (resIndex == (indexSize - 1)) ? f.size() :
|
||||
f.readUint32LE();
|
||||
|
||||
// Read in the resource
|
||||
f.seek(resOffset);
|
||||
Common::SeekableReadStream *stream = f.readStream(nextOffset - resOffset);
|
||||
SimpleFile::open(stream);
|
||||
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Titanic
|
||||
Reference in New Issue
Block a user