Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "global.hxx"
21 : #include "scresid.hxx"
22 : #include "impex.hxx"
23 : #include "asciiopt.hxx"
24 : #include "asciiopt.hrc"
25 : #include <comphelper/string.hxx>
26 : #include <osl/thread.h>
27 : #include <rtl/tencinfo.h>
28 : #include <unotools/transliterationwrapper.hxx>
29 : #include "editutil.hxx"
30 :
31 : static const sal_Char pStrFix[] = "FIX";
32 : static const sal_Char pStrMrg[] = "MRG";
33 :
34 3 : ScAsciiOptions::ScAsciiOptions() :
35 : bFixedLen ( false ),
36 : aFieldSeps ( OUString(';') ),
37 : bMergeFieldSeps ( false ),
38 : bQuotedFieldAsText(false),
39 : bDetectSpecialNumber(false),
40 : cTextSep ( cDefaultTextSep ),
41 3 : eCharSet ( osl_getThreadTextEncoding() ),
42 : eLang ( LANGUAGE_SYSTEM ),
43 : bCharSetSystem ( false ),
44 : nStartRow ( 1 ),
45 : nInfoCount ( 0 ),
46 : pColStart ( NULL ),
47 6 : pColFormat ( NULL )
48 : {
49 3 : }
50 :
51 3 : ScAsciiOptions::ScAsciiOptions(const ScAsciiOptions& rOpt) :
52 : bFixedLen ( rOpt.bFixedLen ),
53 : aFieldSeps ( rOpt.aFieldSeps ),
54 : bMergeFieldSeps ( rOpt.bMergeFieldSeps ),
55 : bQuotedFieldAsText(rOpt.bQuotedFieldAsText),
56 : bDetectSpecialNumber(rOpt.bDetectSpecialNumber),
57 : cTextSep ( rOpt.cTextSep ),
58 : eCharSet ( rOpt.eCharSet ),
59 : eLang ( rOpt.eLang ),
60 : bCharSetSystem ( rOpt.bCharSetSystem ),
61 : nStartRow ( rOpt.nStartRow ),
62 3 : nInfoCount ( rOpt.nInfoCount )
63 : {
64 3 : if (nInfoCount)
65 : {
66 0 : pColStart = new sal_Int32[nInfoCount];
67 0 : pColFormat = new sal_uInt8[nInfoCount];
68 0 : for (sal_uInt16 i=0; i<nInfoCount; i++)
69 : {
70 0 : pColStart[i] = rOpt.pColStart[i];
71 0 : pColFormat[i] = rOpt.pColFormat[i];
72 : }
73 : }
74 : else
75 : {
76 3 : pColStart = NULL;
77 3 : pColFormat = NULL;
78 : }
79 3 : }
80 :
81 12 : ScAsciiOptions::~ScAsciiOptions()
82 : {
83 6 : delete[] pColStart;
84 6 : delete[] pColFormat;
85 6 : }
86 :
87 0 : void ScAsciiOptions::SetColInfo( sal_uInt16 nCount, const sal_Int32* pStart, const sal_uInt8* pFormat )
88 : {
89 0 : delete[] pColStart;
90 0 : delete[] pColFormat;
91 :
92 0 : nInfoCount = nCount;
93 :
94 0 : if (nInfoCount)
95 : {
96 0 : pColStart = new sal_Int32[nInfoCount];
97 0 : pColFormat = new sal_uInt8[nInfoCount];
98 0 : for (sal_uInt16 i=0; i<nInfoCount; i++)
99 : {
100 0 : pColStart[i] = pStart[i];
101 0 : pColFormat[i] = pFormat[i];
102 : }
103 : }
104 : else
105 : {
106 0 : pColStart = NULL;
107 0 : pColFormat = NULL;
108 : }
109 0 : }
110 :
111 0 : void ScAsciiOptions::SetColumnInfo( const ScCsvExpDataVec& rDataVec )
112 : {
113 0 : delete[] pColStart;
114 0 : pColStart = NULL;
115 0 : delete[] pColFormat;
116 0 : pColFormat = NULL;
117 :
118 0 : nInfoCount = static_cast< sal_uInt16 >( rDataVec.size() );
119 0 : if( nInfoCount )
120 : {
121 0 : pColStart = new sal_Int32[ nInfoCount ];
122 0 : pColFormat = new sal_uInt8[ nInfoCount ];
123 0 : for( sal_uInt16 nIx = 0; nIx < nInfoCount; ++nIx )
124 : {
125 0 : pColStart[ nIx ] = rDataVec[ nIx ].mnIndex;
126 0 : pColFormat[ nIx ] = rDataVec[ nIx ].mnType;
127 : }
128 : }
129 0 : }
130 :
131 0 : ScAsciiOptions& ScAsciiOptions::operator=( const ScAsciiOptions& rCpy )
132 : {
133 0 : SetColInfo( rCpy.nInfoCount, rCpy.pColStart, rCpy.pColFormat );
134 :
135 0 : bFixedLen = rCpy.bFixedLen;
136 0 : aFieldSeps = rCpy.aFieldSeps;
137 0 : bMergeFieldSeps = rCpy.bMergeFieldSeps;
138 0 : bQuotedFieldAsText = rCpy.bQuotedFieldAsText;
139 0 : cTextSep = rCpy.cTextSep;
140 0 : eCharSet = rCpy.eCharSet;
141 0 : bCharSetSystem = rCpy.bCharSetSystem;
142 0 : nStartRow = rCpy.nStartRow;
143 :
144 0 : return *this;
145 : }
146 :
147 0 : bool ScAsciiOptions::operator==( const ScAsciiOptions& rCmp ) const
148 : {
149 0 : if ( bFixedLen == rCmp.bFixedLen &&
150 0 : aFieldSeps == rCmp.aFieldSeps &&
151 0 : bMergeFieldSeps == rCmp.bMergeFieldSeps &&
152 0 : bQuotedFieldAsText == rCmp.bQuotedFieldAsText &&
153 0 : cTextSep == rCmp.cTextSep &&
154 0 : eCharSet == rCmp.eCharSet &&
155 0 : bCharSetSystem == rCmp.bCharSetSystem &&
156 0 : nStartRow == rCmp.nStartRow &&
157 0 : nInfoCount == rCmp.nInfoCount )
158 : {
159 : OSL_ENSURE( !nInfoCount || (pColStart && pColFormat && rCmp.pColStart && rCmp.pColFormat),
160 : "NULL pointer in ScAsciiOptions::operator==() column info" );
161 0 : for (sal_uInt16 i=0; i<nInfoCount; i++)
162 0 : if ( pColStart[i] != rCmp.pColStart[i] ||
163 0 : pColFormat[i] != rCmp.pColFormat[i] )
164 0 : return false;
165 :
166 0 : return true;
167 : }
168 0 : return false;
169 : }
170 :
171 0 : static OUString lcl_decodeSepString( const OUString & rSepNums, bool & o_bMergeFieldSeps )
172 : {
173 0 : OUString aFieldSeps;
174 0 : sal_Int32 nSub = comphelper::string::getTokenCount( rSepNums, '/');
175 0 : for (sal_Int32 i=0; i<nSub; ++i)
176 : {
177 0 : OUString aCode = rSepNums.getToken( i, '/' );
178 0 : if ( aCode == pStrMrg )
179 0 : o_bMergeFieldSeps = true;
180 : else
181 : {
182 0 : sal_Int32 nVal = aCode.toInt32();
183 0 : if ( nVal )
184 0 : aFieldSeps += OUString((sal_Unicode) nVal);
185 : }
186 0 : }
187 0 : return aFieldSeps;
188 : }
189 :
190 : // The options string must not contain semicolons (because of the pick list),
191 : // use comma as separator.
192 :
193 0 : void ScAsciiOptions::ReadFromString( const OUString& rString )
194 : {
195 0 : sal_Int32 nCount = comphelper::string::getTokenCount(rString, ',');
196 0 : OUString aToken;
197 :
198 : // Field separator.
199 0 : if ( nCount >= 1 )
200 : {
201 0 : bFixedLen = bMergeFieldSeps = false;
202 :
203 0 : aToken = rString.getToken(0,',');
204 0 : if ( aToken == pStrFix )
205 0 : bFixedLen = true;
206 0 : aFieldSeps = lcl_decodeSepString( aToken, bMergeFieldSeps);
207 : }
208 :
209 : // Text separator.
210 0 : if ( nCount >= 2 )
211 : {
212 0 : aToken = rString.getToken(1,',');
213 0 : sal_Int32 nVal = aToken.toInt32();
214 0 : cTextSep = (sal_Unicode) nVal;
215 : }
216 :
217 : // Text encoding.
218 0 : if ( nCount >= 3 )
219 : {
220 0 : aToken = rString.getToken(2,',');
221 0 : eCharSet = ScGlobal::GetCharsetValue( aToken );
222 : }
223 :
224 : // Number of start row.
225 0 : if ( nCount >= 4 )
226 : {
227 0 : aToken = rString.getToken(3,',');
228 0 : nStartRow = aToken.toInt32();
229 : }
230 :
231 : // Column info.
232 0 : if ( nCount >= 5 )
233 : {
234 0 : delete[] pColStart;
235 0 : delete[] pColFormat;
236 :
237 0 : aToken = rString.getToken(4,',');
238 0 : sal_Int32 nSub = comphelper::string::getTokenCount(aToken, '/');
239 0 : nInfoCount = nSub / 2;
240 0 : if (nInfoCount)
241 : {
242 0 : pColStart = new sal_Int32[nInfoCount];
243 0 : pColFormat = new sal_uInt8[nInfoCount];
244 0 : for (sal_uInt16 nInfo=0; nInfo<nInfoCount; nInfo++)
245 : {
246 0 : pColStart[nInfo] = (sal_Int32) aToken.getToken( 2*nInfo, '/' ).toInt32();
247 0 : pColFormat[nInfo] = (sal_uInt8) aToken.getToken( 2*nInfo+1, '/' ).toInt32();
248 : }
249 : }
250 : else
251 : {
252 0 : pColStart = NULL;
253 0 : pColFormat = NULL;
254 : }
255 : }
256 :
257 : // Language
258 0 : if (nCount >= 6)
259 : {
260 0 : aToken = rString.getToken(5, ',');
261 0 : eLang = static_cast<LanguageType>(aToken.toInt32());
262 : }
263 :
264 : // Import quoted field as text.
265 0 : if (nCount >= 7)
266 : {
267 0 : aToken = rString.getToken(6, ',');
268 0 : bQuotedFieldAsText = aToken == "true";
269 : }
270 :
271 : // Detect special numbers.
272 0 : if (nCount >= 8)
273 : {
274 0 : aToken = rString.getToken(7, ',');
275 0 : bDetectSpecialNumber = aToken == "true";
276 : }
277 : else
278 0 : bDetectSpecialNumber = true; // default of versions that didn't add the parameter
279 :
280 : // 9th token is used for "Save as shown" in export options
281 : // 10th token is used for "Save cell formulas" in export options
282 0 : }
283 :
284 0 : OUString ScAsciiOptions::WriteToString() const
285 : {
286 0 : OUString aOutStr;
287 :
288 : // Field separator.
289 0 : if ( bFixedLen )
290 0 : aOutStr += pStrFix;
291 0 : else if ( aFieldSeps.isEmpty() )
292 0 : aOutStr += "0";
293 : else
294 : {
295 0 : sal_Int32 nLen = aFieldSeps.getLength();
296 0 : for (sal_Int32 i=0; i<nLen; i++)
297 : {
298 0 : if (i)
299 0 : aOutStr += "/";
300 0 : aOutStr += OUString::number(aFieldSeps[i]);
301 : }
302 0 : if ( bMergeFieldSeps )
303 : {
304 0 : aOutStr += "/";
305 0 : aOutStr += pStrMrg;
306 : }
307 : }
308 :
309 : // Text delimiter.
310 0 : aOutStr += "," + OUString::number(cTextSep) + ",";
311 :
312 : // Text encoding.
313 0 : if ( bCharSetSystem ) // force "SYSTEM"
314 0 : aOutStr += ScGlobal::GetCharsetString( RTL_TEXTENCODING_DONTKNOW );
315 : else
316 0 : aOutStr += ScGlobal::GetCharsetString( eCharSet );
317 :
318 : // Number of start row.
319 0 : aOutStr += "," + OUString::number(nStartRow) + ",";
320 :
321 : // Column info.
322 : OSL_ENSURE( !nInfoCount || (pColStart && pColFormat), "NULL pointer in ScAsciiOptions column info" );
323 0 : for (sal_uInt16 nInfo=0; nInfo<nInfoCount; nInfo++)
324 : {
325 0 : if (nInfo)
326 0 : aOutStr += "/";
327 0 : aOutStr += OUString::number(pColStart[nInfo]) +
328 0 : "/" +
329 0 : OUString::number(pColFormat[nInfo]);
330 : }
331 :
332 : // #i112025# the options string is used in macros and linked sheets,
333 : // so new options must be added at the end, to remain compatible
334 :
335 0 : aOutStr += "," +
336 : // Language
337 0 : OUString::number(eLang) + "," +
338 : // Import quoted field as text.
339 0 : OUString::boolean( bQuotedFieldAsText ) + "," +
340 : // Detect special numbers.
341 0 : OUString::boolean( bDetectSpecialNumber );
342 :
343 : // 9th token is used for "Save as shown" in export options
344 : // 10th token is used for "Save cell formulas" in export options
345 :
346 0 : return aOutStr;
347 : }
348 :
349 : // static
350 3 : sal_Unicode ScAsciiOptions::GetWeightedFieldSep( const OUString & rFieldSeps, bool bDecodeNumbers )
351 : {
352 3 : bool bMergeFieldSeps = false;
353 3 : OUString aFieldSeps( bDecodeNumbers ? lcl_decodeSepString( rFieldSeps, bMergeFieldSeps) : rFieldSeps);
354 3 : if (aFieldSeps.isEmpty())
355 : {
356 0 : return 0;
357 : }
358 3 : else if (aFieldSeps.getLength() == 1)
359 3 : return aFieldSeps[0];
360 : else
361 : {
362 : // There can be only one separator for output. See also fdo#53449
363 0 : if (aFieldSeps.indexOf(',') != -1)
364 0 : return ',';
365 0 : else if (aFieldSeps.indexOf('\t') != -1)
366 0 : return '\t';
367 0 : else if (aFieldSeps.indexOf(';') != -1)
368 0 : return ';';
369 0 : else if (aFieldSeps.indexOf(' ') != -1)
370 0 : return ' ';
371 : else
372 0 : return aFieldSeps[0];
373 3 : }
374 156 : }
375 :
376 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|