Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: DXF Translator
4 : * Purpose: Implements low level DXF reading with caching and parsing of
5 : * of the code/value pairs.
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 : /************************************************************************/
36 : /* OGRDXFReader() */
37 : /************************************************************************/
38 :
39 278 : OGRDXFReader::OGRDXFReader()
40 : : fp(nullptr), iSrcBufferOffset(0), nSrcBufferBytes(0),
41 278 : iSrcBufferFileOffset(0), achSrcBuffer{}, nLastValueSize(0), nLineNumber(0)
42 : {
43 278 : }
44 :
45 : /************************************************************************/
46 : /* ~OGRDXFReader() */
47 : /************************************************************************/
48 :
49 278 : OGRDXFReader::~OGRDXFReader()
50 :
51 : {
52 278 : }
53 :
54 : /************************************************************************/
55 : /* Initialize() */
56 : /************************************************************************/
57 :
58 278 : void OGRDXFReader::Initialize(VSILFILE *fpIn)
59 :
60 : {
61 278 : fp = fpIn;
62 278 : }
63 :
64 : /************************************************************************/
65 : /* ResetReadPointer() */
66 : /************************************************************************/
67 :
68 194 : void OGRDXFReader::ResetReadPointer(unsigned int iNewOffset,
69 : int nNewLineNumber /* = 0 */)
70 :
71 : {
72 194 : nSrcBufferBytes = 0;
73 194 : iSrcBufferOffset = 0;
74 194 : iSrcBufferFileOffset = iNewOffset;
75 194 : nLastValueSize = 0;
76 194 : nLineNumber = nNewLineNumber;
77 :
78 194 : VSIFSeekL(fp, iNewOffset, SEEK_SET);
79 194 : }
80 :
81 : /************************************************************************/
82 : /* LoadDiskChunk() */
83 : /* */
84 : /* Load another block (512 bytes) of input from the source */
85 : /* file. */
86 : /************************************************************************/
87 :
88 16443 : void OGRDXFReader::LoadDiskChunk()
89 :
90 : {
91 16443 : if (nSrcBufferBytes - iSrcBufferOffset > 511)
92 0 : return;
93 :
94 16443 : if (iSrcBufferOffset > 0)
95 : {
96 15919 : CPLAssert(nSrcBufferBytes <= 1024);
97 15919 : CPLAssert(iSrcBufferOffset <= nSrcBufferBytes);
98 :
99 15919 : memmove(achSrcBuffer, achSrcBuffer + iSrcBufferOffset,
100 15919 : nSrcBufferBytes - iSrcBufferOffset);
101 15919 : iSrcBufferFileOffset += iSrcBufferOffset;
102 15919 : nSrcBufferBytes -= iSrcBufferOffset;
103 15919 : iSrcBufferOffset = 0;
104 : }
105 :
106 16443 : nSrcBufferBytes +=
107 16443 : static_cast<int>(VSIFReadL(achSrcBuffer + nSrcBufferBytes, 1, 512, fp));
108 16443 : achSrcBuffer[nSrcBufferBytes] = '\0';
109 :
110 16443 : CPLAssert(nSrcBufferBytes <= 1024);
111 16443 : CPLAssert(iSrcBufferOffset <= nSrcBufferBytes);
112 : }
113 :
114 : /************************************************************************/
115 : /* ReadValue() */
116 : /* */
117 : /* Read one type code and value line pair from the DXF file. */
118 : /************************************************************************/
119 :
120 153559 : int OGRDXFReader::ReadValueRaw(char *pszValueBuf, int nValueBufSize)
121 :
122 : {
123 : /* -------------------------------------------------------------------- */
124 : /* Make sure we have lots of data in our buffer for one value. */
125 : /* -------------------------------------------------------------------- */
126 153559 : if (nSrcBufferBytes - iSrcBufferOffset < 512)
127 16440 : LoadDiskChunk();
128 :
129 : /* -------------------------------------------------------------------- */
130 : /* Capture the value code, and skip past it. */
131 : /* -------------------------------------------------------------------- */
132 153559 : unsigned int iStartSrcBufferOffset = iSrcBufferOffset;
133 153559 : int nValueCode = atoi(achSrcBuffer + iSrcBufferOffset);
134 :
135 153559 : nLineNumber++;
136 :
137 : // proceed to newline.
138 1540940 : while (achSrcBuffer[iSrcBufferOffset] != '\n' &&
139 614017 : achSrcBuffer[iSrcBufferOffset] != '\r' &&
140 460640 : achSrcBuffer[iSrcBufferOffset] != '\0')
141 460458 : iSrcBufferOffset++;
142 :
143 153559 : if (achSrcBuffer[iSrcBufferOffset] == '\0')
144 182 : return -1;
145 :
146 : // skip past newline. CR, CRLF, or LFCR
147 153377 : if ((achSrcBuffer[iSrcBufferOffset] == '\r' &&
148 5820 : achSrcBuffer[iSrcBufferOffset + 1] == '\n') ||
149 147573 : (achSrcBuffer[iSrcBufferOffset] == '\n' &&
150 147557 : achSrcBuffer[iSrcBufferOffset + 1] == '\r'))
151 5805 : iSrcBufferOffset += 2;
152 : else
153 147572 : iSrcBufferOffset += 1;
154 :
155 153377 : if (achSrcBuffer[iSrcBufferOffset] == '\0')
156 0 : return -1;
157 :
158 : /* -------------------------------------------------------------------- */
159 : /* Capture the value string. */
160 : /* -------------------------------------------------------------------- */
161 153377 : unsigned int iEOL = iSrcBufferOffset;
162 306754 : CPLString osValue;
163 :
164 153377 : nLineNumber++;
165 :
166 : // proceed to newline.
167 1181890 : while (achSrcBuffer[iEOL] != '\n' && achSrcBuffer[iEOL] != '\r' &&
168 1028510 : achSrcBuffer[iEOL] != '\0')
169 1028510 : iEOL++;
170 :
171 153377 : bool bLongLine = false;
172 153379 : while (achSrcBuffer[iEOL] == '\0' ||
173 153376 : (achSrcBuffer[iEOL] == '\r' && achSrcBuffer[iEOL + 1] == '\0'))
174 : {
175 : // The line is longer than the buffer (or the line ending is split at
176 : // end of buffer). Let's copy what we have so far into our string, and
177 : // read more
178 3 : const auto nValueLength = osValue.length();
179 :
180 3 : if (nValueLength + iEOL - iSrcBufferOffset > 1048576)
181 : {
182 0 : CPLError(CE_Failure, CPLE_AppDefined, "Line %d is too long",
183 : nLineNumber);
184 0 : return -1;
185 : }
186 :
187 3 : osValue.resize(nValueLength + iEOL - iSrcBufferOffset, '\0');
188 3 : std::copy(achSrcBuffer + iSrcBufferOffset, achSrcBuffer + iEOL,
189 3 : osValue.begin() + nValueLength);
190 :
191 3 : iSrcBufferOffset = iEOL;
192 3 : LoadDiskChunk();
193 3 : iEOL = iSrcBufferOffset;
194 3 : bLongLine = true;
195 :
196 : // Have we prematurely reached the end of the file?
197 3 : if (achSrcBuffer[iEOL] == '\0')
198 1 : return -1;
199 :
200 : // Proceed to newline again
201 437 : while (achSrcBuffer[iEOL] != '\n' && achSrcBuffer[iEOL] != '\r' &&
202 435 : achSrcBuffer[iEOL] != '\0')
203 435 : iEOL++;
204 : }
205 :
206 153376 : size_t nValueBufLen = 0;
207 :
208 : // If this was an extremely long line, copy from osValue into the buffer
209 153376 : if (!osValue.empty())
210 : {
211 2 : strncpy(pszValueBuf, osValue.c_str(), nValueBufSize - 1);
212 2 : pszValueBuf[nValueBufSize - 1] = '\0';
213 :
214 2 : nValueBufLen = strlen(pszValueBuf);
215 :
216 2 : if (static_cast<int>(osValue.length()) > nValueBufSize - 1)
217 : {
218 2 : CPLDebug("DXF", "Long line truncated to %d characters.\n%s...",
219 : nValueBufSize - 1, pszValueBuf);
220 : }
221 : }
222 :
223 : // Copy the last (normally, the only) section of this line into the buffer
224 153376 : if (static_cast<int>(iEOL - iSrcBufferOffset) >
225 153376 : nValueBufSize - static_cast<int>(nValueBufLen) - 1)
226 : {
227 2 : strncpy(pszValueBuf + nValueBufLen, achSrcBuffer + iSrcBufferOffset,
228 2 : nValueBufSize - static_cast<int>(nValueBufLen) - 1);
229 2 : pszValueBuf[nValueBufSize - 1] = '\0';
230 :
231 2 : CPLDebug("DXF", "Long line truncated to %d characters.\n%s...",
232 : nValueBufSize - 1, pszValueBuf);
233 : }
234 : else
235 : {
236 153374 : strncpy(pszValueBuf + nValueBufLen, achSrcBuffer + iSrcBufferOffset,
237 153374 : iEOL - iSrcBufferOffset);
238 153374 : pszValueBuf[nValueBufLen + iEOL - iSrcBufferOffset] = '\0';
239 : }
240 :
241 153376 : iSrcBufferOffset = iEOL;
242 :
243 : // skip past newline. CR, CRLF, or LFCR
244 153376 : if ((achSrcBuffer[iSrcBufferOffset] == '\r' &&
245 5816 : achSrcBuffer[iSrcBufferOffset + 1] == '\n') ||
246 147572 : (achSrcBuffer[iSrcBufferOffset] == '\n' &&
247 147560 : achSrcBuffer[iSrcBufferOffset + 1] == '\r'))
248 5804 : iSrcBufferOffset += 2;
249 : else
250 147572 : iSrcBufferOffset += 1;
251 :
252 : /* -------------------------------------------------------------------- */
253 : /* Record how big this value was, so it can be unread safely. */
254 : /* -------------------------------------------------------------------- */
255 153376 : if (bLongLine)
256 2 : nLastValueSize = 0;
257 : else
258 : {
259 153374 : nLastValueSize = iSrcBufferOffset - iStartSrcBufferOffset;
260 153374 : CPLAssert(nLastValueSize > 0);
261 : }
262 :
263 153376 : return nValueCode;
264 : }
265 :
266 153559 : int OGRDXFReader::ReadValue(char *pszValueBuf, int nValueBufSize)
267 : {
268 : int nValueCode;
269 : while (true)
270 : {
271 153559 : nValueCode = ReadValueRaw(pszValueBuf, nValueBufSize);
272 153559 : if (nValueCode == 999)
273 : {
274 : // Skip comments
275 13 : continue;
276 : }
277 153546 : break;
278 : }
279 153546 : return nValueCode;
280 : }
281 :
282 : /************************************************************************/
283 : /* UnreadValue() */
284 : /* */
285 : /* Unread the last value read, accomplished by resetting the */
286 : /* read pointer. */
287 : /************************************************************************/
288 :
289 1935 : void OGRDXFReader::UnreadValue()
290 :
291 : {
292 1935 : if (nLastValueSize == 0)
293 : {
294 1 : CPLError(CE_Failure, CPLE_AppDefined,
295 : "Cannot UnreadValue(), likely due to a previous long line");
296 1 : return;
297 : }
298 1934 : CPLAssert(iSrcBufferOffset >= nLastValueSize);
299 1934 : CPLAssert(nLastValueSize > 0);
300 :
301 1934 : iSrcBufferOffset -= nLastValueSize;
302 1934 : nLineNumber -= 2;
303 1934 : nLastValueSize = 0;
304 : }
|