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