class FileFdPrivate { /*{{{*/
protected:
FileFd * const filefd;
+ static size_t constexpr buffersize_max = 1024;
+ char buffer[buffersize_max];
+ unsigned long long buffersize = 0;
public:
int compressed_fd;
pid_t compressor_pid;
openmode(0), seekpos(0) {};
virtual bool InternalOpen(int const iFd, unsigned int const Mode) = 0;
- virtual ssize_t InternalRead(void * const To, unsigned long long const Size) = 0;
- virtual bool InternalReadError() { return filefd->FileFdErrno("read",_("Read error")); }
- virtual char * InternalReadLine(char * const To, unsigned long long const Size)
+ ssize_t InternalRead(void * To, unsigned long long Size)
{
- unsigned long long read = 0;
- while ((Size - 1) != read)
+ unsigned long long tmp = 0;
+ if (buffersize != 0)
{
- unsigned long long done = 0;
- if (filefd->Read(To + read, 1, &done) == false)
- return NULL;
- if (done == 0)
- break;
- if (To[read++] == '\n')
- break;
+ if (buffersize >= Size)
+ {
+ memcpy(To, buffer, Size);
+ if (buffersize == Size)
+ {
+ buffersize = 0;
+ }
+ else
+ {
+ buffersize -= Size;
+ memmove(buffer, buffer + Size, buffersize);
+ }
+ return Size;
+ }
+ else
+ {
+ memcpy(To, buffer, buffersize);
+ Size -= buffersize;
+ To = static_cast<char *>(To) + buffersize;
+ tmp = buffersize;
+ buffersize = 0;
+ }
}
- if (read == 0)
- return NULL;
- To[read] = '\0';
- return To;
+ return InternalUnbufferedRead(To, Size) + tmp;
+ }
+ virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) = 0;
+ virtual bool InternalReadError() { return filefd->FileFdErrno("read",_("Read error")); }
+ virtual char * InternalReadLine(char * To, unsigned long long Size)
+ {
+ if (unlikely(Size == 0))
+ return nullptr;
+ --Size;
+ To[0] = '\0';
+ if (unlikely(Size == 0))
+ return To;
+ char * const InitialTo = To;
+
+ do {
+ if (buffersize == 0)
+ {
+ unsigned long long actualread = 0;
+ if (filefd->Read(buffer, buffersize_max, &actualread) == false)
+ return nullptr;
+ buffersize = actualread;
+ if (buffersize == 0)
+ {
+ if (To == InitialTo)
+ return nullptr;
+ break;
+ }
+ filefd->Flags &= ~FileFd::HitEof;
+ }
+
+ unsigned long long const OutputSize = std::min(Size, buffersize);
+ char const * const newline = static_cast<char const * const>(memchr(buffer, '\n', OutputSize));
+ if (newline != nullptr)
+ {
+ size_t length = (newline - buffer);
+ ++length;
+ memcpy(To, buffer, length);
+ To += length;
+ if (length < buffersize)
+ {
+ buffersize -= length;
+ memmove(buffer, buffer + length, buffersize);
+ }
+ else
+ buffersize = 0;
+ break;
+ }
+ else
+ {
+ memcpy(To, buffer, OutputSize);
+ To += OutputSize;
+ Size -= OutputSize;
+ buffersize -= OutputSize;
+ memmove(buffer, buffer + OutputSize, buffersize);
+ }
+ } while (Size > 0);
+ *To = '\0';
+ return InitialTo;
}
virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) = 0;
virtual bool InternalWriteError() { return filefd->FileFdErrno("write",_("Write error")); }
if (filefd->OpenInternDescriptor(openmode, compressor) == false)
return filefd->FileFdError("Seek on file %s because it couldn't be reopened", filefd->FileName.c_str());
+ buffersize = 0;
if (To != 0)
return filefd->Skip(To);
// seeking around, but not all users of FileFd use always Seek() and co
// so d->seekpos isn't always true and we can just use it as a hint if
// we have nothing else, but not always as an authority…
- return seekpos;
+ return seekpos - buffersize;
}
virtual unsigned long long InternalSize()
{
filefd->Flags |= FileFd::Compressed;
return gz != nullptr;
}
- virtual ssize_t InternalRead(void * const To, unsigned long long const Size) override
+ virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) override
{
return gzread(gz, To, Size);
}
return filefd->FileFdError("gzread: %s (%d: %s)", _("Read error"), err, errmsg);
return FileFdPrivate::InternalReadError();
}
- virtual char * InternalReadLine(char * const To, unsigned long long const Size) override
+ virtual char * InternalReadLine(char * To, unsigned long long Size) override
{
return gzgets(gz, To, Size);
}
off_t const res = gzseek(gz, To, SEEK_SET);
if (res != (off_t)To)
return filefd->FileFdError("Unable to seek to %llu", To);
-
seekpos = To;
+ buffersize = 0;
return true;
}
virtual bool InternalSkip(unsigned long long Over) override
{
+ if (Over >= buffersize)
+ {
+ Over -= buffersize;
+ buffersize = 0;
+ }
+ else
+ {
+ buffersize -= Over;
+ memmove(buffer, buffer + Over, buffersize);
+ return true;
+ }
+ if (Over == 0)
+ return true;
off_t const res = gzseek(gz, Over, SEEK_CUR);
if (res < 0)
return filefd->FileFdError("Unable to seek ahead %llu",Over);
}
virtual unsigned long long InternalTell() override
{
- return gztell(gz);
+ return gztell(gz) - buffersize;
}
virtual unsigned long long InternalSize() override
{
filefd->Flags |= FileFd::Compressed;
return bz2 != nullptr;
}
- virtual ssize_t InternalRead(void * const To, unsigned long long const Size) override
+ virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) override
{
return BZ2_bzread(bz2, To, Size);
}
}
return true;
}
- virtual ssize_t InternalRead(void * const To, unsigned long long const Size) override
+ virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) override
{
ssize_t Res;
if (lzma->eof == true)
return true;
}
- virtual ssize_t InternalRead(void * const To, unsigned long long const Size) override
+ virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) override
{
return read(filefd->iFd, To, Size);
}
{
public:
virtual bool InternalOpen(int const, unsigned int const) override { return true; }
- virtual ssize_t InternalRead(void * const To, unsigned long long const Size) override
+ virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) override
{
return read(filefd->iFd, To, Size);
}
-
virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) override
{
+ // files opened read+write are strange and only really "supported" for direct files
+ if (buffersize != 0)
+ {
+ lseek(filefd->iFd, -buffersize, SEEK_CUR);
+ buffersize = 0;
+ }
return write(filefd->iFd, From, Size);
}
virtual bool InternalSeek(unsigned long long const To) override
if (res != (off_t)To)
return filefd->FileFdError("Unable to seek to %llu", To);
seekpos = To;
+ buffersize = 0;
return true;
}
virtual bool InternalSkip(unsigned long long Over) override
{
+ if (Over >= buffersize)
+ {
+ Over -= buffersize;
+ buffersize = 0;
+ }
+ else
+ {
+ buffersize -= Over;
+ memmove(buffer, buffer + Over, buffersize);
+ return true;
+ }
+ if (Over == 0)
+ return true;
off_t const res = lseek(filefd->iFd, Over, SEEK_CUR);
if (res < 0)
return filefd->FileFdError("Unable to seek ahead %llu",Over);
}
virtual bool InternalTruncate(unsigned long long const To) override
{
+ if (buffersize != 0)
+ {
+ unsigned long long const seekpos = lseek(filefd->iFd, 0, SEEK_CUR);
+ if ((seekpos - buffersize) >= To)
+ buffersize = 0;
+ else if (seekpos >= To)
+ buffersize = (To - seekpos);
+ else
+ buffersize = 0;
+ }
if (ftruncate(filefd->iFd, To) != 0)
return filefd->FileFdError("Unable to truncate to %llu",To);
return true;
}
virtual unsigned long long InternalTell() override
{
- return lseek(filefd->iFd,0,SEEK_CUR);
+ return lseek(filefd->iFd,0,SEEK_CUR) - buffersize;
}
virtual unsigned long long InternalSize() override
{