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 : * SPDX-License-Identifier: MIT
14 : **********************************************************************/
15 :
16 : #include "cpl_port.h"
17 : #include "mitab.h"
18 :
19 : #include <cstdarg>
20 : #include <cstddef>
21 :
22 : #include "cpl_conv.h"
23 : #include "cpl_csv.h"
24 : #include "cpl_error.h"
25 : #include "cpl_string.h"
26 : #include "cpl_vsi.h"
27 : #include "mitab_priv.h"
28 :
29 : /*=====================================================================
30 : * class MIDDATAFile
31 : *
32 : *====================================================================*/
33 :
34 1146 : MIDDATAFile::MIDDATAFile(const char *pszEncoding)
35 : : m_fp(nullptr), m_pszDelimiter("\t"), // Encom 2003 (was NULL).
36 : m_pszFname(nullptr), m_eAccessMode(TABRead), m_dfXMultiplier(1.0),
37 : m_dfYMultiplier(1.0), m_dfXDisplacement(0.0), m_dfYDisplacement(0.0),
38 1146 : m_bEof(FALSE), m_osEncoding(pszEncoding)
39 : {
40 1146 : }
41 :
42 1146 : MIDDATAFile::~MIDDATAFile()
43 : {
44 1146 : Close();
45 1146 : }
46 :
47 2084 : void MIDDATAFile::SaveLine(const char *pszLine)
48 : {
49 2084 : if (pszLine == nullptr)
50 : {
51 0 : m_osSavedLine.clear();
52 : }
53 : else
54 : {
55 2084 : m_osSavedLine = pszLine;
56 : }
57 2084 : }
58 :
59 2065 : const char *MIDDATAFile::GetSavedLine()
60 : {
61 2065 : return m_osSavedLine.c_str();
62 : }
63 :
64 1146 : int MIDDATAFile::Open(const char *pszFname, const char *pszAccess)
65 : {
66 1146 : if (m_fp)
67 : {
68 0 : return -1;
69 : }
70 :
71 : // Validate access mode and make sure we use Text access.
72 1146 : if (STARTS_WITH_CI(pszAccess, "r"))
73 : {
74 972 : m_eAccessMode = TABRead;
75 972 : pszAccess = "rt";
76 : }
77 174 : else if (STARTS_WITH_CI(pszAccess, "w"))
78 : {
79 174 : m_eAccessMode = TABWrite;
80 174 : pszAccess = "wt";
81 : }
82 : else
83 : {
84 0 : return -1;
85 : }
86 :
87 : // Open file for reading.
88 1146 : m_pszFname = CPLStrdup(pszFname);
89 1146 : m_fp = VSIFOpenL(m_pszFname, pszAccess);
90 :
91 1146 : if (m_fp == nullptr)
92 : {
93 4 : CPLFree(m_pszFname);
94 4 : m_pszFname = nullptr;
95 4 : return -1;
96 : }
97 :
98 1142 : SetEof(FALSE);
99 1142 : return 0;
100 : }
101 :
102 983 : int MIDDATAFile::Rewind()
103 : {
104 983 : if (m_fp == nullptr || m_eAccessMode == TABWrite)
105 0 : return -1;
106 :
107 : else
108 : {
109 983 : VSIRewindL(m_fp);
110 983 : SetEof(FALSE);
111 : }
112 983 : return 0;
113 : }
114 :
115 2288 : int MIDDATAFile::Close()
116 : {
117 2288 : if (m_fp == nullptr)
118 1146 : return 0;
119 :
120 : // Close file
121 1142 : VSIFCloseL(m_fp);
122 1142 : m_fp = nullptr;
123 :
124 : // clear readline buffer.
125 1142 : CPLReadLineL(nullptr);
126 :
127 1142 : CPLFree(m_pszFname);
128 1142 : m_pszFname = nullptr;
129 :
130 1142 : return 0;
131 : }
132 :
133 50142 : const char *MIDDATAFile::GetLine()
134 : {
135 50142 : if (m_eAccessMode != TABRead)
136 : {
137 0 : CPLAssert(false);
138 : return nullptr;
139 : }
140 :
141 : static const int nMaxLineLength =
142 50142 : atoi(CPLGetConfigOption("MITAB_MAX_LINE_LENGTH", "1000000"));
143 50142 : const char *pszLine = CPLReadLine2L(m_fp, nMaxLineLength, nullptr);
144 :
145 50142 : if (pszLine == nullptr)
146 : {
147 615 : if (strstr(CPLGetLastErrorMsg(),
148 615 : "Maximum number of characters allowed reached"))
149 : {
150 0 : CPLError(
151 : CE_Failure, CPLE_AppDefined,
152 : "Maximum number of characters allowed reached. "
153 : "You can set the MITAB_MAX_LINE_LENGTH configuration option "
154 : "to the desired number of bytes (or -1 for unlimited)");
155 : }
156 615 : SetEof(TRUE);
157 615 : m_osLastRead.clear();
158 : }
159 : else
160 : {
161 : // Skip leading spaces and tabs except if the delimiter is tab.
162 84284 : while (*pszLine == ' ' || (*m_pszDelimiter != '\t' && *pszLine == '\t'))
163 34757 : pszLine++;
164 :
165 49527 : m_osLastRead = pszLine;
166 : }
167 :
168 : #if DEBUG_VERBOSE
169 : if (pszLine)
170 : CPLDebug("MITAB", "pszLine: %s", pszLine);
171 : #endif
172 :
173 50142 : return pszLine;
174 : }
175 :
176 32042 : const char *MIDDATAFile::GetLastLine()
177 : {
178 : // Return NULL if EOF.
179 32042 : if (GetEof())
180 : {
181 895 : return nullptr;
182 : }
183 31147 : if (m_eAccessMode == TABRead)
184 : {
185 : #if DEBUG_VERBOSE
186 : CPLDebug("MITAB", "m_osLastRead: %s", m_osLastRead.c_str());
187 : #endif
188 31147 : return m_osLastRead.c_str();
189 : }
190 :
191 : // We should never get here. Read/Write mode not implemented.
192 0 : CPLAssert(false);
193 : return nullptr;
194 : }
195 :
196 367 : char **MIDDATAFile::GetTokenizedNextLine()
197 : {
198 : static const int nMaxLineLength =
199 367 : atoi(CPLGetConfigOption("MITAB_MAX_LINE_LENGTH", "1000000"));
200 : char **papszTokens =
201 367 : CSVReadParseLine3L(m_fp, nMaxLineLength, m_pszDelimiter,
202 : true, // bHonourStrings
203 : false, // bKeepLeadingAndClosingQuotes
204 : false, // bMergeDelimiter
205 : false // bSkipBOM
206 : );
207 367 : if (papszTokens == nullptr)
208 : {
209 0 : if (strstr(CPLGetLastErrorMsg(),
210 0 : "Maximum number of characters allowed reached"))
211 : {
212 0 : CPLError(
213 : CE_Failure, CPLE_AppDefined,
214 : "Maximum number of characters allowed reached. "
215 : "You can set the MITAB_MAX_LINE_LENGTH configuration option "
216 : "to the desired number of bytes (or -1 for unlimited)");
217 : }
218 0 : SetEof(TRUE);
219 : }
220 367 : return papszTokens;
221 : }
222 :
223 1752 : void MIDDATAFile::WriteLine(const char *pszFormat, ...)
224 : {
225 : va_list args;
226 :
227 1752 : if (m_eAccessMode == TABWrite && m_fp)
228 : {
229 1752 : va_start(args, pszFormat);
230 1752 : CPLString osStr;
231 1752 : osStr.vPrintf(pszFormat, args);
232 1752 : VSIFWriteL(osStr.c_str(), 1, osStr.size(), m_fp);
233 1752 : va_end(args);
234 : }
235 : else
236 : {
237 0 : CPLAssert(false);
238 : }
239 1752 : }
240 :
241 1084 : void MIDDATAFile::SetTranslation(double dfXMul, double dfYMul, double dfXTran,
242 : double dfYTran)
243 : {
244 1084 : m_dfXMultiplier = dfXMul;
245 1084 : m_dfYMultiplier = dfYMul;
246 1084 : m_dfXDisplacement = dfXTran;
247 1084 : m_dfYDisplacement = dfYTran;
248 1084 : }
249 :
250 21467 : double MIDDATAFile::GetXTrans(double dfX)
251 : {
252 21467 : return (dfX * m_dfXMultiplier) + m_dfXDisplacement;
253 : }
254 :
255 20835 : double MIDDATAFile::GetYTrans(double dfY)
256 : {
257 20835 : return (dfY * m_dfYMultiplier) + m_dfYDisplacement;
258 : }
259 :
260 23049 : GBool MIDDATAFile::IsValidFeature(const char *pszString)
261 : {
262 23049 : char **papszToken = CSLTokenizeString(pszString);
263 :
264 23049 : if (CSLCount(papszToken) == 0)
265 : {
266 8240 : CSLDestroy(papszToken);
267 8240 : return FALSE;
268 : }
269 :
270 14809 : if (EQUAL(papszToken[0], "NONE") || EQUAL(papszToken[0], "POINT") ||
271 11898 : EQUAL(papszToken[0], "LINE") || EQUAL(papszToken[0], "PLINE") ||
272 9461 : EQUAL(papszToken[0], "REGION") || EQUAL(papszToken[0], "ARC") ||
273 8234 : EQUAL(papszToken[0], "TEXT") || EQUAL(papszToken[0], "RECT") ||
274 7441 : EQUAL(papszToken[0], "ROUNDRECT") || EQUAL(papszToken[0], "ELLIPSE") ||
275 6598 : EQUAL(papszToken[0], "MULTIPOINT") ||
276 6415 : EQUAL(papszToken[0], "COLLECTION"))
277 : {
278 8493 : CSLDestroy(papszToken);
279 8493 : return TRUE;
280 : }
281 :
282 6316 : CSLDestroy(papszToken);
283 6316 : return FALSE;
284 : }
285 :
286 32042 : GBool MIDDATAFile::GetEof()
287 : {
288 32042 : return m_bEof;
289 : }
290 :
291 895 : const CPLString &MIDDATAFile::GetEncoding() const
292 : {
293 895 : return m_osEncoding;
294 : }
295 :
296 1213 : void MIDDATAFile::SetEncoding(const CPLString &osEncoding)
297 : {
298 1213 : m_osEncoding = osEncoding;
299 1213 : }
300 :
301 2740 : void MIDDATAFile::SetEof(GBool bEof)
302 : {
303 2740 : m_bEof = bEof;
304 2740 : }
|