1 : /******************************************************************************
2 : * $Id: ogrodsdatasource.cpp 24173 2012-03-29 21:09:52Z rouault $
3 : *
4 : * Project: ODS Translator
5 : * Purpose: Implements OGRODSDataSource class
6 : * Author: Even Rouault, even dot rouault at mines dash paris dot org
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2012, Even Rouault <even dot rouault at mines dash paris dot org>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "ogr_ods.h"
31 : #include "ogr_mem.h"
32 : #include "ogr_p.h"
33 : #include "cpl_conv.h"
34 : #include "ods_formula.h"
35 : #include <set>
36 :
37 : CPL_CVSID("$Id: ogrodsdatasource.cpp 24173 2012-03-29 21:09:52Z rouault $");
38 :
39 :
40 : /************************************************************************/
41 : /* ODSCellEvaluator */
42 : /************************************************************************/
43 :
44 : class ODSCellEvaluator : public IODSCellEvaluator
45 220 : {
46 : private:
47 : OGRODSLayer* poLayer;
48 : std::set<std::pair<int,int> > oVisisitedCells;
49 :
50 : public:
51 220 : ODSCellEvaluator(OGRODSLayer* poLayerIn) : poLayer(poLayerIn) {}
52 :
53 : int EvaluateRange(int nRow1, int nCol1, int nRow2, int nCol2,
54 : std::vector<ods_formula_node>& aoOutValues);
55 :
56 : int Evaluate(int nRow, int nCol);
57 : };
58 :
59 : /************************************************************************/
60 : /* OGRODSLayer() */
61 : /************************************************************************/
62 :
63 230 : OGRODSLayer::OGRODSLayer( OGRODSDataSource* poDSIn,
64 : const char * pszName,
65 : int bUpdatedIn) :
66 230 : OGRMemLayer(pszName, NULL, wkbNone)
67 : {
68 230 : poDS = poDSIn;
69 230 : bUpdated = bUpdatedIn;
70 230 : bHasHeaderLine = FALSE;
71 230 : }
72 :
73 : /************************************************************************/
74 : /* Updated() */
75 : /************************************************************************/
76 :
77 3616 : void OGRODSLayer::SetUpdated(int bUpdatedIn)
78 : {
79 3616 : if (bUpdatedIn && !bUpdated && poDS->GetUpdatable())
80 : {
81 18 : bUpdated = TRUE;
82 18 : poDS->SetUpdated();
83 : }
84 3598 : else if (bUpdated && !bUpdatedIn)
85 : {
86 34 : bUpdated = FALSE;
87 : }
88 3616 : }
89 :
90 : /************************************************************************/
91 : /* SyncToDisk() */
92 : /************************************************************************/
93 :
94 0 : OGRErr OGRODSLayer::SyncToDisk()
95 : {
96 0 : return poDS->SyncToDisk();
97 : }
98 :
99 : /************************************************************************/
100 : /* GetNextFeature() */
101 : /************************************************************************/
102 :
103 2060 : OGRFeature* OGRODSLayer::GetNextFeature()
104 : {
105 2060 : OGRFeature* poFeature = OGRMemLayer::GetNextFeature();
106 2060 : if (poFeature)
107 1748 : poFeature->SetFID(poFeature->GetFID() + 1 + bHasHeaderLine);
108 2060 : return poFeature;
109 : }
110 :
111 : /************************************************************************/
112 : /* GetFeature() */
113 : /************************************************************************/
114 :
115 4 : OGRFeature* OGRODSLayer::GetFeature( long nFeatureId )
116 : {
117 4 : OGRFeature* poFeature = OGRMemLayer::GetFeature(nFeatureId - (1 + bHasHeaderLine));
118 4 : if (poFeature)
119 4 : poFeature->SetFID(nFeatureId);
120 4 : return poFeature;
121 : }
122 :
123 : /************************************************************************/
124 : /* SetFeature() */
125 : /************************************************************************/
126 :
127 1142 : OGRErr OGRODSLayer::SetFeature( OGRFeature *poFeature )
128 : {
129 1142 : if (poFeature == NULL)
130 0 : return OGRMemLayer::SetFeature(poFeature);
131 :
132 1142 : long nFID = poFeature->GetFID();
133 1142 : if (nFID != OGRNullFID)
134 2 : poFeature->SetFID(nFID - (1 + bHasHeaderLine));
135 1142 : SetUpdated();
136 1142 : OGRErr eErr = OGRMemLayer::SetFeature(poFeature);
137 1142 : poFeature->SetFID(nFID);
138 1142 : return eErr;
139 : }
140 :
141 : /************************************************************************/
142 : /* DeleteFeature() */
143 : /************************************************************************/
144 :
145 0 : OGRErr OGRODSLayer::DeleteFeature( long nFID )
146 : {
147 0 : SetUpdated();
148 0 : return OGRMemLayer::DeleteFeature(nFID - (1 + bHasHeaderLine));
149 : }
150 :
151 : /************************************************************************/
152 : /* OGRODSDataSource() */
153 : /************************************************************************/
154 :
155 28 : OGRODSDataSource::OGRODSDataSource()
156 :
157 : {
158 28 : pszName = NULL;
159 28 : fpContent = NULL;
160 28 : fpSettings = NULL;
161 28 : bUpdatable = FALSE;
162 28 : bUpdated = FALSE;
163 28 : bAnalysedFile = FALSE;
164 :
165 28 : nLayers = 0;
166 28 : papoLayers = NULL;
167 :
168 28 : bFirstLineIsHeaders = FALSE;
169 :
170 28 : oParser = NULL;
171 28 : bStopParsing = FALSE;
172 28 : nWithoutEventCounter = 0;
173 28 : nDataHandlerCounter = 0;
174 28 : nStackDepth = 0;
175 28 : nDepth = 0;
176 28 : nCurLine = 0;
177 28 : nEmptyRowsAccumulated = 0;
178 28 : nCurCol = 0;
179 28 : nRowsRepeated = 0;
180 28 : nCellsRepeated = 0;
181 28 : stateStack[0].eVal = STATE_DEFAULT;
182 28 : stateStack[0].nBeginDepth = 0;
183 28 : bEndTableParsing = FALSE;
184 :
185 28 : poCurLayer = NULL;
186 :
187 : const char* pszODSFieldTypes =
188 28 : CPLGetConfigOption("OGR_ODS_FIELD_TYPES", "");
189 28 : bAutodetectTypes = !EQUAL(pszODSFieldTypes, "STRING");
190 28 : }
191 :
192 : /************************************************************************/
193 : /* ~OGRODSDataSource() */
194 : /************************************************************************/
195 :
196 28 : OGRODSDataSource::~OGRODSDataSource()
197 :
198 : {
199 28 : SyncToDisk();
200 :
201 28 : CPLFree( pszName );
202 :
203 28 : if (fpContent)
204 0 : VSIFCloseL(fpContent);
205 28 : if (fpSettings)
206 0 : VSIFCloseL(fpSettings);
207 :
208 238 : for(int i=0;i<nLayers;i++)
209 210 : delete papoLayers[i];
210 28 : CPLFree( papoLayers );
211 28 : }
212 :
213 : /************************************************************************/
214 : /* TestCapability() */
215 : /************************************************************************/
216 :
217 22 : int OGRODSDataSource::TestCapability( const char * pszCap )
218 :
219 : {
220 22 : if( EQUAL(pszCap,ODsCCreateLayer) )
221 16 : return bUpdatable;
222 6 : else if( EQUAL(pszCap,ODsCDeleteLayer) )
223 0 : return bUpdatable;
224 : else
225 6 : return FALSE;
226 : }
227 :
228 :
229 : /************************************************************************/
230 : /* GetLayer() */
231 : /************************************************************************/
232 :
233 510 : OGRLayer *OGRODSDataSource::GetLayer( int iLayer )
234 :
235 : {
236 510 : AnalyseFile();
237 510 : if (iLayer < 0 || iLayer >= nLayers)
238 0 : return NULL;
239 :
240 510 : return papoLayers[iLayer];
241 : }
242 :
243 : /************************************************************************/
244 : /* GetLayerCount() */
245 : /************************************************************************/
246 :
247 448 : int OGRODSDataSource::GetLayerCount()
248 : {
249 448 : AnalyseFile();
250 448 : return nLayers;
251 : }
252 :
253 : /************************************************************************/
254 : /* Open() */
255 : /************************************************************************/
256 :
257 26 : int OGRODSDataSource::Open( const char * pszFilename,
258 : VSILFILE* fpContentIn,
259 : VSILFILE* fpSettingsIn,
260 : int bUpdatableIn)
261 :
262 : {
263 26 : bUpdatable = bUpdatableIn;
264 :
265 26 : pszName = CPLStrdup( pszFilename );
266 26 : fpContent = fpContentIn;
267 26 : fpSettings = fpSettingsIn;
268 :
269 26 : return TRUE;
270 : }
271 :
272 : /************************************************************************/
273 : /* Create() */
274 : /************************************************************************/
275 :
276 2 : int OGRODSDataSource::Create( const char * pszFilename, char **papszOptions )
277 : {
278 2 : bUpdated = TRUE;
279 2 : bUpdatable = TRUE;
280 2 : bAnalysedFile = TRUE;
281 :
282 2 : pszName = CPLStrdup( pszFilename );
283 :
284 2 : return TRUE;
285 : }
286 :
287 : /************************************************************************/
288 : /* startElementCbk() */
289 : /************************************************************************/
290 :
291 7566 : static void XMLCALL startElementCbk(void *pUserData, const char *pszName,
292 : const char **ppszAttr)
293 : {
294 7566 : ((OGRODSDataSource*)pUserData)->startElementCbk(pszName, ppszAttr);
295 7566 : }
296 :
297 7566 : void OGRODSDataSource::startElementCbk(const char *pszName,
298 : const char **ppszAttr)
299 : {
300 7566 : if (bStopParsing) return;
301 :
302 7566 : nWithoutEventCounter = 0;
303 7566 : switch(stateStack[nStackDepth].eVal)
304 : {
305 1590 : case STATE_DEFAULT: startElementDefault(pszName, ppszAttr); break;
306 1304 : case STATE_TABLE: startElementTable(pszName, ppszAttr); break;
307 3122 : case STATE_ROW: startElementRow(pszName, ppszAttr); break;
308 1550 : case STATE_CELL: startElementCell(pszName, ppszAttr); break;
309 : case STATE_TEXTP: break;
310 : default: break;
311 : }
312 7566 : nDepth++;
313 : }
314 :
315 : /************************************************************************/
316 : /* endElementCbk() */
317 : /************************************************************************/
318 :
319 7566 : static void XMLCALL endElementCbk(void *pUserData, const char *pszName)
320 : {
321 7566 : ((OGRODSDataSource*)pUserData)->endElementCbk(pszName);
322 7566 : }
323 :
324 7566 : void OGRODSDataSource::endElementCbk(const char *pszName)
325 : {
326 7566 : if (bStopParsing) return;
327 :
328 7566 : nWithoutEventCounter = 0;
329 :
330 7566 : nDepth--;
331 7566 : switch(stateStack[nStackDepth].eVal)
332 : {
333 1376 : case STATE_DEFAULT: break;
334 622 : case STATE_TABLE: endElementTable(pszName); break;
335 958 : case STATE_ROW: endElementRow(pszName); break;
336 3774 : case STATE_CELL: endElementCell(pszName); break;
337 : case STATE_TEXTP: break;
338 : default: break;
339 : }
340 :
341 7566 : if (stateStack[nStackDepth].nBeginDepth == nDepth)
342 5032 : nStackDepth --;
343 : }
344 :
345 : /************************************************************************/
346 : /* dataHandlerCbk() */
347 : /************************************************************************/
348 :
349 5706 : static void XMLCALL dataHandlerCbk(void *pUserData, const char *data, int nLen)
350 : {
351 5706 : ((OGRODSDataSource*)pUserData)->dataHandlerCbk(data, nLen);
352 5706 : }
353 :
354 5706 : void OGRODSDataSource::dataHandlerCbk(const char *data, int nLen)
355 : {
356 5706 : if (bStopParsing) return;
357 :
358 5706 : nDataHandlerCounter ++;
359 5706 : if (nDataHandlerCounter >= BUFSIZ)
360 : {
361 : CPLError(CE_Failure, CPLE_AppDefined,
362 0 : "File probably corrupted (million laugh pattern)");
363 0 : XML_StopParser(oParser, XML_FALSE);
364 0 : bStopParsing = TRUE;
365 0 : return;
366 : }
367 :
368 5706 : nWithoutEventCounter = 0;
369 :
370 5706 : switch(stateStack[nStackDepth].eVal)
371 : {
372 612 : case STATE_DEFAULT: break;
373 578 : case STATE_TABLE: break;
374 2014 : case STATE_ROW: break;
375 1594 : case STATE_CELL: break;
376 908 : case STATE_TEXTP: dataHandlerTextP(data, nLen);
377 : default: break;
378 : }
379 : }
380 :
381 : /************************************************************************/
382 : /* PushState() */
383 : /************************************************************************/
384 :
385 5006 : void OGRODSDataSource::PushState(HandlerStateEnum eVal)
386 : {
387 5006 : if (nStackDepth + 1 == STACK_SIZE)
388 : {
389 0 : bStopParsing = TRUE;
390 0 : return;
391 : }
392 5006 : nStackDepth ++;
393 5006 : stateStack[nStackDepth].eVal = eVal;
394 5006 : stateStack[nStackDepth].nBeginDepth = nDepth;
395 : }
396 :
397 : /************************************************************************/
398 : /* GetAttributeValue() */
399 : /************************************************************************/
400 :
401 20988 : static const char* GetAttributeValue(const char **ppszAttr,
402 : const char* pszKey,
403 : const char* pszDefaultVal)
404 : {
405 56402 : while(*ppszAttr)
406 : {
407 20626 : if (strcmp(ppszAttr[0], pszKey) == 0)
408 6200 : return ppszAttr[1];
409 14426 : ppszAttr += 2;
410 : }
411 14788 : return pszDefaultVal;
412 : }
413 :
414 : /************************************************************************/
415 : /* GetOGRFieldType() */
416 : /************************************************************************/
417 :
418 2058 : OGRFieldType OGRODSDataSource::GetOGRFieldType(const char* pszValue,
419 : const char* pszValueType)
420 : {
421 2058 : if (!bAutodetectTypes || pszValueType == NULL)
422 60 : return OFTString;
423 1998 : else if (strcmp(pszValueType, "string") == 0)
424 666 : return OFTString;
425 1332 : else if (strcmp(pszValueType, "float") == 0 ||
426 : strcmp(pszValueType, "currency") == 0)
427 : {
428 680 : if (CPLGetValueType(pszValue) == CPL_VALUE_INTEGER)
429 482 : return OFTInteger;
430 : else
431 198 : return OFTReal;
432 : }
433 652 : else if (strcmp(pszValueType, "percentage") == 0)
434 70 : return OFTReal;
435 582 : else if (strcmp(pszValueType, "date") == 0)
436 : {
437 210 : if (strlen(pszValue) == 4 + 1 + 2 + 1 + 2)
438 104 : return OFTDate;
439 : else
440 106 : return OFTDateTime;
441 : }
442 372 : else if (strcmp(pszValueType, "time") == 0)
443 : {
444 42 : return OFTTime;
445 : }
446 : else
447 330 : return OFTString;
448 : }
449 :
450 : /************************************************************************/
451 : /* SetField() */
452 : /************************************************************************/
453 :
454 2024 : static void SetField(OGRFeature* poFeature,
455 : int i,
456 : const char* pszValue)
457 : {
458 2024 : if (pszValue[0] == '\0')
459 436 : return;
460 :
461 1588 : OGRFieldType eType = poFeature->GetFieldDefnRef(i)->GetType();
462 1588 : if (eType == OFTTime)
463 : {
464 : int nHour, nHourRepeated, nMinute, nSecond;
465 : char c;
466 20 : if (strncmp(pszValue, "PT", 2) == 0 &&
467 : sscanf(pszValue + 2, "%02d%c%02d%c%02d%c",
468 : &nHour, &c, &nMinute, &c, &nSecond, &c) == 6)
469 : {
470 18 : poFeature->SetField(i, 0, 0, 0, nHour, nMinute, nSecond, 0);
471 : }
472 : /* bug with kspread 2.1.2 ? */
473 : /* ex PT121234M56S */
474 2 : else if (strncmp(pszValue, "PT", 2) == 0 &&
475 : sscanf(pszValue + 2, "%02d%02d%02d%c%02d%c",
476 : &nHour, &nHourRepeated, &nMinute, &c, &nSecond, &c) == 6 &&
477 : nHour == nHourRepeated)
478 : {
479 2 : poFeature->SetField(i, 0, 0, 0, nHour, nMinute, nSecond, 0);
480 : }
481 : }
482 1678 : else if (eType == OFTDate || eType == OFTDateTime)
483 : {
484 : int nYear, nMonth, nDay, nHour, nMinute, nTZ;
485 : float fCur;
486 110 : if (OGRParseXMLDateTime( pszValue,
487 : &nYear, &nMonth, &nDay,
488 : &nHour, &nMinute, &fCur, &nTZ) )
489 : {
490 : poFeature->SetField(i, nYear, nMonth, nDay,
491 110 : nHour, nMinute, (int)fCur, nTZ);
492 : }
493 : }
494 : else
495 1458 : poFeature->SetField(i, pszValue);
496 : }
497 :
498 : /************************************************************************/
499 : /* DetectHeaderLine() */
500 : /************************************************************************/
501 :
502 150 : void OGRODSDataSource::DetectHeaderLine()
503 :
504 : {
505 150 : int bHeaderLineCandidate = TRUE;
506 : size_t i;
507 534 : for(i = 0; i < apoFirstLineTypes.size(); i++)
508 : {
509 434 : if (apoFirstLineTypes[i] != "string")
510 : {
511 : /* If the values in the first line are not text, then it is */
512 : /* not a header line */
513 50 : bHeaderLineCandidate = FALSE;
514 50 : break;
515 : }
516 : }
517 :
518 150 : size_t nCountTextOnCurLine = 0;
519 150 : size_t nCountNonEmptyOnCurLine = 0;
520 534 : for(i = 0; bHeaderLineCandidate && i < apoCurLineTypes.size(); i++)
521 : {
522 384 : if (apoCurLineTypes[i] == "string")
523 : {
524 : /* If there are only text values on the second line, then we cannot */
525 : /* know if it is a header line or just a regular line */
526 78 : nCountTextOnCurLine ++;
527 : }
528 306 : else if (apoCurLineTypes[i] != "")
529 : {
530 258 : nCountNonEmptyOnCurLine ++;
531 : }
532 : }
533 :
534 150 : const char* pszODSHeaders = CPLGetConfigOption("OGR_ODS_HEADERS", "");
535 150 : bFirstLineIsHeaders = FALSE;
536 150 : if (EQUAL(pszODSHeaders, "FORCE"))
537 0 : bFirstLineIsHeaders = TRUE;
538 150 : else if (EQUAL(pszODSHeaders, "DISABLE"))
539 12 : bFirstLineIsHeaders = FALSE;
540 138 : else if (osSetLayerHasSplitter.find(poCurLayer->GetName()) !=
541 : osSetLayerHasSplitter.end())
542 : {
543 4 : bFirstLineIsHeaders = TRUE;
544 : }
545 134 : else if (bHeaderLineCandidate &&
546 : apoFirstLineTypes.size() != 0 &&
547 : apoFirstLineTypes.size() == apoCurLineTypes.size() &&
548 : nCountTextOnCurLine != apoFirstLineTypes.size() &&
549 : nCountNonEmptyOnCurLine != 0)
550 : {
551 18 : bFirstLineIsHeaders = TRUE;
552 : }
553 : CPLDebug("ODS", "%s %s",
554 150 : poCurLayer->GetName(),
555 300 : bFirstLineIsHeaders ? "has header line" : "has no header line");
556 150 : }
557 :
558 : /************************************************************************/
559 : /* startElementDefault() */
560 : /************************************************************************/
561 :
562 1590 : void OGRODSDataSource::startElementDefault(const char *pszName,
563 : const char **ppszAttr)
564 : {
565 1590 : if (strcmp(pszName, "table:table") == 0)
566 : {
567 : const char* pszTableName =
568 214 : GetAttributeValue(ppszAttr, "table:name", "unnamed");
569 :
570 214 : poCurLayer = new OGRODSLayer(this, pszTableName);
571 214 : papoLayers = (OGRLayer**)CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
572 214 : papoLayers[nLayers++] = poCurLayer;
573 :
574 214 : nCurLine = 0;
575 214 : nEmptyRowsAccumulated = 0;
576 428 : apoFirstLineValues.resize(0);
577 428 : apoFirstLineTypes.resize(0);
578 214 : PushState(STATE_TABLE);
579 214 : bEndTableParsing = FALSE;
580 : }
581 1590 : }
582 :
583 : /************************************************************************/
584 : /* startElementTable() */
585 : /************************************************************************/
586 :
587 1304 : void OGRODSDataSource::startElementTable(const char *pszName,
588 : const char **ppszAttr)
589 : {
590 1304 : if (strcmp(pszName, "table:table-row") == 0 && !bEndTableParsing)
591 : {
592 : nRowsRepeated = atoi(
593 896 : GetAttributeValue(ppszAttr, "table:number-rows-repeated", "1"));
594 896 : if (nRowsRepeated > 65536)
595 : {
596 0 : bEndTableParsing = TRUE;
597 0 : return;
598 : }
599 :
600 896 : nCurCol = 0;
601 :
602 896 : apoCurLineValues.resize(0);
603 1792 : apoCurLineTypes.resize(0);
604 :
605 896 : PushState(STATE_ROW);
606 : }
607 : }
608 :
609 : /************************************************************************/
610 : /* endElementTable() */
611 : /************************************************************************/
612 :
613 622 : void OGRODSDataSource::endElementTable(const char *pszName)
614 : {
615 622 : if (stateStack[nStackDepth].nBeginDepth == nDepth)
616 : {
617 214 : CPLAssert(strcmp(pszName, "table:table") == 0);
618 :
619 214 : if (nCurLine == 0 ||
620 : (nCurLine == 1 && apoFirstLineValues.size() == 0))
621 : {
622 : /* Remove empty sheet */
623 20 : delete poCurLayer;
624 20 : nLayers --;
625 20 : poCurLayer = NULL;
626 : }
627 194 : else if (nCurLine == 1)
628 : {
629 : /* If we have only one single line in the sheet */
630 : size_t i;
631 72 : for(i = 0; i < apoFirstLineValues.size(); i++)
632 : {
633 48 : const char* pszFieldName = CPLSPrintf("Field%d", (int)i + 1);
634 : OGRFieldType eType = GetOGRFieldType(apoFirstLineValues[i].c_str(),
635 48 : apoFirstLineTypes[i].c_str());
636 48 : OGRFieldDefn oFieldDefn(pszFieldName, eType);
637 48 : poCurLayer->CreateField(&oFieldDefn);
638 : }
639 :
640 24 : OGRFeature* poFeature = new OGRFeature(poCurLayer->GetLayerDefn());
641 72 : for(i = 0; i < apoFirstLineValues.size(); i++)
642 : {
643 48 : SetField(poFeature, i, apoFirstLineValues[i].c_str());
644 : }
645 24 : poCurLayer->CreateFeature(poFeature);
646 24 : delete poFeature;
647 : }
648 :
649 214 : if (poCurLayer)
650 : {
651 : OGRFeature* poFeature;
652 :
653 194 : if (CSLTestBoolean(CPLGetConfigOption("ODS_RESOLVE_FORMULAS", "YES")))
654 : {
655 194 : poCurLayer->ResetReading();
656 :
657 194 : int nRow = 0;
658 194 : poFeature = poCurLayer->GetNextFeature();
659 1442 : while (poFeature)
660 : {
661 6806 : for(int i=0;i<poFeature->GetFieldCount();i++)
662 : {
663 5752 : if (poFeature->IsFieldSet(i) &&
664 : poFeature->GetFieldDefnRef(i)->GetType() == OFTString)
665 : {
666 1190 : const char* pszVal = poFeature->GetFieldAsString(i);
667 1190 : if (strncmp(pszVal, "of:=", 4) == 0)
668 : {
669 220 : ODSCellEvaluator oCellEvaluator(poCurLayer);
670 220 : oCellEvaluator.Evaluate(nRow, i);
671 : }
672 : }
673 : }
674 1054 : delete poFeature;
675 :
676 1054 : poFeature = poCurLayer->GetNextFeature();
677 1054 : nRow ++;
678 : }
679 : }
680 :
681 194 : poCurLayer->ResetReading();
682 :
683 194 : ((OGRMemLayer*)poCurLayer)->SetUpdatable(bUpdatable);
684 194 : ((OGRMemLayer*)poCurLayer)->SetAdvertizeUTF8(TRUE);
685 194 : ((OGRODSLayer*)poCurLayer)->SetUpdated(FALSE);
686 : }
687 :
688 214 : poCurLayer = NULL;
689 : }
690 622 : }
691 :
692 : /************************************************************************/
693 : /* startElementRow() */
694 : /************************************************************************/
695 :
696 3122 : void OGRODSDataSource::startElementRow(const char *pszName,
697 : const char **ppszAttr)
698 : {
699 3122 : if (strcmp(pszName, "table:table-cell") == 0)
700 : {
701 3060 : PushState(STATE_CELL);
702 :
703 3060 : osValueType = GetAttributeValue(ppszAttr, "office:value-type", "");
704 : const char* pszValue =
705 3060 : GetAttributeValue(ppszAttr, "office:value", NULL);
706 3060 : if (pszValue)
707 622 : osValue = pszValue;
708 : else
709 : {
710 : const char* pszDateValue =
711 2438 : GetAttributeValue(ppszAttr, "office:date-value", NULL);
712 2438 : if (pszDateValue)
713 130 : osValue = pszDateValue;
714 : else
715 2308 : osValue = GetAttributeValue(ppszAttr, "office:time-value", "");
716 : }
717 :
718 3060 : const char* pszFormula = GetAttributeValue(ppszAttr, "table:formula", NULL);
719 3334 : if (pszFormula && strncmp(pszFormula, "of:=", 4) == 0)
720 : {
721 274 : osFormula = pszFormula;
722 274 : if (osValueType.size() == 0)
723 220 : osValueType = "formula";
724 : }
725 : else
726 2786 : osFormula = "";
727 :
728 : nCellsRepeated = atoi(
729 3060 : GetAttributeValue(ppszAttr, "table:number-columns-repeated", "1"));
730 : }
731 62 : else if (strcmp(pszName, "table:covered-table-cell") == 0)
732 : {
733 : /* Merged cell */
734 62 : apoCurLineValues.push_back("");
735 124 : apoCurLineTypes.push_back("");
736 :
737 62 : nCurCol += 1;
738 : }
739 3122 : }
740 :
741 : /************************************************************************/
742 : /* endElementRow() */
743 : /************************************************************************/
744 :
745 958 : void OGRODSDataSource::endElementRow(const char *pszName)
746 : {
747 958 : if (stateStack[nStackDepth].nBeginDepth == nDepth)
748 : {
749 896 : CPLAssert(strcmp(pszName, "table:table-row") == 0);
750 :
751 : OGRFeature* poFeature;
752 : size_t i;
753 :
754 : /* Remove blank columns at the right to defer type evaluation */
755 : /* until necessary */
756 896 : i = apoCurLineTypes.size();
757 3976 : while(i > 0)
758 : {
759 2928 : i --;
760 2928 : if (apoCurLineTypes[i] == "")
761 : {
762 2184 : apoCurLineValues.resize(i);
763 4368 : apoCurLineTypes.resize(i);
764 : }
765 : else
766 744 : break;
767 : }
768 :
769 : /* Do not add immediately empty rows. Wait until there is another non */
770 : /* empty row */
771 896 : if (nCurLine >= 2 && apoCurLineTypes.size() == 0)
772 : {
773 56 : nEmptyRowsAccumulated += nRowsRepeated;
774 56 : return;
775 : }
776 840 : else if (nEmptyRowsAccumulated > 0)
777 : {
778 240 : for(i = 0; i < (size_t)nEmptyRowsAccumulated; i++)
779 : {
780 216 : poFeature = new OGRFeature(poCurLayer->GetLayerDefn());
781 216 : poCurLayer->CreateFeature(poFeature);
782 432 : delete poFeature;
783 : }
784 24 : nCurLine += nEmptyRowsAccumulated;
785 24 : nEmptyRowsAccumulated = 0;
786 : }
787 :
788 : /* Backup first line values and types in special arrays */
789 840 : if (nCurLine == 0)
790 : {
791 214 : apoFirstLineTypes = apoCurLineTypes;
792 214 : apoFirstLineValues = apoCurLineValues;
793 :
794 : #if skip_leading_empty_rows
795 : if (apoFirstLineTypes.size() == 0)
796 : {
797 : /* Skip leading empty rows */
798 : apoFirstLineTypes.resize(0);
799 : apoFirstLineValues.resize(0);
800 : return;
801 : }
802 : #endif
803 : }
804 :
805 840 : if (nCurLine == 1)
806 : {
807 150 : DetectHeaderLine();
808 :
809 150 : poCurLayer->SetHasHeaderLine(bFirstLineIsHeaders);
810 :
811 150 : if (bFirstLineIsHeaders)
812 : {
813 286 : for(i = 0; i < apoFirstLineValues.size(); i++)
814 : {
815 264 : const char* pszFieldName = apoFirstLineValues[i].c_str();
816 264 : if (pszFieldName[0] == '\0')
817 0 : pszFieldName = CPLSPrintf("Field%d", (int)i + 1);
818 264 : OGRFieldType eType = OFTString;
819 264 : if (i < apoCurLineValues.size())
820 : {
821 : eType = GetOGRFieldType(apoCurLineValues[i].c_str(),
822 264 : apoCurLineTypes[i].c_str());
823 : }
824 264 : OGRFieldDefn oFieldDefn(pszFieldName, eType);
825 264 : poCurLayer->CreateField(&oFieldDefn);
826 : }
827 : }
828 : else
829 : {
830 326 : for(i = 0; i < apoFirstLineValues.size(); i++)
831 : {
832 : const char* pszFieldName =
833 198 : CPLSPrintf("Field%d", (int)i + 1);
834 : OGRFieldType eType = GetOGRFieldType(
835 : apoFirstLineValues[i].c_str(),
836 198 : apoFirstLineTypes[i].c_str());
837 198 : OGRFieldDefn oFieldDefn(pszFieldName, eType);
838 198 : poCurLayer->CreateField(&oFieldDefn);
839 : }
840 :
841 128 : poFeature = new OGRFeature(poCurLayer->GetLayerDefn());
842 326 : for(i = 0; i < apoFirstLineValues.size(); i++)
843 : {
844 198 : SetField(poFeature, i, apoFirstLineValues[i].c_str());
845 : }
846 128 : poCurLayer->CreateFeature(poFeature);
847 128 : delete poFeature;
848 : }
849 : }
850 :
851 840 : if (nCurLine >= 1 || (nCurLine == 0 && nRowsRepeated > 1))
852 : {
853 : /* Add new fields found on following lines. */
854 1292 : if (apoCurLineValues.size() >
855 646 : (size_t)poCurLayer->GetLayerDefn()->GetFieldCount())
856 : {
857 398 : for(i = (size_t)poCurLayer->GetLayerDefn()->GetFieldCount();
858 : i < apoCurLineValues.size();
859 : i++)
860 : {
861 : const char* pszFieldName =
862 274 : CPLSPrintf("Field%d", (int)i + 1);
863 : OGRFieldType eType = GetOGRFieldType(
864 : apoCurLineValues[i].c_str(),
865 274 : apoCurLineTypes[i].c_str());
866 274 : OGRFieldDefn oFieldDefn(pszFieldName, eType);
867 274 : poCurLayer->CreateField(&oFieldDefn);
868 : }
869 : }
870 :
871 : /* Update field type if necessary */
872 646 : if (bAutodetectTypes)
873 : {
874 2222 : for(i = 0; i < apoCurLineValues.size(); i++)
875 : {
876 1630 : if (apoCurLineValues[i].size())
877 : {
878 : OGRFieldType eValType = GetOGRFieldType(
879 : apoCurLineValues[i].c_str(),
880 1274 : apoCurLineTypes[i].c_str());
881 : OGRFieldType eFieldType =
882 1274 : poCurLayer->GetLayerDefn()->GetFieldDefn(i)->GetType();
883 1274 : if (eFieldType == OFTDateTime &&
884 : (eValType == OFTDate || eValType == OFTTime) )
885 : {
886 : /* ok */
887 : }
888 1274 : else if (eFieldType == OFTReal && eValType == OFTInteger)
889 : {
890 : /* ok */;
891 : }
892 1258 : else if (eFieldType != OFTString && eValType != eFieldType)
893 : {
894 : OGRFieldDefn oNewFieldDefn(
895 52 : poCurLayer->GetLayerDefn()->GetFieldDefn(i));
896 66 : if ((eFieldType == OFTDate || eFieldType == OFTTime) &&
897 : eValType == OFTDateTime)
898 14 : oNewFieldDefn.SetType(OFTDateTime);
899 54 : else if (eFieldType == OFTInteger &&
900 : eValType == OFTReal)
901 16 : oNewFieldDefn.SetType(OFTReal);
902 : else
903 22 : oNewFieldDefn.SetType(OFTString);
904 : poCurLayer->AlterFieldDefn(i, &oNewFieldDefn,
905 52 : ALTER_TYPE_FLAG);
906 : }
907 : }
908 : }
909 : }
910 :
911 : /* Add feature for current line */
912 1332 : for(int j=0;j<nRowsRepeated;j++)
913 : {
914 686 : poFeature = new OGRFeature(poCurLayer->GetLayerDefn());
915 2464 : for(i = 0; i < apoCurLineValues.size(); i++)
916 : {
917 1778 : SetField(poFeature, i, apoCurLineValues[i].c_str());
918 : }
919 686 : poCurLayer->CreateFeature(poFeature);
920 686 : delete poFeature;
921 : }
922 : }
923 :
924 840 : nCurLine += nRowsRepeated;
925 : }
926 : }
927 :
928 : /************************************************************************/
929 : /* startElementCell() */
930 : /************************************************************************/
931 :
932 1550 : void OGRODSDataSource::startElementCell(const char *pszName,
933 : const char **ppszAttr)
934 : {
935 1550 : if (osValue.size() == 0 && strcmp(pszName, "text:p") == 0)
936 : {
937 836 : PushState(STATE_TEXTP);
938 : }
939 1550 : }
940 :
941 : /************************************************************************/
942 : /* endElementCell() */
943 : /************************************************************************/
944 :
945 3774 : void OGRODSDataSource::endElementCell(const char *pszName)
946 : {
947 3774 : if (stateStack[nStackDepth].nBeginDepth == nDepth)
948 : {
949 3060 : CPLAssert(strcmp(pszName, "table:table-cell") == 0);
950 :
951 7450 : for(int i = 0; i < nCellsRepeated; i++)
952 : {
953 4390 : apoCurLineValues.push_back(osValue.size() ? osValue : osFormula);
954 4390 : apoCurLineTypes.push_back(osValueType);
955 : }
956 :
957 3060 : nCurCol += nCellsRepeated;
958 : }
959 3774 : }
960 :
961 : /************************************************************************/
962 : /* dataHandlerTextP() */
963 : /************************************************************************/
964 :
965 908 : void OGRODSDataSource::dataHandlerTextP(const char *data, int nLen)
966 : {
967 908 : osValue.append(data, nLen);
968 908 : }
969 :
970 : /************************************************************************/
971 : /* AnalyseFile() */
972 : /************************************************************************/
973 :
974 974 : void OGRODSDataSource::AnalyseFile()
975 : {
976 974 : if (bAnalysedFile)
977 948 : return;
978 :
979 26 : bAnalysedFile = TRUE;
980 :
981 26 : AnalyseSettings();
982 :
983 26 : oParser = OGRCreateExpatXMLParser();
984 26 : XML_SetElementHandler(oParser, ::startElementCbk, ::endElementCbk);
985 26 : XML_SetCharacterDataHandler(oParser, ::dataHandlerCbk);
986 26 : XML_SetUserData(oParser, this);
987 :
988 26 : nDepth = 0;
989 26 : nStackDepth = 0;
990 26 : stateStack[0].nBeginDepth = 0;
991 26 : bStopParsing = FALSE;
992 26 : nWithoutEventCounter = 0;
993 :
994 26 : VSIFSeekL( fpContent, 0, SEEK_SET );
995 :
996 : char aBuf[BUFSIZ];
997 : int nDone;
998 76 : do
999 : {
1000 76 : nDataHandlerCounter = 0;
1001 : unsigned int nLen =
1002 76 : (unsigned int)VSIFReadL( aBuf, 1, sizeof(aBuf), fpContent );
1003 76 : nDone = VSIFEofL(fpContent);
1004 76 : if (XML_Parse(oParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
1005 : {
1006 : CPLError(CE_Failure, CPLE_AppDefined,
1007 : "XML parsing of ODS file failed : %s at line %d, column %d",
1008 : XML_ErrorString(XML_GetErrorCode(oParser)),
1009 : (int)XML_GetCurrentLineNumber(oParser),
1010 0 : (int)XML_GetCurrentColumnNumber(oParser));
1011 0 : bStopParsing = TRUE;
1012 : }
1013 76 : nWithoutEventCounter ++;
1014 : } while (!nDone && !bStopParsing && nWithoutEventCounter < 10);
1015 :
1016 26 : XML_ParserFree(oParser);
1017 26 : oParser = NULL;
1018 :
1019 26 : if (nWithoutEventCounter == 10)
1020 : {
1021 : CPLError(CE_Failure, CPLE_AppDefined,
1022 0 : "Too much data inside one element. File probably corrupted");
1023 0 : bStopParsing = TRUE;
1024 : }
1025 :
1026 26 : VSIFCloseL(fpContent);
1027 26 : fpContent = NULL;
1028 :
1029 26 : bUpdated = FALSE;
1030 : }
1031 :
1032 : /************************************************************************/
1033 : /* startElementStylesCbk() */
1034 : /************************************************************************/
1035 :
1036 4120 : static void XMLCALL startElementStylesCbk(void *pUserData, const char *pszName,
1037 : const char **ppszAttr)
1038 : {
1039 4120 : ((OGRODSDataSource*)pUserData)->startElementStylesCbk(pszName, ppszAttr);
1040 4120 : }
1041 :
1042 4120 : void OGRODSDataSource::startElementStylesCbk(const char *pszName,
1043 : const char **ppszAttr)
1044 : {
1045 4120 : if (bStopParsing) return;
1046 :
1047 4120 : nWithoutEventCounter = 0;
1048 :
1049 4120 : if (nStackDepth == 0 &&
1050 : strcmp(pszName, "config:config-item-map-named") == 0 &&
1051 : strcmp(GetAttributeValue(ppszAttr, "config:name", ""), "Tables") == 0)
1052 : {
1053 24 : stateStack[++nStackDepth].nBeginDepth = nDepth;
1054 : }
1055 4280 : else if (nStackDepth == 1 && strcmp(pszName, "config:config-item-map-entry") == 0)
1056 : {
1057 184 : const char* pszTableName = GetAttributeValue(ppszAttr, "config:name", NULL);
1058 184 : if (pszTableName)
1059 : {
1060 184 : osCurrentConfigTableName = pszTableName;
1061 184 : nFlags = 0;
1062 184 : stateStack[++nStackDepth].nBeginDepth = nDepth;
1063 : }
1064 : }
1065 3912 : else if (nStackDepth == 2 && strcmp(pszName, "config:config-item") == 0)
1066 : {
1067 2684 : const char* pszConfigName = GetAttributeValue(ppszAttr, "config:name", NULL);
1068 2684 : if (pszConfigName)
1069 : {
1070 2684 : osConfigName = pszConfigName;
1071 2684 : osValue = "";
1072 2684 : stateStack[++nStackDepth].nBeginDepth = nDepth;
1073 : }
1074 : }
1075 :
1076 4120 : nDepth++;
1077 : }
1078 :
1079 : /************************************************************************/
1080 : /* endElementStylesCbk() */
1081 : /************************************************************************/
1082 :
1083 4120 : static void XMLCALL endElementStylesCbk(void *pUserData, const char *pszName)
1084 : {
1085 4120 : ((OGRODSDataSource*)pUserData)->endElementStylesCbk(pszName);
1086 4120 : }
1087 :
1088 4120 : void OGRODSDataSource::endElementStylesCbk(const char *pszName)
1089 : {
1090 4120 : if (bStopParsing) return;
1091 :
1092 4120 : nWithoutEventCounter = 0;
1093 4120 : nDepth--;
1094 :
1095 4120 : if (nStackDepth > 0 && stateStack[nStackDepth].nBeginDepth == nDepth)
1096 : {
1097 2892 : if (nStackDepth == 2)
1098 : {
1099 184 : if (nFlags == (1 | 2))
1100 4 : osSetLayerHasSplitter.insert(osCurrentConfigTableName);
1101 : }
1102 2892 : if (nStackDepth == 3)
1103 : {
1104 2684 : if (osConfigName == "VerticalSplitMode" && osValue == "2")
1105 4 : nFlags |= 1;
1106 2680 : else if (osConfigName == "VerticalSplitPosition" && osValue == "1")
1107 4 : nFlags |= 2;
1108 : }
1109 2892 : nStackDepth --;
1110 : }
1111 : }
1112 :
1113 : /************************************************************************/
1114 : /* dataHandlerStylesCbk() */
1115 : /************************************************************************/
1116 :
1117 4322 : static void XMLCALL dataHandlerStylesCbk(void *pUserData, const char *data, int nLen)
1118 : {
1119 4322 : ((OGRODSDataSource*)pUserData)->dataHandlerStylesCbk(data, nLen);
1120 4322 : }
1121 :
1122 4322 : void OGRODSDataSource::dataHandlerStylesCbk(const char *data, int nLen)
1123 : {
1124 4322 : if (bStopParsing) return;
1125 :
1126 4322 : nDataHandlerCounter ++;
1127 4322 : if (nDataHandlerCounter >= BUFSIZ)
1128 : {
1129 : CPLError(CE_Failure, CPLE_AppDefined,
1130 0 : "File probably corrupted (million laugh pattern)");
1131 0 : XML_StopParser(oParser, XML_FALSE);
1132 0 : bStopParsing = TRUE;
1133 0 : return;
1134 : }
1135 :
1136 4322 : nWithoutEventCounter = 0;
1137 :
1138 4322 : if (nStackDepth == 3)
1139 : {
1140 2684 : osValue.append(data, nLen);
1141 : }
1142 : }
1143 :
1144 : /************************************************************************/
1145 : /* AnalyseSettings() */
1146 : /* */
1147 : /* We parse settings.xml to see which layers have a vertical splitter */
1148 : /* on the first line, so as to use it as the header line. */
1149 : /************************************************************************/
1150 :
1151 26 : void OGRODSDataSource::AnalyseSettings()
1152 : {
1153 26 : if (fpSettings == NULL)
1154 2 : return;
1155 :
1156 24 : oParser = OGRCreateExpatXMLParser();
1157 24 : XML_SetElementHandler(oParser, ::startElementStylesCbk, ::endElementStylesCbk);
1158 24 : XML_SetCharacterDataHandler(oParser, ::dataHandlerStylesCbk);
1159 24 : XML_SetUserData(oParser, this);
1160 :
1161 24 : nDepth = 0;
1162 24 : nStackDepth = 0;
1163 24 : bStopParsing = FALSE;
1164 24 : nWithoutEventCounter = 0;
1165 :
1166 24 : VSIFSeekL( fpSettings, 0, SEEK_SET );
1167 :
1168 : char aBuf[BUFSIZ];
1169 : int nDone;
1170 62 : do
1171 : {
1172 62 : nDataHandlerCounter = 0;
1173 : unsigned int nLen =
1174 62 : (unsigned int)VSIFReadL( aBuf, 1, sizeof(aBuf), fpSettings );
1175 62 : nDone = VSIFEofL(fpSettings);
1176 62 : if (XML_Parse(oParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
1177 : {
1178 : CPLError(CE_Failure, CPLE_AppDefined,
1179 : "XML parsing of styles.xml file failed : %s at line %d, column %d",
1180 : XML_ErrorString(XML_GetErrorCode(oParser)),
1181 : (int)XML_GetCurrentLineNumber(oParser),
1182 0 : (int)XML_GetCurrentColumnNumber(oParser));
1183 0 : bStopParsing = TRUE;
1184 : }
1185 62 : nWithoutEventCounter ++;
1186 : } while (!nDone && !bStopParsing && nWithoutEventCounter < 10);
1187 :
1188 24 : XML_ParserFree(oParser);
1189 24 : oParser = NULL;
1190 :
1191 24 : if (nWithoutEventCounter == 10)
1192 : {
1193 : CPLError(CE_Failure, CPLE_AppDefined,
1194 0 : "Too much data inside one element. File probably corrupted");
1195 0 : bStopParsing = TRUE;
1196 : }
1197 :
1198 24 : VSIFCloseL(fpSettings);
1199 24 : fpSettings = NULL;
1200 : }
1201 :
1202 : /************************************************************************/
1203 : /* CreateLayer() */
1204 : /************************************************************************/
1205 :
1206 : OGRLayer *
1207 16 : OGRODSDataSource::CreateLayer( const char * pszLayerName,
1208 : OGRSpatialReference *poSRS,
1209 : OGRwkbGeometryType eType,
1210 : char ** papszOptions )
1211 :
1212 : {
1213 : /* -------------------------------------------------------------------- */
1214 : /* Verify we are in update mode. */
1215 : /* -------------------------------------------------------------------- */
1216 16 : if( !bUpdatable )
1217 : {
1218 : CPLError( CE_Failure, CPLE_NoWriteAccess,
1219 : "Data source %s opened read-only.\n"
1220 : "New layer %s cannot be created.\n",
1221 0 : pszName, pszLayerName );
1222 :
1223 0 : return NULL;
1224 : }
1225 :
1226 16 : AnalyseFile();
1227 :
1228 : /* -------------------------------------------------------------------- */
1229 : /* Do we already have this layer? If so, should we blow it */
1230 : /* away? */
1231 : /* -------------------------------------------------------------------- */
1232 : int iLayer;
1233 :
1234 72 : for( iLayer = 0; iLayer < nLayers; iLayer++ )
1235 : {
1236 56 : if( EQUAL(pszLayerName,papoLayers[iLayer]->GetName()) )
1237 : {
1238 0 : if( CSLFetchNameValue( papszOptions, "OVERWRITE" ) != NULL
1239 : && !EQUAL(CSLFetchNameValue(papszOptions,"OVERWRITE"),"NO") )
1240 : {
1241 0 : DeleteLayer( pszLayerName );
1242 : }
1243 : else
1244 : {
1245 : CPLError( CE_Failure, CPLE_AppDefined,
1246 : "Layer %s already exists, CreateLayer failed.\n"
1247 : "Use the layer creation option OVERWRITE=YES to "
1248 : "replace it.",
1249 0 : pszLayerName );
1250 0 : return NULL;
1251 : }
1252 : }
1253 : }
1254 :
1255 : /* -------------------------------------------------------------------- */
1256 : /* Create the layer object. */
1257 : /* -------------------------------------------------------------------- */
1258 16 : OGRLayer* poLayer = new OGRODSLayer(this, pszLayerName, TRUE);
1259 :
1260 16 : papoLayers = (OGRLayer**)CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
1261 16 : papoLayers[nLayers] = poLayer;
1262 16 : nLayers ++;
1263 :
1264 16 : bUpdated = TRUE;
1265 :
1266 16 : return poLayer;
1267 : }
1268 :
1269 : /************************************************************************/
1270 : /* DeleteLayer() */
1271 : /************************************************************************/
1272 :
1273 0 : void OGRODSDataSource::DeleteLayer( const char *pszLayerName )
1274 :
1275 : {
1276 : int iLayer;
1277 :
1278 : /* -------------------------------------------------------------------- */
1279 : /* Verify we are in update mode. */
1280 : /* -------------------------------------------------------------------- */
1281 0 : if( !bUpdatable )
1282 : {
1283 : CPLError( CE_Failure, CPLE_NoWriteAccess,
1284 : "Data source %s opened read-only.\n"
1285 : "Layer %s cannot be deleted.\n",
1286 0 : pszName, pszLayerName );
1287 :
1288 0 : return;
1289 : }
1290 :
1291 : /* -------------------------------------------------------------------- */
1292 : /* Try to find layer. */
1293 : /* -------------------------------------------------------------------- */
1294 0 : for( iLayer = 0; iLayer < nLayers; iLayer++ )
1295 : {
1296 0 : if( EQUAL(pszLayerName,papoLayers[iLayer]->GetName()) )
1297 0 : break;
1298 : }
1299 :
1300 0 : if( iLayer == nLayers )
1301 : {
1302 : CPLError( CE_Failure, CPLE_AppDefined,
1303 : "Attempt to delete layer '%s', but this layer is not known to OGR.",
1304 0 : pszLayerName );
1305 0 : return;
1306 : }
1307 :
1308 0 : DeleteLayer(iLayer);
1309 : }
1310 :
1311 : /************************************************************************/
1312 : /* DeleteLayer() */
1313 : /************************************************************************/
1314 :
1315 0 : OGRErr OGRODSDataSource::DeleteLayer(int iLayer)
1316 : {
1317 0 : AnalyseFile();
1318 :
1319 0 : if( iLayer < 0 || iLayer >= nLayers )
1320 : {
1321 : CPLError( CE_Failure, CPLE_AppDefined,
1322 : "Layer %d not in legal range of 0 to %d.",
1323 0 : iLayer, nLayers-1 );
1324 0 : return OGRERR_FAILURE;
1325 : }
1326 :
1327 : /* -------------------------------------------------------------------- */
1328 : /* Blow away our OGR structures related to the layer. This is */
1329 : /* pretty dangerous if anything has a reference to this layer! */
1330 : /* -------------------------------------------------------------------- */
1331 :
1332 0 : delete papoLayers[iLayer];
1333 : memmove( papoLayers + iLayer, papoLayers + iLayer + 1,
1334 0 : sizeof(void *) * (nLayers - iLayer - 1) );
1335 0 : nLayers--;
1336 :
1337 0 : bUpdated = TRUE;
1338 :
1339 0 : return OGRERR_NONE;
1340 : }
1341 :
1342 : /************************************************************************/
1343 : /* HasHeaderLine() */
1344 : /************************************************************************/
1345 :
1346 64 : static int HasHeaderLine(OGRLayer* poLayer)
1347 : {
1348 64 : OGRFeatureDefn* poFDefn = poLayer->GetLayerDefn();
1349 64 : int bHasHeaders = FALSE;
1350 :
1351 304 : for(int j=0;j<poFDefn->GetFieldCount();j++)
1352 : {
1353 240 : if (strcmp(poFDefn->GetFieldDefn(j)->GetNameRef(),
1354 : CPLSPrintf("Field%d", j+1)) != 0)
1355 96 : bHasHeaders = TRUE;
1356 : }
1357 :
1358 64 : return bHasHeaders;
1359 : }
1360 :
1361 : /************************************************************************/
1362 : /* WriteLayer() */
1363 : /************************************************************************/
1364 :
1365 32 : static void WriteLayer(VSILFILE* fp, OGRLayer* poLayer)
1366 : {
1367 : int j;
1368 32 : const char* pszLayerName = poLayer->GetName();
1369 32 : char* pszXML = OGRGetXML_UTF8_EscapedString(pszLayerName);
1370 32 : VSIFPrintfL(fp, "<table:table table:name=\"%s\">\n", pszXML);
1371 32 : CPLFree(pszXML);
1372 :
1373 32 : poLayer->ResetReading();
1374 :
1375 32 : OGRFeature* poFeature = poLayer->GetNextFeature();
1376 :
1377 32 : OGRFeatureDefn* poFDefn = poLayer->GetLayerDefn();
1378 32 : int bHasHeaders = HasHeaderLine(poLayer);
1379 :
1380 152 : for(j=0;j<poFDefn->GetFieldCount();j++)
1381 : {
1382 120 : int nStyleNumber = 1;
1383 120 : if (poFDefn->GetFieldDefn(j)->GetType() == OFTDateTime)
1384 12 : nStyleNumber = 2;
1385 : VSIFPrintfL(fp, "<table:table-column table:style-name=\"co%d\" "
1386 : "table:default-cell-style-name=\"Default\"/>\n",
1387 120 : nStyleNumber);
1388 : }
1389 :
1390 32 : if (bHasHeaders && poFeature != NULL)
1391 : {
1392 4 : VSIFPrintfL(fp, "<table:table-row>\n");
1393 52 : for(j=0;j<poFDefn->GetFieldCount();j++)
1394 : {
1395 48 : const char* pszVal = poFDefn->GetFieldDefn(j)->GetNameRef();
1396 :
1397 48 : VSIFPrintfL(fp, "<table:table-cell office:value-type=\"string\">\n");
1398 48 : pszXML = OGRGetXML_UTF8_EscapedString(pszVal);
1399 48 : VSIFPrintfL(fp, "<text:p>%s</text:p>\n", pszXML);
1400 48 : CPLFree(pszXML);
1401 48 : VSIFPrintfL(fp, "</table:table-cell>\n");
1402 : }
1403 4 : VSIFPrintfL(fp, "</table:table-row>\n");
1404 : }
1405 :
1406 236 : while(poFeature != NULL)
1407 : {
1408 172 : VSIFPrintfL(fp, "<table:table-row>\n");
1409 1020 : for(j=0;j<poFeature->GetFieldCount();j++)
1410 : {
1411 848 : if (poFeature->IsFieldSet(j))
1412 : {
1413 220 : OGRFieldType eType = poFDefn->GetFieldDefn(j)->GetType();
1414 :
1415 220 : if (eType == OFTReal)
1416 : {
1417 : VSIFPrintfL(fp, "<table:table-cell office:value-type=\"float\" "
1418 : "office:value=\"%.16f\"/>\n",
1419 32 : poFeature->GetFieldAsDouble(j));
1420 : }
1421 188 : else if (eType == OFTInteger)
1422 : {
1423 : VSIFPrintfL(fp, "<table:table-cell office:value-type=\"float\" "
1424 : "office:value=\"%d\"/>\n",
1425 24 : poFeature->GetFieldAsInteger(j));
1426 : }
1427 164 : else if (eType == OFTDateTime)
1428 : {
1429 : int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZFlag;
1430 : poFeature->GetFieldAsDateTime(j, &nYear, &nMonth, &nDay,
1431 16 : &nHour, &nMinute, &nSecond, &nTZFlag);
1432 : VSIFPrintfL(fp, "<table:table-cell table:style-name=\"stDateTime\" "
1433 : "office:value-type=\"date\" "
1434 : "office:date-value=\"%04d-%02d-%02dT%02d:%02d:%02d\">\n",
1435 16 : nYear, nMonth, nDay, nHour, nMinute, nSecond);
1436 : VSIFPrintfL(fp, "<text:p>%02d/%02d/%04d %02d:%02d:%02d</text:p>\n",
1437 16 : nDay, nMonth, nYear, nHour, nMinute, nSecond);
1438 16 : VSIFPrintfL(fp, "</table:table-cell>\n");
1439 : }
1440 148 : else if (eType == OFTDateTime)
1441 : {
1442 : int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZFlag;
1443 : poFeature->GetFieldAsDateTime(j, &nYear, &nMonth, &nDay,
1444 0 : &nHour, &nMinute, &nSecond, &nTZFlag);
1445 : VSIFPrintfL(fp, "<table:table-cell table:style-name=\"stDate\" "
1446 : "office:value-type=\"date\" "
1447 : "office:date-value=\"%04d-%02d-%02dT\">\n",
1448 0 : nYear, nMonth, nDay);
1449 : VSIFPrintfL(fp, "<text:p>%02d/%02d/%04d</text:p>\n",
1450 0 : nDay, nMonth, nYear);
1451 0 : VSIFPrintfL(fp, "</table:table-cell>\n");
1452 : }
1453 148 : else if (eType == OFTTime)
1454 : {
1455 : int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZFlag;
1456 : poFeature->GetFieldAsDateTime(j, &nYear, &nMonth, &nDay,
1457 4 : &nHour, &nMinute, &nSecond, &nTZFlag);
1458 : VSIFPrintfL(fp, "<table:table-cell table:style-name=\"stTime\" "
1459 : "office:value-type=\"time\" "
1460 : "office:time-value=\"PT%02dH%02dM%02dS\">\n",
1461 4 : nHour, nMinute, nSecond);
1462 : VSIFPrintfL(fp, "<text:p>%02d:%02d:%02d</text:p>\n",
1463 4 : nHour, nMinute, nSecond);
1464 4 : VSIFPrintfL(fp, "</table:table-cell>\n");
1465 : }
1466 : else
1467 : {
1468 144 : const char* pszVal = poFeature->GetFieldAsString(j);
1469 144 : pszXML = OGRGetXML_UTF8_EscapedString(pszVal);
1470 144 : if (strncmp(pszVal, "of:=", 4) == 0)
1471 : {
1472 0 : VSIFPrintfL(fp, "<table:table-cell table:formula=\"%s\"/>\n", pszXML);
1473 : }
1474 : else
1475 : {
1476 144 : VSIFPrintfL(fp, "<table:table-cell office:value-type=\"string\">\n");
1477 144 : VSIFPrintfL(fp, "<text:p>%s</text:p>\n", pszXML);
1478 144 : VSIFPrintfL(fp, "</table:table-cell>\n");
1479 : }
1480 144 : CPLFree(pszXML);
1481 : }
1482 : }
1483 : else
1484 : {
1485 628 : VSIFPrintfL(fp, "<table:table-cell/>\n");
1486 : }
1487 : }
1488 172 : VSIFPrintfL(fp, "</table:table-row>\n");
1489 :
1490 172 : delete poFeature;
1491 172 : poFeature = poLayer->GetNextFeature();
1492 : }
1493 :
1494 32 : VSIFPrintfL(fp, "</table:table>\n");
1495 32 : }
1496 :
1497 : /************************************************************************/
1498 : /* SyncToDisk() */
1499 : /************************************************************************/
1500 :
1501 28 : OGRErr OGRODSDataSource::SyncToDisk()
1502 : {
1503 28 : if (!bUpdated)
1504 24 : return OGRERR_NONE;
1505 :
1506 4 : CPLAssert(fpSettings == NULL);
1507 4 : CPLAssert(fpContent == NULL);
1508 :
1509 : VSIStatBufL sStat;
1510 4 : if (VSIStatL(pszName, &sStat) == 0)
1511 : {
1512 2 : if (VSIUnlink( pszName ) != 0)
1513 : {
1514 : CPLError(CE_Failure, CPLE_FileIO,
1515 0 : "Cannot delete %s", pszName);
1516 0 : return OGRERR_FAILURE;
1517 : }
1518 : }
1519 :
1520 : /* Maintain new ZIP files opened */
1521 4 : void *hZIP = CPLCreateZip(pszName, NULL);
1522 4 : if (hZIP == NULL)
1523 : {
1524 : CPLError(CE_Failure, CPLE_FileIO,
1525 0 : "Cannot create %s", pszName);
1526 0 : return OGRERR_FAILURE;
1527 : }
1528 :
1529 : /* Write uncopressed mimetype */
1530 4 : char** papszOptions = CSLAddString(NULL, "COMPRESSED=NO");
1531 4 : CPLCreateFileInZip(hZIP, "mimetype", papszOptions );
1532 : CPLWriteFileInZip(hZIP, "application/vnd.oasis.opendocument.spreadsheet",
1533 4 : strlen("application/vnd.oasis.opendocument.spreadsheet"));
1534 4 : CPLCloseFileInZip(hZIP);
1535 4 : CSLDestroy(papszOptions);
1536 :
1537 : /* Now close ZIP file */
1538 4 : CPLCloseZip(hZIP);
1539 4 : hZIP = NULL;
1540 :
1541 : /* Re-open with VSILFILE */
1542 4 : VSILFILE* fpZIP = VSIFOpenL(CPLSPrintf("/vsizip/%s", pszName), "ab");
1543 4 : if (fpZIP == NULL)
1544 0 : return OGRERR_FAILURE;
1545 :
1546 : VSILFILE* fp;
1547 : int i;
1548 :
1549 4 : fp = VSIFOpenL(CPLSPrintf("/vsizip/%s/META-INF/manifest.xml", pszName), "wb");
1550 4 : VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1551 4 : VSIFPrintfL(fp, "<manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\">\n");
1552 : VSIFPrintfL(fp, "<manifest:file-entry "
1553 : "manifest:media-type=\"application/vnd.oasis.opendocument.spreadsheet\" "
1554 4 : "manifest:version=\"1.2\" manifest:full-path=\"/\"/>\n");
1555 : VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
1556 4 : "manifest:full-path=\"content.xml\"/>\n");
1557 : VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
1558 4 : "manifest:full-path=\"styles.xml\"/>\n");
1559 : VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
1560 4 : "manifest:full-path=\"meta.xml\"/>\n");
1561 : VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
1562 4 : "manifest:full-path=\"settings.xml\"/>\n");
1563 4 : VSIFPrintfL(fp, "</manifest:manifest>\n");
1564 4 : VSIFCloseL(fp);
1565 :
1566 4 : fp = VSIFOpenL(CPLSPrintf("/vsizip/%s/meta.xml", pszName), "wb");
1567 4 : VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1568 : VSIFPrintfL(fp, "<office:document-meta "
1569 : "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" "
1570 4 : "office:version=\"1.2\">\n");
1571 4 : VSIFPrintfL(fp, "</office:document-meta>\n");
1572 4 : VSIFCloseL(fp);
1573 :
1574 4 : fp = VSIFOpenL(CPLSPrintf("/vsizip/%s/settings.xml", pszName), "wb");
1575 4 : VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1576 : VSIFPrintfL(fp, "<office:document-settings "
1577 : "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" "
1578 : "xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\" "
1579 : "xmlns:ooo=\"http://openoffice.org/2004/office\" "
1580 4 : "office:version=\"1.2\">\n");
1581 4 : VSIFPrintfL(fp, "<office:settings>\n");
1582 4 : VSIFPrintfL(fp, "<config:config-item-set config:name=\"ooo:view-settings\">\n");
1583 4 : VSIFPrintfL(fp, "<config:config-item-map-indexed config:name=\"Views\">\n");
1584 4 : VSIFPrintfL(fp, "<config:config-item-map-entry>\n");
1585 4 : VSIFPrintfL(fp, "<config:config-item-map-named config:name=\"Tables\">\n");
1586 36 : for(i=0;i<nLayers;i++)
1587 : {
1588 32 : OGRLayer* poLayer = GetLayer(i);
1589 32 : if (HasHeaderLine(poLayer))
1590 : {
1591 : /* Add vertical splitter */
1592 4 : char* pszXML = OGRGetXML_UTF8_EscapedString(GetLayer(i)->GetName());
1593 4 : VSIFPrintfL(fp, "<config:config-item-map-entry config:name=\"%s\">\n", pszXML);
1594 4 : CPLFree(pszXML);
1595 4 : VSIFPrintfL(fp, "<config:config-item config:name=\"VerticalSplitMode\" config:type=\"short\">2</config:config-item>\n");
1596 4 : VSIFPrintfL(fp, "<config:config-item config:name=\"VerticalSplitPosition\" config:type=\"int\">1</config:config-item>\n");
1597 4 : VSIFPrintfL(fp, "<config:config-item config:name=\"ActiveSplitRange\" config:type=\"short\">2</config:config-item>\n");
1598 4 : VSIFPrintfL(fp, "<config:config-item config:name=\"PositionTop\" config:type=\"int\">0</config:config-item>\n");
1599 4 : VSIFPrintfL(fp, "<config:config-item config:name=\"PositionBottom\" config:type=\"int\">1</config:config-item>\n");
1600 4 : VSIFPrintfL(fp, "</config:config-item-map-entry>\n");
1601 : }
1602 : }
1603 4 : VSIFPrintfL(fp, "</config:config-item-map-named>\n");
1604 4 : VSIFPrintfL(fp, "</config:config-item-map-entry>\n");
1605 4 : VSIFPrintfL(fp, "</config:config-item-map-indexed>\n");
1606 4 : VSIFPrintfL(fp, "</config:config-item-set>\n");
1607 4 : VSIFPrintfL(fp, "</office:settings>\n");
1608 4 : VSIFPrintfL(fp, "</office:document-settings>\n");
1609 4 : VSIFCloseL(fp);
1610 :
1611 4 : fp = VSIFOpenL(CPLSPrintf("/vsizip/%s/styles.xml", pszName), "wb");
1612 4 : VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1613 : VSIFPrintfL(fp, "<office:document-styles "
1614 : "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" "
1615 : "xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" "
1616 4 : "office:version=\"1.2\">\n");
1617 4 : VSIFPrintfL(fp, "<office:styles>\n");
1618 : VSIFPrintfL(fp, "<style:style style:name=\"Default\" "
1619 4 : "style:family=\"table-cell\">\n");
1620 4 : VSIFPrintfL(fp, "</style:style>\n");
1621 4 : VSIFPrintfL(fp, "</office:styles>\n");
1622 4 : VSIFPrintfL(fp, "</office:document-styles>\n");
1623 4 : VSIFCloseL(fp);
1624 :
1625 4 : fp = VSIFOpenL(CPLSPrintf("/vsizip/%s/content.xml", pszName), "wb");
1626 4 : VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1627 : VSIFPrintfL(fp, "<office:document-content "
1628 : "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" "
1629 : "xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" "
1630 : "xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" "
1631 : "xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\" "
1632 : "xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\" "
1633 : "xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\" "
1634 : "xmlns:of=\"urn:oasis:names:tc:opendocument:xmlns:of:1.2\" "
1635 4 : "office:version=\"1.2\">\n");
1636 4 : VSIFPrintfL(fp, "<office:scripts/>\n");
1637 4 : VSIFPrintfL(fp, "<office:automatic-styles>\n");
1638 : VSIFPrintfL(fp, "<style:style style:name=\"co1\" "
1639 4 : "style:family=\"table-column\">\n");
1640 : VSIFPrintfL(fp, "<style:table-column-properties "
1641 : "fo:break-before=\"auto\" "
1642 4 : "style:column-width=\"2.5cm\"/>\n");
1643 4 : VSIFPrintfL(fp, "</style:style>\n");
1644 : VSIFPrintfL(fp, "<style:style style:name=\"co2\" "
1645 4 : "style:family=\"table-column\">\n");
1646 : VSIFPrintfL(fp, "<style:table-column-properties "
1647 : "fo:break-before=\"auto\" "
1648 4 : "style:column-width=\"5cm\"/>\n");
1649 4 : VSIFPrintfL(fp, "</style:style>\n");
1650 : VSIFPrintfL(fp, "<number:date-style style:name=\"nDate\" "
1651 4 : "number:automatic-order=\"true\">\n");
1652 4 : VSIFPrintfL(fp, "<number:day number:style=\"long\"/>\n");
1653 4 : VSIFPrintfL(fp, "<number:text>/</number:text>\n");
1654 4 : VSIFPrintfL(fp, "<number:month number:style=\"long\"/>\n");
1655 4 : VSIFPrintfL(fp, "<number:text>/</number:text>\n");
1656 4 : VSIFPrintfL(fp, "<number:year/>\n");
1657 4 : VSIFPrintfL(fp, "</number:date-style>\n");
1658 4 : VSIFPrintfL(fp, "<number:time-style style:name=\"nTime\">\n");
1659 4 : VSIFPrintfL(fp, "<number:hours number:style=\"long\"/>\n");
1660 4 : VSIFPrintfL(fp, "<number:text>:</number:text>\n");
1661 4 : VSIFPrintfL(fp, "<number:minutes number:style=\"long\"/>\n");
1662 4 : VSIFPrintfL(fp, "<number:text>:</number:text>\n");
1663 4 : VSIFPrintfL(fp, "<number:seconds number:style=\"long\"/>\n");
1664 4 : VSIFPrintfL(fp, "</number:time-style>\n");
1665 : VSIFPrintfL(fp, "<number:date-style style:name=\"nDateTime\" "
1666 4 : "number:automatic-order=\"true\">\n");
1667 4 : VSIFPrintfL(fp, "<number:day number:style=\"long\"/>\n");
1668 4 : VSIFPrintfL(fp, "<number:text>/</number:text>\n");
1669 4 : VSIFPrintfL(fp, "<number:month number:style=\"long\"/>\n");
1670 4 : VSIFPrintfL(fp, "<number:text>/</number:text>\n");
1671 4 : VSIFPrintfL(fp, "<number:year number:style=\"long\"/>\n");
1672 4 : VSIFPrintfL(fp, "<number:text> </number:text>\n");
1673 4 : VSIFPrintfL(fp, "<number:hours number:style=\"long\"/>\n");
1674 4 : VSIFPrintfL(fp, "<number:text>:</number:text>\n");
1675 4 : VSIFPrintfL(fp, "<number:minutes number:style=\"long\"/>\n");
1676 4 : VSIFPrintfL(fp, "<number:text>:</number:text>\n");
1677 4 : VSIFPrintfL(fp, "<number:seconds number:style=\"long\"/>\n");
1678 4 : VSIFPrintfL(fp, "</number:date-style>\n");
1679 : VSIFPrintfL(fp, "<style:style style:name=\"stDate\" "
1680 : "style:family=\"table-cell\" "
1681 : "style:parent-style-name=\"Default\" "
1682 4 : "style:data-style-name=\"nDate\"/>\n");
1683 : VSIFPrintfL(fp, "<style:style style:name=\"stTime\" "
1684 : "style:family=\"table-cell\" "
1685 : "style:parent-style-name=\"Default\" "
1686 4 : "style:data-style-name=\"nTime\"/>\n");
1687 : VSIFPrintfL(fp, "<style:style style:name=\"stDateTime\" "
1688 : "style:family=\"table-cell\" "
1689 : "style:parent-style-name=\"Default\" "
1690 4 : "style:data-style-name=\"nDateTime\"/>\n");
1691 4 : VSIFPrintfL(fp, "</office:automatic-styles>\n");
1692 4 : VSIFPrintfL(fp, "<office:body>\n");
1693 4 : VSIFPrintfL(fp, "<office:spreadsheet>\n");
1694 36 : for(i=0;i<nLayers;i++)
1695 : {
1696 32 : WriteLayer(fp, GetLayer(i));
1697 : }
1698 4 : VSIFPrintfL(fp, "</office:spreadsheet>\n");
1699 4 : VSIFPrintfL(fp, "</office:body>\n");
1700 4 : VSIFPrintfL(fp, "</office:document-content>\n");
1701 4 : VSIFCloseL(fp);
1702 :
1703 : /* Now close ZIP file */
1704 4 : VSIFCloseL(fpZIP);
1705 :
1706 : /* Reset updated flag at datasource and layer level */
1707 4 : bUpdated = FALSE;
1708 36 : for(int i = 0; i<nLayers; i++)
1709 : {
1710 32 : ((OGRODSLayer*)papoLayers[i])->SetUpdated(FALSE);
1711 : }
1712 :
1713 4 : return OGRERR_NONE;
1714 : }
1715 :
1716 : /************************************************************************/
1717 : /* EvaluateRange() */
1718 : /************************************************************************/
1719 :
1720 68 : int ODSCellEvaluator::EvaluateRange(int nRow1, int nCol1, int nRow2, int nCol2,
1721 : std::vector<ods_formula_node>& aoOutValues)
1722 : {
1723 136 : if (nRow1 < 0 || nRow1 >= poLayer->GetFeatureCount(FALSE) ||
1724 68 : nCol1 < 0 || nCol1 >= poLayer->GetLayerDefn()->GetFieldCount())
1725 : {
1726 : CPLError(CE_Failure, CPLE_AppDefined,
1727 0 : "Invalid cell (row=%d, col=%d)", nRow1 + 1, nCol1 + 1);
1728 0 : return FALSE;
1729 : }
1730 :
1731 136 : if (nRow2 < 0 || nRow2 >= poLayer->GetFeatureCount(FALSE) ||
1732 68 : nCol2 < 0 || nCol2 >= poLayer->GetLayerDefn()->GetFieldCount())
1733 : {
1734 : CPLError(CE_Failure, CPLE_AppDefined,
1735 0 : "Invalid cell (row=%d, col=%d)", nRow2 + 1, nCol2 + 1);
1736 0 : return FALSE;
1737 : }
1738 :
1739 68 : int nIndexBackup = poLayer->GetNextReadFID();
1740 :
1741 68 : if (poLayer->SetNextByIndex(nRow1) != OGRERR_NONE)
1742 : {
1743 : CPLError(CE_Failure, CPLE_AppDefined,
1744 0 : "Cannot fetch feature for row = %d", nRow1);
1745 0 : return FALSE;
1746 : }
1747 :
1748 130 : for(int nRow = nRow1; nRow <= nRow2; nRow ++)
1749 : {
1750 68 : OGRFeature* poFeature = poLayer->GetNextFeatureWithoutFIDHack();
1751 :
1752 68 : if (poFeature == NULL)
1753 : {
1754 : CPLError(CE_Failure, CPLE_AppDefined,
1755 0 : "Cannot fetch feature for for row = %d", nRow);
1756 0 : poLayer->SetNextByIndex(nIndexBackup);
1757 0 : return FALSE;
1758 : }
1759 :
1760 166 : for(int nCol = nCol1; nCol <= nCol2; nCol++)
1761 : {
1762 104 : if (!poFeature->IsFieldSet(nCol))
1763 : {
1764 12 : aoOutValues.push_back(ods_formula_node());
1765 : }
1766 92 : else if (poFeature->GetFieldDefnRef(nCol)->GetType() == OFTInteger)
1767 : {
1768 0 : aoOutValues.push_back(ods_formula_node(poFeature->GetFieldAsInteger(nCol)));
1769 : }
1770 92 : else if (poFeature->GetFieldDefnRef(nCol)->GetType() == OFTReal)
1771 : {
1772 0 : aoOutValues.push_back(ods_formula_node(poFeature->GetFieldAsDouble(nCol)));
1773 : }
1774 : else
1775 : {
1776 92 : std::string osVal(poFeature->GetFieldAsString(nCol));
1777 184 : if (strncmp(osVal.c_str(), "of:=", 4) == 0)
1778 : {
1779 20 : delete poFeature;
1780 20 : poFeature = NULL;
1781 :
1782 20 : if (!Evaluate(nRow, nCol))
1783 : {
1784 : /*CPLError(CE_Warning, CPLE_AppDefined,
1785 : "Formula at cell (%d, %d) has not yet been resolved",
1786 : nRow + 1, nCol + 1);*/
1787 6 : poLayer->SetNextByIndex(nIndexBackup);
1788 6 : return FALSE;
1789 : }
1790 :
1791 14 : poLayer->SetNextByIndex(nRow);
1792 14 : poFeature = poLayer->GetNextFeatureWithoutFIDHack();
1793 :
1794 14 : if (!poFeature->IsFieldSet(nCol))
1795 : {
1796 0 : aoOutValues.push_back(ods_formula_node());
1797 : }
1798 14 : else if (poFeature->GetFieldDefnRef(nCol)->GetType() == OFTInteger)
1799 : {
1800 0 : aoOutValues.push_back(ods_formula_node(poFeature->GetFieldAsInteger(nCol)));
1801 : }
1802 14 : else if (poFeature->GetFieldDefnRef(nCol)->GetType() == OFTReal)
1803 : {
1804 0 : aoOutValues.push_back(ods_formula_node(poFeature->GetFieldAsDouble(nCol)));
1805 : }
1806 : else
1807 : {
1808 14 : osVal = poFeature->GetFieldAsString(nCol);
1809 14 : if (strncmp(osVal.c_str(), "of:=", 4) != 0)
1810 : {
1811 2 : CPLValueType eType = CPLGetValueType(osVal.c_str());
1812 : /* Try to convert into numeric value if possible */
1813 2 : if (eType != CPL_VALUE_STRING)
1814 2 : aoOutValues.push_back(ods_formula_node(CPLAtofM(osVal.c_str())));
1815 : else
1816 0 : aoOutValues.push_back(ods_formula_node(osVal.c_str()));
1817 : }
1818 : }
1819 : }
1820 : else
1821 : {
1822 72 : CPLValueType eType = CPLGetValueType(osVal.c_str());
1823 : /* Try to convert into numeric value if possible */
1824 72 : if (eType != CPL_VALUE_STRING)
1825 26 : aoOutValues.push_back(ods_formula_node(CPLAtofM(osVal.c_str())));
1826 : else
1827 46 : aoOutValues.push_back(ods_formula_node(osVal.c_str()));
1828 0 : }
1829 : }
1830 : }
1831 :
1832 62 : delete poFeature;
1833 : }
1834 :
1835 62 : poLayer->SetNextByIndex(nIndexBackup);
1836 :
1837 62 : return TRUE;
1838 : }
1839 :
1840 : /************************************************************************/
1841 : /* Evaluate() */
1842 : /************************************************************************/
1843 :
1844 240 : int ODSCellEvaluator::Evaluate(int nRow, int nCol)
1845 : {
1846 240 : if (oVisisitedCells.find(std::pair<int,int>(nRow, nCol)) != oVisisitedCells.end())
1847 : {
1848 : CPLError(CE_Failure, CPLE_AppDefined,
1849 6 : "Circular dependency with (row=%d, col=%d)", nRow + 1, nCol + 1);
1850 6 : return FALSE;
1851 : }
1852 :
1853 234 : oVisisitedCells.insert(std::pair<int,int>(nRow, nCol));
1854 :
1855 234 : if (poLayer->SetNextByIndex(nRow) != OGRERR_NONE)
1856 : {
1857 : CPLError(CE_Failure, CPLE_AppDefined,
1858 0 : "Cannot fetch feature for row = %d", nRow);
1859 0 : return FALSE;
1860 : }
1861 :
1862 234 : OGRFeature* poFeature = poLayer->GetNextFeatureWithoutFIDHack();
1863 234 : if (poFeature->IsFieldSet(nCol) &&
1864 : poFeature->GetFieldDefnRef(nCol)->GetType() == OFTString)
1865 : {
1866 234 : const char* pszVal = poFeature->GetFieldAsString(nCol);
1867 234 : if (strncmp(pszVal, "of:=", 4) == 0)
1868 : {
1869 232 : ods_formula_node* expr_out = ods_formula_compile( pszVal + 4 );
1870 232 : if (expr_out &&
1871 : expr_out->Evaluate(this) &&
1872 : expr_out->eNodeType == SNT_CONSTANT)
1873 : {
1874 : /* Refetch feature in case Evaluate() modified another cell in this row */
1875 212 : delete poFeature;
1876 212 : poLayer->SetNextByIndex(nRow);
1877 212 : poFeature = poLayer->GetNextFeatureWithoutFIDHack();
1878 :
1879 212 : if (expr_out->field_type == ODS_FIELD_TYPE_EMPTY)
1880 : {
1881 0 : poFeature->UnsetField(nCol);
1882 0 : poLayer->SetFeatureWithoutFIDHack(poFeature);
1883 : }
1884 212 : else if (expr_out->field_type == ODS_FIELD_TYPE_INTEGER)
1885 : {
1886 166 : poFeature->SetField(nCol, expr_out->int_value);
1887 166 : poLayer->SetFeatureWithoutFIDHack(poFeature);
1888 : }
1889 46 : else if (expr_out->field_type == ODS_FIELD_TYPE_FLOAT)
1890 : {
1891 14 : poFeature->SetField(nCol, expr_out->float_value);
1892 14 : poLayer->SetFeatureWithoutFIDHack(poFeature);
1893 : }
1894 32 : else if (expr_out->field_type == ODS_FIELD_TYPE_STRING)
1895 : {
1896 32 : poFeature->SetField(nCol, expr_out->string_value);
1897 32 : poLayer->SetFeatureWithoutFIDHack(poFeature);
1898 : }
1899 : }
1900 232 : delete expr_out;
1901 : }
1902 : }
1903 :
1904 234 : delete poFeature;
1905 :
1906 234 : return TRUE;
1907 : }
|