Example #1
0
size_t ZipFile::findCentralDirectoryEnd(SeekableReadStream &zip) {
	const size_t uSizeFile = zip.size();
	const size_t uMaxBack  = MIN<size_t>(0xFFFF, uSizeFile); // Maximum size of global comment

	byte buf[BUFREADCOMMENT + 4];

	size_t uPosFound = 0;
	size_t uBackRead = 4;
	while ((uPosFound == 0) && (uBackRead < uMaxBack)) {
		uBackRead = MIN<size_t>(uMaxBack, uBackRead + BUFREADCOMMENT);

		const size_t uReadPos  = uSizeFile - uBackRead;
		const size_t uReadSize = MIN<size_t>(BUFREADCOMMENT + 4, uSizeFile - uReadPos);

		try {
			zip.seek(uReadPos);
		} catch (...) {
			return 0;
		}

		if (zip.read(buf, uReadSize) != uReadSize) {
			uPosFound = 0;
			break;
		}

		for (size_t i = (uReadSize - 3); i-- > 0; )
			if (READ_LE_UINT32(buf + i) == 0x06054B50) {
				uPosFound = uReadPos + i;
				break;
			}

	}

	return uPosFound;
}
Example #2
0
String NEResources::getResourceString(SeekableReadStream &exe, uint32 offset) {
    uint32 curPos = exe.pos();

    if (!exe.seek(offset)) {
        exe.seek(curPos);
        return "";
    }

    uint8 length = exe.readByte();

    String string;
    for (uint16 i = 0; i < length; i++)
        string += (char)exe.readByte();

    exe.seek(curPos);
    return string;
}
Example #3
0
void StreamTokenizer::nextChunk(SeekableReadStream &stream) {
	skipChunk(stream);

	uint32 c = stream.readChar();
	if (c == ReadStream::kEOF)
		return;

	if (!isIn(c, _chunkEnds))
		stream.seek(-1, SeekableReadStream::kOriginCurrent);
}
Example #4
0
bool StreamTokenizer::isChunkEnd(SeekableReadStream &stream) {
	if (stream.eos())
		return true;

	bool chunkEnd = isIn(stream.readByte(), _chunkEnds);

	stream.seek(-1, SEEK_CUR);

	return chunkEnd;
}
Example #5
0
bool StreamTokenizer::isChunkEnd(SeekableReadStream &stream) {
	uint32 c = stream.readChar();
	if (c == ReadStream::kEOF)
		return true;

	bool chunkEnd = isIn(c, _chunkEnds);

	stream.seek(-1, SeekableReadStream::kOriginCurrent);

	return chunkEnd;
}
Example #6
0
void StreamTokenizer::skipChunk(SeekableReadStream &stream) {
	assert(!_chunkEnds.empty());

	uint32 c;
	while ((c = stream.readChar()) != ReadStream::kEOF) {
		if (isIn(c, _chunkEnds)) {
			stream.seek(-1, SeekableReadStream::kOriginCurrent);
			break;
		}
	}
}
Example #7
0
void printDataHex(SeekableReadStream &stream, size_t size) {
	size_t pos = stream.pos();

	size = MIN<size_t>(stream.size() - pos, size);

	if (size == 0)
		return;

	uint32 offset = 0;
	byte rowData[16];

	while (size > 0) {
		// At max 16 bytes printed per row
		uint32 n = MIN<size_t>(size, 16);
		if (stream.read(rowData, n) != n)
			throw Exception(kReadError);

		// Print an offset
		std::fprintf(stderr, "%08X  ", offset);

		// 2 "blobs" of each 8 bytes per row
		for (uint32 i = 0; i < 2; i++) {
			for (uint32 j = 0; j < 8; j++) {
				uint32 m = i * 8 + j;

				if (m < n)
					// Print the data
					std::fprintf(stderr, "%02X ", rowData[m]);
				else
					// Last row, data count not aligned to 16
					std::fprintf(stderr, "   ");
			}

			// Separate the blobs by an extra space
			std::fprintf(stderr, " ");
		}

		std::fprintf(stderr, "|");

		// If the data byte is a printable character, print it. If not, substitute a '.'
		for (uint32 i = 0; i < n; i++)
			std::fprintf(stderr, "%c", std::isprint(rowData[i]) ? rowData[i] : '.');

		std::fprintf(stderr, "|\n");

		size   -= n;
		offset += n;
	}

	// Seek back
	stream.seek(pos);
}
Example #8
0
void StreamTokenizer::skipChunk(SeekableReadStream &stream) {
	assert(!_chunkEnds.empty());

	while (!stream.eos() && !stream.err()) {
		if (isIn(stream.readByte(), _chunkEnds)) {
			stream.seek(-1, SEEK_CUR);
			break;
		}
	}

	if (stream.err())
		throw Exception(kReadError);
}
Example #9
0
void StreamTokenizer::nextChunk(SeekableReadStream &stream) {
	skipChunk(stream);

	byte c = stream.readByte();

	if (stream.eos() || stream.err())
		return;

	if (!isIn(c, _chunkEnds))
		stream.seek(-1, SEEK_CUR);
	else
		if (stream.pos() == stream.size())
			// This actually the last character, read one more byte to properly set the EOS state
			stream.readByte();
}
Example #10
0
size_t searchBackwards(SeekableReadStream &haystack, const byte *needle, size_t needleSize,
                       size_t maxReadBack) {

	if (needleSize == 0 || maxReadBack == 0)
		return SIZE_MAX;

	assert(maxReadBack >= needleSize);

	static const size_t kReadBufferSize = 0x400;

	const size_t sizeFile = haystack.size();
	const size_t maxBack  = MIN<size_t>(maxReadBack, sizeFile);

	ScopedArray<byte> buf(new byte[kReadBufferSize + needleSize]);

	size_t backRead = needleSize;
	while (backRead < maxBack) {
		backRead = MIN<size_t>(maxBack, backRead + kReadBufferSize);

		const size_t readPos  = sizeFile - backRead;
		const size_t readSize = MIN<size_t>(kReadBufferSize + needleSize, sizeFile - readPos);

		try {
			haystack.seek(readPos);
		} catch (...) {
			break;
		}

		if (haystack.read(buf.get(), readSize) != readSize)
			break;

		for (size_t i = (readSize - (needleSize - 1)); i-- > 0; )
			if (!memcmp(buf.get() + i, needle, needleSize))
				return readPos + i;
	}

	return SIZE_MAX;
}
Example #11
0
void FoxPro::loadFields(SeekableReadStream &dbf, uint32 recordSize) {
	// Read all field descriptions, 0x0D is the end marker
	uint32 fieldsLength = 0;
	while (!dbf.eos() && (dbf.readByte() != 0x0D)) {
		Field field;

		dbf.seek(-1, SeekableReadStream::kOriginCurrent);

		field.name = readStringFixed(dbf, kEncodingASCII, 11);

		field.type     = (Type) dbf.readByte();
		field.offset   = dbf.readUint32LE();
		field.size     = dbf.readByte();
		field.decimals = dbf.readByte();

		field.flags = dbf.readByte();

		field.autoIncNext = dbf.readUint32LE();
		field.autoIncStep = dbf.readByte();

		dbf.skip(8); // Reserved

		if (field.offset != (fieldsLength + 1))
			throw Exception("Field offset makes no sense (%d != %d)",
					field.offset, fieldsLength + 1);

		if (field.type == kTypeMemo)
			_hasMemo = true;

		fieldsLength += field.size;

		_fields.push_back(field);
	}

	if (recordSize != (fieldsLength + 1))
		throw Exception("Length of all fields does not equal the record size");
}
Example #12
0
void ZipFile::getFileProperties(SeekableReadStream &zip, const IFile &file,
		uint16 &compMethod, uint32 &compSize, uint32 &realSize) const {

	zip.seek(file.offset);

	uint32 tag = zip.readUint32LE();
	if (tag != 0x04034B50)
		throw Exception("Unknown ZIP record %08X", tag);

	zip.skip(4);

	compMethod = zip.readUint16LE();

	zip.skip(8);

	compSize = zip.readUint32LE();
	realSize = zip.readUint32LE();

	uint16 nameLength  = zip.readUint16LE();
	uint16 extraLength = zip.readUint16LE();

	zip.skip(nameLength);
	zip.skip(extraLength);
}
Example #13
0
void ZipFile::load(SeekableReadStream &zip) {
	size_t endPos = findCentralDirectoryEnd(zip);
	if (endPos == 0)
		throw Exception("End of central directory record not found");

	zip.seek(endPos);

	zip.skip(4); // Header, already checked

	uint16 curDisk        = zip.readUint16LE();
	uint16 centralDirDisk = zip.readUint16LE();

	uint16 curDiskDirs = zip.readUint16LE();
	uint16 totalDirs   = zip.readUint16LE();

	if ((curDisk != 0) || (curDisk != centralDirDisk) || (curDiskDirs != totalDirs))
		throw Exception("Unsupported multi-disk ZIP file");

	zip.skip(4); // Size of central directory

	uint32 centralDirPos = zip.readUint32LE();
	zip.seek(centralDirPos);

	uint32 tag = zip.readUint32LE();
	if (tag != 0x02014B50)
		throw Exception("Unknown ZIP record %08X", tag);

	_iFiles.reserve(totalDirs);
	while (tag == 0x02014B50) {
		 File  file;
		IFile iFile;

		zip.skip(20);

		iFile.size = zip.readUint32LE();

		uint16 nameLength    = zip.readUint16LE();
		uint16 extraLength   = zip.readUint16LE();
		uint16 commentLength = zip.readUint16LE();
		uint16 diskNum       = zip.readUint16LE();

		if (diskNum != 0)
			throw Exception("Unsupported multi-disk ZIP file");

		zip.skip(6); // File attributes

		iFile.offset = zip.readUint32LE();

		file.name = readStringFixed(zip, kEncodingASCII, nameLength).toLower();

		zip.skip(extraLength);
		zip.skip(commentLength);

		tag = zip.readUint32LE();
		if ((tag != 0x02014B50) && (tag != 0x06054B50))
			throw Exception("Unknown ZIP record %08X", tag);

		// Ignore empty file names
		if (!file.name.empty()) {
			// HACK: Skip any filename with a trailing slash because it's
			// a directory. The proper solution would be to interpret the
			// file attributes.

			if (*(--file.name.end()) != '/') {
				file.index = _iFiles.size();

				_files.push_back(file);
				_iFiles.push_back(iFile);
			}
		}
	}
}
Example #14
0
UString StreamTokenizer::getToken(SeekableReadStream &stream) {
	// Init
	bool   chunkEnd     = false;
	bool   inQuote      = false;
	uint32 separator    = 0xFFFFFFFF;

	UString token;

	// Run through the stream, character by character
	uint32 c;
	while ((c = stream.readChar()) != ReadStream::kEOF) {

		if (isIn(c, _chunkEnds)) {
			// This is a end character, seek back and break
			stream.seek(-1, SeekableReadStream::kOriginCurrent);
			chunkEnd = true;
			break;
		}

		if (isIn(c, _quotes)) {
			// This is a quote character, set state
			inQuote = !inQuote;
			continue;
		}

		if (!inQuote && isIn(c, _separators)) {
			// We're not in a quote and this is a separator

			if (!token.empty()) {
				// We have a token

				separator = c;
				break;
			}

			// We don't yet have a token, let the consecutive separator rule decide what to do

			if (_conSepRule == kRuleHeed) {
				// We heed every separator

				separator = c;
				break;
			}

			if ((_conSepRule == kRuleIgnoreSame) && (separator != 0xFFFFFFFF) && (separator != c)) {
				// We ignore only consecutive separators that are the same
				separator = c;
				break;
			}

			// We ignore all consecutive separators
			separator = c;
			continue;
		}

		if (isIn(c, _ignores))
			// This is a character to be ignored, do so
			continue;

		// A normal character, add it to our token
		token += c;
	}

	// Is the string actually empty?
	if (!token.empty() && (*token.begin() == '\0'))
		token.clear();

	if (!chunkEnd && (_conSepRule != kRuleHeed)) {
		// We have to look for consecutive separators

		while ((c = stream.readChar()) != ReadStream::kEOF) {

			// Use the rule to determine when we should abort skipping consecutive separators
			if (((_conSepRule == kRuleIgnoreSame) && (c != separator)) ||
			    ((_conSepRule == kRuleIgnoreAll ) && !isIn(c, _separators))) {

				stream.seek(-1, SeekableReadStream::kOriginCurrent);
				break;
			}
		}

	}

	// And return the token
	return token;
}