Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: NTF Translator
4 : * Purpose: NTFRecord class implementation.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1999, Frank Warmerdam
9 : * Copyright (c) 2013, Even Rouault <even dot rouault at spatialys.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 "ntf.h"
31 : #include "cpl_conv.h"
32 :
33 : static int nFieldBufSize = 0;
34 : static char *pszFieldBuf = nullptr;
35 :
36 : constexpr int MAX_RECORD_LEN = 160;
37 :
38 : /************************************************************************/
39 : /* NTFRecord() */
40 : /* */
41 : /* The constructor is where the record is read. This includes */
42 : /* transparent merging of continuation lines. */
43 : /************************************************************************/
44 :
45 0 : NTFRecord::NTFRecord(VSILFILE *fp) : nType(99), nLength(0), pszData(nullptr)
46 : {
47 0 : if (fp == nullptr)
48 0 : return;
49 :
50 : /* ==================================================================== */
51 : /* Read lines until we get to one without a continuation mark. */
52 : /* ==================================================================== */
53 0 : char szLine[MAX_RECORD_LEN + 3] = {};
54 0 : int nNewLength = 0;
55 :
56 0 : do
57 : {
58 0 : nNewLength = ReadPhysicalLine(fp, szLine);
59 0 : if (nNewLength == -1 || nNewLength == -2)
60 : break;
61 :
62 0 : while (nNewLength > 0 && szLine[nNewLength - 1] == ' ')
63 0 : szLine[--nNewLength] = '\0';
64 :
65 0 : if (nNewLength < 2 || szLine[nNewLength - 1] != '%')
66 : {
67 0 : CPLError(CE_Failure, CPLE_AppDefined,
68 : "Corrupt NTF record, missing end '%%'.");
69 0 : CPLFree(pszData);
70 0 : pszData = nullptr;
71 0 : break;
72 : }
73 :
74 0 : if (pszData == nullptr)
75 : {
76 0 : nLength = nNewLength - 2;
77 0 : pszData = static_cast<char *>(VSI_MALLOC_VERBOSE(nLength + 1));
78 0 : if (pszData == nullptr)
79 : {
80 0 : return;
81 : }
82 0 : memcpy(pszData, szLine, nLength);
83 0 : pszData[nLength] = '\0';
84 : }
85 : else
86 : {
87 0 : if (!STARTS_WITH_CI(szLine, "00") || nNewLength < 4)
88 : {
89 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid line");
90 0 : VSIFree(pszData);
91 0 : pszData = nullptr;
92 0 : return;
93 : }
94 :
95 : char *pszNewData = static_cast<char *>(
96 0 : VSI_REALLOC_VERBOSE(pszData, nLength + (nNewLength - 4) + 1));
97 0 : if (pszNewData == nullptr)
98 : {
99 0 : VSIFree(pszData);
100 0 : pszData = nullptr;
101 0 : return;
102 : }
103 :
104 0 : pszData = pszNewData;
105 0 : memcpy(pszData + nLength, szLine + 2, nNewLength - 4);
106 0 : nLength += nNewLength - 4;
107 0 : pszData[nLength] = '\0';
108 : }
109 0 : } while (szLine[nNewLength - 2] == '1');
110 :
111 : /* -------------------------------------------------------------------- */
112 : /* Figure out the record type. */
113 : /* -------------------------------------------------------------------- */
114 0 : if (pszData != nullptr)
115 : {
116 : char szType[3];
117 :
118 0 : strncpy(szType, pszData, 2);
119 0 : szType[2] = '\0';
120 :
121 0 : nType = atoi(szType);
122 : }
123 : }
124 :
125 : /************************************************************************/
126 : /* ~NTFRecord() */
127 : /************************************************************************/
128 :
129 0 : NTFRecord::~NTFRecord()
130 :
131 : {
132 0 : CPLFree(pszData);
133 :
134 0 : if (pszFieldBuf != nullptr)
135 : {
136 0 : CPLFree(pszFieldBuf);
137 0 : pszFieldBuf = nullptr;
138 0 : nFieldBufSize = 0;
139 : }
140 0 : }
141 :
142 : /************************************************************************/
143 : /* ReadPhysicalLine() */
144 : /************************************************************************/
145 :
146 0 : int NTFRecord::ReadPhysicalLine(VSILFILE *fp, char *pszLine)
147 :
148 : {
149 : /* -------------------------------------------------------------------- */
150 : /* Read enough data that we are sure we have a whole record. */
151 : /* -------------------------------------------------------------------- */
152 0 : int nRecordStart = static_cast<int>(VSIFTellL(fp));
153 : const int nBytesRead =
154 0 : static_cast<int>(VSIFReadL(pszLine, 1, MAX_RECORD_LEN + 2, fp));
155 :
156 0 : if (nBytesRead == 0)
157 : {
158 0 : if (VSIFEofL(fp))
159 0 : return -1;
160 : else
161 : {
162 0 : CPLError(CE_Failure, CPLE_AppDefined,
163 : "Low level read error occurred while reading NTF file.");
164 0 : return -2;
165 : }
166 : }
167 :
168 : /* -------------------------------------------------------------------- */
169 : /* Search for CR or LF. */
170 : /* -------------------------------------------------------------------- */
171 0 : int i = 0; // Used after for.
172 0 : for (; i < nBytesRead; i++)
173 : {
174 0 : if (pszLine[i] == 10 || pszLine[i] == 13)
175 : break;
176 : }
177 :
178 : /* -------------------------------------------------------------------- */
179 : /* If we don't find EOL within 80 characters something has gone */
180 : /* badly wrong! */
181 : /* -------------------------------------------------------------------- */
182 0 : if (i == MAX_RECORD_LEN + 2)
183 : {
184 0 : CPLError(CE_Failure, CPLE_AppDefined,
185 : "%d byte record too long for NTF format. "
186 : "No line may be longer than 80 characters though up "
187 : "to %d tolerated.",
188 : nBytesRead, MAX_RECORD_LEN);
189 0 : return -2;
190 : }
191 :
192 : /* -------------------------------------------------------------------- */
193 : /* Trim CR/LF. */
194 : /* -------------------------------------------------------------------- */
195 0 : const int l_nLength = i;
196 0 : const int nRecordEnd =
197 0 : nRecordStart + i +
198 0 : (pszLine[i + 1] == 10 || pszLine[i + 1] == 13 ? 2 : 1);
199 :
200 0 : pszLine[l_nLength] = '\0';
201 :
202 : /* -------------------------------------------------------------------- */
203 : /* Restore read pointer to beginning of next record. */
204 : /* -------------------------------------------------------------------- */
205 0 : if (VSIFSeekL(fp, nRecordEnd, SEEK_SET) != 0)
206 0 : return -1;
207 :
208 0 : return l_nLength;
209 : }
210 :
211 : /************************************************************************/
212 : /* GetField() */
213 : /* */
214 : /* Note that the start position is 1 based, to match the */
215 : /* notation in the NTF document. The returned pointer is to an */
216 : /* internal buffer, but is zero terminated. */
217 : /************************************************************************/
218 :
219 0 : const char *NTFRecord::GetField(int nStart, int nEnd)
220 :
221 : {
222 0 : const int nSize = nEnd - nStart + 1;
223 :
224 0 : if (pszData == nullptr)
225 0 : return "";
226 :
227 : /* -------------------------------------------------------------------- */
228 : /* Reallocate working buffer larger if needed. */
229 : /* -------------------------------------------------------------------- */
230 0 : if (nFieldBufSize < nSize + 1)
231 : {
232 0 : CPLFree(pszFieldBuf);
233 0 : nFieldBufSize = nSize + 1;
234 0 : pszFieldBuf = static_cast<char *>(CPLMalloc(nFieldBufSize));
235 : }
236 :
237 : /* -------------------------------------------------------------------- */
238 : /* Copy out desired data. */
239 : /* -------------------------------------------------------------------- */
240 0 : if (nStart + nSize > nLength + 1)
241 : {
242 0 : CPLError(CE_Failure, CPLE_AppDefined,
243 : "Attempt to read %d to %d, beyond the end of %d byte long\n"
244 : "type `%2.2s' record.\n",
245 : nStart, nEnd, nLength, pszData);
246 0 : memset(pszFieldBuf, ' ', nSize);
247 0 : pszFieldBuf[nSize] = '\0';
248 : }
249 : else
250 : {
251 0 : strncpy(pszFieldBuf, pszData + nStart - 1, nSize);
252 0 : pszFieldBuf[nSize] = '\0';
253 : }
254 :
255 0 : return pszFieldBuf;
256 : }
|