1 /******************************************************************************
2  *
3  * Project:  XLS Translator
4  * Purpose:  Implements OGRXLSDataSource class
5  * Author:   Even Rouault, even dot rouault at spatialys.com
6  *
7  ******************************************************************************
8  * Copyright (c) 2011, Even Rouault <even dot rouault at spatialys.com>
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  ****************************************************************************/
28 
29 #include <freexl.h>
30 
31 #ifdef _WIN32
32 #  include <windows.h>
33 #endif
34 
35 #include "ogr_xls.h"
36 #include "cpl_conv.h"
37 #include "cpl_string.h"
38 
39 CPL_CVSID("$Id: ogrxlsdatasource.cpp 355b41831cd2685c85d1aabe5b95665a2c6e99b7 2019-06-19 17:07:04 +0200 Even Rouault $")
40 
41 /************************************************************************/
42 /*                          OGRXLSDataSource()                          */
43 /************************************************************************/
44 
OGRXLSDataSource()45 OGRXLSDataSource::OGRXLSDataSource() :
46     pszName(nullptr),
47     papoLayers(nullptr),
48     nLayers(0),
49     xlshandle(nullptr)
50 {}
51 
52 /************************************************************************/
53 /*                         ~OGRXLSDataSource()                          */
54 /************************************************************************/
55 
~OGRXLSDataSource()56 OGRXLSDataSource::~OGRXLSDataSource()
57 
58 {
59     for( int i = 0; i < nLayers; i++ )
60         delete papoLayers[i];
61     CPLFree( papoLayers );
62 
63     CPLFree( pszName );
64 
65     if( xlshandle )
66         freexl_close(xlshandle);
67 #ifdef WIN32
68     if( m_osTempFilename.empty() )
69     {
70         VSIUnlink(m_osTempFilename);
71     }
72 #endif
73 }
74 
75 /************************************************************************/
76 /*                           TestCapability()                           */
77 /************************************************************************/
78 
TestCapability(CPL_UNUSED const char * pszCap)79 int OGRXLSDataSource::TestCapability( CPL_UNUSED const char * pszCap )
80 
81 {
82     return FALSE;
83 }
84 
85 /************************************************************************/
86 /*                              GetLayer()                              */
87 /************************************************************************/
88 
GetLayer(int iLayer)89 OGRLayer *OGRXLSDataSource::GetLayer( int iLayer )
90 
91 {
92     if( iLayer < 0 || iLayer >= nLayers )
93         return nullptr;
94     else
95         return papoLayers[iLayer];
96 }
97 
98 /************************************************************************/
99 /*                                Open()                                */
100 /************************************************************************/
101 
Open(const char * pszFilename,int bUpdateIn)102 int OGRXLSDataSource::Open( const char * pszFilename, int bUpdateIn)
103 
104 {
105     if (bUpdateIn)
106     {
107         return FALSE;
108     }
109 
110     pszName = CPLStrdup(pszFilename);
111     m_osANSIFilename = pszFilename;
112 #ifdef WIN32
113     if( CPLTestBool( CPLGetConfigOption( "GDAL_FILENAME_IS_UTF8", "YES" ) ) )
114     {
115         CPLErrorReset();
116         CPLPushErrorHandler(CPLQuietErrorHandler);
117         char* pszTmpName = CPLRecode( pszFilename, CPL_ENC_UTF8, CPLString().Printf( "CP%d", GetACP() ) );
118         CPLPopErrorHandler();
119         m_osANSIFilename = pszTmpName;
120         CPLFree(pszTmpName);
121 
122         // In case recoding to the ANSI code page failed, then create a temporary file
123         // in a "safe" location
124         if( CPLGetLastErrorType() != CE_None )
125         {
126             CPLErrorReset();
127 
128             // FIXME: CPLGenerateTempFilename() would normally be expected to return a UTF-8 filename
129             // but I doubt it does in all cases.
130             m_osTempFilename = CPLGenerateTempFilename("temp_xls");
131             m_osANSIFilename = m_osTempFilename;
132             CPLCopyFile( m_osANSIFilename, pszFilename );
133             CPLDebug("XLS", "Create temporary file: %s", m_osTempFilename.c_str());
134         }
135     }
136 #endif
137 
138 // --------------------------------------------------------------------
139 //      Does this appear to be a .xls file?
140 // --------------------------------------------------------------------
141 
142     /* Open only for getting info. To get cell values, we have to use freexl_open */
143     if ( !GetXLSHandle() )
144         return FALSE;
145 
146     unsigned int nSheets = 0;
147     if (freexl_get_info (xlshandle, FREEXL_BIFF_SHEET_COUNT, &nSheets) != FREEXL_OK)
148         return FALSE;
149 
150     for(unsigned short i=0; i<(unsigned short)nSheets; i++)
151     {
152         freexl_select_active_worksheet(xlshandle, i);
153 
154         const char* pszSheetname = nullptr;
155         if (freexl_get_worksheet_name(xlshandle, i, &pszSheetname) != FREEXL_OK)
156             return FALSE;
157 
158         unsigned int nRows = 0;
159         unsigned short nCols = 0;
160         if (freexl_worksheet_dimensions(xlshandle, &nRows, &nCols) != FREEXL_OK)
161             return FALSE;
162 
163         /* Skip empty sheets */
164         if (nRows == 0)
165             continue;
166 
167         papoLayers = (OGRLayer**) CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
168         papoLayers[nLayers ++] = new OGRXLSLayer(this, pszSheetname, i, (int)nRows, nCols);
169     }
170 
171     freexl_close(xlshandle);
172     xlshandle = nullptr;
173 
174     return TRUE;
175 }
176 
177 /************************************************************************/
178 /*                           GetXLSHandle()                             */
179 /************************************************************************/
180 
GetXLSHandle()181 const void* OGRXLSDataSource::GetXLSHandle()
182 {
183     if (xlshandle)
184         return xlshandle;
185 
186     if (freexl_open (m_osANSIFilename, &xlshandle) != FREEXL_OK)
187         return nullptr;
188 
189     return xlshandle;
190 }
191