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_error.h"
40 #include "cpl_string.h"
41 #include "cpl_vsi.h"
42 #include "mitab_priv.h"
43
44 CPL_CVSID("$Id: mitab_middatafile.cpp 7355f684f451b09efde7b4c59aae57454fa85541 2019-03-17 12:47:10 +0100 Even Rouault $")
45
46 /*=====================================================================
47 * class MIDDATAFile
48 *
49 *====================================================================*/
50
MIDDATAFile(const char * pszEncoding)51 MIDDATAFile::MIDDATAFile( const char* pszEncoding ) :
52 m_fp(nullptr),
53 m_pszDelimiter("\t"), // Encom 2003 (was NULL).
54 m_pszFname(nullptr),
55 m_eAccessMode(TABRead),
56 // TODO(schwehr): m_szLastRead({}),
57 // TODO(schwehr): m_szSavedLine({}),
58 m_dfXMultiplier(1.0),
59 m_dfYMultiplier(1.0),
60 m_dfXDisplacement(0.0),
61 m_dfYDisplacement(0.0),
62 m_bEof(FALSE),
63 m_osEncoding(pszEncoding)
64 {
65 m_szLastRead[0] = '\0';
66 m_szSavedLine[0] = '\0';
67 }
68
~MIDDATAFile()69 MIDDATAFile::~MIDDATAFile() { Close(); }
70
SaveLine(const char * pszLine)71 void MIDDATAFile::SaveLine(const char *pszLine)
72 {
73 if(pszLine == nullptr)
74 {
75 m_szSavedLine[0] = '\0';
76 }
77 else
78 {
79 CPLStrlcpy(m_szSavedLine, pszLine, MIDMAXCHAR);
80 }
81 }
82
GetSavedLine()83 const char *MIDDATAFile::GetSavedLine() { return m_szSavedLine; }
84
Open(const char * pszFname,const char * pszAccess)85 int MIDDATAFile::Open(const char *pszFname, const char *pszAccess)
86 {
87 if(m_fp)
88 {
89 return -1;
90 }
91
92 // Validate access mode and make sure we use Text access.
93 if(STARTS_WITH_CI(pszAccess, "r"))
94 {
95 m_eAccessMode = TABRead;
96 pszAccess = "rt";
97 }
98 else if(STARTS_WITH_CI(pszAccess, "w"))
99 {
100 m_eAccessMode = TABWrite;
101 pszAccess = "wt";
102 }
103 else
104 {
105 return -1;
106 }
107
108 // Open file for reading.
109 m_pszFname = CPLStrdup(pszFname);
110 m_fp = VSIFOpenL(m_pszFname, pszAccess);
111
112 if(m_fp == nullptr)
113 {
114 CPLFree(m_pszFname);
115 m_pszFname = nullptr;
116 return -1;
117 }
118
119 SetEof(FALSE);
120 return 0;
121 }
122
Rewind()123 int MIDDATAFile::Rewind()
124 {
125 if(m_fp == nullptr || m_eAccessMode == TABWrite)
126 return -1;
127
128 else
129 {
130 VSIRewindL(m_fp);
131 SetEof(FALSE);
132 }
133 return 0;
134 }
135
Close()136 int MIDDATAFile::Close()
137 {
138 if(m_fp == nullptr)
139 return 0;
140
141 // Close file
142 VSIFCloseL(m_fp);
143 m_fp = nullptr;
144
145 // clear readline buffer.
146 CPLReadLineL(nullptr);
147
148 CPLFree(m_pszFname);
149 m_pszFname = nullptr;
150
151 return 0;
152 }
153
GetLine()154 const char *MIDDATAFile::GetLine()
155 {
156 if(m_eAccessMode != TABRead)
157 {
158 CPLAssert(false);
159 return nullptr;
160 }
161
162 const char *pszLine = CPLReadLine2L(m_fp, MIDMAXCHAR, nullptr);
163
164 if(pszLine == nullptr)
165 {
166 SetEof(TRUE);
167 m_szLastRead[0] = '\0';
168 }
169 else
170 {
171 // Skip leading spaces and tabs except if the delimiter is tab.
172 while(pszLine && (*pszLine == ' ' ||
173 (*m_pszDelimiter != '\t' && *pszLine == '\t')))
174 pszLine++;
175
176 CPLStrlcpy(m_szLastRead, pszLine, MIDMAXCHAR);
177 }
178
179 #if DEBUG_VERBOSE
180 if(pszLine)
181 CPLDebug("MITAB", "pszLine: %s", pszLine);
182 #endif
183
184 return pszLine;
185 }
186
GetLastLine()187 const char *MIDDATAFile::GetLastLine()
188 {
189 // Return NULL if EOF.
190 if(GetEof())
191 {
192 return nullptr;
193 }
194 if(m_eAccessMode == TABRead)
195 {
196 #if DEBUG_VERBOSE
197 CPLDebug("MITAB", "m_szLastRead: %s", m_szLastRead);
198 #endif
199 return m_szLastRead;
200 }
201
202 // We should never get here. Read/Write mode not implemented.
203 CPLAssert(false);
204 return nullptr;
205 }
206
WriteLine(const char * pszFormat,...)207 void MIDDATAFile::WriteLine(const char *pszFormat, ...)
208 {
209 va_list args;
210
211 if(m_eAccessMode == TABWrite && m_fp)
212 {
213 va_start(args, pszFormat);
214 CPLString osStr;
215 osStr.vPrintf(pszFormat, args);
216 VSIFWriteL(osStr.c_str(), 1, osStr.size(), m_fp);
217 va_end(args);
218 }
219 else
220 {
221 CPLAssert(false);
222 }
223 }
224
SetTranslation(double dfXMul,double dfYMul,double dfXTran,double dfYTran)225 void MIDDATAFile::SetTranslation( double dfXMul,double dfYMul,
226 double dfXTran, double dfYTran )
227 {
228 m_dfXMultiplier = dfXMul;
229 m_dfYMultiplier = dfYMul;
230 m_dfXDisplacement = dfXTran;
231 m_dfYDisplacement = dfYTran;
232 }
233
GetXTrans(double dfX)234 double MIDDATAFile::GetXTrans(double dfX)
235 {
236 return (dfX * m_dfXMultiplier) + m_dfXDisplacement;
237 }
238
GetYTrans(double dfY)239 double MIDDATAFile::GetYTrans(double dfY)
240 {
241 return (dfY * m_dfYMultiplier) + m_dfYDisplacement;
242 }
243
IsValidFeature(const char * pszString)244 GBool MIDDATAFile::IsValidFeature(const char *pszString)
245 {
246 char **papszToken = CSLTokenizeString(pszString);
247
248 if(CSLCount(papszToken) == 0)
249 {
250 CSLDestroy(papszToken);
251 return FALSE;
252 }
253
254 if(EQUAL(papszToken[0], "NONE") || EQUAL(papszToken[0], "POINT") ||
255 EQUAL(papszToken[0], "LINE") || EQUAL(papszToken[0], "PLINE") ||
256 EQUAL(papszToken[0], "REGION") || EQUAL(papszToken[0], "ARC") ||
257 EQUAL(papszToken[0], "TEXT") || EQUAL(papszToken[0], "RECT") ||
258 EQUAL(papszToken[0], "ROUNDRECT") || EQUAL(papszToken[0], "ELLIPSE") ||
259 EQUAL(papszToken[0], "MULTIPOINT") || EQUAL(papszToken[0], "COLLECTION"))
260 {
261 CSLDestroy(papszToken);
262 return TRUE;
263 }
264
265 CSLDestroy(papszToken);
266 return FALSE;
267 }
268
GetEof()269 GBool MIDDATAFile::GetEof() { return m_bEof; }
270
GetEncoding() const271 const CPLString& MIDDATAFile::GetEncoding() const
272 {
273 return m_osEncoding;
274 }
275
SetEncoding(const CPLString & osEncoding)276 void MIDDATAFile::SetEncoding( const CPLString& osEncoding )
277 {
278 m_osEncoding = osEncoding;
279 }
280
SetEof(GBool bEof)281 void MIDDATAFile::SetEof(GBool bEof) { m_bEof = bEof; }
282