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