Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: PDS Translator
4 : * Purpose: Implements OGRPDSLayer class.
5 : * Author: Even Rouault, <even dot rouault at spatialys.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "ogr_pds.h"
30 : #include "cpl_conv.h"
31 : #include "cpl_string.h"
32 : #include "ogr_p.h"
33 : #include "cpl_safemaths.hpp"
34 :
35 : #include <algorithm>
36 :
37 : namespace OGRPDS
38 : {
39 :
40 : /************************************************************************/
41 : /* OGRPDSLayer() */
42 : /************************************************************************/
43 :
44 2 : OGRPDSLayer::OGRPDSLayer(const std::string &osTableIDIn,
45 : const char *pszLayerName, VSILFILE *fp,
46 : const std::string &osLabelFilename,
47 : const std::string &osStructureFilename, int nRecordsIn,
48 : int nStartBytesIn, int nRecordSizeIn,
49 2 : GByte *pabyRecordIn, bool bIsASCII)
50 2 : : poFeatureDefn(new OGRFeatureDefn(pszLayerName)), osTableID(osTableIDIn),
51 : fpPDS(fp), nRecords(nRecordsIn), nStartBytes(nStartBytesIn),
52 : nRecordSize(nRecordSizeIn), pabyRecord(pabyRecordIn), nNextFID(0),
53 4 : nLongitudeIndex(-1), nLatitudeIndex(-1), pasFieldDesc(nullptr)
54 : {
55 2 : SetDescription(poFeatureDefn->GetName());
56 2 : poFeatureDefn->Reference();
57 2 : poFeatureDefn->SetGeomType(wkbNone);
58 :
59 2 : if (!osStructureFilename.empty())
60 : {
61 2 : ReadStructure(osStructureFilename);
62 : }
63 : else
64 : {
65 0 : ReadStructure(osLabelFilename);
66 : }
67 :
68 2 : if (bIsASCII && poFeatureDefn->GetFieldCount() == 0)
69 : {
70 0 : VSIFSeekL(fpPDS, nStartBytes, SEEK_SET);
71 0 : VSIFReadL(pabyRecord, nRecordSize, 1, fpPDS);
72 :
73 0 : char **papszTokens = CSLTokenizeString2((const char *)pabyRecord, " ",
74 : CSLT_HONOURSTRINGS);
75 0 : const int nTokens = CSLCount(papszTokens);
76 0 : for (int i = 0; i < nTokens; i++)
77 : {
78 0 : const char *pszStr = papszTokens[i];
79 0 : char ch = '\0';
80 0 : OGRFieldType eFieldType = OFTInteger;
81 0 : while ((ch = *pszStr) != 0)
82 : {
83 0 : if ((ch >= '0' && ch <= '9') || ch == '+' || ch == '-')
84 : {
85 : }
86 0 : else if (ch == '.')
87 : {
88 0 : eFieldType = OFTReal;
89 : }
90 : else
91 : {
92 0 : eFieldType = OFTString;
93 0 : break;
94 : }
95 0 : pszStr++;
96 : }
97 : char szFieldName[32];
98 0 : snprintf(szFieldName, sizeof(szFieldName), "field_%d",
99 0 : poFeatureDefn->GetFieldCount() + 1);
100 0 : OGRFieldDefn oFieldDefn(szFieldName, eFieldType);
101 0 : poFeatureDefn->AddFieldDefn(&oFieldDefn);
102 : }
103 0 : CSLDestroy(papszTokens);
104 : }
105 :
106 2 : if (nLongitudeIndex >= 0 && nLatitudeIndex >= 0)
107 : {
108 1 : poFeatureDefn->SetGeomType(wkbPoint);
109 : }
110 :
111 2 : OGRPDSLayer::ResetReading();
112 2 : }
113 :
114 : /************************************************************************/
115 : /* ~OGRPDSLayer() */
116 : /************************************************************************/
117 :
118 4 : OGRPDSLayer::~OGRPDSLayer()
119 :
120 : {
121 2 : CPLFree(pasFieldDesc);
122 2 : poFeatureDefn->Release();
123 2 : VSIFree(pabyRecord);
124 :
125 2 : VSIFCloseL(fpPDS);
126 4 : }
127 :
128 : /************************************************************************/
129 : /* ReadStructure() */
130 : /************************************************************************/
131 :
132 2 : void OGRPDSLayer::ReadStructure(const std::string &osStructureFilename)
133 :
134 : {
135 2 : VSILFILE *fpStructure = VSIFOpenL(osStructureFilename.c_str(), "rb");
136 2 : if (fpStructure == nullptr)
137 0 : return;
138 :
139 2 : int nFields = 0;
140 2 : bool bInObjectColumn = false;
141 2 : int nExpectedColumnNumber = 0;
142 4 : CPLString osColumnName;
143 4 : CPLString osColumnDataType;
144 4 : CPLString osColumnStartByte;
145 4 : CPLString osColumnBytes;
146 4 : CPLString osColumnFormat;
147 4 : CPLString osColumnUnit;
148 4 : CPLString osColumnItems;
149 4 : CPLString osColumnItemBytes;
150 2 : int nRowBytes = nRecordSize;
151 : while (true)
152 : {
153 871 : CPLPushErrorHandler(CPLQuietErrorHandler);
154 871 : const char *pszLine = CPLReadLine2L(fpStructure, 256, nullptr);
155 871 : CPLPopErrorHandler();
156 871 : CPLErrorReset();
157 871 : if (pszLine == nullptr)
158 2 : break;
159 :
160 : char **papszTokens =
161 869 : CSLTokenizeString2(pszLine, " =", CSLT_HONOURSTRINGS);
162 869 : const int nTokens = CSLCount(papszTokens);
163 :
164 869 : if (bInObjectColumn && nTokens >= 1 &&
165 723 : EQUAL(papszTokens[0], "END_OBJECT"))
166 : {
167 116 : if (!osColumnName.empty() && !osColumnDataType.empty() &&
168 116 : !osColumnStartByte.empty() && !osColumnBytes.empty())
169 : {
170 116 : pasFieldDesc = static_cast<FieldDesc *>(CPLRealloc(
171 58 : pasFieldDesc, (nFields + 1) * sizeof(FieldDesc)));
172 58 : pasFieldDesc[nFields].nStartByte = atoi(osColumnStartByte) - 1;
173 58 : pasFieldDesc[nFields].nByteCount = atoi(osColumnBytes);
174 58 : if (pasFieldDesc[nFields].nStartByte >= 0 &&
175 58 : pasFieldDesc[nFields].nByteCount > 0 &&
176 58 : pasFieldDesc[nFields].nStartByte <
177 58 : INT_MAX - pasFieldDesc[nFields].nByteCount &&
178 58 : pasFieldDesc[nFields].nStartByte +
179 58 : pasFieldDesc[nFields].nByteCount <=
180 58 : nRecordSize)
181 : {
182 58 : OGRFieldType eFieldType = OFTString;
183 58 : OGRFieldSubType eSubType = OFSTNone;
184 58 : pasFieldDesc[nFields].eFormat = CHARACTER;
185 58 : pasFieldDesc[nFields].nItemBytes = atoi(osColumnItemBytes);
186 58 : pasFieldDesc[nFields].nItems = atoi(osColumnItems);
187 58 : if (pasFieldDesc[nFields].nItems == 0)
188 51 : pasFieldDesc[nFields].nItems = 1;
189 58 : if (pasFieldDesc[nFields].nItemBytes == 0 &&
190 51 : pasFieldDesc[nFields].nItems == 1)
191 51 : pasFieldDesc[nFields].nItemBytes =
192 51 : pasFieldDesc[nFields].nByteCount;
193 :
194 58 : if (osColumnDataType.compare("ASCII_REAL") == 0)
195 : {
196 14 : eFieldType = OFTReal;
197 14 : pasFieldDesc[nFields].eFormat = ASCII_REAL;
198 : }
199 44 : else if (osColumnDataType.compare("ASCII_INTEGER") == 0)
200 : {
201 11 : eFieldType = OFTInteger;
202 11 : pasFieldDesc[nFields].eFormat = ASCII_INTEGER;
203 : }
204 33 : else if (osColumnDataType.compare("MSB_UNSIGNED_INTEGER") ==
205 : 0)
206 : {
207 11 : if (pasFieldDesc[nFields].nItemBytes == 1 ||
208 11 : pasFieldDesc[nFields].nItemBytes == 2)
209 : {
210 9 : if (pasFieldDesc[nFields].nItems > 1)
211 0 : eFieldType = OFTIntegerList;
212 : else
213 9 : eFieldType = OFTInteger;
214 : }
215 : else
216 : {
217 2 : pasFieldDesc[nFields].nItemBytes = 4;
218 2 : if (pasFieldDesc[nFields].nItems > 1)
219 0 : eFieldType = OFTRealList;
220 : else
221 2 : eFieldType = OFTReal;
222 : }
223 11 : pasFieldDesc[nFields].eFormat = MSB_UNSIGNED_INTEGER;
224 : }
225 22 : else if (osColumnDataType.compare("MSB_INTEGER") == 0)
226 : {
227 4 : if (pasFieldDesc[nFields].nItemBytes != 1 &&
228 4 : pasFieldDesc[nFields].nItemBytes != 2)
229 4 : pasFieldDesc[nFields].nItemBytes = 4;
230 4 : if (pasFieldDesc[nFields].nItems > 1)
231 0 : eFieldType = OFTIntegerList;
232 : else
233 4 : eFieldType = OFTInteger;
234 4 : pasFieldDesc[nFields].eFormat = MSB_INTEGER;
235 : }
236 18 : else if (osColumnDataType.compare("IEEE_REAL") == 0)
237 : {
238 16 : if (pasFieldDesc[nFields].nItemBytes == 4)
239 : {
240 8 : eSubType = OFSTFloat32;
241 : }
242 8 : else if (pasFieldDesc[nFields].nItemBytes != 8)
243 : {
244 : // Not sure if this is correct, but default to
245 : // Float32
246 0 : pasFieldDesc[nFields].nItemBytes = 4;
247 : }
248 16 : if (pasFieldDesc[nFields].nItems > 1)
249 7 : eFieldType = OFTRealList;
250 : else
251 9 : eFieldType = OFTReal;
252 16 : pasFieldDesc[nFields].eFormat = IEEE_REAL;
253 : }
254 :
255 58 : OGRFieldDefn oFieldDefn(osColumnName, eFieldType);
256 130 : if ((pasFieldDesc[nFields].eFormat == ASCII_REAL &&
257 102 : !osColumnFormat.empty() && osColumnFormat[0] == 'F') ||
258 44 : (pasFieldDesc[nFields].eFormat == ASCII_INTEGER &&
259 11 : !osColumnFormat.empty() && osColumnFormat[0] == 'I'))
260 : {
261 25 : const char *pszFormat = osColumnFormat.c_str();
262 25 : int nWidth = atoi(pszFormat + 1);
263 25 : oFieldDefn.SetWidth(nWidth);
264 25 : const char *pszPoint = strchr(pszFormat, '.');
265 25 : if (pszPoint)
266 : {
267 14 : int nPrecision = atoi(pszPoint + 1);
268 14 : oFieldDefn.SetPrecision(nPrecision);
269 : }
270 : }
271 33 : else if (oFieldDefn.GetType() == OFTString &&
272 33 : !osColumnFormat.empty() &&
273 0 : osColumnFormat[0] == 'A')
274 : {
275 0 : const char *pszFormat = osColumnFormat.c_str();
276 0 : int nWidth = atoi(pszFormat + 1);
277 0 : oFieldDefn.SetWidth(nWidth);
278 : }
279 58 : oFieldDefn.SetSubType(eSubType);
280 58 : poFeatureDefn->AddFieldDefn(&oFieldDefn);
281 :
282 83 : if (oFieldDefn.GetType() == OFTReal &&
283 25 : osColumnUnit.compare("DEGREE") == 0)
284 : {
285 7 : if (osColumnName.compare("LONGITUDE") == 0)
286 1 : nLongitudeIndex = nFields;
287 6 : else if (osColumnName.compare("LATITUDE") == 0)
288 1 : nLatitudeIndex = nFields;
289 : }
290 :
291 58 : nFields++;
292 : }
293 : else
294 : {
295 0 : CPLError(CE_Failure, CPLE_AppDefined,
296 : "Field %d out of record extents", nFields);
297 0 : CSLDestroy(papszTokens);
298 0 : if (nFields == 0)
299 : {
300 0 : CPLFree(pasFieldDesc);
301 0 : pasFieldDesc = nullptr;
302 : }
303 0 : break;
304 : }
305 : }
306 : else
307 : {
308 0 : CPLError(CE_Failure, CPLE_AppDefined,
309 : "Did not get expected records for field %d", nFields);
310 0 : CSLDestroy(papszTokens);
311 0 : break;
312 : }
313 58 : bInObjectColumn = false;
314 : }
315 811 : else if (nTokens == 2)
316 : {
317 490 : if (EQUAL(papszTokens[0], "PDS_VERSION_ID"))
318 : {
319 0 : CSLDestroy(papszTokens);
320 0 : papszTokens = nullptr;
321 : while (true)
322 : {
323 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
324 0 : pszLine = CPLReadLine2L(fpStructure, 256, nullptr);
325 0 : CPLPopErrorHandler();
326 0 : CPLErrorReset();
327 0 : if (pszLine == nullptr)
328 0 : break;
329 : papszTokens =
330 0 : CSLTokenizeString2(pszLine, " =", CSLT_HONOURSTRINGS);
331 0 : int nTokens2 = CSLCount(papszTokens);
332 0 : if (nTokens2 == 2 && EQUAL(papszTokens[0], "OBJECT") &&
333 0 : EQUAL(papszTokens[1], osTableID.c_str()))
334 : {
335 0 : break;
336 : }
337 0 : CSLDestroy(papszTokens);
338 0 : papszTokens = nullptr;
339 0 : }
340 0 : CSLDestroy(papszTokens);
341 0 : papszTokens = nullptr;
342 0 : if (pszLine == nullptr)
343 0 : break;
344 : }
345 490 : else if (EQUAL(papszTokens[0], "ROW_BYTES"))
346 : {
347 1 : nRowBytes = atoi(papszTokens[1]);
348 1 : if (nRowBytes < 0 || nRowBytes > 10 * 1024 * 1024)
349 : {
350 0 : CPLError(CE_Failure, CPLE_NotSupported,
351 : "Invalid value of ROW_BYTES");
352 0 : CSLDestroy(papszTokens);
353 0 : break;
354 : }
355 : }
356 489 : else if (EQUAL(papszTokens[0], "ROW_SUFFIX_BYTES"))
357 : {
358 : try
359 : {
360 : nRowBytes =
361 0 : (CPLSM(nRowBytes) + CPLSM(atoi(papszTokens[1]))).v();
362 : }
363 0 : catch (const CPLSafeIntOverflow &)
364 : {
365 0 : CPLError(CE_Failure, CPLE_NotSupported,
366 : "Invalid value of ROW_SUFFIX_BYTES");
367 0 : CSLDestroy(papszTokens);
368 0 : break;
369 : }
370 0 : if (nRowBytes < 0 || nRowBytes > 10 * 1024 * 1024)
371 : {
372 0 : CPLError(CE_Failure, CPLE_NotSupported,
373 : "Invalid value of ROW_SUFFIX_BYTES");
374 0 : CSLDestroy(papszTokens);
375 0 : break;
376 : }
377 : }
378 489 : else if (EQUAL(papszTokens[0], "OBJECT") &&
379 58 : EQUAL(papszTokens[1], "COLUMN"))
380 : {
381 58 : if (nRowBytes > nRecordSize)
382 : {
383 0 : nRecordSize = nRowBytes;
384 0 : VSIFree(pabyRecord);
385 0 : pabyRecord = (GByte *)CPLMalloc(nRecordSize + 1);
386 0 : pabyRecord[nRecordSize] = 0;
387 : }
388 : else
389 58 : nRecordSize = nRowBytes;
390 :
391 58 : nExpectedColumnNumber++;
392 58 : bInObjectColumn = true;
393 58 : osColumnName = "";
394 58 : osColumnDataType = "";
395 58 : osColumnStartByte = "";
396 58 : osColumnBytes = "";
397 58 : osColumnItems = "";
398 58 : osColumnItemBytes = "";
399 58 : osColumnFormat = "";
400 58 : osColumnUnit = "";
401 : }
402 431 : else if (bInObjectColumn && EQUAL(papszTokens[0], "COLUMN_NUMBER"))
403 : {
404 58 : int nColumnNumber = atoi(papszTokens[1]);
405 58 : if (nColumnNumber != nExpectedColumnNumber)
406 : {
407 0 : CPLError(CE_Failure, CPLE_AppDefined,
408 : "Did not get expected column number");
409 0 : CSLDestroy(papszTokens);
410 0 : break;
411 58 : }
412 : }
413 373 : else if (bInObjectColumn && EQUAL(papszTokens[0], "NAME"))
414 : {
415 58 : osColumnName = "\"";
416 58 : osColumnName += papszTokens[1];
417 58 : osColumnName += "\"";
418 58 : OGRPDSDataSource::CleanString(osColumnName);
419 : }
420 315 : else if (bInObjectColumn && EQUAL(papszTokens[0], "DATA_TYPE"))
421 : {
422 58 : osColumnDataType = papszTokens[1];
423 58 : OGRPDSDataSource::CleanString(osColumnDataType);
424 : }
425 257 : else if (bInObjectColumn && EQUAL(papszTokens[0], "START_BYTE"))
426 : {
427 58 : osColumnStartByte = papszTokens[1];
428 : }
429 199 : else if (bInObjectColumn && EQUAL(papszTokens[0], "BYTES"))
430 : {
431 58 : osColumnBytes = papszTokens[1];
432 : }
433 141 : else if (bInObjectColumn && EQUAL(papszTokens[0], "ITEMS"))
434 : {
435 7 : osColumnItems = papszTokens[1];
436 : }
437 134 : else if (bInObjectColumn && EQUAL(papszTokens[0], "ITEM_BYTES"))
438 : {
439 7 : osColumnItemBytes = papszTokens[1];
440 : }
441 127 : else if (bInObjectColumn && EQUAL(papszTokens[0], "FORMAT"))
442 : {
443 25 : osColumnFormat = papszTokens[1];
444 : }
445 102 : else if (bInObjectColumn && EQUAL(papszTokens[0], "UNIT"))
446 : {
447 11 : osColumnUnit = papszTokens[1];
448 : }
449 : }
450 869 : CSLDestroy(papszTokens);
451 869 : }
452 2 : VSIFCloseL(fpStructure);
453 : }
454 :
455 : /************************************************************************/
456 : /* ResetReading() */
457 : /************************************************************************/
458 :
459 2 : void OGRPDSLayer::ResetReading()
460 :
461 : {
462 2 : nNextFID = 0;
463 2 : VSIFSeekL(fpPDS, nStartBytes, SEEK_SET);
464 2 : }
465 :
466 : /************************************************************************/
467 : /* GetNextRawFeature() */
468 : /************************************************************************/
469 :
470 3 : OGRFeature *OGRPDSLayer::GetNextRawFeature()
471 : {
472 3 : if (nNextFID == nRecords)
473 0 : return nullptr;
474 3 : int nRead = (int)VSIFReadL(pabyRecord, 1, nRecordSize, fpPDS);
475 3 : if (nRead != nRecordSize)
476 0 : return nullptr;
477 :
478 3 : OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
479 3 : int nFieldCount = poFeatureDefn->GetFieldCount();
480 3 : if (pasFieldDesc != nullptr)
481 : {
482 86 : for (int i = 0; i < nFieldCount; i++)
483 : {
484 83 : if (pasFieldDesc[i].eFormat == ASCII_REAL ||
485 55 : pasFieldDesc[i].eFormat == ASCII_INTEGER ||
486 33 : pasFieldDesc[i].eFormat == CHARACTER)
487 : {
488 52 : char *pchEnd = reinterpret_cast<char *>(
489 52 : &pabyRecord[pasFieldDesc[i].nStartByte +
490 52 : pasFieldDesc[i].nByteCount]);
491 52 : char chSaved = *pchEnd;
492 52 : *pchEnd = 0;
493 52 : const char *pszValue =
494 52 : (const char *)(pabyRecord + pasFieldDesc[i].nStartByte);
495 52 : if (pasFieldDesc[i].eFormat == CHARACTER)
496 : {
497 2 : poFeature->SetField(i, pszValue);
498 : }
499 : else
500 : {
501 50 : poFeature->SetField(i, CPLString(pszValue).Trim().c_str());
502 : }
503 52 : *pchEnd = chSaved;
504 : }
505 31 : else if (pasFieldDesc[i].eFormat == MSB_UNSIGNED_INTEGER &&
506 11 : pasFieldDesc[i].nStartByte + pasFieldDesc[i].nItemBytes *
507 11 : pasFieldDesc[i].nItems <=
508 11 : nRecordSize)
509 : {
510 11 : if (pasFieldDesc[i].nItemBytes == 1)
511 : {
512 0 : if (pasFieldDesc[i].nItems > 1)
513 : {
514 : int *panValues = static_cast<int *>(
515 0 : CPLMalloc(sizeof(int) * pasFieldDesc[i].nItems));
516 0 : for (int j = 0; j < pasFieldDesc[i].nItems; j++)
517 : {
518 0 : panValues[j] =
519 0 : pabyRecord[pasFieldDesc[i].nStartByte + j];
520 : }
521 0 : poFeature->SetField(i, pasFieldDesc[i].nItems,
522 : panValues);
523 0 : CPLFree(panValues);
524 : }
525 : else
526 : {
527 0 : poFeature->SetField(
528 0 : i, pabyRecord[pasFieldDesc[i].nStartByte]);
529 : }
530 : }
531 11 : else if (pasFieldDesc[i].nItemBytes == 2)
532 : {
533 9 : if (pasFieldDesc[i].nItems > 1)
534 : {
535 0 : int *panValues = (int *)CPLMalloc(
536 0 : sizeof(int) * pasFieldDesc[i].nItems);
537 0 : for (int j = 0; j < pasFieldDesc[i].nItems; j++)
538 : {
539 0 : unsigned short sVal = 0;
540 0 : memcpy(&sVal,
541 0 : pabyRecord + pasFieldDesc[i].nStartByte +
542 0 : 2 * j,
543 : 2);
544 0 : CPL_MSBPTR16(&sVal);
545 0 : panValues[j] = sVal;
546 : }
547 0 : poFeature->SetField(i, pasFieldDesc[i].nItems,
548 : panValues);
549 0 : CPLFree(panValues);
550 : }
551 : else
552 : {
553 9 : unsigned short sVal = 0;
554 9 : memcpy(&sVal, pabyRecord + pasFieldDesc[i].nStartByte,
555 : 2);
556 9 : CPL_MSBPTR16(&sVal);
557 9 : poFeature->SetField(i, (int)sVal);
558 : }
559 : }
560 2 : else if (pasFieldDesc[i].nItemBytes == 4)
561 : {
562 2 : if (pasFieldDesc[i].nItems > 1)
563 : {
564 0 : double *padfValues = (double *)CPLMalloc(
565 0 : sizeof(double) * pasFieldDesc[i].nItems);
566 0 : for (int j = 0; j < pasFieldDesc[i].nItems; j++)
567 : {
568 0 : unsigned int nVal = 0;
569 0 : memcpy(&nVal,
570 0 : pabyRecord + pasFieldDesc[i].nStartByte +
571 0 : 4 * j,
572 : 4);
573 0 : CPL_MSBPTR32(&nVal);
574 0 : padfValues[j] = (double)nVal;
575 : }
576 0 : poFeature->SetField(i, pasFieldDesc[i].nItems,
577 : padfValues);
578 0 : CPLFree(padfValues);
579 : }
580 : else
581 : {
582 2 : unsigned int nVal = 0;
583 2 : memcpy(&nVal, pabyRecord + pasFieldDesc[i].nStartByte,
584 : 4);
585 2 : CPL_MSBPTR32(&nVal);
586 2 : poFeature->SetField(i, (double)nVal);
587 : }
588 11 : }
589 : }
590 20 : else if (pasFieldDesc[i].eFormat == MSB_INTEGER &&
591 4 : pasFieldDesc[i].nStartByte + pasFieldDesc[i].nItemBytes *
592 4 : pasFieldDesc[i].nItems <=
593 4 : nRecordSize)
594 : {
595 4 : if (pasFieldDesc[i].nItemBytes == 1)
596 : {
597 0 : if (pasFieldDesc[i].nItems > 1)
598 : {
599 0 : int *panValues = (int *)CPLMalloc(
600 0 : sizeof(int) * pasFieldDesc[i].nItems);
601 0 : for (int j = 0; j < pasFieldDesc[i].nItems; j++)
602 : {
603 0 : panValues[j] = ((
604 0 : char *)pabyRecord)[pasFieldDesc[i].nStartByte +
605 0 : j];
606 : }
607 0 : poFeature->SetField(i, pasFieldDesc[i].nItems,
608 : panValues);
609 0 : CPLFree(panValues);
610 : }
611 : else
612 : {
613 0 : poFeature->SetField(
614 : i,
615 0 : ((char *)pabyRecord)[pasFieldDesc[i].nStartByte]);
616 : }
617 : }
618 4 : else if (pasFieldDesc[i].nItemBytes == 2)
619 : {
620 0 : if (pasFieldDesc[i].nItems > 1)
621 : {
622 0 : int *panValues = (int *)CPLMalloc(
623 0 : sizeof(int) * pasFieldDesc[i].nItems);
624 0 : for (int j = 0; j < pasFieldDesc[i].nItems; j++)
625 : {
626 0 : short sVal = 0;
627 0 : memcpy(&sVal,
628 0 : pabyRecord + pasFieldDesc[i].nStartByte +
629 0 : 2 * j,
630 : 2);
631 0 : CPL_MSBPTR16(&sVal);
632 0 : panValues[j] = sVal;
633 : }
634 0 : poFeature->SetField(i, pasFieldDesc[i].nItems,
635 : panValues);
636 0 : CPLFree(panValues);
637 : }
638 : else
639 : {
640 0 : short sVal = 0;
641 0 : memcpy(&sVal, pabyRecord + pasFieldDesc[i].nStartByte,
642 : 2);
643 0 : CPL_MSBPTR16(&sVal);
644 0 : poFeature->SetField(i, (int)sVal);
645 : }
646 : }
647 4 : else if (pasFieldDesc[i].nItemBytes == 4)
648 : {
649 4 : if (pasFieldDesc[i].nItems > 1)
650 : {
651 0 : int *panValues = (int *)CPLMalloc(
652 0 : sizeof(int) * pasFieldDesc[i].nItems);
653 0 : for (int j = 0; j < pasFieldDesc[i].nItems; j++)
654 : {
655 0 : int nVal = 0;
656 0 : memcpy(&nVal,
657 0 : pabyRecord + pasFieldDesc[i].nStartByte +
658 0 : 4 * j,
659 : 4);
660 0 : CPL_MSBPTR32(&nVal);
661 0 : panValues[j] = nVal;
662 : }
663 0 : poFeature->SetField(i, pasFieldDesc[i].nItems,
664 : panValues);
665 0 : CPLFree(panValues);
666 : }
667 : else
668 : {
669 4 : int nVal = 0;
670 4 : memcpy(&nVal, pabyRecord + pasFieldDesc[i].nStartByte,
671 : 4);
672 4 : CPL_MSBPTR32(&nVal);
673 4 : poFeature->SetField(i, nVal);
674 : }
675 4 : }
676 : }
677 16 : else if (pasFieldDesc[i].eFormat == IEEE_REAL &&
678 16 : pasFieldDesc[i].nStartByte + pasFieldDesc[i].nItemBytes *
679 16 : pasFieldDesc[i].nItems <=
680 16 : nRecordSize &&
681 16 : pasFieldDesc[i].nItemBytes == 4)
682 : {
683 8 : if (pasFieldDesc[i].nItems > 1)
684 : {
685 10 : double *padfValues = (double *)CPLMalloc(
686 5 : sizeof(double) * pasFieldDesc[i].nItems);
687 2565 : for (int j = 0; j < pasFieldDesc[i].nItems; j++)
688 : {
689 2560 : float fVal = 0.0f;
690 2560 : memcpy(&fVal,
691 2560 : pabyRecord + pasFieldDesc[i].nStartByte + 4 * j,
692 : 4);
693 2560 : CPL_MSBPTR32(&fVal);
694 2560 : padfValues[j] = (double)fVal;
695 : }
696 5 : poFeature->SetField(i, pasFieldDesc[i].nItems, padfValues);
697 5 : CPLFree(padfValues);
698 : }
699 : else
700 : {
701 3 : float fVal = 0.0f;
702 3 : memcpy(&fVal, pabyRecord + pasFieldDesc[i].nStartByte, 4);
703 3 : CPL_MSBPTR32(&fVal);
704 3 : poFeature->SetField(i, (double)fVal);
705 8 : }
706 : }
707 8 : else if (pasFieldDesc[i].eFormat == IEEE_REAL &&
708 8 : pasFieldDesc[i].nStartByte + pasFieldDesc[i].nItemBytes *
709 8 : pasFieldDesc[i].nItems <=
710 8 : nRecordSize &&
711 8 : pasFieldDesc[i].nItemBytes == 8)
712 : {
713 8 : if (pasFieldDesc[i].nItems > 1)
714 : {
715 4 : double *padfValues = (double *)CPLMalloc(
716 2 : sizeof(double) * pasFieldDesc[i].nItems);
717 12 : for (int j = 0; j < pasFieldDesc[i].nItems; j++)
718 : {
719 10 : double dfVal = 0.0;
720 10 : memcpy(&dfVal,
721 10 : pabyRecord + pasFieldDesc[i].nStartByte + 8 * j,
722 : 8);
723 10 : CPL_MSBPTR64(&dfVal);
724 10 : padfValues[j] = dfVal;
725 : }
726 2 : poFeature->SetField(i, pasFieldDesc[i].nItems, padfValues);
727 2 : CPLFree(padfValues);
728 : }
729 : else
730 : {
731 6 : double dfVal = 0.0;
732 6 : memcpy(&dfVal, pabyRecord + pasFieldDesc[i].nStartByte, 8);
733 6 : CPL_MSBPTR64(&dfVal);
734 6 : poFeature->SetField(i, dfVal);
735 : }
736 : }
737 : }
738 : }
739 : else
740 : {
741 0 : char **papszTokens = CSLTokenizeString2((const char *)pabyRecord, " ",
742 : CSLT_HONOURSTRINGS);
743 0 : const int nTokens = std::min(CSLCount(papszTokens), nFieldCount);
744 0 : for (int i = 0; i < nTokens; i++)
745 : {
746 0 : poFeature->SetField(i, papszTokens[i]);
747 : }
748 0 : CSLDestroy(papszTokens);
749 : }
750 :
751 3 : if (nLongitudeIndex >= 0 && nLatitudeIndex >= 0)
752 2 : poFeature->SetGeometryDirectly(
753 2 : new OGRPoint(poFeature->GetFieldAsDouble(nLongitudeIndex),
754 2 : poFeature->GetFieldAsDouble(nLatitudeIndex)));
755 :
756 3 : poFeature->SetFID(nNextFID++);
757 :
758 3 : return poFeature;
759 : }
760 :
761 : /************************************************************************/
762 : /* TestCapability() */
763 : /************************************************************************/
764 :
765 1 : int OGRPDSLayer::TestCapability(const char *pszCap)
766 :
767 : {
768 1 : if (EQUAL(pszCap, OLCFastFeatureCount) && m_poFilterGeom == nullptr &&
769 1 : m_poAttrQuery == nullptr)
770 1 : return TRUE;
771 :
772 0 : if (EQUAL(pszCap, OLCRandomRead))
773 0 : return TRUE;
774 :
775 0 : if (EQUAL(pszCap, OLCFastSetNextByIndex) && m_poFilterGeom == nullptr &&
776 0 : m_poAttrQuery == nullptr)
777 0 : return TRUE;
778 :
779 0 : return FALSE;
780 : }
781 :
782 : /************************************************************************/
783 : /* GetFeatureCount() */
784 : /************************************************************************/
785 :
786 1 : GIntBig OGRPDSLayer::GetFeatureCount(int bForce)
787 : {
788 1 : if (TestCapability(OLCFastFeatureCount))
789 1 : return nRecords;
790 :
791 0 : return OGRLayer::GetFeatureCount(bForce);
792 : }
793 :
794 : /************************************************************************/
795 : /* GetFeature() */
796 : /************************************************************************/
797 :
798 1 : OGRFeature *OGRPDSLayer::GetFeature(GIntBig nFID)
799 : {
800 1 : if (nFID < 0 || nFID >= nRecords)
801 0 : return nullptr;
802 :
803 1 : nNextFID = (int)nFID;
804 1 : VSIFSeekL(fpPDS, nStartBytes + nNextFID * nRecordSize, SEEK_SET);
805 1 : return GetNextRawFeature();
806 : }
807 :
808 : /************************************************************************/
809 : /* SetNextByIndex() */
810 : /************************************************************************/
811 :
812 0 : OGRErr OGRPDSLayer::SetNextByIndex(GIntBig nIndex)
813 : {
814 0 : if (!TestCapability(OLCFastSetNextByIndex))
815 0 : return OGRLayer::SetNextByIndex(nIndex);
816 :
817 0 : if (nIndex < 0 || nIndex >= nRecords)
818 0 : return OGRERR_FAILURE;
819 :
820 0 : nNextFID = (int)nIndex;
821 0 : VSIFSeekL(fpPDS, nStartBytes + nNextFID * nRecordSize, SEEK_SET);
822 0 : return OGRERR_NONE;
823 : }
824 :
825 : } // namespace OGRPDS
|