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