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