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