Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: DXF Translator
4 : * Purpose: Implements BlockMap reading and management portion of
5 : * OGRDXFDataSource class
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2009, Frank Warmerdam <warmerdam@pobox.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "ogr_dxf.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 : #include "cpl_csv.h"
34 :
35 : #include <algorithm>
36 :
37 : /************************************************************************/
38 : /* ReadBlockSection() */
39 : /************************************************************************/
40 :
41 124 : bool OGRDXFDataSource::ReadBlocksSection()
42 :
43 : {
44 : // Force inlining of blocks to false, for when OGRDXFLayer processes
45 : // INSERT entities
46 124 : const bool bOldInlineBlocks = bInlineBlocks;
47 124 : bInlineBlocks = false;
48 :
49 : OGRDXFLayer *poReaderLayer =
50 124 : static_cast<OGRDXFLayer *>(GetLayerByName("Entities"));
51 :
52 124 : iEntitiesOffset = oReader.iSrcBufferFileOffset + oReader.iSrcBufferOffset;
53 124 : iEntitiesLineNumber = oReader.nLineNumber;
54 :
55 : char szLineBuf[257];
56 124 : int nCode = 0;
57 4271 : while ((nCode = ReadValue(szLineBuf, sizeof(szLineBuf))) > -1 &&
58 2135 : !EQUAL(szLineBuf, "ENDSEC"))
59 : {
60 : // We are only interested in extracting blocks.
61 2012 : if (nCode != 0 || !EQUAL(szLineBuf, "BLOCK"))
62 1939 : continue;
63 :
64 : // Process contents of BLOCK definition till we find the
65 : // first entity.
66 333 : CPLString osBlockName;
67 333 : CPLString osBlockRecordHandle;
68 333 : OGRDXFInsertTransformer oBasePointTransformer;
69 :
70 4220 : while ((nCode = ReadValue(szLineBuf, sizeof(szLineBuf))) > 0)
71 : {
72 3887 : switch (nCode)
73 : {
74 332 : case 2:
75 332 : osBlockName = szLineBuf;
76 332 : break;
77 :
78 238 : case 330:
79 : // get the block record handle as well, for arrowheads
80 238 : osBlockRecordHandle = szLineBuf;
81 238 : break;
82 :
83 330 : case 10:
84 330 : oBasePointTransformer.dfXOffset = -CPLAtof(szLineBuf);
85 330 : break;
86 :
87 330 : case 20:
88 330 : oBasePointTransformer.dfYOffset = -CPLAtof(szLineBuf);
89 330 : break;
90 :
91 330 : case 30:
92 330 : oBasePointTransformer.dfZOffset = -CPLAtof(szLineBuf);
93 330 : break;
94 : }
95 : }
96 333 : if (nCode < 0)
97 : {
98 0 : bInlineBlocks = bOldInlineBlocks;
99 0 : DXF_READER_ERROR();
100 0 : return false;
101 : }
102 :
103 : // store the block record handle mapping even if the block is empty
104 333 : oBlockRecordHandles[osBlockRecordHandle] = osBlockName;
105 :
106 333 : if (EQUAL(szLineBuf, "ENDBLK"))
107 260 : continue;
108 :
109 73 : UnreadValue();
110 :
111 73 : if (oBlockMap.find(osBlockName) != oBlockMap.end())
112 : {
113 0 : bInlineBlocks = bOldInlineBlocks;
114 0 : DXF_READER_ERROR();
115 0 : return false;
116 : }
117 :
118 : // Now we will process entities till we run out at the ENDBLK code.
119 :
120 73 : PushBlockInsertion(osBlockName);
121 :
122 73 : OGRDXFFeature *poFeature = nullptr;
123 73 : int nIters = 0;
124 : const int nMaxIters =
125 73 : atoi(CPLGetConfigOption("DXF_FEATURE_LIMIT_PER_BLOCK", "10000"));
126 1075 : while ((poFeature = poReaderLayer->GetNextUnfilteredFeature()) !=
127 : nullptr)
128 : {
129 1002 : if (nMaxIters >= 0 && nIters == nMaxIters)
130 : {
131 0 : delete poFeature;
132 0 : CPLError(CE_Warning, CPLE_AppDefined,
133 : "Limit of %d features for block %s reached. "
134 : "If you need more, set the "
135 : "DXF_FEATURE_LIMIT_PER_BLOCK configuration "
136 : "option to the maximum value (or -1 for no limit)",
137 : nMaxIters, osBlockName.c_str());
138 0 : break;
139 : }
140 :
141 : // Apply the base point translation
142 1002 : OGRGeometry *poFeatureGeom = poFeature->GetGeometryRef();
143 1002 : if (poFeatureGeom)
144 1001 : poFeatureGeom->transform(&oBasePointTransformer);
145 :
146 : // Also apply the base point translation to the original
147 : // coordinates of block references
148 1002 : if (poFeature->IsBlockReference())
149 : {
150 791 : DXFTriple oTriple = poFeature->GetInsertOCSCoords();
151 791 : OGRPoint oPoint(oTriple.dfX, oTriple.dfY, oTriple.dfZ);
152 791 : oPoint.transform(&oBasePointTransformer);
153 791 : poFeature->SetInsertOCSCoords(
154 1582 : DXFTriple(oPoint.getX(), oPoint.getY(), oPoint.getZ()));
155 : }
156 :
157 1002 : oBlockMap[osBlockName].apoFeatures.push_back(poFeature);
158 1002 : nIters++;
159 : }
160 :
161 73 : PopBlockInsertion();
162 : }
163 124 : if (nCode < 0)
164 : {
165 1 : bInlineBlocks = bOldInlineBlocks;
166 1 : DXF_READER_ERROR();
167 1 : return false;
168 : }
169 :
170 123 : CPLDebug("DXF", "Read %d blocks with meaningful geometry.",
171 123 : (int)oBlockMap.size());
172 :
173 : // Restore old inline blocks setting
174 123 : bInlineBlocks = bOldInlineBlocks;
175 :
176 123 : return true;
177 : }
178 :
179 : /************************************************************************/
180 : /* LookupBlock() */
181 : /* */
182 : /* Find the geometry collection corresponding to a name if it */
183 : /* exists. Note that the returned geometry pointer is to a */
184 : /* geometry that continues to be owned by the datasource. It */
185 : /* should be cloned for use. */
186 : /************************************************************************/
187 :
188 342 : DXFBlockDefinition *OGRDXFDataSource::LookupBlock(const char *pszName)
189 :
190 : {
191 684 : CPLString l_osName = pszName;
192 :
193 342 : if (oBlockMap.count(l_osName) == 0)
194 134 : return nullptr;
195 : else
196 208 : return &(oBlockMap[l_osName]);
197 : }
198 :
199 : /************************************************************************/
200 : /* GetBlockNameByRecordHandle() */
201 : /* */
202 : /* Find the name of the block with the given BLOCK_RECORD handle. */
203 : /* If there is no such block, an empty string is returned. */
204 : /************************************************************************/
205 :
206 18 : CPLString OGRDXFDataSource::GetBlockNameByRecordHandle(const char *pszID)
207 :
208 : {
209 36 : CPLString l_osID = pszID;
210 :
211 18 : if (oBlockRecordHandles.count(l_osID) == 0)
212 2 : return "";
213 : else
214 16 : return oBlockRecordHandles[l_osID];
215 : }
216 :
217 : /************************************************************************/
218 : /* PushBlockInsertion() */
219 : /* */
220 : /* Add a block name to the stack of blocks being inserted. */
221 : /* Returns false if we are already inserting this block. */
222 : /************************************************************************/
223 :
224 1285 : bool OGRDXFDataSource::PushBlockInsertion(const CPLString &osBlockName)
225 :
226 : {
227 : // Make sure we are not recursing too deeply (avoid stack overflows) or
228 : // inserting a block within itself (avoid billion-laughs type issues).
229 : // 128 is a totally arbitrary limit
230 2570 : if (aosBlockInsertionStack.size() > 128 ||
231 0 : std::find(aosBlockInsertionStack.begin(), aosBlockInsertionStack.end(),
232 2570 : osBlockName) != aosBlockInsertionStack.end())
233 : {
234 1003 : CPLError(CE_Warning, CPLE_AppDefined,
235 : "Dangerous block recursion detected. "
236 : "Some blocks have not been inserted.");
237 1003 : return false;
238 : }
239 :
240 282 : aosBlockInsertionStack.push_back(osBlockName);
241 282 : return true;
242 : }
243 :
244 : /************************************************************************/
245 : /* ~DXFBlockDefinition() */
246 : /* */
247 : /* Safe cleanup of a block definition. */
248 : /************************************************************************/
249 :
250 73 : DXFBlockDefinition::~DXFBlockDefinition()
251 : {
252 1075 : while (!apoFeatures.empty())
253 : {
254 1002 : delete apoFeatures.back();
255 1002 : apoFeatures.pop_back();
256 : }
257 73 : }
|