ENH: direct access to wrapped ifstream/ofstream with compression (#1805)

- previously hidden as Detail::[IO]FstreamAllocator, now exposed
  directly as [io]fstreamPointer, which allows reuse for
  std::ifstream, std::ofstream wrapping, without the additional
  ISstream, OSstream layers.

  These stream pointers have some characteristics similar to a
  unique_ptr.

- restrict direct gzstream usage to two files (fstreamPointers.C,
  gzstream.C) which improves localization and makes it simpler to
  enable/disable with the `HAVE_LIBZ` define.

  The HAVE_LIBZ define is currently simply hard-coded in the
  Make/options.

  If compiled WITHOUT libz support:
    - reading gz files : FatalError
    - writing gz files : emit warning and downgrade to uncompressed
    - warn if compression is specified in the case controlDict
      and downgrade to uncompressed

ENH: minor updates to gzstream interface for C++11

- support construct/open with std::string for the file names.

CONFIG: provisioning for have_libz detection as wmake/script
This commit is contained in:
Mark Olesen
2020-08-07 17:45:48 +02:00
parent b2bded48c9
commit 6e2b7be983
18 changed files with 956 additions and 350 deletions

View File

@ -0,0 +1,3 @@
Test-fstreamPointer.C
EXE = $(FOAM_USER_APPBIN)/Test-fstreamPointer

View File

@ -0,0 +1,2 @@
/* EXE_INC = */
/* EXE_LIBS = */

View File

@ -0,0 +1,114 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
Application
Test-fstreamPointer
Description
Low-level fstream tests
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "refPtr.H"
#include "fstreamPointer.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program:
int main(int argc, char *argv[])
{
argList::noBanner();
argList::noParallel();
argList::addOption
(
"output",
"file",
"Output file name for cat"
);
argList::addArgument("file1");
argList::addArgument("...");
argList::addArgument("fileN");
argList::noMandatoryArgs();
#include "setRootCase.H"
if (args.size() <= 1)
{
InfoErr<< "\nNo input files specified .. stopping\n" << endl;
return 0;
}
refPtr<std::ostream> osRef;
fileName outputName;
if (args.readIfPresent("output", outputName))
{
InfoErr<< "output: " << outputName;
IOstreamOption::compressionType comp(IOstreamOption::UNCOMPRESSED);
if (outputName.hasExt("gz"))
{
comp = IOstreamOption::COMPRESSED;
outputName.removeExt();
InfoErr<< " [compress]";
}
InfoErr<< nl;
osRef.reset(ofstreamPointer(outputName, comp).release());
}
else
{
osRef.ref(std::cout);
InfoErr<< "output: stdout" << nl;
}
auto& os = osRef.ref();
for (label argi = 1; argi < args.size(); ++argi)
{
const fileName inputName(args[argi]);
InfoErr<< "input: " << inputName;
ifstreamPointer isPtr(inputName);
if (!isPtr.get() || !isPtr->good())
{
InfoErr<< " (not good)" << nl;
continue;
}
InfoErr<< nl;
auto& is = *isPtr;
// Loop getting single characters
// - not efficient, but that is not the test here anyhow
char c;
while (is.get(c))
{
os << c;
}
}
InfoErr<< "\nEnd\n" << endl;
return 0;
}
// ************************************************************************* //

View File

@ -238,6 +238,7 @@ $(memstream)/ListStream.C
Fstreams = $(Streams)/Fstreams
$(Fstreams)/IFstream.C
$(Fstreams)/OFstream.C
$(Fstreams)/fstreamPointers.C
$(Fstreams)/masterOFstream.C
Tstreams = $(Streams)/Tstreams

View File

@ -13,5 +13,7 @@ else
LIB_LIBS += -L$(FOAM_LIBBIN)/dummy -lPstream
endif
LIB_LIBS += \
-lz
/* libz */
EXE_INC += -DHAVE_LIBZ
LIB_LIBS += -lz

View File

@ -5,35 +5,20 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017 OpenCFD Ltd.
Copyright (C) 2017-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM 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 3 of the License, or
(at your option) any later version.
OpenFOAM 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 OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
InClass
Foam::Fstream
This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
Description
Input/output from file streams.
File stream includes.
\*---------------------------------------------------------------------------*/
#ifndef Fstream_H
#define Fstream_H
#include "fstreamPointer.H"
#include "IFstream.H"
#include "OFstream.H"

View File

@ -28,7 +28,6 @@ License
#include "IFstream.H"
#include "OSspecific.H"
#include "gzstream.h"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -38,43 +37,6 @@ namespace Foam
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::Detail::IFstreamAllocator::IFstreamAllocator(const fileName& pathname)
:
allocatedPtr_(nullptr),
detectedCompression_(IOstream::UNCOMPRESSED)
{
if (pathname.empty())
{
if (IFstream::debug)
{
InfoInFunction << "Cannot open null file " << endl;
}
}
const std::ios_base::openmode mode(std::ios_base::in|std::ios_base::binary);
allocatedPtr_.reset(new std::ifstream(pathname, mode));
// If the file is compressed, decompress it before reading.
if (!allocatedPtr_->good() && isFile(pathname + ".gz", false))
{
if (IFstream::debug)
{
InfoInFunction << "Decompressing " << pathname + ".gz" << endl;
}
allocatedPtr_.reset(new igzstream((pathname + ".gz").c_str(), mode));
if (allocatedPtr_->good())
{
detectedCompression_ = IOstream::COMPRESSED;
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::IFstream::IFstream
@ -83,32 +45,47 @@ Foam::IFstream::IFstream
IOstreamOption streamOpt
)
:
Detail::IFstreamAllocator(pathname),
ISstream(*allocatedPtr_, pathname, streamOpt)
Foam::ifstreamPointer(pathname),
ISstream(*(ifstreamPointer::get()), pathname, streamOpt)
{
IOstream::compression(IFstreamAllocator::detectedCompression_);
IOstream::compression(ifstreamPointer::whichCompression());
setClosed();
setState(allocatedPtr_->rdstate());
setState(ifstreamPointer::get()->rdstate());
if (!good())
{
if (debug)
{
InfoInFunction
<< "Could not open file " << pathname
<< " for input" << nl << info() << Foam::endl;
}
setBad();
}
else
if (good())
{
setOpened();
}
else
{
setBad();
}
lineNumber_ = 1;
if (debug)
{
if (pathname.empty())
{
InfoInFunction
<< "Cannot open empty file name"
<< Foam::endl;
}
else if (IOstreamOption::COMPRESSED == IOstream::compression())
{
InfoInFunction
<< "Decompressing " << (this->name() + ".gz") << Foam::endl;
}
if (!opened())
{
InfoInFunction
<< "Could not open file " << pathname
<< " for input\n" << info() << Foam::endl;
}
}
}
@ -116,51 +93,44 @@ Foam::IFstream::IFstream
std::istream& Foam::IFstream::stdStream()
{
if (!allocatedPtr_)
std::istream* ptr = ifstreamPointer::get();
if (!ptr)
{
FatalErrorInFunction
<< "No stream allocated"
<< "No stream allocated\n"
<< abort(FatalError);
}
return *allocatedPtr_;
return *ptr;
}
const std::istream& Foam::IFstream::stdStream() const
{
if (!allocatedPtr_)
const std::istream* ptr = ifstreamPointer::get();
if (!ptr)
{
FatalErrorInFunction
<< "No stream allocated"
<< "No stream allocated\n"
<< abort(FatalError);
}
return *allocatedPtr_;
return *ptr;
}
void Foam::IFstream::rewind()
{
lineNumber_ = 1; // Reset line number
lineNumber_ = 1; // Reset line number
igzstream* gzPtr = nullptr;
try
if (IOstreamOption::COMPRESSED == ifstreamPointer::whichCompression())
{
gzPtr = dynamic_cast<igzstream*>(allocatedPtr_.get());
}
catch (const std::bad_cast&)
{
gzPtr = nullptr;
}
// Special treatment for compressed stream
ifstreamPointer::reopen_gz(this->name() + ".gz");
if (gzPtr)
{
// Need special treatment for gzstream.
gzPtr->close();
gzPtr->clear();
gzPtr->open((this->name() + ".gz").c_str());
setState(gzPtr->rdstate());
setState(ifstreamPointer::get()->rdstate());
}
else
{

View File

@ -39,53 +39,21 @@ SourceFiles
#define IFstream_H
#include "ISstream.H"
#include "fileName.H"
#include "className.H"
#include <fstream>
#include <memory>
#include "fstreamPointer.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace Detail
{
/*---------------------------------------------------------------------------*\
Class Detail::IFstreamAllocator Declaration
\*---------------------------------------------------------------------------*/
//- A std::istream with the ability to handle compressed files
class IFstreamAllocator
{
protected:
// Member Data
//- The allocated stream pointer (ifstream or igzstream).
std::unique_ptr<std::istream> allocatedPtr_;
//- The detected compression type
IOstream::compressionType detectedCompression_;
// Constructors
//- Construct from pathname
IFstreamAllocator(const fileName& pathname);
};
} // End namespace Detail
/*---------------------------------------------------------------------------*\
Class IFstream Declaration
\*---------------------------------------------------------------------------*/
class IFstream
:
public Detail::IFstreamAllocator,
private Foam::ifstreamPointer,
public ISstream
{
public:
@ -107,8 +75,8 @@ public:
IFstream
(
const fileName& pathname,
streamFormat fmt,
versionNumber ver = currentVersion
IOstreamOption::streamFormat fmt,
IOstreamOption::versionNumber ver = currentVersion
)
:
IFstream(pathname, IOstreamOption(fmt, ver))
@ -121,7 +89,8 @@ public:
// Member Functions
// Access
//- Get character(s)
using ISstream::get;
//- Read/write access to the name of the stream
using ISstream::name;
@ -141,7 +110,7 @@ public:
// Print
//- Print stream description to Ostream
//- Print stream description
virtual void print(Ostream& os) const;

View File

@ -28,7 +28,6 @@ License
#include "OFstream.H"
#include "OSspecific.H"
#include "gzstream.h"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -38,74 +37,6 @@ namespace Foam
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Foam::Detail::OFstreamAllocator::OFstreamAllocator
(
const fileName& pathname,
IOstream::compressionType comp,
const bool append
)
:
allocatedPtr_(nullptr)
{
if (pathname.empty())
{
if (OFstream::debug)
{
InfoInFunction << "Cannot open null file " << endl;
}
}
std::ios_base::openmode mode(std::ios_base::out|std::ios_base::binary);
if (append)
{
mode |= std::ios_base::app;
}
if (comp == IOstream::COMPRESSED)
{
// Get identically named uncompressed version out of the way
fileName gzPathName(pathname + ".gz");
fileName::Type pathType = Foam::type(pathname, false);
if (pathType == fileName::FILE || pathType == fileName::LINK)
{
rm(pathname);
}
if (!append && Foam::type(gzPathName) == fileName::LINK)
{
// Disallow writing into softlink to avoid any problems with
// e.g. softlinked initial fields
rm(gzPathName);
}
allocatedPtr_.reset(new ogzstream(gzPathName.c_str(), mode));
}
else
{
// Get identically named compressed version out of the way
fileName gzPathName(pathname + ".gz");
fileName::Type gzType = Foam::type(gzPathName, false);
if (gzType == fileName::FILE || gzType == fileName::LINK)
{
rm(gzPathName);
}
if (!append && Foam::type(pathname, false) == fileName::LINK)
{
// Disallow writing into softlink to avoid any problems with
// e.g. softlinked initial fields
rm(pathname);
}
allocatedPtr_.reset(new std::ofstream(pathname, mode));
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::OFstream::OFstream
@ -115,29 +46,39 @@ Foam::OFstream::OFstream
const bool append
)
:
Detail::OFstreamAllocator(pathname, streamOpt.compression(), append),
OSstream(*allocatedPtr_, pathname, streamOpt)
Foam::ofstreamPointer(pathname, streamOpt.compression(), append),
OSstream(*(ofstreamPointer::get()), pathname, streamOpt)
{
setClosed();
setState(allocatedPtr_->rdstate());
setState(ofstreamPointer::get()->rdstate());
if (!good())
{
if (debug)
{
InfoInFunction
<< "Could not open file " << pathname
<< " for output" << nl << info() << Foam::endl;
}
setBad();
}
else
if (good())
{
setOpened();
}
else
{
setBad();
}
lineNumber_ = 1;
if (debug)
{
if (pathname.empty())
{
InfoInFunction
<< "Cannot open empty file name"
<< Foam::endl;
}
if (!opened())
{
InfoInFunction
<< "Could not open file " << pathname
<< " for output\n" << info() << Foam::endl;
}
}
}
@ -145,23 +86,31 @@ Foam::OFstream::OFstream
std::ostream& Foam::OFstream::stdStream()
{
if (!allocatedPtr_)
std::ostream* ptr = ofstreamPointer::get();
if (!ptr)
{
FatalErrorInFunction
<< "No stream allocated." << abort(FatalError);
<< "No stream allocated\n"
<< abort(FatalError);
}
return *allocatedPtr_;
return *ptr;
}
const std::ostream& Foam::OFstream::stdStream() const
{
if (!allocatedPtr_)
const std::ostream* ptr = ofstreamPointer::get();
if (!ptr)
{
FatalErrorInFunction
<< "No stream allocated." << abort(FatalError);
<< "No stream allocated\n"
<< abort(FatalError);
}
return *allocatedPtr_;
return *ptr;
}

View File

@ -39,55 +39,21 @@ SourceFiles
#define OFstream_H
#include "OSstream.H"
#include "fileName.H"
#include "className.H"
#include <fstream>
#include <memory>
#include "fstreamPointer.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace Detail
{
/*---------------------------------------------------------------------------*\
Class Detail::OFstreamAllocator Declaration
\*---------------------------------------------------------------------------*/
//- A std::ostream with the ability to handle compressed files
class OFstreamAllocator
{
protected:
// Member Data
//- The allocated stream pointer (ofstream or ogzstream).
std::unique_ptr<std::ostream> allocatedPtr_;
// Constructors
//- Construct from pathname
OFstreamAllocator
(
const fileName& pathname,
IOstream::compressionType comp = IOstream::UNCOMPRESSED,
const bool append = false
);
};
} // End namespace Detail
/*---------------------------------------------------------------------------*\
Class OFstream Declaration
\*---------------------------------------------------------------------------*/
class OFstream
:
public Detail::OFstreamAllocator,
private Foam::ofstreamPointer,
public OSstream
{
public:
@ -110,9 +76,9 @@ public:
OFstream
(
const fileName& pathname,
streamFormat fmt,
versionNumber ver = currentVersion,
compressionType comp = compressionType::UNCOMPRESSED,
IOstreamOption::streamFormat fmt,
IOstreamOption::versionNumber ver = currentVersion,
IOstreamOption::compressionType comp = IOstreamOption::UNCOMPRESSED,
const bool append = false
)
:
@ -126,8 +92,6 @@ public:
// Member Functions
// Access
//- Read/write access to the name of the stream
using OSstream::name;
@ -143,7 +107,7 @@ public:
// Print
//- Print stream description to Ostream
//- Print stream description
void print(Ostream& os) const;
};

View File

@ -0,0 +1,262 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM 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 3 of the License, or
(at your option) any later version.
OpenFOAM 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 OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::ifstreamPointer
Description
A wrapped \c std::ifstream with possible compression handling
(igzstream) that behaves much like a \c std::unique_ptr.
Note
No <tt>operator bool</tt> to avoid inheritance ambiguity with
<tt>std::ios::operator bool</tt>.
SourceFiles
fstreamPointers.C
Class
Foam::ofstreamPointer
Description
A wrapped \c std::ofstream with possible compression handling
(ogzstream) that behaves much like a \c std::unique_ptr.
Note
No <tt>operator bool</tt> to avoid inheritance ambiguity with
<tt>std::ios::operator bool</tt>.
SourceFiles
fstreamPointers.C
\*---------------------------------------------------------------------------*/
#ifndef fstreamPointer_H
#define fstreamPointer_H
#include "IOstreamOption.H"
#include "fileName.H"
#include <fstream>
#include <memory>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class ifstreamPointer Declaration
\*---------------------------------------------------------------------------*/
class ifstreamPointer
{
// Private Data
//- The stream pointer (ifstream or igzstream)
std::unique_ptr<std::istream> ptr_;
protected:
// Protected Member Functions
//- Special 'rewind' method for compressed stream
void reopen_gz(const fileName& pathname_gz);
public:
// Generated Methods
//- Default construct (empty)
ifstreamPointer() noexcept = default;
//- No copy construct
ifstreamPointer(const ifstreamPointer&) = delete;
//- Move construct
ifstreamPointer(ifstreamPointer&&) = default;
//- No copy assignment
void operator=(const ifstreamPointer&) = delete;
//- Move assignment
ifstreamPointer& operator=(ifstreamPointer&&) = default;
//- Destructor
~ifstreamPointer() = default;
// Constructors
//- Construct from pathname
explicit ifstreamPointer(const fileName& pathname);
// Member Functions
//- True if compiled with libz support
static bool supports_gz();
// Access
//- The stream pointer (ifstream or igzstream)
std::istream* get() noexcept { return ptr_.get(); }
//- The stream pointer (ifstream or igzstream)
const std::istream* get() const noexcept { return ptr_.get(); }
//- Which compression type?
IOstreamOption::compressionType whichCompression() const;
// Edit
//- Return managed pointer and release ownership
std::istream* release() noexcept { return ptr_.release(); }
//- Replace the managed pointer
void reset(std::istream* ptr) noexcept { ptr_.reset(ptr); }
// Operators
//- Reference to the stream (no nullptr checking)
std::istream& operator*() { return *ptr_; }
//- Const-reference to the stream (no nullptr checking)
const std::istream& operator*() const { return *ptr_; }
//- Pointer dereference
std::istream* operator->() noexcept { return ptr_.get(); }
//- Pointer dereference
const std::istream* operator->() const noexcept { return ptr_.get(); }
};
/*---------------------------------------------------------------------------*\
Class ofstreamPointer Declaration
\*---------------------------------------------------------------------------*/
class ofstreamPointer
{
// Private Data
//- The stream pointer (ofstream or ogzstream)
std::unique_ptr<std::ostream> ptr_;
public:
// Generated Methods
//- Default construct (empty)
ofstreamPointer() noexcept = default;
//- No copy construct
ofstreamPointer(const ofstreamPointer&) = delete;
//- Move construct
ofstreamPointer(ofstreamPointer&&) = default;
//- No copy assignment
void operator=(const ofstreamPointer&) = delete;
//- Move assignment
ofstreamPointer& operator=(ofstreamPointer&&) = default;
//- Destructor
~ofstreamPointer() = default;
// Constructors
//- Construct from pathname, with specified append option
ofstreamPointer(const fileName& pathname, const bool append)
:
ofstreamPointer(pathname, IOstreamOption::UNCOMPRESSED, append)
{}
//- Construct from pathname,
//- with preferred compression and specified append option
explicit ofstreamPointer
(
const fileName& pathname,
IOstreamOption::compressionType comp = IOstreamOption::UNCOMPRESSED,
const bool append = false
);
// Member Functions
//- True if compiled with libz support
static bool supports_gz();
// Access
//- The stream pointer (ofstream or ogzstream)
std::ostream* get() noexcept { return ptr_.get(); }
//- The stream pointer (ofstream or ogzstream)
const std::ostream* get() const noexcept { return ptr_.get(); }
//- Which compression type?
IOstreamOption::compressionType whichCompression() const;
// Edit
//- Return managed pointer and release ownership
std::ostream* release() noexcept { return ptr_.release(); }
//- Replace the managed pointer
void reset(std::ostream* ptr) noexcept { ptr_.reset(ptr); }
// Operators
//- Reference to the stream (no nullptr checking)
std::ostream& operator*() { return *ptr_; }
//- Const-reference to the stream (no nullptr checking)
const std::ostream& operator*() const { return *ptr_; }
//- Pointer dereference
std::ostream* operator->() noexcept { return ptr_.get(); }
//- Pointer dereference
const std::ostream* operator->() const noexcept { return ptr_.get(); }
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,231 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011 OpenFOAM Foundation
Copyright (C) 2018-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM 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 3 of the License, or
(at your option) any later version.
OpenFOAM 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 OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "fstreamPointer.H"
#include "OSspecific.H"
// HAVE_LIBZ defined externally
// #define HAVE_LIBZ
#ifdef HAVE_LIBZ
#include "gzstream.h"
#endif /* HAVE_LIBZ */
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
static inline void removeConflictingFiles
(
const fileName& otherName,
const bool append,
const fileName& targetName
)
{
// Remove other (compressed/uncompressed) version
const fileName::Type pathType = Foam::type(otherName, false);
if (pathType == fileName::FILE || pathType == fileName::LINK)
{
Foam::rm(otherName);
}
// Disallow writing into symlinked files.
// Eg, avoid problems with symlinked initial fields
if (!append && Foam::type(targetName) == fileName::LINK)
{
Foam::rm(targetName);
}
}
}
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
bool Foam::ifstreamPointer::supports_gz()
{
#ifdef HAVE_LIBZ
return true;
#else
return false;
#endif
}
bool Foam::ofstreamPointer::supports_gz()
{
#ifdef HAVE_LIBZ
return true;
#else
return false;
#endif
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::ifstreamPointer::ifstreamPointer
(
const fileName& pathname
)
:
ptr_(nullptr)
{
const std::ios_base::openmode mode
(
std::ios_base::in | std::ios_base::binary
);
ptr_.reset(new std::ifstream(pathname, mode));
if (!ptr_->good())
{
// Try compressed version instead
const fileName pathname_gz(pathname + ".gz");
if (isFile(pathname_gz, false))
{
#ifdef HAVE_LIBZ
ptr_.reset(new igzstream(pathname_gz, mode));
#else /* HAVE_LIBZ */
FatalError
<< "No read support for gz compressed files (libz)"
<< " : could use 'gunzip' from the command-line" << nl
<< "file: " << pathname_gz << endl
<< exit(FatalError);
#endif /* HAVE_LIBZ */
}
}
}
Foam::ofstreamPointer::ofstreamPointer
(
const fileName& pathname,
IOstreamOption::compressionType comp,
const bool append
)
:
ptr_(nullptr)
{
std::ios_base::openmode mode
(
std::ios_base::out | std::ios_base::binary
);
if (append)
{
mode |= std::ios_base::app;
}
const fileName pathname_gz(pathname + ".gz");
if (IOstreamOption::COMPRESSED == comp)
{
// Output compression requested
#ifdef HAVE_LIBZ
removeConflictingFiles(pathname, append, pathname_gz);
ptr_.reset(new ogzstream(pathname_gz, mode));
#else /* HAVE_LIBZ */
comp = IOstreamOption::UNCOMPRESSED;
Warning
<< nl
<< "No write support for gz compressed files (libz)"
<< " : downgraded to UNCOMPRESSED" << nl
<< "file: " << pathname_gz << endl;
#endif /* HAVE_LIBZ */
}
if (IOstreamOption::UNCOMPRESSED == comp)
{
removeConflictingFiles(pathname_gz, append, pathname);
ptr_.reset(new std::ofstream(pathname, mode));
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::ifstreamPointer::reopen_gz(const fileName& pathname_gz)
{
#ifdef HAVE_LIBZ
igzstream* gz = dynamic_cast<igzstream*>(ptr_.get());
if (gz)
{
// Special treatment for gzstream
gz->close();
gz->clear();
gz->open(pathname_gz);
}
#endif /* HAVE_LIBZ */
}
Foam::IOstreamOption::compressionType
Foam::ifstreamPointer::whichCompression() const
{
#ifdef HAVE_LIBZ
if (dynamic_cast<const igzstream*>(ptr_.get()))
{
return IOstreamOption::compressionType::COMPRESSED;
}
#endif /* HAVE_LIBZ */
return IOstreamOption::compressionType::UNCOMPRESSED;
}
Foam::IOstreamOption::compressionType
Foam::ofstreamPointer::whichCompression() const
{
#ifdef HAVE_LIBZ
if (dynamic_cast<const ogzstream*>(ptr_.get()))
{
return IOstreamOption::compressionType::COMPRESSED;
}
#endif /* HAVE_LIBZ */
return IOstreamOption::compressionType::UNCOMPRESSED;
}
// ************************************************************************* //

View File

@ -190,7 +190,7 @@ Foam::Istream& Foam::Istream::operator()() const
{
if (!good())
{
check("Istream::operator()");
check(FUNCTION_NAME);
FatalIOError.exit();
}

View File

@ -25,10 +25,21 @@
// Standard streambuf implementation following Nicolai Josuttis,
// "The Standard C++ Library".
// ============================================================================
//
// Modifications:
// 2020-08-07 OpenCFD Ltd.
// - added HAVE_LIBZ conditional
// - <cstring> instead of <string.h>
// - nullptr for return values
// ============================================================================
// HAVE_LIBZ defined externally
// #define HAVE_LIBZ
#ifdef HAVE_LIBZ
#include "gzstream.h"
#include <iostream>
#include <string.h> // for memcpy
#include <cstring> // for memcpy
#ifdef GZSTREAM_NAMESPACE
namespace GZSTREAM_NAMESPACE {
@ -44,12 +55,12 @@ namespace GZSTREAM_NAMESPACE {
gzstreambuf* gzstreambuf::open( const char* _name, int _open_mode) {
if ( is_open())
return 0;
return nullptr;
mode = _open_mode;
// no append nor read/write mode
if ((mode & std::ios::ate) || (mode & std::ios::app)
|| ((mode & std::ios::in) && (mode & std::ios::out)))
return 0;
return nullptr;
char fmode[10];
char* fmodeptr = fmode;
if ( mode & std::ios::in)
@ -59,8 +70,8 @@ gzstreambuf* gzstreambuf::open( const char* _name, int _open_mode) {
*fmodeptr++ = 'b';
*fmodeptr = '\0';
file = gzopen( _name, fmode);
if (file == 0)
return 0;
if (file == nullptr)
return nullptr;
opened = 1;
return this;
}
@ -72,7 +83,7 @@ gzstreambuf * gzstreambuf::close() {
if ( gzclose( file) == Z_OK)
return this;
}
return 0;
return nullptr;
}
int gzstreambuf::underflow() { // used for input buffer only
@ -85,7 +96,7 @@ int gzstreambuf::underflow() { // used for input buffer only
int n_putback = gptr() - eback();
if ( n_putback > 4)
n_putback = 4;
memcpy( buffer + (4 - n_putback), gptr() - n_putback, n_putback);
std::memcpy( buffer + (4 - n_putback), gptr() - n_putback, n_putback);
int num = gzread( file, buffer+4, bufferSize-4);
if (num <= 0) // ERROR or EOF
@ -163,5 +174,8 @@ void gzstreambase::close() {
} // namespace GZSTREAM_NAMESPACE
#endif
#endif /* HAVE_LIBZ */
// ============================================================================
// EOF //

View File

@ -25,6 +25,12 @@
// Standard streambuf implementation following Nicolai Josuttis,
// "The Standard C++ Library".
// ============================================================================
//
// Modifications:
// 2020-08-07 OpenCFD Ltd.
// - construct/open with std::string as per C++11
// - constexpr
// ============================================================================
#ifndef GZSTREAM_H
#define GZSTREAM_H 1
@ -55,7 +61,7 @@ private:
//------------------------------------
static const int bufferSize = 47+256;
static constexpr const int bufferSize = 47+256;
// totals 512 bytes under g++ for igzstream at the end.
//------------------------------------
@ -155,11 +161,16 @@ public:
igzstream()
: std::istream( &buf)
{}
explicit
igzstream( const char* _name,
int _open_mode = std::ios::in )
: std::istream( &buf )
, gzstreambase( _name, _open_mode )
{}
explicit
igzstream(const std::string& _name, int _open_mode = std::ios::in)
: igzstream(_name.c_str(), _open_mode)
{}
//------------------------------------
@ -172,6 +183,10 @@ public:
{
gzstreambase::open( _name, _open_mode );
}
void open(const std::string& _name, int _open_mode = std::ios::in)
{
gzstreambase::open(_name.c_str(), _open_mode);
}
};
// ----------------------------------------------------------------------------
@ -195,6 +210,10 @@ public:
: gzstreambase( _name, _open_mode )
, std::ostream( &buf)
{}
explicit
ogzstream(const std::string& _name, int _open_mode = std::ios::out)
: ogzstream(_name.c_str(), _open_mode)
{}
//------------------------------------
@ -207,6 +226,10 @@ public:
{
gzstreambase::open( _name, _open_mode );
}
void open(const std::string& _name, int _open_mode = std::ios::out)
{
gzstreambase::open(_name.c_str(), _open_mode);
}
};
#ifdef GZSTREAM_NAMESPACE

View File

@ -34,6 +34,7 @@ License
#include "profiling.H"
#include "IOdictionary.H"
#include "fileOperation.H"
#include "fstreamPointer.H"
#include <iomanip>
@ -394,18 +395,26 @@ void Foam::Time::readDict()
controlDict_.get<word>("writeCompression")
);
if
(
writeStreamOption_.compression() == IOstream::COMPRESSED
&& writeStreamOption_.format() == IOstream::BINARY
)
if (writeStreamOption_.compression() == IOstreamOption::COMPRESSED)
{
IOWarningInFunction(controlDict_)
<< "Disabled binary format compression"
<< " (inefficient/ineffective)"
<< endl;
if (writeStreamOption_.format() == IOstreamOption::BINARY)
{
IOWarningInFunction(controlDict_)
<< "Disabled binary format compression"
<< " (inefficient/ineffective)"
<< endl;
writeStreamOption_.compression(IOstream::UNCOMPRESSED);
writeStreamOption_.compression(IOstreamOption::UNCOMPRESSED);
}
else if (!ofstreamPointer::supports_gz())
{
IOWarningInFunction(controlDict_)
<< "Disabled output compression"
<< " (missing libz support)"
<< endl;
writeStreamOption_.compression(IOstreamOption::UNCOMPRESSED);
}
}
}
@ -523,7 +532,7 @@ bool Foam::Time::writeTimeDict() const
return timeDict.regIOobject::writeObject
(
IOstreamOption(IOstream::ASCII),
IOstreamOption(IOstreamOption::ASCII),
true
);
}

View File

@ -27,17 +27,17 @@ License
\*---------------------------------------------------------------------------*/
#include "STLCore.H"
#include "gzstream.h"
#include "OSspecific.H"
#include "IFstream.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
//! \cond fileScope
// The number of bytes in the STL binary header
static constexpr const unsigned STLHeaderSize = 80;
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
// Check if "SOLID" or "solid" appears as the first non-space content.
// Assume that any leading space is less than 75 chars or so, otherwise
// it is really bad input.
@ -59,7 +59,6 @@ static bool startsWithSolid(const char header[STLHeaderSize])
&& std::toupper(header[pos+4]) == 'D'
);
}
//! \endcond
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
@ -73,7 +72,7 @@ bool Foam::fileFormats::STLCore::isBinaryName
return
(
format == STLFormat::UNKNOWN
? (filename.ext() == "stlb")
? filename.hasExt("stlb")
: format == STLFormat::BINARY
);
}
@ -90,19 +89,11 @@ int Foam::fileFormats::STLCore::detectBinaryHeader
const fileName& filename
)
{
bool compressed = false;
std::unique_ptr<std::istream> streamPtr
{
new std::ifstream(filename, std::ios::binary)
};
// Handle compressed (.gz) or uncompressed input files
// If the file is compressed, decompress it before further checking.
if (!streamPtr->good() && isFile(filename + ".gz", false))
{
compressed = true;
streamPtr.reset(new igzstream((filename + ".gz").c_str()));
}
auto& is = *streamPtr;
ifstreamPointer isPtr(filename);
const bool unCompressed(IOstream::UNCOMPRESSED == isPtr.whichCompression());
auto& is = *isPtr;
if (!is.good())
{
@ -130,29 +121,25 @@ int Foam::fileFormats::STLCore::detectBinaryHeader
// Check that stream is OK and number of triangles is positive,
// if not this may be an ASCII file
//
// Also compare the file size with that expected from the number of tris
// If the comparison is still not sensible then it may be an ASCII file
if (!is || nTris < 0)
{
return 0;
}
else if (!compressed)
bool bad = (!is || nTris < 0);
if (!bad && unCompressed)
{
// Compare file size with that expected from number of tris
// If this is not sensible, it may be an ASCII file
const off_t dataFileSize = Foam::fileSize(filename);
if
(
nTris < int(dataFileSize - STLHeaderSize)/50
|| nTris > int(dataFileSize - STLHeaderSize)/25
)
{
return 0;
}
bad =
(
nTris < int(dataFileSize - STLHeaderSize)/50
|| nTris > int(dataFileSize - STLHeaderSize)/25
);
}
// looks like it might be BINARY, return number of triangles
return nTris;
// Return number of triangles if it appears to be BINARY and good.
return (bad ? 0 : nTris);
}
@ -163,20 +150,18 @@ Foam::fileFormats::STLCore::readBinaryHeader
label& nTrisEstimated
)
{
bool bad = false;
bool compressed = false;
nTrisEstimated = 0;
std::unique_ptr<std::istream> streamPtr
{
new std::ifstream(filename, std::ios::binary)
};
std::unique_ptr<std::istream> streamPtr;
bool unCompressed(true);
// If the file is compressed, decompress it before reading.
if (!streamPtr->good() && isFile(filename + ".gz", false))
// Handle compressed (.gz) or uncompressed input files
{
compressed = true;
streamPtr.reset(new igzstream((filename + ".gz").c_str()));
ifstreamPointer isPtr(filename);
unCompressed = (IOstream::UNCOMPRESSED == isPtr.whichCompression());
// Take ownership
streamPtr.reset(isPtr.release());
}
auto& is = *streamPtr;
@ -208,25 +193,21 @@ Foam::fileFormats::STLCore::readBinaryHeader
// Check that stream is OK and number of triangles is positive,
// if not this maybe an ASCII file
//
// Also compare the file size with that expected from the number of tris
// If the comparison is not sensible then it may be an ASCII file
if (!is || nTris < 0)
{
bad = true;
}
else if (!compressed)
bool bad = (!is || nTris < 0);
if (!bad && unCompressed)
{
// Compare file size with that expected from number of tris
// If this is not sensible, it may be an ASCII file
const off_t dataFileSize = Foam::fileSize(filename);
if
(
nTris < int(dataFileSize - STLHeaderSize)/50
|| nTris > int(dataFileSize - STLHeaderSize)/25
)
{
bad = true;
}
bad =
(
nTris < int(dataFileSize - STLHeaderSize)/50
|| nTris > int(dataFileSize - STLHeaderSize)/25
);
}
if (bad)
@ -237,6 +218,7 @@ Foam::fileFormats::STLCore::readBinaryHeader
}
nTrisEstimated = nTris;
return streamPtr;
}

126
wmake/scripts/have_libz Normal file
View File

@ -0,0 +1,126 @@
#----------------------------------*-sh-*--------------------------------------
# ========= |
# \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
# \\ / O peration |
# \\ / A nd | www.openfoam.com
# \\/ M anipulation |
#------------------------------------------------------------------------------
# Copyright (C) 2020 OpenCFD Ltd.
#------------------------------------------------------------------------------
# License
# This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
#
# Script
# have_libz
#
# Description
# Detection/setup of LIBZ (zlib)
#
# Requires
# None
#
# Functions provided
# have_libz, no_libz, echo_libz, search_libz
#
# Variables set on success
# HAVE_LIBZ - as per GNU autoconf
# LIBZ_INC_DIR
# LIBZ_LIB_DIR
#
#------------------------------------------------------------------------------
. ${WM_PROJECT_DIR:?}/wmake/scripts/sysFunctions # General system functions
#------------------------------------------------------------------------------
# Reset
no_libz()
{
unset HAVE_LIBZ LIBZ_INC_DIR LIBZ_LIB_DIR
}
# Report
echo_libz()
{
echo "libz=${HAVE_LIBZ:-false}"
echo "include=\"$LIBZ_INC_DIR\""
echo "library=\"$LIBZ_LIB_DIR\""
}
# Search
# $1 : prefix (*_ARCH_PATH, system, ...)
#
# On success, return 0 and export variables
# -> HAVE_LIBZ, LIBZ_INC_DIR, LIBZ_LIB_DIR
search_libz()
{
local warn # warn="==> skip libz"
local incName="zlib.h"
local libName="libz"
local prefix="${1:-system}"
local header library
# ----------------------------------
if isNone "$prefix"
then
[ -n "$warn" ] && echo "$warn (disabled)"
return 1
elif hasAbsdir "$prefix"
then
header=$(findFirstFile "$prefix/include/$incName")
library=$(findExtLib "$libName")
elif isSystem "$prefix"
then
header=$(findSystemInclude -name="$incName")
prefix=$(sysPrefix "$header")
else
unset prefix
fi
# ----------------------------------
# Header
[ -n "$header" ] || {
[ -n "$warn" ] && echo "$warn (no header)"
return 2
}
# Library
[ -n "$library" ] \
|| library=$(findLibrary -prefix="$prefix" -name="$libName") \
|| {
[ -n "$warn" ] && echo "$warn (no library)"
return 2
}
# ----------------------------------
# OK
export HAVE_LIBZ=true
export LIBZ_INC_DIR="${header%/*}" # Basename
export LIBZ_LIB_DIR="${library%/*}" # Basename
}
# Output as per search_* function
have_libz()
{
search_libz system
}
#------------------------------------------------------------------------------
# Reset
no_libz
# Test/query
case "$1" in
-test)
have_libz
echo_libz
;;
esac
#------------------------------------------------------------------------------