diff --git a/applications/test/fstreamPointer/Make/files b/applications/test/fstreamPointer/Make/files new file mode 100644 index 0000000000..eb97518749 --- /dev/null +++ b/applications/test/fstreamPointer/Make/files @@ -0,0 +1,3 @@ +Test-fstreamPointer.C + +EXE = $(FOAM_USER_APPBIN)/Test-fstreamPointer diff --git a/applications/test/fstreamPointer/Make/options b/applications/test/fstreamPointer/Make/options new file mode 100644 index 0000000000..18e6fe47af --- /dev/null +++ b/applications/test/fstreamPointer/Make/options @@ -0,0 +1,2 @@ +/* EXE_INC = */ +/* EXE_LIBS = */ diff --git a/applications/test/fstreamPointer/Test-fstreamPointer.C b/applications/test/fstreamPointer/Test-fstreamPointer.C new file mode 100644 index 0000000000..6f12abd9a0 --- /dev/null +++ b/applications/test/fstreamPointer/Test-fstreamPointer.C @@ -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 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; +} + + +// ************************************************************************* // diff --git a/src/OpenFOAM/Make/files b/src/OpenFOAM/Make/files index 3c05c00de9..8fc015b0a5 100644 --- a/src/OpenFOAM/Make/files +++ b/src/OpenFOAM/Make/files @@ -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 diff --git a/src/OpenFOAM/Make/options b/src/OpenFOAM/Make/options index d12d74d12b..3805e3c923 100644 --- a/src/OpenFOAM/Make/options +++ b/src/OpenFOAM/Make/options @@ -13,5 +13,7 @@ else LIB_LIBS += -L$(FOAM_LIBBIN)/dummy -lPstream endif -LIB_LIBS += \ - -lz +/* libz */ +EXE_INC += -DHAVE_LIBZ + +LIB_LIBS += -lz diff --git a/src/OpenFOAM/db/IOstreams/Fstreams/Fstream.H b/src/OpenFOAM/db/IOstreams/Fstreams/Fstream.H index 9a8995e5a0..94aee79123 100644 --- a/src/OpenFOAM/db/IOstreams/Fstreams/Fstream.H +++ b/src/OpenFOAM/db/IOstreams/Fstreams/Fstream.H @@ -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 . - -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" diff --git a/src/OpenFOAM/db/IOstreams/Fstreams/IFstream.C b/src/OpenFOAM/db/IOstreams/Fstreams/IFstream.C index 1728aa9a91..59e20b3530 100644 --- a/src/OpenFOAM/db/IOstreams/Fstreams/IFstream.C +++ b/src/OpenFOAM/db/IOstreams/Fstreams/IFstream.C @@ -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(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 { diff --git a/src/OpenFOAM/db/IOstreams/Fstreams/IFstream.H b/src/OpenFOAM/db/IOstreams/Fstreams/IFstream.H index cc5f097221..1361725ec2 100644 --- a/src/OpenFOAM/db/IOstreams/Fstreams/IFstream.H +++ b/src/OpenFOAM/db/IOstreams/Fstreams/IFstream.H @@ -39,53 +39,21 @@ SourceFiles #define IFstream_H #include "ISstream.H" -#include "fileName.H" #include "className.H" -#include -#include +#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 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; diff --git a/src/OpenFOAM/db/IOstreams/Fstreams/OFstream.C b/src/OpenFOAM/db/IOstreams/Fstreams/OFstream.C index b78ca64d7e..dede1ed7a0 100644 --- a/src/OpenFOAM/db/IOstreams/Fstreams/OFstream.C +++ b/src/OpenFOAM/db/IOstreams/Fstreams/OFstream.C @@ -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; } diff --git a/src/OpenFOAM/db/IOstreams/Fstreams/OFstream.H b/src/OpenFOAM/db/IOstreams/Fstreams/OFstream.H index 39c4c22ec7..b1a144b5c6 100644 --- a/src/OpenFOAM/db/IOstreams/Fstreams/OFstream.H +++ b/src/OpenFOAM/db/IOstreams/Fstreams/OFstream.H @@ -39,55 +39,21 @@ SourceFiles #define OFstream_H #include "OSstream.H" -#include "fileName.H" #include "className.H" -#include -#include +#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 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; }; diff --git a/src/OpenFOAM/db/IOstreams/Fstreams/fstreamPointer.H b/src/OpenFOAM/db/IOstreams/Fstreams/fstreamPointer.H new file mode 100644 index 0000000000..8e5c2c3b2c --- /dev/null +++ b/src/OpenFOAM/db/IOstreams/Fstreams/fstreamPointer.H @@ -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 . + +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 operator bool to avoid inheritance ambiguity with + std::ios::operator bool. + +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 operator bool to avoid inheritance ambiguity with + std::ios::operator bool. + +SourceFiles + fstreamPointers.C + +\*---------------------------------------------------------------------------*/ + +#ifndef fstreamPointer_H +#define fstreamPointer_H + +#include "IOstreamOption.H" +#include "fileName.H" +#include +#include + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class ifstreamPointer Declaration +\*---------------------------------------------------------------------------*/ + +class ifstreamPointer +{ + // Private Data + + //- The stream pointer (ifstream or igzstream) + std::unique_ptr 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 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 + +// ************************************************************************* // diff --git a/src/OpenFOAM/db/IOstreams/Fstreams/fstreamPointers.C b/src/OpenFOAM/db/IOstreams/Fstreams/fstreamPointers.C new file mode 100644 index 0000000000..be4316e012 --- /dev/null +++ b/src/OpenFOAM/db/IOstreams/Fstreams/fstreamPointers.C @@ -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 . + +\*---------------------------------------------------------------------------*/ + +#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(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(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(ptr_.get())) + { + return IOstreamOption::compressionType::COMPRESSED; + } + #endif /* HAVE_LIBZ */ + + return IOstreamOption::compressionType::UNCOMPRESSED; +} + + +// ************************************************************************* // diff --git a/src/OpenFOAM/db/IOstreams/IOstreams/Istream.C b/src/OpenFOAM/db/IOstreams/IOstreams/Istream.C index 997731813a..a2d1b60dbd 100644 --- a/src/OpenFOAM/db/IOstreams/IOstreams/Istream.C +++ b/src/OpenFOAM/db/IOstreams/IOstreams/Istream.C @@ -190,7 +190,7 @@ Foam::Istream& Foam::Istream::operator()() const { if (!good()) { - check("Istream::operator()"); + check(FUNCTION_NAME); FatalIOError.exit(); } diff --git a/src/OpenFOAM/db/IOstreams/gzstream/gzstream.C b/src/OpenFOAM/db/IOstreams/gzstream/gzstream.C index e886181811..634e724008 100644 --- a/src/OpenFOAM/db/IOstreams/gzstream/gzstream.C +++ b/src/OpenFOAM/db/IOstreams/gzstream/gzstream.C @@ -25,10 +25,21 @@ // Standard streambuf implementation following Nicolai Josuttis, // "The Standard C++ Library". // ============================================================================ +// +// Modifications: +// 2020-08-07 OpenCFD Ltd. +// - added HAVE_LIBZ conditional +// - instead of +// - nullptr for return values +// ============================================================================ +// HAVE_LIBZ defined externally +// #define HAVE_LIBZ + +#ifdef HAVE_LIBZ #include "gzstream.h" #include -#include // for memcpy +#include // 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 // diff --git a/src/OpenFOAM/db/IOstreams/gzstream/gzstream.h b/src/OpenFOAM/db/IOstreams/gzstream/gzstream.h index 179fd05cc5..259517a05b 100644 --- a/src/OpenFOAM/db/IOstreams/gzstream/gzstream.h +++ b/src/OpenFOAM/db/IOstreams/gzstream/gzstream.h @@ -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 diff --git a/src/OpenFOAM/db/Time/TimeIO.C b/src/OpenFOAM/db/Time/TimeIO.C index 6a70757081..1b9232392c 100644 --- a/src/OpenFOAM/db/Time/TimeIO.C +++ b/src/OpenFOAM/db/Time/TimeIO.C @@ -34,6 +34,7 @@ License #include "profiling.H" #include "IOdictionary.H" #include "fileOperation.H" +#include "fstreamPointer.H" #include @@ -394,18 +395,26 @@ void Foam::Time::readDict() controlDict_.get("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 ); } diff --git a/src/fileFormats/stl/STLCore.C b/src/fileFormats/stl/STLCore.C index de43611e32..08109a5dad 100644 --- a/src/fileFormats/stl/STLCore.C +++ b/src/fileFormats/stl/STLCore.C @@ -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 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 streamPtr - { - new std::ifstream(filename, std::ios::binary) - }; + std::unique_ptr 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; } diff --git a/wmake/scripts/have_libz b/wmake/scripts/have_libz new file mode 100644 index 0000000000..17ad17ac92 --- /dev/null +++ b/wmake/scripts/have_libz @@ -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 + +#------------------------------------------------------------------------------