Update ooo320-m1
[ooovba.git] / connectivity / source / drivers / evoab / LFolderList.cxx
blob577d950ca695d3706e381700d2dd84fd7a513f20
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: LFolderList.cxx,v $
10 * $Revision: 1.15 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_connectivity.hxx"
34 #include <ctype.h>
35 #include <algorithm>
36 #include "LFolderList.hxx"
37 #include <com/sun/star/sdbc/ColumnValue.hpp>
38 #include <com/sun/star/sdbc/DataType.hpp>
39 #include <svtools/converter.hxx>
40 #include "LConnection.hxx"
41 #include "LColumns.hxx"
42 #include <osl/thread.h>
43 #include <tools/config.hxx>
44 #include <comphelper/sequence.hxx>
45 #include <svtools/zforlist.hxx>
46 #include <rtl/math.hxx>
47 #include <stdio.h> //sprintf
48 #include <comphelper/extract.hxx>
49 #include <comphelper/numbers.hxx>
50 #include "LDriver.hxx"
51 #include <com/sun/star/util/NumberFormat.hpp>
52 #include <unotools/configmgr.hxx>
53 #include <i18npool/mslangid.hxx>
54 #include "connectivity/dbconversion.hxx"
55 #include <comphelper/types.hxx>
56 #include <unotools/ucbstreamhelper.hxx>
57 #include <tools/debug.hxx>
58 #include "connectivity/dbexception.hxx"
59 #ifndef CONNECTIVITY_EVOAB_DEBUG_HELPER_HXX
60 #include "LDebug.hxx"
61 #endif
62 #include <svtools/syslocale.hxx>
64 using namespace ::comphelper;
65 using namespace connectivity;
66 using namespace connectivity::evoab;
67 using namespace connectivity::file;
68 using namespace ::cppu;
69 using namespace utl;
70 using namespace ::com::sun::star::uno;
71 using namespace ::com::sun::star::beans;
72 using namespace ::com::sun::star::sdbcx;
73 using namespace ::com::sun::star::sdbc;
74 using namespace ::com::sun::star::container;
75 using namespace ::com::sun::star::lang;
77 // -------------------------------------------------------------------------
78 void OEvoabFolderList::fillColumns(const ::com::sun::star::lang::Locale& _aLocale)
80 BOOL bRead = TRUE;
82 QuotedTokenizedString aHeaderLine;
83 OEvoabConnection* pConnection = (OEvoabConnection*)m_pConnection;
85 // read first row
86 QuotedTokenizedString aFirstLine;
87 bRead = m_pFileStream->ReadByteStringLine(aFirstLine,pConnection->getTextEncoding());
89 while(bRead && !aFirstLine.Len())
91 bRead = m_pFileStream->ReadByteStringLine(aFirstLine,pConnection->getTextEncoding());
93 // use first row as headerline because we need the number of columns
94 aHeaderLine = aFirstLine;
96 // column count
97 xub_StrLen nFieldCount = aHeaderLine.GetTokenCount(pConnection->getFieldDelimiter(),pConnection->getStringDelimiter());
99 if(!m_aColumns.isValid())
100 m_aColumns = new OSQLColumns();
101 else
102 m_aColumns->get().clear();
104 m_aTypes.clear();
105 m_aPrecisions.clear();
106 m_aScales.clear();
107 // reserve some space
108 m_aColumns->get().reserve(nFieldCount);
109 m_aTypes.reserve(nFieldCount);
110 m_aPrecisions.reserve(nFieldCount);
111 m_aScales.reserve(nFieldCount);
113 sal_Bool bCase = getConnection()->getMetaData()->storesMixedCaseQuotedIdentifiers();
114 CharClass aCharClass(pConnection->getDriver()->getFactory(),_aLocale);
115 // read description
116 sal_Unicode cDecimalDelimiter = pConnection->getDecimalDelimiter();
117 sal_Unicode cThousandDelimiter = pConnection->getThousandDelimiter();
118 String aColumnName;
119 ::rtl::OUString aTypeName;
120 ::comphelper::UStringMixEqual aCase(bCase);
121 xub_StrLen nStartPosFirstLine = 0; // use for eficient way to get the tokens
122 xub_StrLen nStartPosFirstLine2 = 0;
123 for (xub_StrLen i = 0; i < nFieldCount; i++)
126 // no column name so ...
127 aColumnName = 'C';
128 aColumnName += String::CreateFromInt32(i+1);
130 sal_Int32 eType;
131 UINT16 nPrecision = 0;
132 UINT16 nScale = 0;
134 BOOL bNumeric = FALSE;
135 ULONG nIndex = 0;
137 // first without fielddelimiter
138 String aField;
139 aFirstLine.GetTokenSpecial(aField,nStartPosFirstLine,pConnection->getFieldDelimiter(),'\0');
140 if (aField.Len() == 0 ||
141 (pConnection->getStringDelimiter() && pConnection->getStringDelimiter() == aField.GetChar(0)))
143 bNumeric = FALSE;
145 else
147 String aField2;
148 if ( pConnection->getStringDelimiter() != '\0' )
149 aFirstLine.GetTokenSpecial(aField2,nStartPosFirstLine2,pConnection->getFieldDelimiter(),pConnection->getStringDelimiter());
150 else
151 aField2 = aField;
153 if (aField2.Len() == 0)
155 bNumeric = FALSE;
157 else
159 bNumeric = TRUE;
160 xub_StrLen nDot = 0;
161 for (xub_StrLen j = 0; j < aField2.Len(); j++)
163 sal_Unicode c = aField2.GetChar(j);
164 // nur Ziffern und Dezimalpunkt und Tausender-Trennzeichen?
165 if ((!cDecimalDelimiter || c != cDecimalDelimiter) &&
166 (!cThousandDelimiter || c != cThousandDelimiter) &&
167 !aCharClass.isDigit(aField2,j))
169 bNumeric = FALSE;
170 break;
172 if (cDecimalDelimiter && c == cDecimalDelimiter)
174 nPrecision = 15; // we have an decimal value
175 nScale = 2;
176 nDot++;
180 if (nDot > 1) // if there is more than one dot it isn't a number
181 bNumeric = FALSE;
182 if (bNumeric && cThousandDelimiter)
184 // Ist der Trenner richtig angegeben?
185 String aValue = aField2.GetToken(0,cDecimalDelimiter);
186 for (sal_Int32 j = aValue.Len() - 4; j >= 0; j -= 4)
188 sal_Unicode c = aValue.GetChar(j);
189 // nur Ziffern und Dezimalpunkt und Tausender-Trennzeichen?
190 if (c == cThousandDelimiter && j)
191 continue;
192 else
194 bNumeric = FALSE;
195 break;
200 // jetzt koennte es noch ein Datumsfeld sein
201 if (!bNumeric)
205 nIndex = m_xNumberFormatter->detectNumberFormat(::com::sun::star::util::NumberFormat::ALL,aField2);
207 catch(Exception&)
214 sal_Int32 nFlags = 0;
215 if (bNumeric)
217 if (cDecimalDelimiter)
219 if(nPrecision)
221 eType = DataType::DECIMAL;
222 aTypeName = ::rtl::OUString::createFromAscii("DECIMAL");
224 else
226 eType = DataType::DOUBLE;
227 aTypeName = ::rtl::OUString::createFromAscii("DOUBLE");
230 else
231 eType = DataType::INTEGER;
232 nFlags = ColumnSearch::BASIC;
234 else
237 switch (comphelper::getNumberFormatType(m_xNumberFormatter,nIndex))
239 case NUMBERFORMAT_DATE:
240 eType = DataType::DATE;
241 aTypeName = ::rtl::OUString::createFromAscii("DATE");
242 break;
243 case NUMBERFORMAT_DATETIME:
244 eType = DataType::TIMESTAMP;
245 aTypeName = ::rtl::OUString::createFromAscii("TIMESTAMP");
246 break;
247 case NUMBERFORMAT_TIME:
248 eType = DataType::TIME;
249 aTypeName = ::rtl::OUString::createFromAscii("TIME");
250 break;
251 default:
252 eType = DataType::VARCHAR;
253 nPrecision = 0; // nyi: Daten koennen aber laenger sein!
254 nScale = 0;
255 aTypeName = ::rtl::OUString::createFromAscii("VARCHAR");
257 nFlags |= ColumnSearch::CHAR;
260 // check if the columname already exists
261 String aAlias(aColumnName);
262 OSQLColumns::Vector::const_iterator aFind = connectivity::find(m_aColumns->get().begin(),m_aColumns->get().end(),aAlias,aCase);
263 sal_Int32 nExprCnt = 0;
264 while(aFind != m_aColumns->get().end())
266 (aAlias = aColumnName) += String::CreateFromInt32(++nExprCnt);
267 aFind = connectivity::find(m_aColumns->get().begin(),m_aColumns->get().end(),aAlias,aCase);
270 sdbcx::OColumn* pColumn = new sdbcx::OColumn(aAlias,aTypeName,::rtl::OUString(),
271 ColumnValue::NULLABLE,
272 nPrecision,
273 nScale,
274 eType,
275 sal_False,
276 sal_False,
277 sal_False,
278 bCase);
279 Reference< XPropertySet> xCol = pColumn;
280 m_aColumns->get().push_back(xCol);
281 m_aTypes.push_back(eType);
282 m_aPrecisions.push_back(nPrecision);
283 m_aScales.push_back(nScale);
285 m_pFileStream->Seek(STREAM_SEEK_TO_BEGIN);
287 // -------------------------------------------------------------------------
288 DBG_NAME( OEvoabFolderList );
289 OEvoabFolderList::OEvoabFolderList(OEvoabConnection* _pConnection)
290 :m_nFilePos(0)
291 ,m_pFileStream(NULL)
292 ,m_pConnection(_pConnection)
293 ,m_bIsNull(sal_False)
295 DBG_CTOR( OEvoabFolderList, NULL );
296 m_aColumns = new OSQLColumns();
298 construct();
300 // -----------------------------------------------------------------------------
301 void OEvoabFolderList::construct()
303 SvtSysLocale aLocale;
304 ::com::sun::star::lang::Locale aAppLocale(aLocale.GetLocaleDataPtr()->getLocale());
305 Sequence< ::com::sun::star::uno::Any > aArg(1);
306 aArg[0] <<= aAppLocale;
308 Reference< ::com::sun::star::util::XNumberFormatsSupplier > xSupplier(m_pConnection->getDriver()->getFactory()->createInstanceWithArguments(::rtl::OUString::createFromAscii("com.sun.star.util.NumberFormatsSupplier"),aArg),UNO_QUERY);
309 m_xNumberFormatter = Reference< ::com::sun::star::util::XNumberFormatter >(m_pConnection->getDriver()->getFactory()->createInstance(::rtl::OUString::createFromAscii("com.sun.star.util.NumberFormatter")),UNO_QUERY);
310 m_xNumberFormatter->attachNumberFormatsSupplier(xSupplier);
312 INetURLObject aURL;
313 aURL.SetURL(m_pConnection->getDriver()->getEvoFolderListFileURL());
315 String aFileName = aURL.GetMainURL(INetURLObject::NO_DECODE);
317 EVO_TRACE_STRING("OJ::construct()::aFileName = %s\n", aFileName );
318 m_pFileStream = createStream_simpleError( aFileName,STREAM_READWRITE | STREAM_NOCREATE | STREAM_SHARE_DENYWRITE);
320 if(!m_pFileStream)
321 m_pFileStream = createStream_simpleError( aFileName,STREAM_READ | STREAM_NOCREATE | STREAM_SHARE_DENYNONE);
323 if(m_pFileStream)
325 m_pFileStream->Seek(STREAM_SEEK_TO_END);
326 sal_Int32 nSize = m_pFileStream->Tell();
327 m_pFileStream->Seek(STREAM_SEEK_TO_BEGIN);
329 // Buffersize abhaengig von der Filegroesse
330 m_pFileStream->SetBufferSize(nSize > 1000000 ? 32768 :
331 nSize > 100000 ? 16384 :
332 nSize > 10000 ? 4096 : 1024);
333 OSL_TRACE("OEvoabFolderList::construct()::m_pFileStream->Tell() = %d\n", nSize );
335 fillColumns(aAppLocale);
340 //------------------------------------------------------------------
341 sal_Bool OEvoabFolderList::fetchRow(OValueRow _rRow,const OSQLColumns & _rCols)
343 (_rRow->get())[0] = m_nFilePos; // the "bookmark"
345 OEvoabConnection* pConnection = (OEvoabConnection*)m_pConnection;
346 // Felder:
347 xub_StrLen nStartPos = 0;
348 String aStr;
349 OSQLColumns::Vector::const_iterator aIter = _rCols.get().begin();
350 for (sal_Int32 i = 0; aIter != _rCols.get().end();++aIter, ++i)
352 m_aCurrentLine.GetTokenSpecial(aStr,nStartPos,pConnection->getFieldDelimiter(),pConnection->getStringDelimiter());
353 //OSL_TRACE("OEvoabFolderList::fetchRow()::aStr = %s\n", ((OUtoCStr(::rtl::OUString(aStr))) ? (OUtoCStr(::rtl::OUString(aStr))):("NULL")) );
355 if (aStr.Len() == 0)
356 (_rRow->get())[i+1].setNull();
357 else
359 // length depending on the data type
360 sal_Int32 nType = m_aTypes[i];
361 switch(nType)
363 case DataType::TIMESTAMP:
364 case DataType::DATE:
365 case DataType::TIME:
367 double nRes = 0.0;
370 nRes = m_xNumberFormatter->convertStringToNumber(::com::sun::star::util::NumberFormat::ALL,aStr);
371 Reference<XPropertySet> xProp(m_xNumberFormatter->getNumberFormatsSupplier()->getNumberFormatSettings(),UNO_QUERY);
372 com::sun::star::util::Date aDate;
373 xProp->getPropertyValue(::rtl::OUString::createFromAscii("NullDate")) >>= aDate;
375 switch(nType)
377 case DataType::DATE:
378 (_rRow->get())[i+1] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDate(nRes,aDate));
379 break;
380 case DataType::TIMESTAMP:
381 (_rRow->get())[i+1] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDateTime(nRes,aDate));
382 break;
383 default:
384 (_rRow->get())[i+1] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toTime(nRes));
387 catch(Exception&)
389 (_rRow->get())[i+1].setNull();
391 } break;
392 case DataType::DOUBLE:
393 case DataType::INTEGER:
394 case DataType::DECIMAL: // #99178# OJ
395 case DataType::NUMERIC:
397 sal_Unicode cDecimalDelimiter = pConnection->getDecimalDelimiter();
398 sal_Unicode cThousandDelimiter = pConnection->getThousandDelimiter();
399 String aStrConverted;
401 OSL_ENSURE(cDecimalDelimiter && nType != DataType::INTEGER ||
402 !cDecimalDelimiter && nType == DataType::INTEGER,
403 "FalscherTyp");
405 // In Standard-Notation (DezimalPUNKT ohne Tausender-Komma) umwandeln:
406 for (xub_StrLen j = 0; j < aStr.Len(); ++j)
408 if (cDecimalDelimiter && aStr.GetChar(j) == cDecimalDelimiter)
409 aStrConverted += '.';
410 else if ( aStr.GetChar(j) == '.' ) // special case, if decimal seperator isn't '.' we have to vut the string after it
411 break; // #99189# OJ
412 else if (cThousandDelimiter && aStr.GetChar(j) == cThousandDelimiter)
414 // weglassen
416 else
417 aStrConverted += aStr.GetChar(j) ;
419 double nVal = ::rtl::math::stringToDouble(aStrConverted.GetBuffer(),',','.',NULL,NULL);
421 // #99178# OJ
422 if ( DataType::DECIMAL == nType || DataType::NUMERIC == nType )
423 (_rRow->get())[i+1] = String::CreateFromDouble(nVal);
424 else
425 (_rRow->get())[i+1] = nVal;
426 } break;
428 default:
430 // Wert als String in Variable der Row uebernehmen
431 (_rRow->get())[i+1] = aStr;
433 break;
437 return sal_True;
441 //------------------------------------------------------------------
442 sal_Bool OEvoabFolderList::seekRow(IResultSetHelper::Movement eCursorPosition)
444 //OSL_TRACE("OEvoabFolderList::seekRow()::(before SeekRow)m_aCurrentLine = %d\n", ((OUtoCStr(::rtl::OUString(m_aCurrentLine))) ? (OUtoCStr(::rtl::OUString(m_aCurrentLine))):("NULL")) );
446 if ( !m_pFileStream )
447 return sal_False;
448 OEvoabConnection* pConnection = (OEvoabConnection*)m_pConnection;
449 // ----------------------------------------------------------
450 // Positionierung vorbereiten:
451 //OSL_TRACE("OEvoabFolderList::seekRow()::(before SeekRow,m_pFileStriam Exist)m_aCurrentLine = %d\n", ((OUtoCStr(::rtl::OUString(m_aCurrentLine))) ? (OUtoCStr(::rtl::OUString(m_aCurrentLine))):("NULL")) );
453 switch(eCursorPosition)
455 case IResultSetHelper::FIRST:
456 m_nFilePos = 0;
457 // run through
459 case IResultSetHelper::NEXT:
460 m_pFileStream->Seek(m_nFilePos);
462 if (m_pFileStream->IsEof())
464 OSL_TRACE( "OEvoabFolderList::seekRow: EOF /before/ reading the line." );
465 return sal_False;
468 m_pFileStream->ReadByteStringLine(m_aCurrentLine,pConnection->getTextEncoding());
469 if (m_pFileStream->IsEof())
471 OSL_TRACE( "OEvoabFolderList::seekRow: EOF /after/ reading the line." );
472 if ( !m_aCurrentLine.Len() )
474 OSL_TRACE( "OEvoabFolderList::seekRow: empty line read." );
475 return sal_False;
478 m_nFilePos = m_pFileStream->Tell();
479 break;
481 default:
482 OSL_ENSURE( sal_False, "OEvoabFolderList::seekRow: unsupported positioning!" );
483 break;
486 //OSL_TRACE("OEvoabFolderList::seekRow()::(after SeekRow)m_aCurrentLine = %d\n", ((OUtoCStr(::rtl::OUString(m_aCurrentLine))) ? (OUtoCStr(::rtl::OUString(m_aCurrentLine))):("NULL")) );
488 return sal_True;
490 // -----------------------------------------------------------------------------
491 SvStream* OEvoabFolderList::createStream_simpleError( const String& _rFileName, StreamMode _eOpenMode)
493 utl::UcbLockBytesHandler* p_null_dummy=NULL;
494 SvStream* pReturn = ::utl::UcbStreamHelper::CreateStream( _rFileName, _eOpenMode, p_null_dummy);
495 if (pReturn && (ERRCODE_NONE != pReturn->GetErrorCode()))
497 delete pReturn;
498 pReturn = NULL;
500 return pReturn;
502 // -----------------------------------------------------------------------------
503 const ORowSetValue& OEvoabFolderList::getValue(sal_Int32 _nColumnIndex ) throw(::com::sun::star::sdbc::SQLException)
505 checkIndex( _nColumnIndex );
507 m_bIsNull = (m_aRow->get())[_nColumnIndex].isNull();
508 return (m_aRow->get())[_nColumnIndex];
510 // -----------------------------------------------------------------------------
511 void OEvoabFolderList::checkIndex(sal_Int32 _nColumnIndex ) throw(::com::sun::star::sdbc::SQLException)
513 if ( _nColumnIndex <= 0 || _nColumnIndex >= (sal_Int32)m_aRow->get().size() ) {
514 // ::dbtools::throwInvalidIndexException();
518 // -------------------------------------------------------------------------
519 ::rtl::OUString SAL_CALL OEvoabFolderList::getString( sal_Int32 _nColumnIndex ) throw(SQLException, RuntimeException)
521 return getValue(_nColumnIndex);
523 // -------------------------------------------------------------------------
524 sal_Int32 SAL_CALL OEvoabFolderList::getInt( sal_Int32 _nColumnIndex ) throw(SQLException, RuntimeException)
526 return getValue( _nColumnIndex );
528 // -----------------------------------------------------------------------------
529 void OEvoabFolderList::initializeRow(sal_Int32 _nColumnCount)
531 if(!m_aRow.isValid())
533 m_aRow = new OValueVector(_nColumnCount);
534 (m_aRow->get())[0].setBound(sal_True);
535 ::std::for_each(m_aRow->get().begin()+1,m_aRow->get().end(),TSetBound(sal_False));
537 //OSL_TRACE("OEvoabFolderList::initializeRow()::_nColumnCount = %d\n", _nColumnCount);
540 // -------------------------------------------------------------------------
542 sal_Bool SAL_CALL OEvoabFolderList::first( ) throw(SQLException, RuntimeException)
544 sal_Bool bSuccess = seekRow(IResultSetHelper::FIRST);
546 EVO_TRACE_STRING("OEvoabFolderList::first(): returning %s\n", ::rtl::OUString::valueOf(bSuccess) );
547 return bSuccess;
549 // -------------------------------------------------------------------------
551 sal_Bool SAL_CALL OEvoabFolderList::next( ) throw(SQLException, RuntimeException)
553 sal_Bool bSuccess = seekRow(IResultSetHelper::NEXT);
555 EVO_TRACE_STRING("OEvoabFolderList::next(): returning %s\n", ::rtl::OUString::valueOf(bSuccess) );
556 return bSuccess;
558 // -------------------------------------------------------------------------
560 sal_Int32 SAL_CALL OEvoabFolderList::getRow( ) throw(SQLException, RuntimeException)
562 sal_Bool bRet = fetchRow(m_aRow,getTableColumns().getBody());
563 EVO_TRACE_STRING("OEvoabFolderList::getRow()::fetchRow() = %s\n", ::rtl::OUString::valueOf(bRet) );
565 return bRet;