STLCore.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ========= |
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4 \\ / O peration |
5 \\ / A nd | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2011-2016 OpenFOAM Foundation
9 Copyright (C) 2016-2020 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
12 This file is part of OpenFOAM.
13
14 OpenFOAM is free software: you can redistribute it and/or modify it
15 under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26
27\*---------------------------------------------------------------------------*/
28
29#include "STLCore.H"
30#include "OSspecific.H"
31#include "IFstream.H"
32
33// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34
35// The number of bytes in the STL binary header
36static constexpr const unsigned STLHeaderSize = 80;
37
38
39// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
40
41// Check if "SOLID" or "solid" appears as the first non-space content.
42// Assume that any leading space is less than 75 chars or so, otherwise
43// it is really bad input.
44static bool startsWithSolid(const char header[STLHeaderSize])
45{
46 unsigned pos = 0;
47 while (std::isspace(header[pos]) && pos < STLHeaderSize)
48 {
49 ++pos;
50 }
51
52 return
53 (
54 pos < (STLHeaderSize-5) // At least 5 chars remaining
55 && std::toupper(header[pos+0]) == 'S'
56 && std::toupper(header[pos+1]) == 'O'
57 && std::toupper(header[pos+2]) == 'L'
58 && std::toupper(header[pos+3]) == 'I'
59 && std::toupper(header[pos+4]) == 'D'
60 );
61}
62
63
64// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
65
67(
68 const fileName& filename,
69 const STLFormat format
70)
71{
72 return
73 (
75 ? filename.hasExt("stlb")
77 );
78}
79
80
81// Check binary by getting the header and number of facets
82// this seems to work better than the old token-based method
83// - using wordToken can cause an abort if non-word (binary) content
84// is detected ... this is not exactly what we want.
85// - some programs (eg, PROSTAR) have 'solid' as the first word in
86// the binary header. This is just wrong and not our fault.
88(
89 const fileName& filename
90)
91{
92 // Handle compressed (.gz) or uncompressed input files
93
94 ifstreamPointer isPtr(filename);
95 const bool unCompressed(IOstream::UNCOMPRESSED == isPtr.whichCompression());
96 auto& is = *isPtr;
97
98 if (!is.good())
99 {
101 << "Cannot read file " << filename
102 << " or file " << filename + ".gz"
103 << exit(FatalError);
104 }
105
106 // Read the STL header
107 char header[STLHeaderSize];
108 is.read(header, STLHeaderSize);
109
110 // If the stream is bad, it can't be a binary STL
111 if (!is.good() || startsWithSolid(header))
112 {
113 return 0;
114 }
115
116
117 // Read the number of triangles in the STL file
118 // (note: read as signed so we can check whether >2^31)
119 int32_t nTris;
120 is.read(reinterpret_cast<char*>(&nTris), sizeof(int32_t));
121
122 // Check that stream is OK and number of triangles is positive,
123 // if not this may be an ASCII file
124
125 bool bad = (!is || nTris < 0);
126
127 if (!bad && unCompressed)
128 {
129 // Compare file size with that expected from number of tris
130 // If this is not sensible, it may be an ASCII file
131
132 const off_t dataFileSize = Foam::fileSize(filename);
133
134 bad =
135 (
136 nTris < int(dataFileSize - STLHeaderSize)/50
137 || nTris > int(dataFileSize - STLHeaderSize)/25
138 );
139 }
140
141 // Return number of triangles if it appears to be BINARY and good.
142 return (bad ? 0 : nTris);
143}
144
145
146std::unique_ptr<std::istream>
148(
149 const fileName& filename,
150 label& nTrisEstimated
151)
152{
153 nTrisEstimated = 0;
154
155 std::unique_ptr<std::istream> streamPtr;
156 bool unCompressed(true);
157
158 // Handle compressed (.gz) or uncompressed input files
159 {
160 ifstreamPointer isPtr(filename);
161 unCompressed = (IOstream::UNCOMPRESSED == isPtr.whichCompression());
162
163 // Take ownership
164 streamPtr.reset(isPtr.release());
165 }
166 auto& is = *streamPtr;
167
168 if (!is.good())
169 {
171 << "Cannot read file " << filename
172 << " or file " << filename + ".gz"
173 << exit(FatalError);
174 }
175
176
177 // Read the STL header
178 char header[STLHeaderSize];
179 is.read(header, STLHeaderSize);
180
181 // Check that stream is OK, if not this may be an ASCII file
182 if (!is.good()) // could check again: startsWithSolid(header)
183 {
185 << "problem reading header, perhaps file is not binary "
186 << exit(FatalError);
187 }
188
189 // Read the number of triangles in the STl file
190 // (note: read as int so we can check whether >2^31)
191 int32_t nTris;
192 is.read(reinterpret_cast<char*>(&nTris), sizeof(int32_t));
193
194 // Check that stream is OK and number of triangles is positive,
195 // if not this maybe an ASCII file
196
197 bool bad = (!is || nTris < 0);
198
199 if (!bad && unCompressed)
200 {
201 // Compare file size with that expected from number of tris
202 // If this is not sensible, it may be an ASCII file
203
204 const off_t dataFileSize = Foam::fileSize(filename);
205
206 bad =
207 (
208 nTris < int(dataFileSize - STLHeaderSize)/50
209 || nTris > int(dataFileSize - STLHeaderSize)/25
210 );
211 }
212
213 if (bad)
214 {
216 << "problem reading number of triangles, perhaps file is not binary"
217 << exit(FatalError);
218 }
219
220 nTrisEstimated = nTris;
221
222 return streamPtr;
223}
224
225
227(
228 ostream& os,
229 uint32_t nTris
230)
231{
232 // STL header with extra information about nTris
233 char header[STLHeaderSize];
234 sprintf(header, "STL binary file %u facets", nTris);
235
236 // avoid trailing junk
237 for (size_t i = strlen(header); i < STLHeaderSize; ++i)
238 {
239 header[i] = 0;
240 }
241
242 os.write(header, STLHeaderSize);
243 os.write(reinterpret_cast<char*>(&nTris), sizeof(uint32_t));
244}
245
246
247// ************************************************************************* //
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
static bool startsWithSolid(const char header[STLHeaderSize])
Definition: STLCore.C:44
static constexpr const unsigned STLHeaderSize
Definition: STLCore.C:36
@ UNCOMPRESSED
compression = false
Ostream & writeBinaryHeader()
Write "C Binary" string for binary files (eg, geometry/measured)
Definition: ensightFile.C:339
Istream & readBinaryHeader()
Read "C Binary" for binary files (eg, geometry/measured)
static bool isBinaryName(const fileName &filename, const STLFormat format)
Detect 'stlb' extension as binary when format = UNKNOWN.
Definition: STLCore.C:67
static int detectBinaryHeader(const fileName &filename)
Check contents to detect if the file is a binary STL.
Definition: STLCore.C:88
STLFormat
Enumeration for the format of data in the stream.
Definition: STLCore.H:62
@ UNKNOWN
Detect based on (input) content or (output) extension.
Definition: STLCore.H:65
A class for handling file names.
Definition: fileName.H:76
bool hasExt() const
Various checks for extensions.
Definition: stringI.H:56
A wrapped std::ifstream with possible compression handling (igzstream) that behaves much like a std::...
IOstreamOption::compressionType whichCompression() const
Which compression type?
std::istream * release() noexcept
Return managed pointer and release ownership.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
OBJstream os(runTime.globalPath()/outputName)
off_t fileSize(const fileName &name, const bool followLink=true)
Return size of file or -1 on failure (normally follows symbolic links).
Definition: MSwindows.C:684
error FatalError
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
word format(conversionProperties.get< word >("format"))