blob: efa0e25632adb6f6002c0427d70168f9cd59b20c [file] [log] [blame]
/*------------------------------------------------------------------------------
* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team
*
* Distributable under the terms of either the Apache License (Version 2.0) or
* the GNU Lesser General Public License, as specified in the COPYING file.
*
* Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
------------------------------------------------------------------------------*/
#include "CLucene/StdHeader.h"
#include "CompoundFile.h"
#include "CLucene/util/Misc.h"
CL_NS_USE(store)
CL_NS_USE(util)
CL_NS_DEF(index)
CompoundFileReader::CSIndexInput::CSIndexInput(CL_NS(store)::IndexInput* base,
const int64_t fileOffset, const int64_t length)
{
this->base = base;
this->fileOffset = fileOffset;
this->_length = length;
}
void CompoundFileReader::CSIndexInput::readInternal(uint8_t* b, const int32_t len)
{
SCOPED_LOCK_MUTEX(base->THIS_LOCK)
int64_t start = getFilePointer();
if(start + len > _length)
_CLTHROWA(CL_ERR_IO, "read past EOF");
base->seek(fileOffset + start);
base->readBytes(b, len);
}
CompoundFileReader::CSIndexInput::~CSIndexInput()
{
}
IndexInput* CompoundFileReader::CSIndexInput::clone() const
{
return _CLNEW CSIndexInput(*this);
}
CompoundFileReader::CSIndexInput::CSIndexInput(const CSIndexInput& clone)
: BufferedIndexInput(clone)
{
this->base = clone.base; //no need to clone this..
this->fileOffset = clone.fileOffset;
this->_length = clone._length;
}
void CompoundFileReader::CSIndexInput::close()
{
}
CompoundFileReader::CompoundFileReader(Directory* dir, const QString& name)
: entries(false, true)
{
directory = dir;
fileName = name;
bool success = false;
try {
stream = dir->openInput(name);
// read the directory and init files
int32_t count = stream->readVInt();
FileEntry* entry = NULL;
TCHAR tid[CL_MAX_PATH];
for (int32_t i = 0; i < count; i++) {
int64_t offset = stream->readLong();
int32_t read = stream->readString(tid, CL_MAX_PATH);
QString aid(QString::fromWCharArray(tid, read));
// set length of the previous entry
if (entry != NULL)
entry->length = offset - entry->offset;
entry = _CLNEW FileEntry(offset);
entries.put(aid, entry);
}
// set the length of the final entry
if (entry != NULL)
entry->length = stream->length() - entry->offset;
success = true;
} _CLFINALLY (
if (!success && (stream != NULL)) {
try {
stream->close();
_CLDELETE(stream);
} catch (CLuceneError& err) {
if (err.number() != CL_ERR_IO)
throw err;
}
}
)
}
CompoundFileReader::~CompoundFileReader()
{
close();
}
Directory* CompoundFileReader::getDirectory()
{
return directory;
}
QString CompoundFileReader::getName() const
{
return fileName;
}
void CompoundFileReader::close()
{
SCOPED_LOCK_MUTEX(THIS_LOCK)
if (stream != NULL) {
entries.clear();
stream->close();
_CLDELETE(stream);
}
}
IndexInput* CompoundFileReader::openInput(const QString& id)
{
SCOPED_LOCK_MUTEX(THIS_LOCK)
if (stream == NULL)
_CLTHROWA(CL_ERR_IO, "Stream closed");
const FileEntry* entry = entries.get(id);
if (entry == NULL) {
char buf[CL_MAX_PATH + 30];
strcpy(buf,"No sub-file with id ");
strncat(buf, id.toLocal8Bit().constData(), CL_MAX_PATH);
strcat(buf, " found");
_CLTHROWA(CL_ERR_IO,buf);
}
return _CLNEW CSIndexInput(stream, entry->offset, entry->length);
}
QStringList CompoundFileReader::list() const
{
// for (EntriesType::const_iterator i=entries.begin();i!=entries.end();i++){
// names->push_back(i->first);
// ++i;
// }
QStringList names;
EntriesType::const_iterator itr;
// TODO: verify this, see old code above ???
for (itr = entries.begin(); itr != entries.end(); ++itr)
names.push_back(itr->first);
return names;
}
bool CompoundFileReader::fileExists(const QString& name) const
{
return entries.exists(name);
}
int64_t CompoundFileReader::fileModified(const QString& name) const
{
return directory->fileModified(fileName);
}
void CompoundFileReader::touchFile(const QString& name)
{
directory->touchFile(fileName);
}
bool CompoundFileReader::doDeleteFile(const QString& name)
{
_CLTHROWA(CL_ERR_UnsupportedOperation,
"UnsupportedOperationException: CompoundFileReader::doDeleteFile");
}
void CompoundFileReader::renameFile(const QString& from, const QString& to)
{
_CLTHROWA(CL_ERR_UnsupportedOperation,
"UnsupportedOperationException: CompoundFileReader::renameFile");
}
int64_t CompoundFileReader::fileLength(const QString& name) const
{
FileEntry* e = entries.get(name);
if (e == NULL) {
char buf[CL_MAX_PATH + 30];
strcpy(buf,"File ");
strncat(buf, name.toLocal8Bit().constData(), CL_MAX_PATH);
strcat(buf," does not exist");
_CLTHROWA(CL_ERR_IO,buf);
}
return e->length;
}
IndexOutput* CompoundFileReader::createOutput(const QString& name)
{
_CLTHROWA(CL_ERR_UnsupportedOperation,
"UnsupportedOperationException: CompoundFileReader::createOutput");
}
LuceneLock* CompoundFileReader::makeLock(const QString& name)
{
_CLTHROWA(CL_ERR_UnsupportedOperation,
"UnsupportedOperationException: CompoundFileReader::makeLock");
}
QString CompoundFileReader::toString() const
{
QString ret(QLatin1String("CompoundFileReader@"));
return ret.append(fileName);
}
CompoundFileWriter::CompoundFileWriter(Directory* dir, const QString& name)
: ids(false)
, entries(true)
{
if (dir == NULL)
_CLTHROWA(CL_ERR_NullPointer, "directory cannot be null");
if (name.isEmpty())
_CLTHROWA(CL_ERR_NullPointer, "name cannot be null");
merged = false;
directory = dir;
fileName = name;
}
CompoundFileWriter::~CompoundFileWriter()
{
}
Directory* CompoundFileWriter::getDirectory()
{
return directory;
}
/** Returns the name of the compound file. */
QString CompoundFileWriter::getName() const
{
return fileName;
}
void CompoundFileWriter::addFile(const QString& file)
{
if (merged)
_CLTHROWA(CL_ERR_IO, "Can't add extensions after merge has been called");
if (file.isEmpty())
_CLTHROWA(CL_ERR_NullPointer, "file cannot be null");
if (ids.find(file) != ids.end()) {
char buf[CL_MAX_PATH + 30];
strcpy(buf, "File ");
strncat(buf, file.toLocal8Bit().constData(), CL_MAX_PATH);
strcat(buf," already added");
_CLTHROWA(CL_ERR_IO,buf);
}
ids.insert(file);
entries.push_back(_CLNEW WriterFileEntry(file));
}
void CompoundFileWriter::close()
{
if (merged)
_CLTHROWA(CL_ERR_IO, "Merge already performed");
if (entries.size() == 0) // isEmpty()
_CLTHROWA(CL_ERR_IO, "No entries to merge have been defined");
merged = true;
// open the compound stream
IndexOutput* os = NULL;
try {
os = directory->createOutput(fileName);
// Write the number of entries
os->writeVInt(entries.size());
// Write the directory with all offsets at 0.
// Remember the positions of directory entries so that we can
// adjust the offsets later
{ //msvc6 for scope fix
TCHAR tfile[CL_MAX_PATH];
for (CLLinkedList<WriterFileEntry*>::iterator i = entries.begin();
i != entries.end(); i++) {
WriterFileEntry* fe = *i;
fe->directoryOffset = os->getFilePointer();
os->writeLong(0); // for now
tfile[fe->file.toWCharArray(tfile)] = '\0';
os->writeString(tfile, _tcslen(tfile));
}
}
// Open the files and copy their data into the stream.
// Remember the locations of each file's data section.
{ //msvc6 for scope fix
int32_t bufferLength = 1024;
uint8_t buffer[1024];
for (CLLinkedList<WriterFileEntry*>::iterator i = entries.begin();
i != entries.end(); i++) {
WriterFileEntry* fe = *i;
fe->dataOffset = os->getFilePointer();
copyFile(fe, os, buffer, bufferLength);
}
}
{ //msvc6 for scope fix
// Write the data offsets into the directory of the compound stream
for (CLLinkedList<WriterFileEntry*>::iterator i = entries.begin();
i != entries.end(); i++) {
WriterFileEntry* fe = *i;
os->seek(fe->directoryOffset);
os->writeLong(fe->dataOffset);
}
}
} _CLFINALLY (
if (os != NULL) {
try {
os->close();
_CLDELETE(os);
} catch (...) { }
}
);
}
void CompoundFileWriter::copyFile(WriterFileEntry* source, IndexOutput* os,
uint8_t* buffer, int32_t bufferLength)
{
IndexInput* is = NULL;
try {
int64_t startPtr = os->getFilePointer();
is = directory->openInput(source->file);
int64_t length = is->length();
int64_t remainder = length;
int32_t chunk = bufferLength;
while(remainder > 0) {
int32_t len = (int32_t)min((int64_t)chunk, remainder);
is->readBytes(buffer, len);
os->writeBytes(buffer, len);
remainder -= len;
}
// Verify that remainder is 0
if (remainder != 0) {
TCHAR buf[CL_MAX_PATH+100];
_sntprintf(buf, CL_MAX_PATH + 100, _T("Non-zero remainder length ")
_T("after copying: %d (id: %s, length: %d, buffer size: %d)"),
remainder, source->file.toLocal8Bit().constData(), length, chunk);
_CLTHROWT(CL_ERR_IO, buf);
}
// Verify that the output length diff is equal to original file
int64_t endPtr = os->getFilePointer();
int64_t diff = endPtr - startPtr;
if (diff != length) {
TCHAR buf[100];
_sntprintf(buf, 100, _T("Difference in the output file offsets %d ")
_T("does not match the original file length %d"), diff, length);
_CLTHROWT(CL_ERR_IO,buf);
}
} _CLFINALLY (
if (is != NULL) {
is->close();
_CLDELETE(is);
}
);
}
CL_NS_END