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 58 : void OGRXLSLayer::ResetReading()
49 :
50 : {
51 58 : if (poFeatureDefn != nullptr)
52 : {
53 58 : nNextFID = bFirstLineIsHeaders ? 1 : 0;
54 : }
55 58 : }
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 265 : OGRFeatureDefn *OGRXLSLayer::GetLayerDefn()
173 : {
174 265 : if (poFeatureDefn)
175 262 : 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 : 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 : DetectColumnTypes(xlshandle, paeFieldTypes);
204 :
205 18 : for (unsigned short i = 0; i < nCols; i++)
206 : {
207 15 : OGRFieldType eType = (OGRFieldType)paeFieldTypes[i];
208 15 : if (paeFieldTypes[i] < 0)
209 5 : eType = OFTString;
210 45 : if (bFirstLineIsHeaders &&
211 15 : freexl_get_cell_value(xlshandle, 0, i, &sCellValue) ==
212 30 : FREEXL_OK &&
213 15 : (sCellValue.type == FREEXL_CELL_TEXT ||
214 15 : sCellValue.type == FREEXL_CELL_SST_TEXT))
215 : {
216 30 : OGRFieldDefn oField(sCellValue.value.text_value, eType);
217 15 : poFeatureDefn->AddFieldDefn(&oField);
218 : }
219 : else
220 : {
221 0 : OGRFieldDefn oField(CPLSPrintf("Field%d", i + 1), eType);
222 0 : poFeatureDefn->AddFieldDefn(&oField);
223 : }
224 : }
225 :
226 3 : CPLFree(paeFieldTypes);
227 : }
228 :
229 3 : ResetReading();
230 :
231 3 : return poFeatureDefn;
232 : }
233 :
234 : /************************************************************************/
235 : /* GetFeatureCount() */
236 : /************************************************************************/
237 :
238 13 : GIntBig OGRXLSLayer::GetFeatureCount(int bForce)
239 : {
240 13 : if (m_poAttrQuery == nullptr /* && m_poFilterGeom == NULL */)
241 : {
242 11 : const char *pszXLSHeaders = CPLGetConfigOption("OGR_XLS_HEADERS", "");
243 11 : if (EQUAL(pszXLSHeaders, "DISABLE"))
244 1 : return nRows;
245 :
246 10 : GetLayerDefn();
247 10 : return bFirstLineIsHeaders ? nRows - 1 : nRows;
248 : }
249 :
250 2 : return OGRLayer::GetFeatureCount(bForce);
251 : }
252 :
253 : /************************************************************************/
254 : /* GetNextRawFeature() */
255 : /************************************************************************/
256 :
257 79 : OGRFeature *OGRXLSLayer::GetNextRawFeature()
258 : {
259 79 : GetLayerDefn();
260 :
261 79 : if (nNextFID == nRows)
262 18 : return nullptr;
263 :
264 61 : const void *xlshandle = poDS->GetXLSHandle();
265 61 : if (xlshandle == nullptr)
266 0 : return nullptr;
267 :
268 61 : freexl_select_active_worksheet(xlshandle, (unsigned short)iSheet);
269 :
270 61 : OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
271 :
272 : FreeXL_CellValue sCellValue;
273 366 : for (unsigned short i = 0;
274 366 : i < (unsigned short)poFeatureDefn->GetFieldCount(); i++)
275 : {
276 305 : if (freexl_get_cell_value(xlshandle, nNextFID, i, &sCellValue) ==
277 : FREEXL_OK)
278 : {
279 305 : switch (sCellValue.type)
280 : {
281 88 : case FREEXL_CELL_INT:
282 88 : poFeature->SetField(i, sCellValue.value.int_value);
283 88 : break;
284 17 : case FREEXL_CELL_DOUBLE:
285 17 : poFeature->SetField(i, sCellValue.value.double_value);
286 17 : break;
287 34 : case FREEXL_CELL_TEXT:
288 : case FREEXL_CELL_SST_TEXT:
289 34 : poFeature->SetField(i, sCellValue.value.text_value);
290 34 : break;
291 105 : case FREEXL_CELL_DATE:
292 : case FREEXL_CELL_DATETIME:
293 : case FREEXL_CELL_TIME:
294 105 : poFeature->SetField(i, sCellValue.value.text_value);
295 105 : break;
296 61 : case FREEXL_CELL_NULL:
297 61 : break;
298 0 : default:
299 0 : CPLDebug("XLS", "Unknown cell type = %d", sCellValue.type);
300 0 : break;
301 : }
302 : }
303 : }
304 :
305 61 : poFeature->SetFID(nNextFID + 1);
306 61 : nNextFID++;
307 :
308 61 : return poFeature;
309 : }
310 :
311 : /************************************************************************/
312 : /* TestCapability() */
313 : /************************************************************************/
314 :
315 32 : int OGRXLSLayer::TestCapability(const char *pszCap)
316 :
317 : {
318 32 : if (EQUAL(pszCap, OLCFastFeatureCount))
319 0 : return m_poAttrQuery == nullptr /* && m_poFilterGeom == NULL */;
320 32 : else if (EQUAL(pszCap, OLCStringsAsUTF8))
321 10 : return TRUE;
322 :
323 22 : return FALSE;
324 : }
325 :
326 : /************************************************************************/
327 : /* GetDataset() */
328 : /************************************************************************/
329 :
330 1 : GDALDataset *OGRXLSLayer::GetDataset()
331 : {
332 1 : return poDS;
333 : }
|