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 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 1012 : OGRFeature* OGRODSLayer::GetNextFeature()
104 : {
105 1012 : OGRFeature* poFeature = OGRMemLayer::GetNextFeature();
106 1012 : if (poFeature)
107 848 : poFeature->SetFID(poFeature->GetFID() + 1 + bHasHeaderLine);
108 1012 : 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 381 : OGRLayer *OGRODSDataSource::GetLayer( int iLayer )
234 :
235 : {
236 381 : AnalyseFile();
237 381 : if (iLayer < 0 || iLayer >= nLayers)
238 2 : return NULL;
239 :
240 379 : return papoLayers[iLayer];
241 : }
242 :
243 : /************************************************************************/
244 : /* GetLayerCount() */
245 : /************************************************************************/
246 :
247 351 : int OGRODSDataSource::GetLayerCount()
248 : {
249 351 : AnalyseFile();
250 351 : 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 : apoCurLineValues.push_back(osValue.size() ? osValue : osFormula);
954 2195 : apoCurLineTypes.push_back(osValueType);
955 : }
956 :
957 1530 : nCurCol += nCellsRepeated;
958 : }
959 1887 : }
960 :
961 : /************************************************************************/
962 : /* dataHandlerTextP() */
963 : /************************************************************************/
964 :
965 454 : void OGRODSDataSource::dataHandlerTextP(const char *data, int nLen)
966 : {
967 454 : osValue.append(data, nLen);
968 454 : }
969 :
970 : /************************************************************************/
971 : /* AnalyseFile() */
972 : /************************************************************************/
973 :
974 740 : void OGRODSDataSource::AnalyseFile()
975 : {
976 740 : if (bAnalysedFile)
977 727 : return;
978 :
979 13 : bAnalysedFile = TRUE;
980 :
981 13 : AnalyseSettings();
982 :
983 13 : oParser = OGRCreateExpatXMLParser();
984 13 : XML_SetElementHandler(oParser, ::startElementCbk, ::endElementCbk);
985 13 : XML_SetCharacterDataHandler(oParser, ::dataHandlerCbk);
986 13 : XML_SetUserData(oParser, this);
987 :
988 13 : nDepth = 0;
989 13 : nStackDepth = 0;
990 13 : stateStack[0].nBeginDepth = 0;
991 13 : bStopParsing = FALSE;
992 13 : nWithoutEventCounter = 0;
993 :
994 13 : VSIFSeekL( fpContent, 0, SEEK_SET );
995 :
996 : char aBuf[BUFSIZ];
997 : int nDone;
998 50 : do
999 : {
1000 50 : nDataHandlerCounter = 0;
1001 : unsigned int nLen =
1002 50 : (unsigned int)VSIFReadL( aBuf, 1, sizeof(aBuf), fpContent );
1003 50 : nDone = VSIFEofL(fpContent);
1004 50 : 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 50 : nWithoutEventCounter ++;
1014 : } while (!nDone && !bStopParsing && nWithoutEventCounter < 10);
1015 :
1016 13 : XML_ParserFree(oParser);
1017 13 : oParser = NULL;
1018 :
1019 13 : 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 13 : VSIFCloseL(fpContent);
1027 13 : fpContent = NULL;
1028 :
1029 13 : bUpdated = FALSE;
1030 : }
1031 :
1032 : /************************************************************************/
1033 : /* startElementStylesCbk() */
1034 : /************************************************************************/
1035 :
1036 2060 : static void XMLCALL startElementStylesCbk(void *pUserData, const char *pszName,
1037 : const char **ppszAttr)
1038 : {
1039 2060 : ((OGRODSDataSource*)pUserData)->startElementStylesCbk(pszName, ppszAttr);
1040 2060 : }
1041 :
1042 2060 : void OGRODSDataSource::startElementStylesCbk(const char *pszName,
1043 : const char **ppszAttr)
1044 : {
1045 2060 : if (bStopParsing) return;
1046 :
1047 2060 : nWithoutEventCounter = 0;
1048 :
1049 2060 : if (nStackDepth == 0 &&
1050 : strcmp(pszName, "config:config-item-map-named") == 0 &&
1051 : strcmp(GetAttributeValue(ppszAttr, "config:name", ""), "Tables") == 0)
1052 : {
1053 12 : stateStack[++nStackDepth].nBeginDepth = nDepth;
1054 : }
1055 2140 : else if (nStackDepth == 1 && strcmp(pszName, "config:config-item-map-entry") == 0)
1056 : {
1057 92 : const char* pszTableName = GetAttributeValue(ppszAttr, "config:name", NULL);
1058 92 : if (pszTableName)
1059 : {
1060 92 : osCurrentConfigTableName = pszTableName;
1061 92 : nFlags = 0;
1062 92 : stateStack[++nStackDepth].nBeginDepth = nDepth;
1063 : }
1064 : }
1065 1956 : else if (nStackDepth == 2 && strcmp(pszName, "config:config-item") == 0)
1066 : {
1067 1342 : const char* pszConfigName = GetAttributeValue(ppszAttr, "config:name", NULL);
1068 1342 : if (pszConfigName)
1069 : {
1070 1342 : osConfigName = pszConfigName;
1071 1342 : osValue = "";
1072 1342 : stateStack[++nStackDepth].nBeginDepth = nDepth;
1073 : }
1074 : }
1075 :
1076 2060 : nDepth++;
1077 : }
1078 :
1079 : /************************************************************************/
1080 : /* endElementStylesCbk() */
1081 : /************************************************************************/
1082 :
1083 2060 : static void XMLCALL endElementStylesCbk(void *pUserData, const char *pszName)
1084 : {
1085 2060 : ((OGRODSDataSource*)pUserData)->endElementStylesCbk(pszName);
1086 2060 : }
1087 :
1088 2060 : void OGRODSDataSource::endElementStylesCbk(const char *pszName)
1089 : {
1090 2060 : if (bStopParsing) return;
1091 :
1092 2060 : nWithoutEventCounter = 0;
1093 2060 : nDepth--;
1094 :
1095 2060 : if (nStackDepth > 0 && stateStack[nStackDepth].nBeginDepth == nDepth)
1096 : {
1097 1446 : if (nStackDepth == 2)
1098 : {
1099 92 : if (nFlags == (1 | 2))
1100 2 : osSetLayerHasSplitter.insert(osCurrentConfigTableName);
1101 : }
1102 1446 : if (nStackDepth == 3)
1103 : {
1104 1342 : if (osConfigName == "VerticalSplitMode" && osValue == "2")
1105 2 : nFlags |= 1;
1106 1340 : else if (osConfigName == "VerticalSplitPosition" && osValue == "1")
1107 2 : nFlags |= 2;
1108 : }
1109 1446 : nStackDepth --;
1110 : }
1111 : }
1112 :
1113 : /************************************************************************/
1114 : /* dataHandlerStylesCbk() */
1115 : /************************************************************************/
1116 :
1117 2161 : static void XMLCALL dataHandlerStylesCbk(void *pUserData, const char *data, int nLen)
1118 : {
1119 2161 : ((OGRODSDataSource*)pUserData)->dataHandlerStylesCbk(data, nLen);
1120 2161 : }
1121 :
1122 2161 : void OGRODSDataSource::dataHandlerStylesCbk(const char *data, int nLen)
1123 : {
1124 2161 : if (bStopParsing) return;
1125 :
1126 2161 : nDataHandlerCounter ++;
1127 2161 : 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 2161 : nWithoutEventCounter = 0;
1137 :
1138 2161 : if (nStackDepth == 3)
1139 : {
1140 1342 : 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 13 : void OGRODSDataSource::AnalyseSettings()
1152 : {
1153 13 : if (fpSettings == NULL)
1154 1 : return;
1155 :
1156 12 : oParser = OGRCreateExpatXMLParser();
1157 12 : XML_SetElementHandler(oParser, ::startElementStylesCbk, ::endElementStylesCbk);
1158 12 : XML_SetCharacterDataHandler(oParser, ::dataHandlerStylesCbk);
1159 12 : XML_SetUserData(oParser, this);
1160 :
1161 12 : nDepth = 0;
1162 12 : nStackDepth = 0;
1163 12 : bStopParsing = FALSE;
1164 12 : nWithoutEventCounter = 0;
1165 :
1166 12 : VSIFSeekL( fpSettings, 0, SEEK_SET );
1167 :
1168 : char aBuf[BUFSIZ];
1169 : int nDone;
1170 43 : do
1171 : {
1172 43 : nDataHandlerCounter = 0;
1173 : unsigned int nLen =
1174 43 : (unsigned int)VSIFReadL( aBuf, 1, sizeof(aBuf), fpSettings );
1175 43 : nDone = VSIFEofL(fpSettings);
1176 43 : 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 43 : nWithoutEventCounter ++;
1186 : } while (!nDone && !bStopParsing && nWithoutEventCounter < 10);
1187 :
1188 12 : XML_ParserFree(oParser);
1189 12 : oParser = NULL;
1190 :
1191 12 : 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 12 : VSIFCloseL(fpSettings);
1199 12 : fpSettings = NULL;
1200 : }
1201 :
1202 : /************************************************************************/
1203 : /* CreateLayer() */
1204 : /************************************************************************/
1205 :
1206 : OGRLayer *
1207 8 : 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 8 : 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 8 : AnalyseFile();
1227 :
1228 : /* -------------------------------------------------------------------- */
1229 : /* Do we already have this layer? If so, should we blow it */
1230 : /* away? */
1231 : /* -------------------------------------------------------------------- */
1232 : int iLayer;
1233 :
1234 36 : for( iLayer = 0; iLayer < nLayers; iLayer++ )
1235 : {
1236 28 : 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 8 : OGRLayer* poLayer = new OGRODSLayer(this, pszLayerName, TRUE);
1259 :
1260 8 : papoLayers = (OGRLayer**)CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
1261 8 : papoLayers[nLayers] = poLayer;
1262 8 : nLayers ++;
1263 :
1264 8 : bUpdated = TRUE;
1265 :
1266 8 : 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 32 : static int HasHeaderLine(OGRLayer* poLayer)
1347 : {
1348 32 : OGRFeatureDefn* poFDefn = poLayer->GetLayerDefn();
1349 32 : int bHasHeaders = FALSE;
1350 :
1351 152 : for(int j=0;j<poFDefn->GetFieldCount();j++)
1352 : {
1353 120 : if (strcmp(poFDefn->GetFieldDefn(j)->GetNameRef(),
1354 : CPLSPrintf("Field%d", j+1)) != 0)
1355 48 : bHasHeaders = TRUE;
1356 : }
1357 :
1358 32 : return bHasHeaders;
1359 : }
1360 :
1361 : /************************************************************************/
1362 : /* WriteLayer() */
1363 : /************************************************************************/
1364 :
1365 16 : static void WriteLayer(VSILFILE* fp, OGRLayer* poLayer)
1366 : {
1367 : int j;
1368 16 : const char* pszLayerName = poLayer->GetName();
1369 16 : char* pszXML = OGRGetXML_UTF8_EscapedString(pszLayerName);
1370 16 : VSIFPrintfL(fp, "<table:table table:name=\"%s\">\n", pszXML);
1371 16 : CPLFree(pszXML);
1372 :
1373 16 : poLayer->ResetReading();
1374 :
1375 16 : OGRFeature* poFeature = poLayer->GetNextFeature();
1376 :
1377 16 : OGRFeatureDefn* poFDefn = poLayer->GetLayerDefn();
1378 16 : int bHasHeaders = HasHeaderLine(poLayer);
1379 :
1380 76 : for(j=0;j<poFDefn->GetFieldCount();j++)
1381 : {
1382 60 : int nStyleNumber = 1;
1383 60 : if (poFDefn->GetFieldDefn(j)->GetType() == OFTDateTime)
1384 6 : nStyleNumber = 2;
1385 : VSIFPrintfL(fp, "<table:table-column table:style-name=\"co%d\" "
1386 : "table:default-cell-style-name=\"Default\"/>\n",
1387 60 : nStyleNumber);
1388 : }
1389 :
1390 16 : if (bHasHeaders && poFeature != NULL)
1391 : {
1392 2 : VSIFPrintfL(fp, "<table:table-row>\n");
1393 26 : for(j=0;j<poFDefn->GetFieldCount();j++)
1394 : {
1395 24 : const char* pszVal = poFDefn->GetFieldDefn(j)->GetNameRef();
1396 :
1397 24 : VSIFPrintfL(fp, "<table:table-cell office:value-type=\"string\">\n");
1398 24 : pszXML = OGRGetXML_UTF8_EscapedString(pszVal);
1399 24 : VSIFPrintfL(fp, "<text:p>%s</text:p>\n", pszXML);
1400 24 : CPLFree(pszXML);
1401 24 : VSIFPrintfL(fp, "</table:table-cell>\n");
1402 : }
1403 2 : VSIFPrintfL(fp, "</table:table-row>\n");
1404 : }
1405 :
1406 118 : while(poFeature != NULL)
1407 : {
1408 86 : VSIFPrintfL(fp, "<table:table-row>\n");
1409 510 : for(j=0;j<poFeature->GetFieldCount();j++)
1410 : {
1411 424 : if (poFeature->IsFieldSet(j))
1412 : {
1413 110 : OGRFieldType eType = poFDefn->GetFieldDefn(j)->GetType();
1414 :
1415 110 : if (eType == OFTReal)
1416 : {
1417 : VSIFPrintfL(fp, "<table:table-cell office:value-type=\"float\" "
1418 : "office:value=\"%.16f\"/>\n",
1419 16 : poFeature->GetFieldAsDouble(j));
1420 : }
1421 94 : else if (eType == OFTInteger)
1422 : {
1423 : VSIFPrintfL(fp, "<table:table-cell office:value-type=\"float\" "
1424 : "office:value=\"%d\"/>\n",
1425 12 : poFeature->GetFieldAsInteger(j));
1426 : }
1427 82 : else if (eType == OFTDateTime)
1428 : {
1429 : int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZFlag;
1430 : poFeature->GetFieldAsDateTime(j, &nYear, &nMonth, &nDay,
1431 8 : &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 8 : nYear, nMonth, nDay, nHour, nMinute, nSecond);
1436 : VSIFPrintfL(fp, "<text:p>%02d/%02d/%04d %02d:%02d:%02d</text:p>\n",
1437 8 : nDay, nMonth, nYear, nHour, nMinute, nSecond);
1438 8 : VSIFPrintfL(fp, "</table:table-cell>\n");
1439 : }
1440 74 : 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 74 : else if (eType == OFTTime)
1454 : {
1455 : int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZFlag;
1456 : poFeature->GetFieldAsDateTime(j, &nYear, &nMonth, &nDay,
1457 2 : &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 2 : nHour, nMinute, nSecond);
1462 : VSIFPrintfL(fp, "<text:p>%02d:%02d:%02d</text:p>\n",
1463 2 : nHour, nMinute, nSecond);
1464 2 : VSIFPrintfL(fp, "</table:table-cell>\n");
1465 : }
1466 : else
1467 : {
1468 72 : const char* pszVal = poFeature->GetFieldAsString(j);
1469 72 : pszXML = OGRGetXML_UTF8_EscapedString(pszVal);
1470 72 : if (strncmp(pszVal, "of:=", 4) == 0)
1471 : {
1472 0 : VSIFPrintfL(fp, "<table:table-cell table:formula=\"%s\"/>\n", pszXML);
1473 : }
1474 : else
1475 : {
1476 72 : VSIFPrintfL(fp, "<table:table-cell office:value-type=\"string\">\n");
1477 72 : VSIFPrintfL(fp, "<text:p>%s</text:p>\n", pszXML);
1478 72 : VSIFPrintfL(fp, "</table:table-cell>\n");
1479 : }
1480 72 : CPLFree(pszXML);
1481 : }
1482 : }
1483 : else
1484 : {
1485 314 : VSIFPrintfL(fp, "<table:table-cell/>\n");
1486 : }
1487 : }
1488 86 : VSIFPrintfL(fp, "</table:table-row>\n");
1489 :
1490 86 : delete poFeature;
1491 86 : poFeature = poLayer->GetNextFeature();
1492 : }
1493 :
1494 16 : VSIFPrintfL(fp, "</table:table>\n");
1495 16 : }
1496 :
1497 : /************************************************************************/
1498 : /* SyncToDisk() */
1499 : /************************************************************************/
1500 :
1501 14 : OGRErr OGRODSDataSource::SyncToDisk()
1502 : {
1503 14 : if (!bUpdated)
1504 12 : return OGRERR_NONE;
1505 :
1506 2 : CPLAssert(fpSettings == NULL);
1507 2 : CPLAssert(fpContent == NULL);
1508 :
1509 : VSIStatBufL sStat;
1510 2 : if (VSIStatL(pszName, &sStat) == 0)
1511 : {
1512 1 : 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 2 : void *hZIP = CPLCreateZip(pszName, NULL);
1522 2 : 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 2 : char** papszOptions = CSLAddString(NULL, "COMPRESSED=NO");
1531 2 : CPLCreateFileInZip(hZIP, "mimetype", papszOptions );
1532 : CPLWriteFileInZip(hZIP, "application/vnd.oasis.opendocument.spreadsheet",
1533 2 : strlen("application/vnd.oasis.opendocument.spreadsheet"));
1534 2 : CPLCloseFileInZip(hZIP);
1535 2 : CSLDestroy(papszOptions);
1536 :
1537 : /* Now close ZIP file */
1538 2 : CPLCloseZip(hZIP);
1539 2 : hZIP = NULL;
1540 :
1541 : /* Re-open with VSILFILE */
1542 2 : VSILFILE* fpZIP = VSIFOpenL(CPLSPrintf("/vsizip/%s", pszName), "ab");
1543 2 : if (fpZIP == NULL)
1544 0 : return OGRERR_FAILURE;
1545 :
1546 : VSILFILE* fp;
1547 : int i;
1548 :
1549 2 : fp = VSIFOpenL(CPLSPrintf("/vsizip/%s/META-INF/manifest.xml", pszName), "wb");
1550 2 : VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1551 2 : 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 2 : "manifest:version=\"1.2\" manifest:full-path=\"/\"/>\n");
1555 : VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
1556 2 : "manifest:full-path=\"content.xml\"/>\n");
1557 : VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
1558 2 : "manifest:full-path=\"styles.xml\"/>\n");
1559 : VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
1560 2 : "manifest:full-path=\"meta.xml\"/>\n");
1561 : VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
1562 2 : "manifest:full-path=\"settings.xml\"/>\n");
1563 2 : VSIFPrintfL(fp, "</manifest:manifest>\n");
1564 2 : VSIFCloseL(fp);
1565 :
1566 2 : fp = VSIFOpenL(CPLSPrintf("/vsizip/%s/meta.xml", pszName), "wb");
1567 2 : 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 2 : "office:version=\"1.2\">\n");
1571 2 : VSIFPrintfL(fp, "</office:document-meta>\n");
1572 2 : VSIFCloseL(fp);
1573 :
1574 2 : fp = VSIFOpenL(CPLSPrintf("/vsizip/%s/settings.xml", pszName), "wb");
1575 2 : 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 2 : "office:version=\"1.2\">\n");
1581 2 : VSIFPrintfL(fp, "<office:settings>\n");
1582 2 : VSIFPrintfL(fp, "<config:config-item-set config:name=\"ooo:view-settings\">\n");
1583 2 : VSIFPrintfL(fp, "<config:config-item-map-indexed config:name=\"Views\">\n");
1584 2 : VSIFPrintfL(fp, "<config:config-item-map-entry>\n");
1585 2 : VSIFPrintfL(fp, "<config:config-item-map-named config:name=\"Tables\">\n");
1586 18 : for(i=0;i<nLayers;i++)
1587 : {
1588 16 : OGRLayer* poLayer = GetLayer(i);
1589 16 : if (HasHeaderLine(poLayer))
1590 : {
1591 : /* Add vertical splitter */
1592 2 : char* pszXML = OGRGetXML_UTF8_EscapedString(GetLayer(i)->GetName());
1593 2 : VSIFPrintfL(fp, "<config:config-item-map-entry config:name=\"%s\">\n", pszXML);
1594 2 : CPLFree(pszXML);
1595 2 : VSIFPrintfL(fp, "<config:config-item config:name=\"VerticalSplitMode\" config:type=\"short\">2</config:config-item>\n");
1596 2 : VSIFPrintfL(fp, "<config:config-item config:name=\"VerticalSplitPosition\" config:type=\"int\">1</config:config-item>\n");
1597 2 : VSIFPrintfL(fp, "<config:config-item config:name=\"ActiveSplitRange\" config:type=\"short\">2</config:config-item>\n");
1598 2 : VSIFPrintfL(fp, "<config:config-item config:name=\"PositionTop\" config:type=\"int\">0</config:config-item>\n");
1599 2 : VSIFPrintfL(fp, "<config:config-item config:name=\"PositionBottom\" config:type=\"int\">1</config:config-item>\n");
1600 2 : VSIFPrintfL(fp, "</config:config-item-map-entry>\n");
1601 : }
1602 : }
1603 2 : VSIFPrintfL(fp, "</config:config-item-map-named>\n");
1604 2 : VSIFPrintfL(fp, "</config:config-item-map-entry>\n");
1605 2 : VSIFPrintfL(fp, "</config:config-item-map-indexed>\n");
1606 2 : VSIFPrintfL(fp, "</config:config-item-set>\n");
1607 2 : VSIFPrintfL(fp, "</office:settings>\n");
1608 2 : VSIFPrintfL(fp, "</office:document-settings>\n");
1609 2 : VSIFCloseL(fp);
1610 :
1611 2 : fp = VSIFOpenL(CPLSPrintf("/vsizip/%s/styles.xml", pszName), "wb");
1612 2 : 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 2 : "office:version=\"1.2\">\n");
1617 2 : VSIFPrintfL(fp, "<office:styles>\n");
1618 : VSIFPrintfL(fp, "<style:style style:name=\"Default\" "
1619 2 : "style:family=\"table-cell\">\n");
1620 2 : VSIFPrintfL(fp, "</style:style>\n");
1621 2 : VSIFPrintfL(fp, "</office:styles>\n");
1622 2 : VSIFPrintfL(fp, "</office:document-styles>\n");
1623 2 : VSIFCloseL(fp);
1624 :
1625 2 : fp = VSIFOpenL(CPLSPrintf("/vsizip/%s/content.xml", pszName), "wb");
1626 2 : 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 2 : "office:version=\"1.2\">\n");
1636 2 : VSIFPrintfL(fp, "<office:scripts/>\n");
1637 2 : VSIFPrintfL(fp, "<office:automatic-styles>\n");
1638 : VSIFPrintfL(fp, "<style:style style:name=\"co1\" "
1639 2 : "style:family=\"table-column\">\n");
1640 : VSIFPrintfL(fp, "<style:table-column-properties "
1641 : "fo:break-before=\"auto\" "
1642 2 : "style:column-width=\"2.5cm\"/>\n");
1643 2 : VSIFPrintfL(fp, "</style:style>\n");
1644 : VSIFPrintfL(fp, "<style:style style:name=\"co2\" "
1645 2 : "style:family=\"table-column\">\n");
1646 : VSIFPrintfL(fp, "<style:table-column-properties "
1647 : "fo:break-before=\"auto\" "
1648 2 : "style:column-width=\"5cm\"/>\n");
1649 2 : VSIFPrintfL(fp, "</style:style>\n");
1650 : VSIFPrintfL(fp, "<number:date-style style:name=\"nDate\" "
1651 2 : "number:automatic-order=\"true\">\n");
1652 2 : VSIFPrintfL(fp, "<number:day number:style=\"long\"/>\n");
1653 2 : VSIFPrintfL(fp, "<number:text>/</number:text>\n");
1654 2 : VSIFPrintfL(fp, "<number:month number:style=\"long\"/>\n");
1655 2 : VSIFPrintfL(fp, "<number:text>/</number:text>\n");
1656 2 : VSIFPrintfL(fp, "<number:year/>\n");
1657 2 : VSIFPrintfL(fp, "</number:date-style>\n");
1658 2 : VSIFPrintfL(fp, "<number:time-style style:name=\"nTime\">\n");
1659 2 : VSIFPrintfL(fp, "<number:hours number:style=\"long\"/>\n");
1660 2 : VSIFPrintfL(fp, "<number:text>:</number:text>\n");
1661 2 : VSIFPrintfL(fp, "<number:minutes number:style=\"long\"/>\n");
1662 2 : VSIFPrintfL(fp, "<number:text>:</number:text>\n");
1663 2 : VSIFPrintfL(fp, "<number:seconds number:style=\"long\"/>\n");
1664 2 : VSIFPrintfL(fp, "</number:time-style>\n");
1665 : VSIFPrintfL(fp, "<number:date-style style:name=\"nDateTime\" "
1666 2 : "number:automatic-order=\"true\">\n");
1667 2 : VSIFPrintfL(fp, "<number:day number:style=\"long\"/>\n");
1668 2 : VSIFPrintfL(fp, "<number:text>/</number:text>\n");
1669 2 : VSIFPrintfL(fp, "<number:month number:style=\"long\"/>\n");
1670 2 : VSIFPrintfL(fp, "<number:text>/</number:text>\n");
1671 2 : VSIFPrintfL(fp, "<number:year number:style=\"long\"/>\n");
1672 2 : VSIFPrintfL(fp, "<number:text> </number:text>\n");
1673 2 : VSIFPrintfL(fp, "<number:hours number:style=\"long\"/>\n");
1674 2 : VSIFPrintfL(fp, "<number:text>:</number:text>\n");
1675 2 : VSIFPrintfL(fp, "<number:minutes number:style=\"long\"/>\n");
1676 2 : VSIFPrintfL(fp, "<number:text>:</number:text>\n");
1677 2 : VSIFPrintfL(fp, "<number:seconds number:style=\"long\"/>\n");
1678 2 : 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 2 : "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 2 : "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 2 : "style:data-style-name=\"nDateTime\"/>\n");
1691 2 : VSIFPrintfL(fp, "</office:automatic-styles>\n");
1692 2 : VSIFPrintfL(fp, "<office:body>\n");
1693 2 : VSIFPrintfL(fp, "<office:spreadsheet>\n");
1694 18 : for(i=0;i<nLayers;i++)
1695 : {
1696 16 : WriteLayer(fp, GetLayer(i));
1697 : }
1698 2 : VSIFPrintfL(fp, "</office:spreadsheet>\n");
1699 2 : VSIFPrintfL(fp, "</office:body>\n");
1700 2 : VSIFPrintfL(fp, "</office:document-content>\n");
1701 2 : VSIFCloseL(fp);
1702 :
1703 : /* Now close ZIP file */
1704 2 : VSIFCloseL(fpZIP);
1705 :
1706 : /* Reset updated flag at datasource and layer level */
1707 2 : bUpdated = FALSE;
1708 18 : for(int i = 0; i<nLayers; i++)
1709 : {
1710 16 : ((OGRODSLayer*)papoLayers[i])->SetUpdated(FALSE);
1711 : }
1712 :
1713 2 : return OGRERR_NONE;
1714 : }
1715 :
1716 : /************************************************************************/
1717 : /* EvaluateRange() */
1718 : /************************************************************************/
1719 :
1720 34 : int ODSCellEvaluator::EvaluateRange(int nRow1, int nCol1, int nRow2, int nCol2,
1721 : std::vector<ods_formula_node>& aoOutValues)
1722 : {
1723 68 : if (nRow1 < 0 || nRow1 >= poLayer->GetFeatureCount(FALSE) ||
1724 34 : 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 68 : if (nRow2 < 0 || nRow2 >= poLayer->GetFeatureCount(FALSE) ||
1732 34 : 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 34 : int nIndexBackup = poLayer->GetNextReadFID();
1740 :
1741 34 : 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 65 : for(int nRow = nRow1; nRow <= nRow2; nRow ++)
1749 : {
1750 34 : OGRFeature* poFeature = poLayer->GetNextFeatureWithoutFIDHack();
1751 :
1752 34 : 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 83 : for(int nCol = nCol1; nCol <= nCol2; nCol++)
1761 : {
1762 52 : if (!poFeature->IsFieldSet(nCol))
1763 : {
1764 6 : aoOutValues.push_back(ods_formula_node());
1765 : }
1766 46 : else if (poFeature->GetFieldDefnRef(nCol)->GetType() == OFTInteger)
1767 : {
1768 0 : aoOutValues.push_back(ods_formula_node(poFeature->GetFieldAsInteger(nCol)));
1769 : }
1770 46 : else if (poFeature->GetFieldDefnRef(nCol)->GetType() == OFTReal)
1771 : {
1772 0 : aoOutValues.push_back(ods_formula_node(poFeature->GetFieldAsDouble(nCol)));
1773 : }
1774 : else
1775 : {
1776 46 : std::string osVal(poFeature->GetFieldAsString(nCol));
1777 92 : if (strncmp(osVal.c_str(), "of:=", 4) == 0)
1778 : {
1779 10 : delete poFeature;
1780 10 : poFeature = NULL;
1781 :
1782 10 : 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 3 : poLayer->SetNextByIndex(nIndexBackup);
1788 3 : return FALSE;
1789 : }
1790 :
1791 7 : poLayer->SetNextByIndex(nRow);
1792 7 : poFeature = poLayer->GetNextFeatureWithoutFIDHack();
1793 :
1794 7 : if (!poFeature->IsFieldSet(nCol))
1795 : {
1796 0 : aoOutValues.push_back(ods_formula_node());
1797 : }
1798 7 : else if (poFeature->GetFieldDefnRef(nCol)->GetType() == OFTInteger)
1799 : {
1800 0 : aoOutValues.push_back(ods_formula_node(poFeature->GetFieldAsInteger(nCol)));
1801 : }
1802 7 : else if (poFeature->GetFieldDefnRef(nCol)->GetType() == OFTReal)
1803 : {
1804 0 : aoOutValues.push_back(ods_formula_node(poFeature->GetFieldAsDouble(nCol)));
1805 : }
1806 : else
1807 : {
1808 7 : osVal = poFeature->GetFieldAsString(nCol);
1809 7 : if (strncmp(osVal.c_str(), "of:=", 4) != 0)
1810 : {
1811 1 : CPLValueType eType = CPLGetValueType(osVal.c_str());
1812 : /* Try to convert into numeric value if possible */
1813 1 : if (eType != CPL_VALUE_STRING)
1814 1 : 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 36 : CPLValueType eType = CPLGetValueType(osVal.c_str());
1823 : /* Try to convert into numeric value if possible */
1824 36 : if (eType != CPL_VALUE_STRING)
1825 13 : aoOutValues.push_back(ods_formula_node(CPLAtofM(osVal.c_str())));
1826 : else
1827 23 : aoOutValues.push_back(ods_formula_node(osVal.c_str()));
1828 0 : }
1829 : }
1830 : }
1831 :
1832 31 : delete poFeature;
1833 : }
1834 :
1835 31 : poLayer->SetNextByIndex(nIndexBackup);
1836 :
1837 31 : return TRUE;
1838 : }
1839 :
1840 : /************************************************************************/
1841 : /* Evaluate() */
1842 : /************************************************************************/
1843 :
1844 120 : int ODSCellEvaluator::Evaluate(int nRow, int nCol)
1845 : {
1846 120 : if (oVisisitedCells.find(std::pair<int,int>(nRow, nCol)) != oVisisitedCells.end())
1847 : {
1848 : CPLError(CE_Failure, CPLE_AppDefined,
1849 3 : "Circular dependency with (row=%d, col=%d)", nRow + 1, nCol + 1);
1850 3 : return FALSE;
1851 : }
1852 :
1853 117 : oVisisitedCells.insert(std::pair<int,int>(nRow, nCol));
1854 :
1855 117 : 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 117 : OGRFeature* poFeature = poLayer->GetNextFeatureWithoutFIDHack();
1863 117 : if (poFeature->IsFieldSet(nCol) &&
1864 : poFeature->GetFieldDefnRef(nCol)->GetType() == OFTString)
1865 : {
1866 117 : const char* pszVal = poFeature->GetFieldAsString(nCol);
1867 117 : if (strncmp(pszVal, "of:=", 4) == 0)
1868 : {
1869 116 : ods_formula_node* expr_out = ods_formula_compile( pszVal + 4 );
1870 116 : 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 106 : delete poFeature;
1876 106 : poLayer->SetNextByIndex(nRow);
1877 106 : poFeature = poLayer->GetNextFeatureWithoutFIDHack();
1878 :
1879 106 : if (expr_out->field_type == ODS_FIELD_TYPE_EMPTY)
1880 : {
1881 0 : poFeature->UnsetField(nCol);
1882 0 : poLayer->SetFeatureWithoutFIDHack(poFeature);
1883 : }
1884 106 : else if (expr_out->field_type == ODS_FIELD_TYPE_INTEGER)
1885 : {
1886 83 : poFeature->SetField(nCol, expr_out->int_value);
1887 83 : poLayer->SetFeatureWithoutFIDHack(poFeature);
1888 : }
1889 23 : else if (expr_out->field_type == ODS_FIELD_TYPE_FLOAT)
1890 : {
1891 7 : poFeature->SetField(nCol, expr_out->float_value);
1892 7 : poLayer->SetFeatureWithoutFIDHack(poFeature);
1893 : }
1894 16 : else if (expr_out->field_type == ODS_FIELD_TYPE_STRING)
1895 : {
1896 16 : poFeature->SetField(nCol, expr_out->string_value);
1897 16 : poLayer->SetFeatureWithoutFIDHack(poFeature);
1898 : }
1899 : }
1900 116 : delete expr_out;
1901 : }
1902 : }
1903 :
1904 117 : delete poFeature;
1905 :
1906 117 : return TRUE;
1907 : }
|