fs/io: move to io/
This commit is contained in:
@@ -41,7 +41,7 @@
|
||||
#ifdef USE_XDG
|
||||
#include "util/StringStrip.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
#include "io/TextFile.hxx"
|
||||
#include "fs/io/TextFile.hxx"
|
||||
#include <string.h>
|
||||
#include <utility>
|
||||
#endif
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright 2003-2021 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "AutoGunzipReader.hxx"
|
||||
#include "GunzipReader.hxx"
|
||||
|
||||
AutoGunzipReader::AutoGunzipReader(Reader &_next) noexcept
|
||||
:peek(_next) {}
|
||||
|
||||
AutoGunzipReader::~AutoGunzipReader() noexcept = default;
|
||||
|
||||
[[gnu::pure]]
|
||||
static bool
|
||||
IsGzip(const uint8_t data[4]) noexcept
|
||||
{
|
||||
return data[0] == 0x1f && data[1] == 0x8b && data[2] == 0x08 &&
|
||||
(data[3] & 0xe0) == 0;
|
||||
}
|
||||
|
||||
inline void
|
||||
AutoGunzipReader::Detect()
|
||||
{
|
||||
const auto *data = (const uint8_t *)peek.Peek(4);
|
||||
if (data == nullptr) {
|
||||
next = &peek;
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsGzip(data))
|
||||
next = (gunzip = std::make_unique<GunzipReader>(peek)).get();
|
||||
else
|
||||
next = &peek;
|
||||
}
|
||||
|
||||
size_t
|
||||
AutoGunzipReader::Read(void *data, size_t size)
|
||||
{
|
||||
if (next == nullptr)
|
||||
Detect();
|
||||
|
||||
assert(next != nullptr);
|
||||
return next->Read(data, size);
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright 2003-2021 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MPD_AUTO_GUNZIP_READER_HXX
|
||||
#define MPD_AUTO_GUNZIP_READER_HXX
|
||||
|
||||
#include "PeekReader.hxx"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class GunzipReader;
|
||||
|
||||
/**
|
||||
* A filter that detects gzip compression and optionally inserts a
|
||||
* #GunzipReader.
|
||||
*/
|
||||
class AutoGunzipReader final : public Reader {
|
||||
Reader *next = nullptr;
|
||||
PeekReader peek;
|
||||
std::unique_ptr<GunzipReader> gunzip;
|
||||
|
||||
public:
|
||||
explicit AutoGunzipReader(Reader &_next) noexcept;
|
||||
~AutoGunzipReader() noexcept;
|
||||
|
||||
/* virtual methods from class Reader */
|
||||
size_t Read(void *data, size_t size) override;
|
||||
|
||||
private:
|
||||
void Detect();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Max Kellermann <max.kellermann@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "BufferedOutputStream.hxx"
|
||||
#include "OutputStream.hxx"
|
||||
|
||||
#include <cstdarg>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef _UNICODE
|
||||
#include "system/Error.hxx"
|
||||
#include <stringapiset.h>
|
||||
#endif
|
||||
|
||||
bool
|
||||
BufferedOutputStream::AppendToBuffer(const void *data, std::size_t size) noexcept
|
||||
{
|
||||
auto r = buffer.Write();
|
||||
if (r.size < size)
|
||||
return false;
|
||||
|
||||
memcpy(r.data, data, size);
|
||||
buffer.Append(size);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
BufferedOutputStream::Write(const void *data, std::size_t size)
|
||||
{
|
||||
/* try to append to the current buffer */
|
||||
if (AppendToBuffer(data, size))
|
||||
return;
|
||||
|
||||
/* not enough room in the buffer - flush it */
|
||||
Flush();
|
||||
|
||||
/* see if there's now enough room */
|
||||
if (AppendToBuffer(data, size))
|
||||
return;
|
||||
|
||||
/* too large for the buffer: direct write */
|
||||
os.Write(data, size);
|
||||
}
|
||||
|
||||
void
|
||||
BufferedOutputStream::Write(const char *p)
|
||||
{
|
||||
Write(p, strlen(p));
|
||||
}
|
||||
|
||||
void
|
||||
BufferedOutputStream::Format(const char *fmt, ...)
|
||||
{
|
||||
auto r = buffer.Write();
|
||||
if (r.empty()) {
|
||||
Flush();
|
||||
r = buffer.Write();
|
||||
}
|
||||
|
||||
/* format into the buffer */
|
||||
std::va_list ap;
|
||||
va_start(ap, fmt);
|
||||
std::size_t size = vsnprintf(r.data, r.size, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (gcc_unlikely(size >= r.size)) {
|
||||
/* buffer was not large enough; flush it and try
|
||||
again */
|
||||
|
||||
Flush();
|
||||
|
||||
r = buffer.Write();
|
||||
|
||||
if (gcc_unlikely(size >= r.size)) {
|
||||
/* still not enough space: grow the buffer and
|
||||
try again */
|
||||
r.size = size + 1;
|
||||
r.data = buffer.Write(r.size);
|
||||
}
|
||||
|
||||
/* format into the new buffer */
|
||||
va_start(ap, fmt);
|
||||
size = vsnprintf(r.data, r.size, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
/* this time, it must fit */
|
||||
assert(size < r.size);
|
||||
}
|
||||
|
||||
buffer.Append(size);
|
||||
}
|
||||
|
||||
#ifdef _UNICODE
|
||||
|
||||
void
|
||||
BufferedOutputStream::Write(const wchar_t *p)
|
||||
{
|
||||
WriteWideToUTF8(p, wcslen(p));
|
||||
}
|
||||
|
||||
void
|
||||
BufferedOutputStream::WriteWideToUTF8(const wchar_t *src,
|
||||
std::size_t src_length)
|
||||
{
|
||||
if (src_length == 0)
|
||||
return;
|
||||
|
||||
auto r = buffer.Write();
|
||||
if (r.empty()) {
|
||||
Flush();
|
||||
r = buffer.Write();
|
||||
}
|
||||
|
||||
int length = WideCharToMultiByte(CP_UTF8, 0, src, src_length,
|
||||
r.data, r.size, nullptr, nullptr);
|
||||
if (length <= 0) {
|
||||
const auto error = GetLastError();
|
||||
if (error != ERROR_INSUFFICIENT_BUFFER)
|
||||
throw MakeLastError(error, "UTF-8 conversion failed");
|
||||
|
||||
/* how much buffer do we need? */
|
||||
length = WideCharToMultiByte(CP_UTF8, 0, src, src_length,
|
||||
nullptr, 0, nullptr, nullptr);
|
||||
if (length <= 0)
|
||||
throw MakeLastError(error, "UTF-8 conversion failed");
|
||||
|
||||
/* grow the buffer and try again */
|
||||
length = WideCharToMultiByte(CP_UTF8, 0, src, src_length,
|
||||
buffer.Write(length), length,
|
||||
nullptr, nullptr);
|
||||
if (length <= 0)
|
||||
throw MakeLastError(error, "UTF-8 conversion failed");
|
||||
}
|
||||
|
||||
buffer.Append(length);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
BufferedOutputStream::Flush()
|
||||
{
|
||||
auto r = buffer.Read();
|
||||
if (r.empty())
|
||||
return;
|
||||
|
||||
os.Write(r.data, r.size);
|
||||
buffer.Consume(r.size);
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2021 Max Kellermann <max.kellermann@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef BUFFERED_OUTPUT_STREAM_HXX
|
||||
#define BUFFERED_OUTPUT_STREAM_HXX
|
||||
|
||||
#include "util/Compiler.h"
|
||||
#include "util/DynamicFifoBuffer.hxx"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#ifdef _UNICODE
|
||||
#include <wchar.h>
|
||||
#endif
|
||||
|
||||
class OutputStream;
|
||||
|
||||
/**
|
||||
* An #OutputStream wrapper that buffers its output to reduce the
|
||||
* number of OutputStream::Write() calls.
|
||||
*
|
||||
* All wchar_t based strings are converted to UTF-8.
|
||||
*
|
||||
* To make sure everything is written to the underlying #OutputStream,
|
||||
* call Flush() before destructing this object.
|
||||
*/
|
||||
class BufferedOutputStream {
|
||||
OutputStream &os;
|
||||
|
||||
DynamicFifoBuffer<char> buffer;
|
||||
|
||||
public:
|
||||
explicit BufferedOutputStream(OutputStream &_os,
|
||||
size_t buffer_size=32768) noexcept
|
||||
:os(_os), buffer(buffer_size) {}
|
||||
|
||||
/**
|
||||
* Write the contents of a buffer.
|
||||
*/
|
||||
void Write(const void *data, std::size_t size);
|
||||
|
||||
/**
|
||||
* Write the given object. Note that this is only safe with
|
||||
* POD types. Types with padding can expose sensitive data.
|
||||
*/
|
||||
template<typename T>
|
||||
void WriteT(const T &value) {
|
||||
Write(&value, sizeof(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write one narrow character.
|
||||
*/
|
||||
void Write(const char &ch) {
|
||||
WriteT(ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a null-terminated string.
|
||||
*/
|
||||
void Write(const char *p);
|
||||
|
||||
/**
|
||||
* Write a printf-style formatted string.
|
||||
*/
|
||||
gcc_printf(2,3)
|
||||
void Format(const char *fmt, ...);
|
||||
|
||||
#ifdef _UNICODE
|
||||
/**
|
||||
* Write one narrow character.
|
||||
*/
|
||||
void Write(const wchar_t &ch) {
|
||||
WriteWideToUTF8(&ch, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a null-terminated wide string.
|
||||
*/
|
||||
void Write(const wchar_t *p);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Write buffer contents to the #OutputStream.
|
||||
*/
|
||||
void Flush();
|
||||
|
||||
/**
|
||||
* Discard buffer contents.
|
||||
*/
|
||||
void Discard() noexcept {
|
||||
buffer.Clear();
|
||||
}
|
||||
|
||||
private:
|
||||
bool AppendToBuffer(const void *data, std::size_t size) noexcept;
|
||||
|
||||
#ifdef _UNICODE
|
||||
void WriteWideToUTF8(const wchar_t *p, std::size_t length);
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function which constructs a #BufferedOutputStream, calls the
|
||||
* given function and flushes the #BufferedOutputStream.
|
||||
*/
|
||||
template<typename F>
|
||||
void
|
||||
WithBufferedOutputStream(OutputStream &os, F &&f)
|
||||
{
|
||||
BufferedOutputStream bos(os);
|
||||
f(bos);
|
||||
bos.Flush();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,133 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2019 Max Kellermann <max.kellermann@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "BufferedReader.hxx"
|
||||
#include "Reader.hxx"
|
||||
#include "util/TextFile.hxx"
|
||||
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
bool
|
||||
BufferedReader::Fill(bool need_more)
|
||||
{
|
||||
if (eof)
|
||||
return !need_more;
|
||||
|
||||
auto w = buffer.Write();
|
||||
if (w.empty()) {
|
||||
if (buffer.GetCapacity() >= MAX_SIZE)
|
||||
return !need_more;
|
||||
|
||||
buffer.Grow(buffer.GetCapacity() * 2);
|
||||
w = buffer.Write();
|
||||
assert(!w.empty());
|
||||
}
|
||||
|
||||
size_t nbytes = reader.Read(w.data, w.size);
|
||||
if (nbytes == 0) {
|
||||
eof = true;
|
||||
return !need_more;
|
||||
}
|
||||
|
||||
buffer.Append(nbytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
void *
|
||||
BufferedReader::ReadFull(size_t size)
|
||||
{
|
||||
while (true) {
|
||||
auto r = Read();
|
||||
if (r.size >= size)
|
||||
return r.data;
|
||||
|
||||
if (!Fill(true))
|
||||
throw std::runtime_error("Premature end of file");
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
BufferedReader::ReadFromBuffer(WritableBuffer<void> dest) noexcept
|
||||
{
|
||||
auto src = Read();
|
||||
size_t nbytes = std::min(src.size, dest.size);
|
||||
memcpy(dest.data, src.data, nbytes);
|
||||
Consume(nbytes);
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
void
|
||||
BufferedReader::ReadFull(WritableBuffer<void> _dest)
|
||||
{
|
||||
auto dest = WritableBuffer<uint8_t>::FromVoid(_dest);
|
||||
assert(dest.size == _dest.size);
|
||||
|
||||
while (true) {
|
||||
size_t nbytes = ReadFromBuffer(dest.ToVoid());
|
||||
dest.skip_front(nbytes);
|
||||
if (dest.size == 0)
|
||||
break;
|
||||
|
||||
if (!Fill(true))
|
||||
throw std::runtime_error("Premature end of file");
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
BufferedReader::ReadLine()
|
||||
{
|
||||
do {
|
||||
char *line = ReadBufferedLine(buffer);
|
||||
if (line != nullptr) {
|
||||
++line_number;
|
||||
return line;
|
||||
}
|
||||
} while (Fill(true));
|
||||
|
||||
if (!eof || buffer.empty())
|
||||
return nullptr;
|
||||
|
||||
auto w = buffer.Write();
|
||||
if (w.empty()) {
|
||||
buffer.Grow(buffer.GetCapacity() + 1);
|
||||
w = buffer.Write();
|
||||
assert(!w.empty());
|
||||
}
|
||||
|
||||
/* terminate the last line */
|
||||
w[0] = 0;
|
||||
|
||||
char *line = buffer.Read().data;
|
||||
buffer.Clear();
|
||||
++line_number;
|
||||
return line;
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2019 Max Kellermann <max.kellermann@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef BUFFERED_READER_HXX
|
||||
#define BUFFERED_READER_HXX
|
||||
|
||||
#include "util/DynamicFifoBuffer.hxx"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
class Reader;
|
||||
|
||||
class BufferedReader {
|
||||
static constexpr size_t MAX_SIZE = 512 * 1024;
|
||||
|
||||
Reader &reader;
|
||||
|
||||
DynamicFifoBuffer<char> buffer;
|
||||
|
||||
bool eof = false;
|
||||
|
||||
unsigned line_number = 0;
|
||||
|
||||
public:
|
||||
explicit BufferedReader(Reader &_reader) noexcept
|
||||
:reader(_reader), buffer(16384) {}
|
||||
|
||||
/**
|
||||
* Reset the internal state. Should be called after rewinding
|
||||
* the underlying #Reader.
|
||||
*/
|
||||
void Reset() noexcept {
|
||||
buffer.Clear();
|
||||
eof = false;
|
||||
line_number = 0;
|
||||
}
|
||||
|
||||
bool Fill(bool need_more);
|
||||
|
||||
[[gnu::pure]]
|
||||
WritableBuffer<void> Read() const noexcept {
|
||||
return buffer.Read().ToVoid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a buffer of exactly the given size (without consuming
|
||||
* it). Throws std::runtime_error if not enough data is
|
||||
* available.
|
||||
*/
|
||||
void *ReadFull(size_t size);
|
||||
|
||||
void Consume(size_t n) noexcept {
|
||||
buffer.Consume(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read (and consume) data from the input buffer into the
|
||||
* given buffer. Does not attempt to refill the buffer.
|
||||
*/
|
||||
size_t ReadFromBuffer(WritableBuffer<void> dest) noexcept;
|
||||
|
||||
/**
|
||||
* Read data into the given buffer and consume it from our
|
||||
* buffer. Throw an exception if the request cannot be
|
||||
* forfilled.
|
||||
*/
|
||||
void ReadFull(WritableBuffer<void> dest);
|
||||
|
||||
char *ReadLine();
|
||||
|
||||
unsigned GetLineNumber() const noexcept {
|
||||
return line_number;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,304 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Max Kellermann <max.kellermann@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "FileOutputStream.hxx"
|
||||
#include "system/Error.hxx"
|
||||
#include "util/StringFormat.hxx"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
FileOutputStream::FileOutputStream(FileDescriptor _directory_fd,
|
||||
Path _path, Mode _mode)
|
||||
:path(_path),
|
||||
directory_fd(_directory_fd),
|
||||
mode(_mode)
|
||||
{
|
||||
Open();
|
||||
}
|
||||
#endif
|
||||
|
||||
FileOutputStream::FileOutputStream(Path _path, Mode _mode)
|
||||
:path(_path),
|
||||
#ifdef __linux__
|
||||
directory_fd(AT_FDCWD),
|
||||
#endif
|
||||
mode(_mode)
|
||||
{
|
||||
Open();
|
||||
}
|
||||
|
||||
inline void
|
||||
FileOutputStream::Open()
|
||||
{
|
||||
switch (mode) {
|
||||
case Mode::CREATE:
|
||||
OpenCreate(false);
|
||||
break;
|
||||
|
||||
case Mode::CREATE_VISIBLE:
|
||||
OpenCreate(true);
|
||||
break;
|
||||
|
||||
case Mode::APPEND_EXISTING:
|
||||
OpenAppend(false);
|
||||
break;
|
||||
|
||||
case Mode::APPEND_OR_CREATE:
|
||||
OpenAppend(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
inline void
|
||||
FileOutputStream::OpenCreate([[maybe_unused]] bool visible)
|
||||
{
|
||||
handle = CreateFile(path.c_str(), GENERIC_WRITE, 0, nullptr,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH,
|
||||
nullptr);
|
||||
if (!IsDefined())
|
||||
throw FormatLastError("Failed to create %s",
|
||||
path.ToUTF8().c_str());
|
||||
}
|
||||
|
||||
inline void
|
||||
FileOutputStream::OpenAppend(bool create)
|
||||
{
|
||||
handle = CreateFile(path.c_str(), GENERIC_WRITE, 0, nullptr,
|
||||
create ? OPEN_ALWAYS : OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH,
|
||||
nullptr);
|
||||
if (!IsDefined())
|
||||
throw FormatLastError("Failed to append to %s",
|
||||
path.ToUTF8().c_str());
|
||||
|
||||
if (!SeekEOF()) {
|
||||
auto code = GetLastError();
|
||||
Close();
|
||||
throw FormatLastError(code, "Failed seek end-of-file of %s",
|
||||
path.ToUTF8().c_str());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint64_t
|
||||
FileOutputStream::Tell() const noexcept
|
||||
{
|
||||
LONG high = 0;
|
||||
DWORD low = SetFilePointer(handle, 0, &high, FILE_CURRENT);
|
||||
if (low == 0xffffffff)
|
||||
return 0;
|
||||
|
||||
return uint64_t(high) << 32 | uint64_t(low);
|
||||
}
|
||||
|
||||
void
|
||||
FileOutputStream::Write(const void *data, size_t size)
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
DWORD nbytes;
|
||||
if (!WriteFile(handle, data, size, &nbytes, nullptr))
|
||||
throw FormatLastError("Failed to write to %s",
|
||||
GetPath().c_str());
|
||||
|
||||
if (size_t(nbytes) != size)
|
||||
throw FormatLastError(ERROR_DISK_FULL, "Failed to write to %s",
|
||||
GetPath().c_str());
|
||||
}
|
||||
|
||||
void
|
||||
FileOutputStream::Commit()
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
void
|
||||
FileOutputStream::Cancel() noexcept
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
Close();
|
||||
|
||||
DeleteFile(GetPath().c_str());
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <cerrno>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef HAVE_O_TMPFILE
|
||||
#ifndef O_TMPFILE
|
||||
/* supported since Linux 3.11 */
|
||||
#define __O_TMPFILE 020000000
|
||||
#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Open a file using Linux's O_TMPFILE for writing the given file.
|
||||
*/
|
||||
static bool
|
||||
OpenTempFile(FileDescriptor directory_fd,
|
||||
FileDescriptor &fd, Path path) noexcept
|
||||
{
|
||||
if (directory_fd != FileDescriptor(AT_FDCWD))
|
||||
return fd.Open(directory_fd, ".", O_TMPFILE|O_WRONLY, 0666);
|
||||
|
||||
const auto directory = path.GetDirectoryName();
|
||||
if (directory.IsNull())
|
||||
return false;
|
||||
|
||||
return fd.Open(directory.c_str(), O_TMPFILE|O_WRONLY, 0666);
|
||||
}
|
||||
|
||||
#endif /* HAVE_O_TMPFILE */
|
||||
|
||||
inline void
|
||||
FileOutputStream::OpenCreate(bool visible)
|
||||
{
|
||||
#ifdef HAVE_O_TMPFILE
|
||||
/* try Linux's O_TMPFILE first */
|
||||
is_tmpfile = !visible && OpenTempFile(directory_fd, fd, GetPath());
|
||||
if (!is_tmpfile) {
|
||||
#endif
|
||||
/* fall back to plain POSIX */
|
||||
if (!fd.Open(
|
||||
#ifdef __linux__
|
||||
directory_fd,
|
||||
#endif
|
||||
GetPath().c_str(),
|
||||
O_WRONLY|O_CREAT|O_TRUNC,
|
||||
0666))
|
||||
throw FormatErrno("Failed to create %s",
|
||||
GetPath().c_str());
|
||||
#ifdef HAVE_O_TMPFILE
|
||||
}
|
||||
#else
|
||||
(void)visible;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void
|
||||
FileOutputStream::OpenAppend(bool create)
|
||||
{
|
||||
int flags = O_WRONLY|O_APPEND;
|
||||
if (create)
|
||||
flags |= O_CREAT;
|
||||
|
||||
if (!fd.Open(
|
||||
#ifdef __linux__
|
||||
directory_fd,
|
||||
#endif
|
||||
path.c_str(), flags))
|
||||
throw FormatErrno("Failed to append to %s",
|
||||
path.c_str());
|
||||
}
|
||||
|
||||
uint64_t
|
||||
FileOutputStream::Tell() const noexcept
|
||||
{
|
||||
return fd.Tell();
|
||||
}
|
||||
|
||||
void
|
||||
FileOutputStream::Write(const void *data, size_t size)
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
ssize_t nbytes = fd.Write(data, size);
|
||||
if (nbytes < 0)
|
||||
throw FormatErrno("Failed to write to %s", GetPath().c_str());
|
||||
else if ((size_t)nbytes < size)
|
||||
throw FormatErrno(ENOSPC, "Failed to write to %s",
|
||||
GetPath().c_str());
|
||||
}
|
||||
|
||||
void
|
||||
FileOutputStream::Commit()
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
#ifdef HAVE_O_TMPFILE
|
||||
if (is_tmpfile) {
|
||||
unlinkat(directory_fd.Get(), GetPath().c_str(), 0);
|
||||
|
||||
/* hard-link the temporary file to the final path */
|
||||
if (linkat(AT_FDCWD,
|
||||
StringFormat<64>("/proc/self/fd/%d", fd.Get()),
|
||||
directory_fd.Get(), path.c_str(),
|
||||
AT_SYMLINK_FOLLOW) < 0)
|
||||
throw FormatErrno("Failed to commit %s",
|
||||
path.c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!Close()) {
|
||||
throw FormatErrno("Failed to commit %s", path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FileOutputStream::Cancel() noexcept
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
Close();
|
||||
|
||||
switch (mode) {
|
||||
case Mode::CREATE:
|
||||
#ifdef HAVE_O_TMPFILE
|
||||
if (!is_tmpfile)
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
unlinkat(directory_fd.Get(), GetPath().c_str(), 0);
|
||||
#else
|
||||
unlink(GetPath().c_str());
|
||||
#endif
|
||||
break;
|
||||
|
||||
case Mode::CREATE_VISIBLE:
|
||||
case Mode::APPEND_EXISTING:
|
||||
case Mode::APPEND_OR_CREATE:
|
||||
/* can't roll this back */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Max Kellermann <max.kellermann@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef FILE_OUTPUT_STREAM_HXX
|
||||
#define FILE_OUTPUT_STREAM_HXX
|
||||
|
||||
#include "OutputStream.hxx"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include "io/FileDescriptor.hxx"
|
||||
#endif
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <fileapi.h>
|
||||
#include <windef.h> // for HWND (needed by winbase.h)
|
||||
#include <handleapi.h> // for INVALID_HANDLE_VALUE
|
||||
#include <winbase.h> // for FILE_END
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && !defined(ANDROID)
|
||||
/* we don't use O_TMPFILE on Android because Android's braindead
|
||||
SELinux policy disallows hardlinks
|
||||
(https://android.googlesource.com/platform/external/sepolicy/+/85ce2c7),
|
||||
even hardlinks from /proc/self/fd/N, which however is required to
|
||||
use O_TMPFILE */
|
||||
#define HAVE_O_TMPFILE
|
||||
#endif
|
||||
|
||||
class Path;
|
||||
|
||||
class FileOutputStream final : public OutputStream {
|
||||
const AllocatedPath path;
|
||||
|
||||
#ifdef __linux__
|
||||
const FileDescriptor directory_fd;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
FileDescriptor fd = FileDescriptor::Undefined();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_O_TMPFILE
|
||||
/**
|
||||
* Was O_TMPFILE used? If yes, then linkat() must be used to
|
||||
* create a link to this file.
|
||||
*/
|
||||
bool is_tmpfile = false;
|
||||
#endif
|
||||
|
||||
public:
|
||||
enum class Mode : uint8_t {
|
||||
/**
|
||||
* Create a new file, or replace an existing file.
|
||||
* File contents may not be visible until Commit() has
|
||||
* been called.
|
||||
*/
|
||||
CREATE,
|
||||
|
||||
/**
|
||||
* Like #CREATE, but no attempt is made to hide file
|
||||
* contents during the transaction (e.g. via O_TMPFILE
|
||||
* or a hidden temporary file).
|
||||
*/
|
||||
CREATE_VISIBLE,
|
||||
|
||||
/**
|
||||
* Append to a file that already exists. If it does
|
||||
* not, an exception is thrown.
|
||||
*/
|
||||
APPEND_EXISTING,
|
||||
|
||||
/**
|
||||
* Like #APPEND_EXISTING, but create the file if it
|
||||
* does not exist.
|
||||
*/
|
||||
APPEND_OR_CREATE,
|
||||
};
|
||||
|
||||
private:
|
||||
Mode mode;
|
||||
|
||||
public:
|
||||
explicit FileOutputStream(Path _path, Mode _mode=Mode::CREATE);
|
||||
|
||||
#ifdef __linux__
|
||||
FileOutputStream(FileDescriptor _directory_fd, Path _path,
|
||||
Mode _mode=Mode::CREATE);
|
||||
#endif
|
||||
|
||||
~FileOutputStream() noexcept {
|
||||
if (IsDefined())
|
||||
Cancel();
|
||||
}
|
||||
|
||||
FileOutputStream(const FileOutputStream &) = delete;
|
||||
FileOutputStream &operator=(const FileOutputStream &) = delete;
|
||||
|
||||
public:
|
||||
Path GetPath() const noexcept {
|
||||
return path;
|
||||
}
|
||||
|
||||
[[gnu::pure]]
|
||||
uint64_t Tell() const noexcept;
|
||||
|
||||
/* virtual methods from class OutputStream */
|
||||
void Write(const void *data, size_t size) override;
|
||||
|
||||
void Commit();
|
||||
void Cancel() noexcept;
|
||||
|
||||
private:
|
||||
void OpenCreate(bool visible);
|
||||
void OpenAppend(bool create);
|
||||
void Open();
|
||||
|
||||
bool Close() noexcept {
|
||||
assert(IsDefined());
|
||||
|
||||
#ifdef _WIN32
|
||||
CloseHandle(handle);
|
||||
handle = INVALID_HANDLE_VALUE;
|
||||
return true;
|
||||
#else
|
||||
return fd.Close();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
bool SeekEOF() noexcept {
|
||||
return SetFilePointer(handle, 0, nullptr,
|
||||
FILE_END) != 0xffffffff;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool IsDefined() const noexcept {
|
||||
#ifdef _WIN32
|
||||
return handle != INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
return fd.IsDefined();
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2019 Max Kellermann <max.kellermann@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "FileReader.hxx"
|
||||
#include "fs/FileInfo.hxx"
|
||||
#include "system/Error.hxx"
|
||||
#include "io/Open.hxx"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
FileReader::FileReader(Path _path)
|
||||
:path(_path),
|
||||
handle(CreateFile(path.c_str(), GENERIC_READ, FILE_SHARE_READ,
|
||||
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
|
||||
nullptr))
|
||||
{
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
throw FormatLastError("Failed to open %s", path.ToUTF8().c_str());
|
||||
}
|
||||
|
||||
FileInfo
|
||||
FileReader::GetFileInfo() const
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
return FileInfo(path);
|
||||
}
|
||||
|
||||
size_t
|
||||
FileReader::Read(void *data, size_t size)
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
DWORD nbytes;
|
||||
if (!ReadFile(handle, data, size, &nbytes, nullptr))
|
||||
throw FormatLastError("Failed to read from %s",
|
||||
path.ToUTF8().c_str());
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
void
|
||||
FileReader::Seek(off_t offset)
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
auto result = SetFilePointer(handle, offset, nullptr, FILE_BEGIN);
|
||||
if (result == INVALID_SET_FILE_POINTER)
|
||||
throw MakeLastError("Failed to seek");
|
||||
}
|
||||
|
||||
void
|
||||
FileReader::Skip(off_t offset)
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
auto result = SetFilePointer(handle, offset, nullptr, FILE_CURRENT);
|
||||
if (result == INVALID_SET_FILE_POINTER)
|
||||
throw MakeLastError("Failed to seek");
|
||||
}
|
||||
|
||||
void
|
||||
FileReader::Close() noexcept
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
CloseHandle(handle);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
FileReader::FileReader(Path _path)
|
||||
:path(_path), fd(OpenReadOnly(path.c_str()))
|
||||
{
|
||||
}
|
||||
|
||||
FileInfo
|
||||
FileReader::GetFileInfo() const
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
FileInfo info;
|
||||
const bool success = fstat(fd.Get(), &info.st) == 0;
|
||||
if (!success)
|
||||
throw FormatErrno("Failed to access %s",
|
||||
path.ToUTF8().c_str());
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
size_t
|
||||
FileReader::Read(void *data, size_t size)
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
ssize_t nbytes = fd.Read(data, size);
|
||||
if (nbytes < 0)
|
||||
throw FormatErrno("Failed to read from %s", path.ToUTF8().c_str());
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
void
|
||||
FileReader::Seek(off_t offset)
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
auto result = fd.Seek(offset);
|
||||
const bool success = result >= 0;
|
||||
if (!success)
|
||||
throw MakeErrno("Failed to seek");
|
||||
}
|
||||
|
||||
void
|
||||
FileReader::Skip(off_t offset)
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
auto result = fd.Skip(offset);
|
||||
const bool success = result >= 0;
|
||||
if (!success)
|
||||
throw MakeErrno("Failed to seek");
|
||||
}
|
||||
|
||||
void
|
||||
FileReader::Close() noexcept
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
fd.Close();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,133 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2019 Max Kellermann <max.kellermann@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef FILE_READER_HXX
|
||||
#define FILE_READER_HXX
|
||||
|
||||
#include "Reader.hxx"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <fileapi.h>
|
||||
#include <handleapi.h> // for INVALID_HANDLE_VALUE
|
||||
#include <windef.h> // for HWND (needed by winbase.h)
|
||||
#include <winbase.h> // for FILE_CURRENT
|
||||
#else
|
||||
#include "io/UniqueFileDescriptor.hxx"
|
||||
#endif
|
||||
|
||||
class Path;
|
||||
class FileInfo;
|
||||
|
||||
class FileReader final : public Reader {
|
||||
AllocatedPath path;
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE handle;
|
||||
#else
|
||||
UniqueFileDescriptor fd;
|
||||
#endif
|
||||
|
||||
public:
|
||||
explicit FileReader(Path _path);
|
||||
|
||||
#ifdef _WIN32
|
||||
FileReader(FileReader &&other) noexcept
|
||||
:path(std::move(other.path)),
|
||||
handle(std::exchange(other.handle, INVALID_HANDLE_VALUE)) {}
|
||||
|
||||
~FileReader() noexcept {
|
||||
if (IsDefined())
|
||||
Close();
|
||||
}
|
||||
#else
|
||||
FileReader(FileReader &&other) noexcept
|
||||
:path(std::move(other.path)),
|
||||
fd(std::move(other.fd)) {}
|
||||
#endif
|
||||
|
||||
|
||||
protected:
|
||||
bool IsDefined() const noexcept {
|
||||
#ifdef _WIN32
|
||||
return handle != INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
return fd.IsDefined();
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
#ifndef _WIN32
|
||||
FileDescriptor GetFD() const noexcept {
|
||||
return fd;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Close() noexcept;
|
||||
|
||||
FileInfo GetFileInfo() const;
|
||||
|
||||
[[gnu::pure]]
|
||||
uint64_t GetSize() const noexcept {
|
||||
#ifdef _WIN32
|
||||
LARGE_INTEGER size;
|
||||
return GetFileSizeEx(handle, &size)
|
||||
? size.QuadPart
|
||||
: 0;
|
||||
#else
|
||||
return fd.GetSize();
|
||||
#endif
|
||||
}
|
||||
|
||||
[[gnu::pure]]
|
||||
uint64_t GetPosition() const noexcept {
|
||||
#ifdef _WIN32
|
||||
LARGE_INTEGER zero;
|
||||
zero.QuadPart = 0;
|
||||
LARGE_INTEGER position;
|
||||
return SetFilePointerEx(handle, zero, &position, FILE_CURRENT)
|
||||
? position.QuadPart
|
||||
: 0;
|
||||
#else
|
||||
return fd.Tell();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Rewind() {
|
||||
Seek(0);
|
||||
}
|
||||
|
||||
void Seek(off_t offset);
|
||||
void Skip(off_t offset);
|
||||
|
||||
/* virtual methods from class Reader */
|
||||
size_t Read(void *data, size_t size) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2019 Max Kellermann <max.kellermann@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "GunzipReader.hxx"
|
||||
#include "lib/zlib/Error.hxx"
|
||||
|
||||
GunzipReader::GunzipReader(Reader &_next)
|
||||
:next(_next)
|
||||
{
|
||||
z.next_in = nullptr;
|
||||
z.avail_in = 0;
|
||||
z.zalloc = Z_NULL;
|
||||
z.zfree = Z_NULL;
|
||||
z.opaque = Z_NULL;
|
||||
|
||||
int result = inflateInit2(&z, 16 + MAX_WBITS);
|
||||
if (result != Z_OK)
|
||||
throw ZlibError(result);
|
||||
}
|
||||
|
||||
inline bool
|
||||
GunzipReader::FillBuffer()
|
||||
{
|
||||
auto w = buffer.Write();
|
||||
assert(!w.empty());
|
||||
|
||||
size_t nbytes = next.Read(w.data, w.size);
|
||||
if (nbytes == 0)
|
||||
return false;
|
||||
|
||||
buffer.Append(nbytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t
|
||||
GunzipReader::Read(void *data, size_t size)
|
||||
{
|
||||
if (eof)
|
||||
return 0;
|
||||
|
||||
z.next_out = (Bytef *)data;
|
||||
z.avail_out = size;
|
||||
|
||||
while (true) {
|
||||
int flush = Z_NO_FLUSH;
|
||||
|
||||
auto r = buffer.Read();
|
||||
if (r.empty()) {
|
||||
if (FillBuffer())
|
||||
r = buffer.Read();
|
||||
else
|
||||
flush = Z_FINISH;
|
||||
}
|
||||
|
||||
z.next_in = r.data;
|
||||
z.avail_in = r.size;
|
||||
|
||||
int result = inflate(&z, flush);
|
||||
if (result == Z_STREAM_END) {
|
||||
eof = true;
|
||||
return size - z.avail_out;
|
||||
} else if (result != Z_OK)
|
||||
throw ZlibError(result);
|
||||
|
||||
buffer.Consume(r.size - z.avail_in);
|
||||
|
||||
if (z.avail_out < size)
|
||||
return size - z.avail_out;
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2019 Max Kellermann <max.kellermann@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef GUNZIP_READER_HXX
|
||||
#define GUNZIP_READER_HXX
|
||||
|
||||
#include "Reader.hxx"
|
||||
#include "util/StaticFifoBuffer.hxx"
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
/**
|
||||
* A filter that decompresses data using zlib.
|
||||
*/
|
||||
class GunzipReader final : public Reader {
|
||||
Reader &next;
|
||||
|
||||
bool eof = false;
|
||||
|
||||
z_stream z;
|
||||
|
||||
StaticFifoBuffer<Bytef, 65536> buffer;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct the filter.
|
||||
*
|
||||
* Throws on error.
|
||||
*/
|
||||
explicit GunzipReader(Reader &_next);
|
||||
|
||||
~GunzipReader() noexcept {
|
||||
inflateEnd(&z);
|
||||
}
|
||||
|
||||
/* virtual methods from class Reader */
|
||||
size_t Read(void *data, size_t size) override;
|
||||
|
||||
private:
|
||||
bool FillBuffer();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Max Kellermann <max.kellermann@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "GzipOutputStream.hxx"
|
||||
#include "lib/zlib/Error.hxx"
|
||||
|
||||
GzipOutputStream::GzipOutputStream(OutputStream &_next)
|
||||
:next(_next)
|
||||
{
|
||||
z.next_in = nullptr;
|
||||
z.avail_in = 0;
|
||||
z.zalloc = Z_NULL;
|
||||
z.zfree = Z_NULL;
|
||||
z.opaque = Z_NULL;
|
||||
|
||||
constexpr int windowBits = 15;
|
||||
constexpr int gzip_encoding = 16;
|
||||
|
||||
int result = deflateInit2(&z, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
|
||||
windowBits | gzip_encoding,
|
||||
8, Z_DEFAULT_STRATEGY);
|
||||
if (result != Z_OK)
|
||||
throw ZlibError(result);
|
||||
}
|
||||
|
||||
GzipOutputStream::~GzipOutputStream()
|
||||
{
|
||||
deflateEnd(&z);
|
||||
}
|
||||
|
||||
void
|
||||
GzipOutputStream::Flush()
|
||||
{
|
||||
/* no more input */
|
||||
z.next_in = nullptr;
|
||||
z.avail_in = 0;
|
||||
|
||||
while (true) {
|
||||
Bytef output[16384];
|
||||
z.next_out = output;
|
||||
z.avail_out = sizeof(output);
|
||||
|
||||
int result = deflate(&z, Z_FINISH);
|
||||
if (z.next_out > output)
|
||||
next.Write(output, z.next_out - output);
|
||||
|
||||
if (result == Z_STREAM_END)
|
||||
break;
|
||||
else if (result != Z_OK)
|
||||
throw ZlibError(result);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GzipOutputStream::Write(const void *_data, size_t size)
|
||||
{
|
||||
/* zlib's API requires non-const input pointer */
|
||||
void *data = const_cast<void *>(_data);
|
||||
|
||||
z.next_in = reinterpret_cast<Bytef *>(data);
|
||||
z.avail_in = size;
|
||||
|
||||
while (z.avail_in > 0) {
|
||||
Bytef output[16384];
|
||||
z.next_out = output;
|
||||
z.avail_out = sizeof(output);
|
||||
|
||||
int result = deflate(&z, Z_NO_FLUSH);
|
||||
if (result != Z_OK)
|
||||
throw ZlibError(result);
|
||||
|
||||
if (z.next_out > output)
|
||||
next.Write(output, z.next_out - output);
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Max Kellermann <max.kellermann@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef GZIP_OUTPUT_STREAM_HXX
|
||||
#define GZIP_OUTPUT_STREAM_HXX
|
||||
|
||||
#include "OutputStream.hxx"
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
/**
|
||||
* A filter that compresses data written to it using zlib, forwarding
|
||||
* compressed data in the "gzip" format.
|
||||
*
|
||||
* Don't forget to call Flush() before destructing this object.
|
||||
*/
|
||||
class GzipOutputStream final : public OutputStream {
|
||||
OutputStream &next;
|
||||
|
||||
z_stream z;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct the filter.
|
||||
*/
|
||||
explicit GzipOutputStream(OutputStream &_next);
|
||||
~GzipOutputStream();
|
||||
|
||||
/**
|
||||
* Finish the file and write all data remaining in zlib's
|
||||
* output buffer.
|
||||
*/
|
||||
void Flush();
|
||||
|
||||
/* virtual methods from class OutputStream */
|
||||
void Write(const void *data, size_t size) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright 2003-2021 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class LineReader
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Reads a line from the input file, and strips trailing
|
||||
* space. There is a reasonable maximum line length, only to
|
||||
* prevent denial of service.
|
||||
*
|
||||
* @return a pointer to the line, or nullptr on end-of-file
|
||||
*/
|
||||
virtual char *ReadLine() = 0;
|
||||
};
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2019 Max Kellermann <max.kellermann@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef OUTPUT_STREAM_HXX
|
||||
#define OUTPUT_STREAM_HXX
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
class OutputStream {
|
||||
public:
|
||||
OutputStream() = default;
|
||||
OutputStream(const OutputStream &) = delete;
|
||||
|
||||
/**
|
||||
* Throws std::exception on error.
|
||||
*/
|
||||
virtual void Write(const void *data, size_t size) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright 2003-2021 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "PeekReader.hxx"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
const void *
|
||||
PeekReader::Peek(size_t size)
|
||||
{
|
||||
assert(size > 0);
|
||||
assert(size < sizeof(buffer));
|
||||
assert(buffer_size == 0);
|
||||
assert(buffer_position == 0);
|
||||
|
||||
do {
|
||||
size_t nbytes = next.Read(buffer + buffer_size,
|
||||
size - buffer_size);
|
||||
if (nbytes == 0)
|
||||
return nullptr;
|
||||
|
||||
buffer_size += nbytes;
|
||||
} while (buffer_size < size);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
size_t
|
||||
PeekReader::Read(void *data, size_t size)
|
||||
{
|
||||
size_t buffer_remaining = buffer_size - buffer_position;
|
||||
if (buffer_remaining > 0) {
|
||||
size_t nbytes = std::min(buffer_remaining, size);
|
||||
memcpy(data, buffer + buffer_position, nbytes);
|
||||
buffer_position += nbytes;
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
return next.Read(data, size);
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright 2003-2021 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MPD_PEEK_READER_HXX
|
||||
#define MPD_PEEK_READER_HXX
|
||||
|
||||
#include "Reader.hxx"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
* A filter that allows the caller to peek the first few bytes without
|
||||
* consuming them. The first call must be Peek(), and the following
|
||||
* Read() will deliver the same bytes again.
|
||||
*/
|
||||
class PeekReader final : public Reader {
|
||||
Reader &next;
|
||||
|
||||
size_t buffer_size = 0, buffer_position = 0;
|
||||
|
||||
uint8_t buffer[64];
|
||||
|
||||
public:
|
||||
explicit PeekReader(Reader &_next)
|
||||
:next(_next) {}
|
||||
|
||||
const void *Peek(size_t size);
|
||||
|
||||
/* virtual methods from class Reader */
|
||||
size_t Read(void *data, size_t size) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2019 Max Kellermann <max.kellermann@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef READER_HXX
|
||||
#define READER_HXX
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
/**
|
||||
* An interface that can read bytes from a stream until the stream
|
||||
* ends.
|
||||
*
|
||||
* This interface is simpler and less cumbersome to use than
|
||||
* #InputStream.
|
||||
*/
|
||||
class Reader {
|
||||
public:
|
||||
Reader() = default;
|
||||
Reader(const Reader &) = delete;
|
||||
|
||||
/**
|
||||
* Read data from the stream.
|
||||
*
|
||||
* @return the number of bytes read into the given buffer or 0
|
||||
* on end-of-stream
|
||||
*/
|
||||
[[gnu::nonnull]]
|
||||
virtual size_t Read(void *data, size_t size) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2021 Max Kellermann <max.kellermann@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef STDIO_OUTPUT_STREAM_HXX
|
||||
#define STDIO_OUTPUT_STREAM_HXX
|
||||
|
||||
#include "OutputStream.hxx"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
class StdioOutputStream final : public OutputStream {
|
||||
FILE *const file;
|
||||
|
||||
public:
|
||||
explicit StdioOutputStream(FILE *_file) noexcept:file(_file) {}
|
||||
|
||||
/* virtual methods from class OutputStream */
|
||||
void Write(const void *data, size_t size) override {
|
||||
fwrite(data, 1, size, file);
|
||||
|
||||
/* this class is debug-only and ignores errors */
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -18,9 +18,9 @@
|
||||
*/
|
||||
|
||||
#include "TextFile.hxx"
|
||||
#include "FileReader.hxx"
|
||||
#include "AutoGunzipReader.hxx"
|
||||
#include "BufferedReader.hxx"
|
||||
#include "io/FileReader.hxx"
|
||||
#include "io/BufferedReader.hxx"
|
||||
#include "lib/zlib/AutoGunzipReader.hxx"
|
||||
#include "fs/Path.hxx"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef MPD_TEXT_FILE_HXX
|
||||
#define MPD_TEXT_FILE_HXX
|
||||
|
||||
#include "LineReader.hxx"
|
||||
#include "io/LineReader.hxx"
|
||||
#include "config.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -14,12 +14,7 @@ fs_sources = [
|
||||
'CheckFile.cxx',
|
||||
'LookupFile.cxx',
|
||||
'DirectoryReader.cxx',
|
||||
'io/PeekReader.cxx',
|
||||
'io/FileReader.cxx',
|
||||
'io/BufferedReader.cxx',
|
||||
'io/TextFile.cxx',
|
||||
'io/FileOutputStream.cxx',
|
||||
'io/BufferedOutputStream.cxx',
|
||||
]
|
||||
|
||||
if is_windows
|
||||
@@ -28,14 +23,6 @@ else
|
||||
shlwapi_dep = dependency('', required: false)
|
||||
endif
|
||||
|
||||
if zlib_dep.found()
|
||||
fs_sources += [
|
||||
'io/GunzipReader.cxx',
|
||||
'io/AutoGunzipReader.cxx',
|
||||
'io/GzipOutputStream.cxx',
|
||||
]
|
||||
endif
|
||||
|
||||
fs = static_library(
|
||||
'fs',
|
||||
fs_sources,
|
||||
|
||||
Reference in New Issue
Block a user