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);
}
}
};
LZMAFILE* lzma;
+ static uint32_t findXZlevel(std::vector<std::string> const &Args)
+ {
+ for (auto a = Args.rbegin(); a != Args.rend(); ++a)
+ if (a->empty() == false && (*a)[0] == '-' && (*a)[1] != '-')
+ {
+ auto const number = a->find_last_of("0123456789");
+ if (number == std::string::npos)
+ continue;
+ auto const extreme = a->find("e", number);
+ uint32_t level = (extreme != std::string::npos) ? LZMA_PRESET_EXTREME : 0;
+ switch ((*a)[number])
+ {
+ case '0': return level | 0;
+ case '1': return level | 1;
+ case '2': return level | 2;
+ case '3': return level | 3;
+ case '4': return level | 4;
+ case '5': return level | 5;
+ case '6': return level | 6;
+ case '7': return level | 7;
+ case '8': return level | 8;
+ case '9': return level | 9;
+ }
+ }
+ return 6;
+ }
public:
virtual bool InternalOpen(int const iFd, unsigned int const Mode) override
{
if (lzma->file == nullptr)
return false;
- uint32_t const xzlevel = 6;
- uint64_t const memlimit = UINT64_MAX;
lzma_stream tmp_stream = LZMA_STREAM_INIT;
lzma->stream = tmp_stream;
if ((Mode & FileFd::WriteOnly) == FileFd::WriteOnly)
{
+ uint32_t const xzlevel = findXZlevel(compressor.CompressArgs);
if (compressor.Name == "xz")
{
- if (lzma_easy_encoder(&lzma->stream, xzlevel, LZMA_CHECK_CRC32) != LZMA_OK)
+ if (lzma_easy_encoder(&lzma->stream, xzlevel, LZMA_CHECK_CRC64) != LZMA_OK)
return false;
}
else
}
else
{
+ uint64_t const memlimit = UINT64_MAX;
if (compressor.Name == "xz")
{
if (lzma_auto_decoder(&lzma->stream, memlimit, 0) != LZMA_OK)
}
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
{