Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: XLS Translator
4 : * Purpose: Implements OGRXLSLayer class.
5 : * Author: Even Rouault, <even dot rouault at spatialys.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2011-2012, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "include_freexl.h"
14 :
15 : #include "ogr_xls.h"
16 : #include "cpl_conv.h"
17 : #include "cpl_string.h"
18 :
19 : /************************************************************************/
20 : /* OGRXLSLayer() */
21 : /************************************************************************/
22 :
23 4 : OGRXLSLayer::OGRXLSLayer(OGRXLSDataSource *poDSIn, const char *pszSheetname,
24 4 : int iSheetIn, int nRowsIn, unsigned short nColsIn)
25 8 : : poDS(poDSIn), poFeatureDefn(nullptr), pszName(CPLStrdup(pszSheetname)),
26 : iSheet(iSheetIn), bFirstLineIsHeaders(false), nRows(nRowsIn),
27 4 : nCols(nColsIn), nNextFID(0)
28 : {
29 4 : SetDescription(pszName);
30 4 : }
31 :
32 : /************************************************************************/
33 : /* ~OGRXLSLayer() */
34 : /************************************************************************/
35 :
36 8 : OGRXLSLayer::~OGRXLSLayer()
37 :
38 : {
39 4 : CPLFree(pszName);
40 4 : if (poFeatureDefn)
41 3 : poFeatureDefn->Release();
42 8 : }
43 :
44 : /************************************************************************/
45 : /* ResetReading() */
46 : /************************************************************************/
47 :
48 60 : void OGRXLSLayer::ResetReading()
49 :
50 : {
51 60 : if (poFeatureDefn != nullptr)
52 : {
53 60 : nNextFID = bFirstLineIsHeaders ? 1 : 0;
54 : }
55 60 : }
56 :
57 : /************************************************************************/
58 : /* DetectHeaderLine() */
59 : /************************************************************************/
60 :
61 3 : void OGRXLSLayer::DetectHeaderLine(const void *xlshandle)
62 :
63 : {
64 : FreeXL_CellValue sCellValue;
65 3 : int nCountTextOnSecondLine = 0;
66 3 : unsigned short i = 0; // Used after for.
67 18 : for (; i < nCols && nRows >= 2; i++)
68 : {
69 15 : if (freexl_get_cell_value(xlshandle, 0, i, &sCellValue) == FREEXL_OK)
70 : {
71 15 : if (sCellValue.type != FREEXL_CELL_TEXT &&
72 15 : sCellValue.type != FREEXL_CELL_SST_TEXT)
73 : {
74 : /* If the values in the first line are not text, then it is */
75 : /* not a header line */
76 0 : break;
77 : }
78 : }
79 15 : if (freexl_get_cell_value(xlshandle, 1, i, &sCellValue) == FREEXL_OK)
80 : {
81 15 : if (sCellValue.type == FREEXL_CELL_TEXT ||
82 15 : sCellValue.type == FREEXL_CELL_SST_TEXT)
83 : {
84 : /* If there are only text values on the second line, then we
85 : * cannot */
86 : /* know if it is a header line or just a regular line */
87 0 : nCountTextOnSecondLine++;
88 : }
89 : }
90 : }
91 :
92 3 : const char *pszXLSHeaders = CPLGetConfigOption("OGR_XLS_HEADERS", "");
93 3 : if (EQUAL(pszXLSHeaders, "FORCE"))
94 0 : bFirstLineIsHeaders = true;
95 3 : else if (EQUAL(pszXLSHeaders, "DISABLE"))
96 0 : bFirstLineIsHeaders = false;
97 3 : else if (i == nCols && nCountTextOnSecondLine != nCols)
98 3 : bFirstLineIsHeaders = true;
99 3 : }
100 :
101 : /************************************************************************/
102 : /* DetectColumnTypes() */
103 : /************************************************************************/
104 :
105 2 : void OGRXLSLayer::DetectColumnTypes(const void *xlshandle, int *paeFieldTypes)
106 :
107 : {
108 : FreeXL_CellValue sCellValue;
109 8 : for (int j = bFirstLineIsHeaders ? 1 : 0; j < nRows; j++)
110 : {
111 36 : for (unsigned short i = 0; i < nCols; i++)
112 : {
113 30 : if (freexl_get_cell_value(xlshandle, j, i, &sCellValue) ==
114 : FREEXL_OK)
115 : {
116 30 : int eType = paeFieldTypes[i];
117 30 : switch (sCellValue.type)
118 : {
119 8 : case FREEXL_CELL_INT:
120 8 : eType = OFTInteger;
121 8 : break;
122 2 : case FREEXL_CELL_DOUBLE:
123 2 : eType = OFTReal;
124 2 : break;
125 4 : case FREEXL_CELL_TEXT:
126 : case FREEXL_CELL_SST_TEXT:
127 4 : eType = OFTString;
128 4 : break;
129 6 : case FREEXL_CELL_DATE:
130 6 : eType = OFTDate;
131 6 : break;
132 2 : case FREEXL_CELL_DATETIME:
133 2 : eType = OFTDateTime;
134 2 : break;
135 2 : case FREEXL_CELL_TIME:
136 2 : eType = OFTTime;
137 2 : break;
138 6 : case FREEXL_CELL_NULL:
139 6 : break;
140 0 : default:
141 0 : break;
142 : }
143 :
144 30 : if (paeFieldTypes[i] < 0)
145 : {
146 12 : paeFieldTypes[i] = eType;
147 : }
148 18 : else if (eType != paeFieldTypes[i])
149 : {
150 8 : if ((paeFieldTypes[i] == OFTDate ||
151 6 : paeFieldTypes[i] == OFTTime ||
152 8 : paeFieldTypes[i] == OFTDateTime) &&
153 4 : (eType == OFTDate || eType == OFTTime ||
154 : eType == OFTDateTime))
155 4 : paeFieldTypes[i] = OFTDateTime;
156 4 : else if (paeFieldTypes[i] == OFTReal && eType == OFTInteger)
157 : /* nothing */;
158 2 : else if (paeFieldTypes[i] == OFTInteger && eType == OFTReal)
159 2 : paeFieldTypes[i] = OFTReal;
160 : else
161 0 : paeFieldTypes[i] = OFTString;
162 : }
163 : }
164 : }
165 : }
166 2 : }
167 :
168 : /************************************************************************/
169 : /* GetLayerDefn() */
170 : /************************************************************************/
171 :
172 272 : const OGRFeatureDefn *OGRXLSLayer::GetLayerDefn() const
173 : {
174 272 : if (poFeatureDefn)
175 269 : return poFeatureDefn;
176 :
177 3 : poFeatureDefn = new OGRFeatureDefn(pszName);
178 3 : poFeatureDefn->Reference();
179 3 : poFeatureDefn->SetGeomType(wkbNone);
180 :
181 3 : const void *xlshandle = poDS->GetXLSHandle();
182 3 : if (xlshandle == nullptr)
183 0 : return poFeatureDefn;
184 :
185 3 : freexl_select_active_worksheet(xlshandle, (unsigned short)iSheet);
186 :
187 3 : if (nRows > 0)
188 : {
189 :
190 : FreeXL_CellValue sCellValue;
191 :
192 3 : const_cast<OGRXLSLayer *>(this)->DetectHeaderLine(xlshandle);
193 :
194 3 : int *paeFieldTypes = (int *)CPLMalloc(nCols * sizeof(int));
195 18 : for (unsigned short i = 0; i < nCols; i++)
196 : {
197 15 : paeFieldTypes[i] = -1;
198 : }
199 :
200 : const char *pszXLSFieldTypes =
201 3 : CPLGetConfigOption("OGR_XLS_FIELD_TYPES", "");
202 3 : if (!EQUAL(pszXLSFieldTypes, "STRING"))
203 2 : const_cast<OGRXLSLayer *>(this)->DetectColumnTypes(xlshandle,
204 : paeFieldTypes);
205 :
206 18 : for (unsigned short i = 0; i < nCols; i++)
207 : {
208 15 : OGRFieldType eType = (OGRFieldType)paeFieldTypes[i];
209 15 : if (paeFieldTypes[i] < 0)
210 5 : eType = OFTString;
211 45 : if (bFirstLineIsHeaders &&
212 15 : freexl_get_cell_value(xlshandle, 0, i, &sCellValue) ==
213 30 : FREEXL_OK &&
214 15 : (sCellValue.type == FREEXL_CELL_TEXT ||
215 15 : sCellValue.type == FREEXL_CELL_SST_TEXT))
216 : {
217 30 : OGRFieldDefn oField(sCellValue.value.text_value, eType);
218 15 : poFeatureDefn->AddFieldDefn(&oField);
219 : }
220 : else
221 : {
222 0 : OGRFieldDefn oField(CPLSPrintf("Field%d", i + 1), eType);
223 0 : poFeatureDefn->AddFieldDefn(&oField);
224 : }
225 : }
226 :
227 3 : CPLFree(paeFieldTypes);
228 : }
229 :
230 3 : const_cast<OGRXLSLayer *>(this)->ResetReading();
231 :
232 3 : return poFeatureDefn;
233 : }
234 :
235 : /************************************************************************/
236 : /* GetFeatureCount() */
237 : /************************************************************************/
238 :
239 13 : GIntBig OGRXLSLayer::GetFeatureCount(int bForce)
240 : {
241 13 : if (m_poAttrQuery == nullptr /* && m_poFilterGeom == NULL */)
242 : {
243 11 : const char *pszXLSHeaders = CPLGetConfigOption("OGR_XLS_HEADERS", "");
244 11 : if (EQUAL(pszXLSHeaders, "DISABLE"))
245 1 : return nRows;
246 :
247 10 : GetLayerDefn();
248 10 : return bFirstLineIsHeaders ? nRows - 1 : nRows;
249 : }
250 :
251 2 : return OGRLayer::GetFeatureCount(bForce);
252 : }
253 :
254 : /************************************************************************/
255 : /* GetNextRawFeature() */
256 : /************************************************************************/
257 :
258 86 : OGRFeature *OGRXLSLayer::GetNextRawFeature()
259 : {
260 86 : GetLayerDefn();
261 :
262 86 : if (nNextFID == nRows)
263 21 : return nullptr;
264 :
265 65 : const void *xlshandle = poDS->GetXLSHandle();
266 65 : if (xlshandle == nullptr)
267 0 : return nullptr;
268 :
269 65 : freexl_select_active_worksheet(xlshandle, (unsigned short)iSheet);
270 :
271 65 : OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
272 :
273 : FreeXL_CellValue sCellValue;
274 390 : for (unsigned short i = 0;
275 390 : i < (unsigned short)poFeatureDefn->GetFieldCount(); i++)
276 : {
277 325 : if (freexl_get_cell_value(xlshandle, nNextFID, i, &sCellValue) ==
278 : FREEXL_OK)
279 : {
280 325 : switch (sCellValue.type)
281 : {
282 94 : case FREEXL_CELL_INT:
283 94 : poFeature->SetField(i, sCellValue.value.int_value);
284 94 : break;
285 18 : case FREEXL_CELL_DOUBLE:
286 18 : poFeature->SetField(i, sCellValue.value.double_value);
287 18 : break;
288 36 : case FREEXL_CELL_TEXT:
289 : case FREEXL_CELL_SST_TEXT:
290 36 : poFeature->SetField(i, sCellValue.value.text_value);
291 36 : break;
292 112 : case FREEXL_CELL_DATE:
293 : case FREEXL_CELL_DATETIME:
294 : case FREEXL_CELL_TIME:
295 112 : poFeature->SetField(i, sCellValue.value.text_value);
296 112 : break;
297 65 : case FREEXL_CELL_NULL:
298 65 : break;
299 0 : default:
300 0 : CPLDebug("XLS", "Unknown cell type = %d", sCellValue.type);
301 0 : break;
302 : }
303 : }
304 : }
305 :
306 65 : poFeature->SetFID(nNextFID + 1);
307 65 : nNextFID++;
308 :
309 65 : return poFeature;
310 : }
311 :
312 : /************************************************************************/
313 : /* TestCapability() */
314 : /************************************************************************/
315 :
316 33 : int OGRXLSLayer::TestCapability(const char *pszCap) const
317 :
318 : {
319 33 : if (EQUAL(pszCap, OLCFastFeatureCount))
320 0 : return m_poAttrQuery == nullptr /* && m_poFilterGeom == NULL */;
321 33 : else if (EQUAL(pszCap, OLCStringsAsUTF8))
322 10 : return TRUE;
323 :
324 23 : return FALSE;
325 : }
326 :
327 : /************************************************************************/
328 : /* GetDataset() */
329 : /************************************************************************/
330 :
331 1 : GDALDataset *OGRXLSLayer::GetDataset()
332 : {
333 1 : return poDS;
334 : }
|