Line data Source code
1 : /**********************************************************************
2 : *
3 : * Name: mitab_datfile.cpp
4 : * Project: MapInfo TAB Read/Write library
5 : * Language: C++
6 : * Purpose: Implementation of the MIDDATAFile class used to handle
7 : * reading/writing of the MID/MIF files
8 : * Author: Stephane Villeneuve, stephane.v@videotron.ca
9 : *
10 : **********************************************************************
11 : * Copyright (c) 1999, 2000, Stephane Villeneuve
12 : *
13 : * Permission is hereby granted, free of charge, to any person obtaining a
14 : * copy of this software and associated documentation files (the "Software"),
15 : * to deal in the Software without restriction, including without limitation
16 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 : * and/or sell copies of the Software, and to permit persons to whom the
18 : * Software is furnished to do so, subject to the following conditions:
19 : *
20 : * The above copyright notice and this permission notice shall be included
21 : * in all copies or substantial portions of the Software.
22 : *
23 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 : * DEALINGS IN THE SOFTWARE.
30 : **********************************************************************/
31 :
32 : #include "cpl_port.h"
33 : #include "mitab.h"
34 :
35 : #include <cstdarg>
36 : #include <cstddef>
37 :
38 : #include "cpl_conv.h"
39 : #include "cpl_csv.h"
40 : #include "cpl_error.h"
41 : #include "cpl_string.h"
42 : #include "cpl_vsi.h"
43 : #include "mitab_priv.h"
44 :
45 : /*=====================================================================
46 : * class MIDDATAFile
47 : *
48 : *====================================================================*/
49 :
50 1130 : MIDDATAFile::MIDDATAFile(const char *pszEncoding)
51 : : m_fp(nullptr), m_pszDelimiter("\t"), // Encom 2003 (was NULL).
52 : m_pszFname(nullptr), m_eAccessMode(TABRead), m_dfXMultiplier(1.0),
53 : m_dfYMultiplier(1.0), m_dfXDisplacement(0.0), m_dfYDisplacement(0.0),
54 1130 : m_bEof(FALSE), m_osEncoding(pszEncoding)
55 : {
56 1130 : }
57 :
58 1130 : MIDDATAFile::~MIDDATAFile()
59 : {
60 1130 : Close();
61 1130 : }
62 :
63 2080 : void MIDDATAFile::SaveLine(const char *pszLine)
64 : {
65 2080 : if (pszLine == nullptr)
66 : {
67 0 : m_osSavedLine.clear();
68 : }
69 : else
70 : {
71 2080 : m_osSavedLine = pszLine;
72 : }
73 2080 : }
74 :
75 2061 : const char *MIDDATAFile::GetSavedLine()
76 : {
77 2061 : return m_osSavedLine.c_str();
78 : }
79 :
80 1130 : int MIDDATAFile::Open(const char *pszFname, const char *pszAccess)
81 : {
82 1130 : if (m_fp)
83 : {
84 0 : return -1;
85 : }
86 :
87 : // Validate access mode and make sure we use Text access.
88 1130 : if (STARTS_WITH_CI(pszAccess, "r"))
89 : {
90 962 : m_eAccessMode = TABRead;
91 962 : pszAccess = "rt";
92 : }
93 168 : else if (STARTS_WITH_CI(pszAccess, "w"))
94 : {
95 168 : m_eAccessMode = TABWrite;
96 168 : pszAccess = "wt";
97 : }
98 : else
99 : {
100 0 : return -1;
101 : }
102 :
103 : // Open file for reading.
104 1130 : m_pszFname = CPLStrdup(pszFname);
105 1130 : m_fp = VSIFOpenL(m_pszFname, pszAccess);
106 :
107 1130 : if (m_fp == nullptr)
108 : {
109 4 : CPLFree(m_pszFname);
110 4 : m_pszFname = nullptr;
111 4 : return -1;
112 : }
113 :
114 1126 : SetEof(FALSE);
115 1126 : return 0;
116 : }
117 :
118 971 : int MIDDATAFile::Rewind()
119 : {
120 971 : if (m_fp == nullptr || m_eAccessMode == TABWrite)
121 0 : return -1;
122 :
123 : else
124 : {
125 971 : VSIRewindL(m_fp);
126 971 : SetEof(FALSE);
127 : }
128 971 : return 0;
129 : }
130 :
131 2256 : int MIDDATAFile::Close()
132 : {
133 2256 : if (m_fp == nullptr)
134 1130 : return 0;
135 :
136 : // Close file
137 1126 : VSIFCloseL(m_fp);
138 1126 : m_fp = nullptr;
139 :
140 : // clear readline buffer.
141 1126 : CPLReadLineL(nullptr);
142 :
143 1126 : CPLFree(m_pszFname);
144 1126 : m_pszFname = nullptr;
145 :
146 1126 : return 0;
147 : }
148 :
149 49987 : const char *MIDDATAFile::GetLine()
150 : {
151 49987 : if (m_eAccessMode != TABRead)
152 : {
153 0 : CPLAssert(false);
154 : return nullptr;
155 : }
156 :
157 : static const int nMaxLineLength =
158 49987 : atoi(CPLGetConfigOption("MITAB_MAX_LINE_LENGTH", "1000000"));
159 49987 : const char *pszLine = CPLReadLine2L(m_fp, nMaxLineLength, nullptr);
160 :
161 49987 : if (pszLine == nullptr)
162 : {
163 609 : if (strstr(CPLGetLastErrorMsg(),
164 609 : "Maximum number of characters allowed reached"))
165 : {
166 0 : CPLError(
167 : CE_Failure, CPLE_AppDefined,
168 : "Maximum number of characters allowed reached. "
169 : "You can set the MITAB_MAX_LINE_LENGTH configuration option "
170 : "to the desired number of bytes (or -1 for unlimited)");
171 : }
172 609 : SetEof(TRUE);
173 609 : m_osLastRead.clear();
174 : }
175 : else
176 : {
177 : // Skip leading spaces and tabs except if the delimiter is tab.
178 84009 : while (*pszLine == ' ' || (*m_pszDelimiter != '\t' && *pszLine == '\t'))
179 34631 : pszLine++;
180 :
181 49378 : m_osLastRead = pszLine;
182 : }
183 :
184 : #if DEBUG_VERBOSE
185 : if (pszLine)
186 : CPLDebug("MITAB", "pszLine: %s", pszLine);
187 : #endif
188 :
189 49987 : return pszLine;
190 : }
191 :
192 31992 : const char *MIDDATAFile::GetLastLine()
193 : {
194 : // Return NULL if EOF.
195 31992 : if (GetEof())
196 : {
197 888 : return nullptr;
198 : }
199 31104 : if (m_eAccessMode == TABRead)
200 : {
201 : #if DEBUG_VERBOSE
202 : CPLDebug("MITAB", "m_osLastRead: %s", m_osLastRead.c_str());
203 : #endif
204 31104 : return m_osLastRead.c_str();
205 : }
206 :
207 : // We should never get here. Read/Write mode not implemented.
208 0 : CPLAssert(false);
209 : return nullptr;
210 : }
211 :
212 356 : char **MIDDATAFile::GetTokenizedNextLine()
213 : {
214 : static const int nMaxLineLength =
215 356 : atoi(CPLGetConfigOption("MITAB_MAX_LINE_LENGTH", "1000000"));
216 : char **papszTokens =
217 356 : CSVReadParseLine3L(m_fp, nMaxLineLength, m_pszDelimiter,
218 : true, // bHonourStrings
219 : false, // bKeepLeadingAndClosingQuotes
220 : false, // bMergeDelimiter
221 : false // bSkipBOM
222 : );
223 356 : if (papszTokens == nullptr)
224 : {
225 0 : if (strstr(CPLGetLastErrorMsg(),
226 0 : "Maximum number of characters allowed reached"))
227 : {
228 0 : CPLError(
229 : CE_Failure, CPLE_AppDefined,
230 : "Maximum number of characters allowed reached. "
231 : "You can set the MITAB_MAX_LINE_LENGTH configuration option "
232 : "to the desired number of bytes (or -1 for unlimited)");
233 : }
234 0 : SetEof(TRUE);
235 : }
236 356 : return papszTokens;
237 : }
238 :
239 1701 : void MIDDATAFile::WriteLine(const char *pszFormat, ...)
240 : {
241 : va_list args;
242 :
243 1701 : if (m_eAccessMode == TABWrite && m_fp)
244 : {
245 1701 : va_start(args, pszFormat);
246 1701 : CPLString osStr;
247 1701 : osStr.vPrintf(pszFormat, args);
248 1701 : VSIFWriteL(osStr.c_str(), 1, osStr.size(), m_fp);
249 1701 : va_end(args);
250 : }
251 : else
252 : {
253 0 : CPLAssert(false);
254 : }
255 1701 : }
256 :
257 1068 : void MIDDATAFile::SetTranslation(double dfXMul, double dfYMul, double dfXTran,
258 : double dfYTran)
259 : {
260 1068 : m_dfXMultiplier = dfXMul;
261 1068 : m_dfYMultiplier = dfYMul;
262 1068 : m_dfXDisplacement = dfXTran;
263 1068 : m_dfYDisplacement = dfYTran;
264 1068 : }
265 :
266 21452 : double MIDDATAFile::GetXTrans(double dfX)
267 : {
268 21452 : return (dfX * m_dfXMultiplier) + m_dfXDisplacement;
269 : }
270 :
271 20820 : double MIDDATAFile::GetYTrans(double dfY)
272 : {
273 20820 : return (dfY * m_dfYMultiplier) + m_dfYDisplacement;
274 : }
275 :
276 23014 : GBool MIDDATAFile::IsValidFeature(const char *pszString)
277 : {
278 23014 : char **papszToken = CSLTokenizeString(pszString);
279 :
280 23014 : if (CSLCount(papszToken) == 0)
281 : {
282 8229 : CSLDestroy(papszToken);
283 8229 : return FALSE;
284 : }
285 :
286 14785 : if (EQUAL(papszToken[0], "NONE") || EQUAL(papszToken[0], "POINT") ||
287 11888 : EQUAL(papszToken[0], "LINE") || EQUAL(papszToken[0], "PLINE") ||
288 9452 : EQUAL(papszToken[0], "REGION") || EQUAL(papszToken[0], "ARC") ||
289 8226 : EQUAL(papszToken[0], "TEXT") || EQUAL(papszToken[0], "RECT") ||
290 7433 : EQUAL(papszToken[0], "ROUNDRECT") || EQUAL(papszToken[0], "ELLIPSE") ||
291 6590 : EQUAL(papszToken[0], "MULTIPOINT") ||
292 6407 : EQUAL(papszToken[0], "COLLECTION"))
293 : {
294 8477 : CSLDestroy(papszToken);
295 8477 : return TRUE;
296 : }
297 :
298 6308 : CSLDestroy(papszToken);
299 6308 : return FALSE;
300 : }
301 :
302 31992 : GBool MIDDATAFile::GetEof()
303 : {
304 31992 : return m_bEof;
305 : }
306 :
307 863 : const CPLString &MIDDATAFile::GetEncoding() const
308 : {
309 863 : return m_osEncoding;
310 : }
311 :
312 1194 : void MIDDATAFile::SetEncoding(const CPLString &osEncoding)
313 : {
314 1194 : m_osEncoding = osEncoding;
315 1194 : }
316 :
317 2706 : void MIDDATAFile::SetEof(GBool bEof)
318 : {
319 2706 : m_bEof = bEof;
320 2706 : }
|