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__anon2b3e87a70111::FilterTitleMatch142 FilterTitleMatch( const rtl::OUString _rTitle ) : rTitle( _rTitle ) { }
143
144 //............................................................................
operator ()__anon2b3e87a70111::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 ()__anon2b3e87a70111::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 throw( ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException ) {
316 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "title", aTitle, "filter", aFilterString);
317
318 ::vos::OGuard aGuard( Application::GetSolarMutex() );
319
320 if( FilterNameExists( aTitle ) ) {
321 throw com::sun::star::lang::IllegalArgumentException();
322 }
323
324 // ensure that we have a filter list
325 ensureFilterList( aTitle );
326
327 // append the filter
328 OUStringList suffixList;
329 fillSuffixList(suffixList, aFilterString);
330 m_pFilterList->push_back(FilterEntry( aTitle, suffixList ) );
331
332 DBG_PRINT_EXIT(CLASS_NAME, __func__);
333 }
334
setCurrentFilter(const::rtl::OUString & aTitle)335 void FilterHelper::setCurrentFilter( const ::rtl::OUString& aTitle )
336 throw( ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException ) {
337 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "aTitle", OUStringToOString(aTitle, RTL_TEXTENCODING_UTF8).getStr());
338
339 SetCurFilter(aTitle);
340
341 DBG_PRINT_EXIT(CLASS_NAME, __func__);
342 }
343
getCurrentFilter()344 ::rtl::OUString SAL_CALL FilterHelper::getCurrentFilter( )
345 throw( ::com::sun::star::uno::RuntimeException ) {
346 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
347
348 ::rtl::OUString sReturn = (m_aCurrentFilter);
349
350 DBG_PRINT_EXIT(CLASS_NAME, __func__, OUStringToOString(sReturn, RTL_TEXTENCODING_UTF8).getStr());
351
352 return sReturn;
353 }
354
appendFilterGroup(const::rtl::OUString & sGroupTitle,const::com::sun::star::uno::Sequence<::com::sun::star::beans::StringPair> & aFilters)355 void SAL_CALL FilterHelper::appendFilterGroup( const ::rtl::OUString& sGroupTitle, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair >& aFilters )
356 throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) {
357
358 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "title", OUStringToOString(sGroupTitle, RTL_TEXTENCODING_UTF8).getStr());
359
360 ::vos::OGuard aGuard( Application::GetSolarMutex() );
361
362 //add a separator if this is not the first group to be added
363 sal_Bool bPrependSeparator = m_pFilterList != NULL;
364
365 // ensure that we have a filter list
366 ::rtl::OUString sInitialCurrentFilter;
367 if( aFilters.getLength() > 0)
368 sInitialCurrentFilter = aFilters[0].First;
369 ensureFilterList( sInitialCurrentFilter );
370
371 // append the filter
372 if (bPrependSeparator) {
373 rtl::OUString dash = rtl::OUString::createFromAscii("-");
374 OUStringList emptyList;
375 m_pFilterList->push_back(FilterEntry(dash, emptyList));
376 }
377
378 const com::sun::star::beans::StringPair* pSubFilters = aFilters.getConstArray();
379 const com::sun::star::beans::StringPair* pSubFiltersEnd = pSubFilters + aFilters.getLength();
380 for( ; pSubFilters != pSubFiltersEnd; ++pSubFilters ) {
381 appendFilter(pSubFilters->First, pSubFilters->Second);
382 }
383
384 DBG_PRINT_EXIT(CLASS_NAME, __func__);
385 }
386
filenameMatchesFilter(NSString * sFilename)387 sal_Bool FilterHelper::filenameMatchesFilter(NSString* sFilename)
388 {
389 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
390
391 if (m_aCurrentFilter == NULL) {
392 OSL_TRACE("filter name is null");
393 return sal_True;
394 }
395
396 NSFileManager *manager = [NSFileManager defaultManager];
397 NSDictionary* pAttribs = [manager fileAttributesAtPath: sFilename traverseLink: NO];
398 if( pAttribs )
399 {
400 NSObject* pType = [pAttribs objectForKey: NSFileType];
401 if( pType && [pType isKindOfClass: [NSString class]] )
402 {
403 NSString* pT = (NSString*)pType;
404 if( [pT isEqualToString: NSFileTypeDirectory] ||
405 [pT isEqualToString: NSFileTypeSymbolicLink] )
406 return sal_True;
407 }
408 }
409
410 FilterList::iterator filter = ::std::find_if(m_pFilterList->begin(), m_pFilterList->end(), FilterTitleMatch(m_aCurrentFilter));
411 if (filter == m_pFilterList->end()) {
412 OSL_TRACE("filter not found in list");
413 return sal_True;
414 }
415
416 OUStringList suffixList = filter->getFilterSuffixList();
417
418 {
419 rtl::OUString aName = [sFilename OUString];
420 rtl::OUString allMatcher = rtl::OUString::createFromAscii(".*");
421 for(OUStringList::iterator iter = suffixList.begin(); iter != suffixList.end(); iter++) {
422 if (aName.matchIgnoreAsciiCase(*iter, aName.getLength() - (*iter).getLength()) || ((*iter).equals(allMatcher))) {
423 return sal_True;
424 }
425 }
426 }
427
428 // might be an alias
429 NSString* pResolved = resolveAlias( sFilename );
430 if( pResolved )
431 {
432 sal_Bool bResult = filenameMatchesFilter( pResolved );
433 [pResolved autorelease];
434 if( bResult )
435 return sal_True;
436 }
437
438 DBG_PRINT_EXIT(CLASS_NAME, __func__);
439
440 return sal_False;
441 }
442
getFilterList()443 FilterList* FilterHelper::getFilterList() {
444 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
445 DBG_PRINT_EXIT(CLASS_NAME, __func__);
446
447 return m_pFilterList;
448 }
449
getFilterNames()450 NSStringList* FilterHelper::getFilterNames() {
451 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
452
453 if (NULL == m_pFilterList)
454 return NULL;
455 if (NULL == m_pFilterNames) {
456 //build filter names list
457 m_pFilterNames = new NSStringList;
458 for (FilterList::iterator iter = m_pFilterList->begin(); iter != m_pFilterList->end(); iter++) {
459 m_pFilterNames->push_back([[NSString stringWithOUString:iter->getTitle()] retain]);
460 }
461 }
462
463 DBG_PRINT_EXIT(CLASS_NAME, __func__);
464
465 return m_pFilterNames;
466 }
467
SetFilterAtIndex(unsigned index)468 void FilterHelper::SetFilterAtIndex(unsigned index) {
469 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "index", index);
470
471 if (m_pFilterList->size() <= index) {
472 index = 0;
473 }
474 FilterEntry entry = m_pFilterList->at(index);
475 SetCurFilter(entry.getTitle());
476
477 DBG_PRINT_EXIT(CLASS_NAME, __func__);
478 }
479
fillSuffixList(OUStringList & aSuffixList,const::rtl::OUString & suffixString)480 void FilterHelper::fillSuffixList(OUStringList& aSuffixList, const ::rtl::OUString& suffixString) {
481 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "aSuffixList", suffixString);
482
483 sal_Int32 nIndex = 0;
484 do {
485 rtl::OUString aToken = suffixString.getToken( 0, ';', nIndex );
486 aSuffixList.push_back(aToken.copy(1));
487 } while ( nIndex >= 0 );
488
489 DBG_PRINT_EXIT(CLASS_NAME, __func__);
490 }
491
getCurrentFilterIndex()492 int FilterHelper::getCurrentFilterIndex() {
493 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
494
495 int result = 0;//default to first filter
496 if (m_aCurrentFilter.getLength() > 0) {
497 int i = 0;
498 for (FilterList::iterator iter = m_pFilterList->begin(); iter != m_pFilterList->end(); iter++, i++) {
499 rtl::OUString aTitle = iter->getTitle();
500 if (m_aCurrentFilter.equals(aTitle)) {
501 result = i;
502 break;
503 } else {
504 aTitle = shrinkFilterName(aTitle).trim();
505 if (m_aCurrentFilter.equals(aTitle)) {
506 result = i;
507 break;
508 }
509 }
510 }
511 }
512
513 DBG_PRINT_EXIT(CLASS_NAME, __func__, result);
514
515 return result;
516 }
517
getCurrentFilterSuffixList()518 OUStringList FilterHelper::getCurrentFilterSuffixList() {
519 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
520
521 OUStringList retVal;
522 if (m_aCurrentFilter.getLength() > 0) {
523 for (FilterList::iterator iter = m_pFilterList->begin(); iter != m_pFilterList->end(); iter++) {
524 rtl::OUString aTitle = iter->getTitle();
525 if (m_aCurrentFilter.equals(aTitle)) {
526 retVal = iter->getFilterSuffixList();
527 break;
528 } else {
529 aTitle = shrinkFilterName(aTitle).trim();
530 if (m_aCurrentFilter.equals(aTitle)) {
531 retVal = iter->getFilterSuffixList();
532 break;
533 }
534 }
535 }
536 }
537
538 DBG_PRINT_EXIT(CLASS_NAME, __func__);
539
540 return retVal;
541 }
542