bool EReaderPlugin::readMetaInfo(Book &book) const {
	shared_ptr<ZLInputStream> stream = book.file().inputStream();
	if (stream.isNull() || ! stream->open()) {
		return false;
	}
	PdbHeader header;
	if (!header.read(stream)) {
		return false;
	}
	stream->seek(header.Offsets[0] + 46, true);
	unsigned short metaInfoOffset;
	PdbUtil::readUnsignedShort(*stream, metaInfoOffset);
	if (metaInfoOffset == 0 || metaInfoOffset >= header.Offsets.size()) {
		return false;
	}
	std::size_t currentOffset = header.Offsets[metaInfoOffset];
	std::size_t nextOffset =
		(metaInfoOffset + 1 < (unsigned short)header.Offsets.size()) ?
			header.Offsets[metaInfoOffset + 1] : stream->sizeOfOpened();
	if (nextOffset <= currentOffset) {
		return false;
	}
	std::size_t length = nextOffset - currentOffset;

	char* metaInfoBuffer = new char[length];
	stream->seek(currentOffset, true);
	stream->read(metaInfoBuffer, length);
	std::string metaInfoStr(metaInfoBuffer, length);
	delete[] metaInfoBuffer;

	std::string metaInfoData[5]; // Title; Author; Rights; Publisher; isbn;
	for (std::size_t i = 0; i < 5; ++i) { 
		const std::size_t index = metaInfoStr.find('\0');
		metaInfoData[i] = metaInfoStr.substr(0,index);
		metaInfoStr = metaInfoStr.substr(index + 1);
	}
	
	if (!metaInfoData[0].empty()) {
		book.setTitle(metaInfoData[0]);
	}
	
	if (!metaInfoData[1].empty()) {
		book.addAuthor(metaInfoData[1]);
	}

	stream->close();
	return SimplePdbPlugin::readMetaInfo(book);
}
bool PluckerBookReader::readDocument() {
	myStream = ZLFile(myFilePath).inputStream();
	if (myStream.isNull() || !myStream->open()) {
		return false;
	}

	PdbHeader header;
	if (!header.read(myStream)) {
		myStream->close();
		return false;
	}

	setMainTextModel();
	myFont = FT_REGULAR;

	for (std::vector<unsigned long>::const_iterator it = header.Offsets.begin(); it != header.Offsets.end(); ++it) {
		size_t currentOffset = myStream->offset();
		if (currentOffset > *it) {
			break;
		}
		myStream->seek(*it - currentOffset, false);
		if (myStream->offset() != *it) {
			break;
		}
		size_t recordSize = ((it != header.Offsets.end() - 1) ? *(it + 1) : myStream->sizeOfOpened()) - *it;
		readRecord(recordSize);
	}
	myStream->close();

	for (std::set<std::pair<int,int> >::const_iterator it = myReferencedParagraphs.begin(); it != myReferencedParagraphs.end(); ++it) {
		std::map<int,std::vector<int> >::const_iterator jt = myParagraphMap.find(it->first);
		if (jt != myParagraphMap.end()) {
			for (unsigned int k = it->second; k < jt->second.size(); ++k) {
				if (jt->second[k] != -1) {
					addHyperlinkLabel(fromNumber(it->first) + '#' + fromNumber(it->second), jt->second[k]);
					break;
				}
			}
		}
	}
	myReferencedParagraphs.clear();
	myParagraphMap.clear();
	return true;
}
bool MobipocketPlugin::readDescription(const std::string &path, BookDescription &description) const {
	shared_ptr<ZLInputStream> stream = ZLFile(path).inputStream();
	if (stream.isNull() || ! stream->open()) {
		return false;
	}
	PdbHeader header;
	if (!header.read(stream)) {
		return false;
	}
	stream->seek(header.Offsets[0] + 16, true);
	char test[5];
	test[4] = '\0';
	stream->read(test, 4);
	static const std::string MOBI = "MOBI";
	if (MOBI != test) {
		return PalmDocLikePlugin::readDescription(path, description);
	}

	WritableBookDescription wDescription(description);

	unsigned long length;
	PdbUtil::readUnsignedLong(*stream, length);

	stream->seek(4, false);

	unsigned long encodingCode;
	PdbUtil::readUnsignedLong(*stream, encodingCode);
	if (wDescription.encoding().empty()) {
		ZLEncodingConverterInfoPtr info = ZLEncodingCollection::instance().info(encodingCode);
		if (!info.isNull()) {
			wDescription.encoding() = info->name();
		}
	}

	stream->seek(52, false);

	unsigned long fullNameOffset;
	PdbUtil::readUnsignedLong(*stream, fullNameOffset);
	unsigned long fullNameLength;
	PdbUtil::readUnsignedLong(*stream, fullNameLength);

	unsigned long languageCode;
	PdbUtil::readUnsignedLong(*stream, languageCode);
	wDescription.language() = ZLLanguageUtil::languageByCode(languageCode & 0xFF, (languageCode >> 8) & 0xFF);

	stream->seek(32, false);

	unsigned long exthFlags;
	PdbUtil::readUnsignedLong(*stream, exthFlags);
	if (exthFlags & 0x40) {
		stream->seek(header.Offsets[0] + 16 + length, true);

		stream->read(test, 4);
		static const std::string EXTH = "EXTH";
		if (EXTH == test) {
			stream->seek(4, false);
			unsigned long recordsNum;
			PdbUtil::readUnsignedLong(*stream, recordsNum);
			for (unsigned long i = 0; i < recordsNum; ++i) {
				unsigned long type;
				PdbUtil::readUnsignedLong(*stream, type);
				unsigned long size;
				PdbUtil::readUnsignedLong(*stream, size);
				if (size > 8) {
					std::string value(size - 8, '\0');
					stream->read((char*)value.data(), size - 8);
					switch (type) {
						case 100:
						{
							int index = value.find(',');
							if (index != -1) {
								std::string part0 = value.substr(0, index);
								std::string part1 = value.substr(index + 1);
								ZLStringUtil::stripWhiteSpaces(part0);
								ZLStringUtil::stripWhiteSpaces(part1);
								value = part1 + ' ' + part0;
							} else {
								ZLStringUtil::stripWhiteSpaces(value);
							}
							wDescription.addAuthor(value);
							break;
						}
						case 105:
							wDescription.addTag(value);
							break;
					}
				}
			}
		}
	}

	stream->seek(header.Offsets[0] + fullNameOffset, true);
	std::string title(fullNameLength, '\0');
	stream->read((char*)title.data(), fullNameLength);
	wDescription.title() = title;

	stream->close();
	return PalmDocLikePlugin::readDescription(path, description);
}