Files
openfoam/src/fileFormats/obj/OBJstream.C
Mark Olesen 44a243a94d ENH: improve stream handling of expansions (#2095)
* removed internal upper limit on word/string length for parsed input.

  - Although it has not caused many problems, no reason to retain
    these limits.
  - simplify some of the internal logic for reading string-like items.
  - localize parsers for better separation from the header

  - expose new function seekCommentEnd_Cstyle(), as useful
    handler of C-style comments

* exclude imbalanced closing ')' from word/variable

  - previously included this into the word/variable, but makes more
    sense to leave on the parser for the following token.

    Prevents content like 'vector (10 20 $zmax);' from being parsed
    as '$zmax)' instead of as '$zmax' followed by a ')'.
    No conceivable reason that the former would actually be desirable,
    but can still be obtained with brace notation: Eg, '${zmax)}'

* consistent handling of ${{ ... }} expressions

  - within a dictionary content, the following construct was
    incorrectly processed:

        value ${{2*sqrt(0.5)}};

    Complains about no dictionary/env variable "{2*sqrt(0.5)}"

    Now trap expressions directly and assign their own token type
    while reading. Later expansion can then be properly passed to
    the exprDriver (evalEntry) instead of incorrectly trying
    variable expansion.

    Does not alter the use of expressions embedded within other
    expansions. Eg, "file${{10*2}}"

* improve #eval { ... } brace slurping

  - the initial implementation of this was rudimentary and simply
    grabbed everything until the next '}'.  Now continue to grab
    content until braces are properly balanced

    Eg, the content:   value #eval{${radius}*2};

    would have previously terminated prematurely with "${radius" for
    the expression!

NOTE:
    both the ${{ expr }} parsed input and the #eval { ... } input
    discard C/C++ comments during reading to reduce intermediate
    overhead for content that will be discarded before evaluation
    anyhow.

* tighten recognition of verbatim strings and expressions.

  - parser was previously sloppy and would have accepted content such
    as "# { ..." (for example) as an verbatim string introducer.
    Now only accept parse if there are no intermediate characters
    discarded.
2021-05-18 15:41:26 +02:00

430 lines
9.1 KiB
C

/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2012-2016 OpenFOAM Foundation
Copyright (C) 2020-2021 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 "OBJstream.H"
#include "primitivePatch.H"
#include "treeBoundBox.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(OBJstream, 0);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::OBJstream::writeAndCheck(const char c)
{
if (c == '\n')
{
startOfLine_ = true;
}
else if (startOfLine_)
{
startOfLine_ = false;
if (c == 'v')
{
++nVertices_;
}
}
OFstream::write(c);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::OBJstream::OBJstream
(
const fileName& pathname,
IOstreamOption streamOpt
)
:
OFstream(pathname, streamOpt),
startOfLine_(true),
nVertices_(0)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::Ostream& Foam::OBJstream::write(const char c)
{
writeAndCheck(c);
return *this;
}
Foam::Ostream& Foam::OBJstream::write(const char* str)
{
for (const char* iter = str; *iter; ++iter)
{
writeAndCheck(*iter);
}
return *this;
}
Foam::Ostream& Foam::OBJstream::write(const word& str)
{
return writeQuoted(str, false);
}
Foam::Ostream& Foam::OBJstream::write(const string& str)
{
return writeQuoted(str, true);
}
Foam::Ostream& Foam::OBJstream::writeQuoted
(
const std::string& str,
const bool quoted
)
{
if (!quoted)
{
// Output unquoted, only advance line number on newline
for (auto iter = str.cbegin(); iter != str.cend(); ++iter)
{
writeAndCheck(*iter);
}
return *this;
}
// Output with surrounding quotes and backslash escaping
OFstream::write(static_cast<char>(token::DQUOTE));
unsigned backslash = 0;
for (auto iter = str.cbegin(); iter != str.cend(); ++iter)
{
const char c = *iter;
if (c == '\\')
{
++backslash;
continue; // only output after escaped character is known
}
else if (c == token::NL)
{
++lineNumber_;
++backslash; // backslash escape for newline
}
else if (c == token::DQUOTE)
{
++backslash; // backslash escape for quote
}
// output all pending backslashes
while (backslash)
{
OFstream::write('\\');
--backslash;
}
writeAndCheck(c);
}
// silently drop any trailing backslashes
// they would otherwise appear like an escaped end-quote
OFstream::write(static_cast<char>(token::DQUOTE));
return *this;
}
Foam::Ostream& Foam::OBJstream::write(const point& pt)
{
write("v ") << pt.x() << ' ' << pt.y() << ' ' << pt.z() << nl;
return *this;
}
Foam::Ostream& Foam::OBJstream::write(const point& pt, const vector& n)
{
write(pt);
OFstream::write("vn ") << n.x() << ' ' << n.y() << ' ' << n.z() << nl;
return *this;
}
Foam::Ostream& Foam::OBJstream::write(const edge& e, const UList<point>& points)
{
write(points[e[0]]);
write(points[e[1]]);
write("l ") << nVertices_-1 << ' ' << nVertices_ << nl;
return *this;
}
Foam::Ostream& Foam::OBJstream::write(const linePointRef& ln)
{
write(ln.start());
write(ln.end());
write("l ") << nVertices_-1 << ' ' << nVertices_ << nl;
return *this;
}
Foam::Ostream& Foam::OBJstream::write
(
const linePointRef& ln,
const vector& n0,
const vector& n1
)
{
write(ln.start(), n0);
write(ln.end(), n1);
write("l ") << nVertices_-1 << ' ' << nVertices_ << nl;
return *this;
}
Foam::Ostream& Foam::OBJstream::write
(
const triPointRef& f,
const bool lines
)
{
const label start = nVertices_+1; // 1-offset for obj included here
write(f.a());
write(f.b());
write(f.c());
if (lines)
{
write('l');
for (int i = 0; i < 3; i++)
{
write(' ') << i+start;
}
write(' ') << start << '\n';
}
else
{
write('f');
for (int i = 0; i < 3; i++)
{
write(' ') << i+start;
}
write('\n');
}
return *this;
}
Foam::Ostream& Foam::OBJstream::write
(
const face& f,
const UList<point>& points,
const bool lines
)
{
const label start = nVertices_+1; // 1-offset for obj included here
forAll(f, i)
{
write(points[f[i]]);
}
if (lines)
{
write('l');
forAll(f, i)
{
write(' ') << i+start;
}
write(' ') << start << '\n';
}
else
{
write('f');
forAll(f, i)
{
write(' ') << i+start;
}
write('\n');
}
return *this;
}
Foam::Ostream& Foam::OBJstream::write
(
const UList<face>& faces,
const pointField& points,
const bool lines
)
{
SubList<face> allFcs(faces, faces.size());
primitivePatch pp(allFcs, points);
const pointField& localPoints = pp.localPoints();
const faceList& localFaces = pp.localFaces();
const label start = nVertices_+1; // 1-offset for obj included here
forAll(localPoints, i)
{
write(localPoints[i]);
}
if (lines)
{
const edgeList& edges = pp.edges();
forAll(edges, edgeI)
{
const edge& e = edges[edgeI];
write("l ") << e[0]+start << ' ' << e[1]+start << nl;
}
}
else
{
forAll(localFaces, facei)
{
const face& f = localFaces[facei];
write('f');
forAll(f, i)
{
write(' ') << f[i]+start;
}
write('\n');
}
}
return *this;
}
Foam::Ostream& Foam::OBJstream::write
(
const UList<edge>& edges,
const UList<point>& points,
const bool compact
)
{
if (compact)
{
// Code similar to PrimitivePatch::calcMeshData()
// Unsorted version
label objPointId = nVertices_+1; // 1-offset for obj included here
Map<label> markedPoints(2*edges.size());
forAll(edges, edgei)
{
const edge& e = edges[edgei];
if (markedPoints.insert(e[0], objPointId))
{
write(points[e[0]]);
++objPointId;
}
if (markedPoints.insert(e[1], objPointId))
{
write(points[e[1]]);
++objPointId;
}
}
forAll(edges, edgei)
{
const edge& e = edges[edgei];
write("l ")
<< markedPoints[e[0]] << ' '
<< markedPoints[e[1]] << nl;
}
}
else
{
const label start = nVertices_+1; // 1-offset for obj included here
forAll(points, i)
{
write(points[i]);
}
forAll(edges, edgei)
{
const edge& e = edges[edgei];
write("l ")
<< e[0]+start << ' ' << e[1]+start << nl;
}
}
return *this;
}
Foam::Ostream& Foam::OBJstream::write
(
const treeBoundBox& bb,
const bool lines
)
{
const label start = nVertices_+1; // 1-offset for obj included here
pointField points(bb.points());
forAll(points, i)
{
write(points[i]);
}
if (lines)
{
forAll(treeBoundBox::edges, edgei)
{
const edge& e = treeBoundBox::edges[edgei];
write("l ") << e[0]+start << ' ' << e[1]+start << nl;
}
}
else
{
forAll(treeBoundBox::faces, facei)
{
const face& f = treeBoundBox::faces[facei];
write('f');
forAll(f, i)
{
write(' ') << f[i]+start;
}
write('\n');
}
}
return *this;
}
// ************************************************************************* //