1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include <functional>
25 #include <algorithm>
26 #include <vos/mutex.hxx>
27 #include <vcl/svapp.hxx>
28
29 // #ifndef _OSL_DIAGNOSE_H_
30 // #include <osl/diagnose.h>
31 // #endif
32 #include "CFStringUtilities.hxx"
33 #include "NSString_OOoAdditions.hxx"
34 #include "NSURL_OOoAdditions.hxx"
35
36 #include "FilterHelper.hxx"
37
38 #pragma mark DEFINES
39 #define CLASS_NAME "FilterEntry"
40
41 #pragma mark FilterEntry
42 //---------------------------------------------------------------------
FilterEntry(const rtl::OUString & _rTitle,const UnoFilterList & _rSubFilters)43 FilterEntry::FilterEntry( const rtl::OUString& _rTitle, const UnoFilterList& _rSubFilters )
44 :m_sTitle( _rTitle )
45 ,m_aSubFilters( _rSubFilters )
46 {
47 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "title", _rTitle);
48 DBG_PRINT_EXIT(CLASS_NAME, __func__);
49 }
50
51 //---------------------------------------------------------------------
hasSubFilters() const52 sal_Bool FilterEntry::hasSubFilters() const
53 {
54 // OSL_TRACE(">>> FilterEntry::%s", __func__);
55 sal_Bool bReturn = ( 0 < m_aSubFilters.getLength() );
56 // OSL_TRACE("<<< FilterEntry::%s retVal: %d", __func__, bReturn);
57 return bReturn;
58 }
59
60 //---------------------------------------------------------------------
getSubFilters(UnoFilterList & _rSubFilterList)61 sal_Int32 FilterEntry::getSubFilters( UnoFilterList& _rSubFilterList )
62 {
63 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
64
65 _rSubFilterList = m_aSubFilters;
66 sal_Int32 nReturn = m_aSubFilters.getLength();
67
68 DBG_PRINT_EXIT(CLASS_NAME, __func__, nReturn);
69
70 return nReturn;
71 }
72
73 #pragma mark statics
74 static bool
isFilterString(const rtl::OUString & rFilterString,const char * pMatch)75 isFilterString( const rtl::OUString& rFilterString, const char *pMatch )
76 {
77 sal_Int32 nIndex = 0;
78 rtl::OUString aToken;
79 bool bIsFilter = true;
80
81 rtl::OUString aMatch(rtl::OUString::createFromAscii(pMatch));
82
83 do
84 {
85 aToken = rFilterString.getToken( 0, ';', nIndex );
86 if( !aToken.match( aMatch ) )
87 {
88 bIsFilter = false;
89 break;
90 }
91 }
92 while( nIndex >= 0 );
93
94 return bIsFilter;
95 }
96
97 //=====================================================================
98
99 static rtl::OUString
shrinkFilterName(const rtl::OUString aFilterName,bool bAllowNoStar=false)100 shrinkFilterName( const rtl::OUString aFilterName, bool bAllowNoStar = false )
101 {
102 // DBG_PRINT_ENTRY(CLASS_NAME, "shrinkFilterName", "filterName", aFilterName);
103
104 int i;
105 int nBracketLen = -1;
106 int nBracketEnd = -1;
107 rtl::OUString rFilterName = aFilterName;
108 const sal_Unicode* pStr = rFilterName.getStr();
109 rtl::OUString aRealName = rFilterName;
110
111 for( i = aRealName.getLength() - 1; i > 0; i-- )
112 {
113 if( pStr[i] == ')' )
114 nBracketEnd = i;
115 else if( pStr[i] == '(' )
116 {
117 nBracketLen = nBracketEnd - i;
118 if( nBracketEnd <= 0 )
119 continue;
120 if( isFilterString( rFilterName.copy( i + 1, nBracketLen - 1 ), "*." ) )
121 aRealName = aRealName.replaceAt( i, nBracketLen + 1, rtl::OUString() );
122 else if (bAllowNoStar)
123 {
124 if( isFilterString( rFilterName.copy( i + 1, nBracketLen - 1 ), ".") )
125 aRealName = aRealName.replaceAt( i, nBracketLen + 1, rtl::OUString() );
126 }
127 }
128 }
129
130 return aRealName;
131 }
132
133 //------------------------------------------------------------------------------------
134 namespace {
135 //................................................................................
136 struct FilterTitleMatch : public ::std::unary_function< FilterEntry, bool >
137 {
138 protected:
139 const rtl::OUString rTitle;
140
141 public:
FilterTitleMatch__anon243a73870111::FilterTitleMatch142 FilterTitleMatch( const rtl::OUString _rTitle ) : rTitle( _rTitle ) { }
143
144 //............................................................................
operator ()__anon243a73870111::FilterTitleMatch145 bool operator () ( const FilterEntry& _rEntry )
146 {
147 sal_Bool bMatch;
148 if( !_rEntry.hasSubFilters() ) {
149 //first try the complete filter name
150 rtl::OUString title = _rEntry.getTitle();
151 bMatch = ( title.equals(rTitle) );
152 if (!bMatch) {
153 //we didn't find a match using the full name, let's give it another
154 //try using the shrunk version
155 rtl::OUString aShrunkName = shrinkFilterName( _rEntry.getTitle() ).trim();
156 bMatch = ( aShrunkName.equals(rTitle) );
157 }
158 }
159 else
160 // a filter group -> search the sub filters
161 bMatch =
162 _rEntry.endSubFilters() != ::std::find_if(
163 _rEntry.beginSubFilters(),
164 _rEntry.endSubFilters(),
165 *this
166 );
167
168 return bMatch ? true : false;
169 }
170
operator ()__anon243a73870111::FilterTitleMatch171 bool operator () ( const UnoFilterEntry& _rEntry )
172 {
173 rtl::OUString aShrunkName = shrinkFilterName( _rEntry.First );
174 bool retVal = aShrunkName.equals(rTitle);
175 return retVal;
176 }
177 };
178 }
179
180 #undef CLASS_NAME
181 #define CLASS_NAME "FilterHelper"
182
FilterHelper()183 FilterHelper::FilterHelper()
184 : m_pFilterList(NULL)
185 , m_pFilterNames(NULL)
186 {
187 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
188 DBG_PRINT_EXIT(CLASS_NAME, __func__);
189 }
190
~FilterHelper()191 FilterHelper::~FilterHelper()
192 {
193 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
194
195 NSAutoreleasePool *pool = [NSAutoreleasePool new];
196
197 if (NULL != m_pFilterList) {
198 delete m_pFilterList;
199 }
200
201 if (NULL != m_pFilterNames) {
202 //we called retain when we added the strings to the list, so we should release them now
203 for (NSStringList::iterator iter = m_pFilterNames->begin(); iter != m_pFilterNames->end(); iter++) {
204 [*iter release];
205 }
206 delete m_pFilterNames;
207 }
208
209 [pool release];
210
211 DBG_PRINT_EXIT(CLASS_NAME, __func__);
212 }
213
214 //------------------------------------------------------------------------------------
FilterNameExists(const rtl::OUString rTitle)215 sal_Bool FilterHelper::FilterNameExists( const rtl::OUString rTitle )
216 {
217 sal_Bool bRet = sal_False;
218
219 if( m_pFilterList )
220 bRet =
221 m_pFilterList->end() != ::std::find_if(
222 m_pFilterList->begin(),
223 m_pFilterList->end(),
224 FilterTitleMatch( rTitle )
225 );
226
227 return bRet;
228 }
229
230 //------------------------------------------------------------------------------------
FilterNameExists(const UnoFilterList & _rGroupedFilters)231 sal_Bool FilterHelper::FilterNameExists( const UnoFilterList& _rGroupedFilters )
232 {
233 sal_Bool bRet = sal_False;
234
235 if( m_pFilterList )
236 {
237 const UnoFilterEntry* pStart = _rGroupedFilters.getConstArray();
238 const UnoFilterEntry* pEnd = pStart + _rGroupedFilters.getLength();
239 for( ; pStart != pEnd; ++pStart )
240 if( m_pFilterList->end() != ::std::find_if(
241 m_pFilterList->begin(),
242 m_pFilterList->end(),
243 FilterTitleMatch( pStart->First ) ) )
244 break;
245
246 bRet = (pStart != pEnd);
247 }
248
249 return bRet;
250 }
251
252 //------------------------------------------------------------------------------------
ensureFilterList(const::rtl::OUString & _rInitialCurrentFilter)253 void FilterHelper::ensureFilterList( const ::rtl::OUString& _rInitialCurrentFilter )
254 {
255 //OSL_TRACE(">>> FilterHelper::%s", __func__);
256 if( NULL == m_pFilterList )
257 {
258 m_pFilterList = new FilterList;
259
260 // set the first filter to the current filter
261 m_aCurrentFilter = _rInitialCurrentFilter;
262 OSL_TRACE("ensureFilterList filter:%s", OUStringToOString(m_aCurrentFilter, RTL_TEXTENCODING_UTF8).getStr());
263 }
264 //OSL_TRACE("<<< FilterHelper::%s", __func__);
265 }
266
SetCurFilter(const rtl::OUString & rFilter)267 void FilterHelper::SetCurFilter( const rtl::OUString& rFilter )
268 {
269 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "filter", rFilter);
270
271 ::vos::OGuard aGuard( Application::GetSolarMutex() );
272
273 if(m_aCurrentFilter.equals(rFilter) == false)
274 {
275 m_aCurrentFilter = rFilter;
276 }
277
278 //only for output purposes
279 #if OSL_DEBUG_LEVEL > 1
280 FilterList::iterator aFilter = ::std::find_if(m_pFilterList->begin(), m_pFilterList->end(), FilterTitleMatch(m_aCurrentFilter));
281 if (aFilter != m_pFilterList->end()) {
282 OUStringList suffixes = aFilter->getFilterSuffixList();
283 if (!suffixes.empty()) {
284 OSL_TRACE("Current active suffixes: ");
285 OUStringList::iterator suffIter = suffixes.begin();
286 while(suffIter != suffixes.end()) {
287 OSL_TRACE("%s", OUStringToOString((*suffIter), RTL_TEXTENCODING_UTF8).getStr());
288 suffIter++;
289 }
290 }
291 } else {
292 OSL_TRACE("No filter entry was found for that name!");
293 }
294 #endif
295
296 DBG_PRINT_EXIT(CLASS_NAME, __func__);
297 }
298
SetFilters()299 void FilterHelper::SetFilters()
300 {
301 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
302
303 // set the default filter
304 if( m_aCurrentFilter.getLength() > 0 )
305 {
306 OSL_TRACE( "Setting current filter to %s", OUStringToOString(m_aCurrentFilter, RTL_TEXTENCODING_UTF8).getStr());
307
308 SetCurFilter( m_aCurrentFilter );
309 }
310
311 DBG_PRINT_EXIT(CLASS_NAME, __func__);
312 }
313
appendFilter(const::rtl::OUString & aTitle,const::rtl::OUString & aFilterString)314 void FilterHelper::appendFilter(const ::rtl::OUString& aTitle, const ::rtl::OUString& aFilterString) {
315 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "title", aTitle, "filter", aFilterString);
316
317 ::vos::OGuard aGuard( Application::GetSolarMutex() );
318
319 if( FilterNameExists( aTitle ) ) {
320 throw com::sun::star::lang::IllegalArgumentException();
321 }
322
323 // ensure that we have a filter list
324 ensureFilterList( aTitle );
325
326 // append the filter
327 OUStringList suffixList;
328 fillSuffixList(suffixList, aFilterString);
329 m_pFilterList->push_back(FilterEntry( aTitle, suffixList ) );
330
331 DBG_PRINT_EXIT(CLASS_NAME, __func__);
332 }
333
setCurrentFilter(const::rtl::OUString & aTitle)334 void FilterHelper::setCurrentFilter( const ::rtl::OUString& aTitle ) {
335 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "aTitle", OUStringToOString(aTitle, RTL_TEXTENCODING_UTF8).getStr());
336
337 SetCurFilter(aTitle);
338
339 DBG_PRINT_EXIT(CLASS_NAME, __func__);
340 }
341
getCurrentFilter()342 ::rtl::OUString SAL_CALL FilterHelper::getCurrentFilter( ) {
343 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
344
345 ::rtl::OUString sReturn = (m_aCurrentFilter);
346
347 DBG_PRINT_EXIT(CLASS_NAME, __func__, OUStringToOString(sReturn, RTL_TEXTENCODING_UTF8).getStr());
348
349 return sReturn;
350 }
351
appendFilterGroup(const::rtl::OUString & sGroupTitle,const::com::sun::star::uno::Sequence<::com::sun::star::beans::StringPair> & aFilters)352 void SAL_CALL FilterHelper::appendFilterGroup( const ::rtl::OUString& sGroupTitle, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair >& aFilters ) {
353
354 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "title", OUStringToOString(sGroupTitle, RTL_TEXTENCODING_UTF8).getStr());
355
356 ::vos::OGuard aGuard( Application::GetSolarMutex() );
357
358 //add a separator if this is not the first group to be added
359 sal_Bool bPrependSeparator = m_pFilterList != NULL;
360
361 // ensure that we have a filter list
362 ::rtl::OUString sInitialCurrentFilter;
363 if( aFilters.getLength() > 0)
364 sInitialCurrentFilter = aFilters[0].First;
365 ensureFilterList( sInitialCurrentFilter );
366
367 // append the filter
368 if (bPrependSeparator) {
369 rtl::OUString dash = rtl::OUString::createFromAscii("-");
370 OUStringList emptyList;
371 m_pFilterList->push_back(FilterEntry(dash, emptyList));
372 }
373
374 const com::sun::star::beans::StringPair* pSubFilters = aFilters.getConstArray();
375 const com::sun::star::beans::StringPair* pSubFiltersEnd = pSubFilters + aFilters.getLength();
376 for( ; pSubFilters != pSubFiltersEnd; ++pSubFilters ) {
377 appendFilter(pSubFilters->First, pSubFilters->Second);
378 }
379
380 DBG_PRINT_EXIT(CLASS_NAME, __func__);
381 }
382
filenameMatchesFilter(NSString * sFilename)383 sal_Bool FilterHelper::filenameMatchesFilter(NSString* sFilename)
384 {
385 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
386
387 if (m_aCurrentFilter == NULL) {
388 OSL_TRACE("filter name is null");
389 return sal_True;
390 }
391
392 NSFileManager *manager = [NSFileManager defaultManager];
393 NSDictionary* pAttribs = [manager fileAttributesAtPath: sFilename traverseLink: NO];
394 if( pAttribs )
395 {
396 NSObject* pType = [pAttribs objectForKey: NSFileType];
397 if( pType && [pType isKindOfClass: [NSString class]] )
398 {
399 NSString* pT = (NSString*)pType;
400 if( [pT isEqualToString: NSFileTypeDirectory] ||
401 [pT isEqualToString: NSFileTypeSymbolicLink] )
402 return sal_True;
403 }
404 }
405
406 FilterList::iterator filter = ::std::find_if(m_pFilterList->begin(), m_pFilterList->end(), FilterTitleMatch(m_aCurrentFilter));
407 if (filter == m_pFilterList->end()) {
408 OSL_TRACE("filter not found in list");
409 return sal_True;
410 }
411
412 OUStringList suffixList = filter->getFilterSuffixList();
413
414 {
415 rtl::OUString aName = [sFilename OUString];
416 rtl::OUString allMatcher = rtl::OUString::createFromAscii(".*");
417 for(OUStringList::iterator iter = suffixList.begin(); iter != suffixList.end(); iter++) {
418 if (aName.matchIgnoreAsciiCase(*iter, aName.getLength() - (*iter).getLength()) || ((*iter).equals(allMatcher))) {
419 return sal_True;
420 }
421 }
422 }
423
424 // might be an alias
425 NSString* pResolved = resolveAlias( sFilename );
426 if( pResolved )
427 {
428 sal_Bool bResult = filenameMatchesFilter( pResolved );
429 [pResolved autorelease];
430 if( bResult )
431 return sal_True;
432 }
433
434 DBG_PRINT_EXIT(CLASS_NAME, __func__);
435
436 return sal_False;
437 }
438
getFilterList()439 FilterList* FilterHelper::getFilterList() {
440 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
441 DBG_PRINT_EXIT(CLASS_NAME, __func__);
442
443 return m_pFilterList;
444 }
445
getFilterNames()446 NSStringList* FilterHelper::getFilterNames() {
447 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
448
449 if (NULL == m_pFilterList)
450 return NULL;
451 if (NULL == m_pFilterNames) {
452 //build filter names list
453 m_pFilterNames = new NSStringList;
454 for (FilterList::iterator iter = m_pFilterList->begin(); iter != m_pFilterList->end(); iter++) {
455 m_pFilterNames->push_back([[NSString stringWithOUString:iter->getTitle()] retain]);
456 }
457 }
458
459 DBG_PRINT_EXIT(CLASS_NAME, __func__);
460
461 return m_pFilterNames;
462 }
463
SetFilterAtIndex(unsigned index)464 void FilterHelper::SetFilterAtIndex(unsigned index) {
465 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "index", index);
466
467 if (m_pFilterList->size() <= index) {
468 index = 0;
469 }
470 FilterEntry entry = m_pFilterList->at(index);
471 SetCurFilter(entry.getTitle());
472
473 DBG_PRINT_EXIT(CLASS_NAME, __func__);
474 }
475
fillSuffixList(OUStringList & aSuffixList,const::rtl::OUString & suffixString)476 void FilterHelper::fillSuffixList(OUStringList& aSuffixList, const ::rtl::OUString& suffixString) {
477 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "aSuffixList", suffixString);
478
479 sal_Int32 nIndex = 0;
480 do {
481 rtl::OUString aToken = suffixString.getToken( 0, ';', nIndex );
482 aSuffixList.push_back(aToken.copy(1));
483 } while ( nIndex >= 0 );
484
485 DBG_PRINT_EXIT(CLASS_NAME, __func__);
486 }
487
getCurrentFilterIndex()488 int FilterHelper::getCurrentFilterIndex() {
489 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
490
491 int result = 0;//default to first filter
492 if (m_aCurrentFilter.getLength() > 0) {
493 int i = 0;
494 for (FilterList::iterator iter = m_pFilterList->begin(); iter != m_pFilterList->end(); iter++, i++) {
495 rtl::OUString aTitle = iter->getTitle();
496 if (m_aCurrentFilter.equals(aTitle)) {
497 result = i;
498 break;
499 } else {
500 aTitle = shrinkFilterName(aTitle).trim();
501 if (m_aCurrentFilter.equals(aTitle)) {
502 result = i;
503 break;
504 }
505 }
506 }
507 }
508
509 DBG_PRINT_EXIT(CLASS_NAME, __func__, result);
510
511 return result;
512 }
513
getCurrentFilterSuffixList()514 OUStringList FilterHelper::getCurrentFilterSuffixList() {
515 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
516
517 OUStringList retVal;
518 if (m_aCurrentFilter.getLength() > 0) {
519 for (FilterList::iterator iter = m_pFilterList->begin(); iter != m_pFilterList->end(); iter++) {
520 rtl::OUString aTitle = iter->getTitle();
521 if (m_aCurrentFilter.equals(aTitle)) {
522 retVal = iter->getFilterSuffixList();
523 break;
524 } else {
525 aTitle = shrinkFilterName(aTitle).trim();
526 if (m_aCurrentFilter.equals(aTitle)) {
527 retVal = iter->getFilterSuffixList();
528 break;
529 }
530 }
531 }
532 }
533
534 DBG_PRINT_EXIT(CLASS_NAME, __func__);
535
536 return retVal;
537 }
538