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