1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_ucb.hxx"
30 
31 /**************************************************************************
32 								TODO
33  **************************************************************************
34 
35  *************************************************************************/
36 #include <ucbhelper/contentidentifier.hxx>
37 #include "odma_provider.hxx"
38 #include "odma_content.hxx"
39 #include "odma_contentprops.hxx"
40 #include <com/sun/star/util/Date.hpp>
41 #include <com/sun/star/util/Time.hpp>
42 #include <rtl/uri.hxx>
43 #include <algorithm>
44 #include <osl/file.hxx>
45 
46 using namespace com::sun::star;
47 using namespace odma;
48 
49 //=========================================================================
50 //=========================================================================
51 //
52 // ContentProvider Implementation.
53 //
54 //=========================================================================
55 //=========================================================================
56 ODMHANDLE ContentProvider::m_aOdmHandle = NULL;
57 
58 ContentProvider::ContentProvider(
59                 const uno::Reference< lang::XMultiServiceFactory >& rSMgr )
60 : ::ucbhelper::ContentProviderImplHelper( rSMgr )
61 {
62 
63 }
64 
65 //=========================================================================
66 // virtual
67 ContentProvider::~ContentProvider()
68 {
69 	ContentsMap::iterator aIter = m_aContents.begin();
70 	for (;aIter != m_aContents.end() ;++aIter )
71 	{
72 		if(aIter->second->m_bIsOpen)
73 			closeDocument(aIter->first);
74 	}
75 	if(m_aOdmHandle)
76 	{
77 		NODMUnRegisterApp(m_aOdmHandle);
78 		m_aOdmHandle = NULL;
79 	}
80 }
81 // -----------------------------------------------------------------------------
82 ODMHANDLE ContentProvider::getHandle()
83 {
84 	if(!m_aOdmHandle)
85 	{
86 		ODMSTATUS odm = NODMRegisterApp(&m_aOdmHandle,ODM_API_VERSION,ODMA_ODMA_REGNAME,NULL,NULL);
87 		switch(odm)
88 		{
89 		case ODM_SUCCESS:
90 			break;
91 		case ODM_E_NODMS:
92 			break;
93 		case ODM_E_CANTINIT:
94 			break;
95 		case ODM_E_VERSION:
96 			break;
97 		default:
98 			break;
99 		}
100 	}
101 	return m_aOdmHandle;
102 }
103 // -----------------------------------------------------------------------------
104 
105 //=========================================================================
106 //
107 // XInterface methods.
108 //
109 //=========================================================================
110 
111 // @@@ Add own interfaces.
112 XINTERFACE_IMPL_3( ContentProvider,
113                    lang::XTypeProvider,
114                    lang::XServiceInfo,
115                    ucb::XContentProvider );
116 
117 //=========================================================================
118 //
119 // XTypeProvider methods.
120 //
121 //=========================================================================
122 
123 // @@@ Add own interfaces.
124 XTYPEPROVIDER_IMPL_3( ContentProvider,
125                       lang::XTypeProvider,
126                       lang::XServiceInfo,
127                       ucb::XContentProvider );
128 
129 //=========================================================================
130 //
131 // XServiceInfo methods.
132 //
133 //=========================================================================
134 
135 // @@@ Adjust implementation name. Keep the prefix "com.sun.star.comp."!
136 // @@@ Adjust service name.
137 XSERVICEINFO_IMPL_1( ContentProvider,
138                      rtl::OUString::createFromAscii(
139                             "com.sun.star.comp.odma.ContentProvider" ),
140                      rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(ODMA_CONTENT_PROVIDER_SERVICE_NAME) ) );
141 
142 //=========================================================================
143 //
144 // Service factory implementation.
145 //
146 //=========================================================================
147 
148 ONE_INSTANCE_SERVICE_FACTORY_IMPL( ContentProvider );
149 
150 //=========================================================================
151 //
152 // XContentProvider methods.
153 //
154 //=========================================================================
155 
156 // virtual
157 uno::Reference< ucb::XContent > SAL_CALL ContentProvider::queryContent(
158         const uno::Reference< ucb::XContentIdentifier >& Identifier )
159     throw( ucb::IllegalIdentifierException, uno::RuntimeException )
160 {
161 	// Check URL scheme...
162 	if(!getHandle())
163 		throw ucb::IllegalIdentifierException();
164 
165     rtl::OUString aScheme( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(ODMA_URL_SCHEME) ) );
166 	sal_Int32 nIndex = 0;
167 	rtl::OUString sOdma = aScheme.getToken(3,'.',nIndex);
168 	rtl::OUString sCanonicURL = Identifier->getContentIdentifier();
169 	// check if url starts with odma
170     if ( !(Identifier->getContentProviderScheme().equalsIgnoreAsciiCase( aScheme ) ||
171 		   Identifier->getContentProviderScheme().equalsIgnoreAsciiCase( sOdma )) )
172         throw ucb::IllegalIdentifierException();
173 
174 	if(!(	sCanonicURL.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM(ODMA_URL_SCHEME_SHORT ODMA_URL_SHORT)) ||
175 			sCanonicURL.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM(ODMA_URL_SCHEME ODMA_URL_SHORT))))
176 		throw ucb::IllegalIdentifierException();
177 
178 	// @@@ Further id checks may go here...
179 #if 0
180 	if ( id-check-failes )
181         throw ucb::IllegalIdentifierException();
182 #endif
183 
184 	// @@@ Id normalization may go here...
185 #if 0
186 	// Normalize URL and create new Id.
187     rtl::OUString aCanonicURL = ( Identifier->getContentIdentifier() );
188     uno::Reference< ucb::XContentIdentifier > xCanonicId
189         = new ::ucb::ContentIdentifier( m_xSMgr, aCanonicURL );
190 #else
191     uno::Reference< ucb::XContentIdentifier > xCanonicId = Identifier;
192 #endif
193 
194 	osl::MutexGuard aGuard( m_aMutex );
195 
196 	// Check, if a content with given id already exists...
197     uno::Reference< ucb::XContent > xContent
198 		= queryExistingContent( xCanonicId ).get();
199 	if ( xContent.is() )
200 		return xContent;
201 
202 	// @@@ Decision, which content implementation to instanciate may be
203 	//     made here ( in case you have different content classes ).
204 
205 	// Create a new content.
206 
207 	sCanonicURL = convertURL(sCanonicURL);
208 
209 	::rtl::Reference<ContentProperties> aProp;
210 	// first check if we got an ODMA ID from outside
211 	if( sCanonicURL.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM(ODMA_URL_ODMAID)))
212 	{// we get an orignal ODMA id so we have to look for the name
213 		::rtl::OString sDocId = ::rtl::OUStringToOString(sCanonicURL,RTL_TEXTENCODING_MS_1252);
214 		sal_Char* lpszDocName = new sal_Char[ODM_NAME_MAX];
215 
216 		ODMSTATUS odm = NODMGetDocInfo(	getHandle(),
217 										const_cast<sal_Char*>(sDocId.getStr()),
218 										ODM_NAME,
219 										lpszDocName,
220 										ODM_NAME_MAX
221 									);
222 		if(odm == ODM_SUCCESS)
223 		{
224 			aProp = new ContentProperties();
225 			aProp->m_sDocumentName = ::rtl::OStringToOUString(rtl::OString(lpszDocName),RTL_TEXTENCODING_ASCII_US);
226 			aProp->m_sDocumentId   = sDocId;
227 			aProp->m_sContentType  = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(ODMA_CONTENT_TYPE));
228 			append(aProp);
229 		}
230 		delete [] lpszDocName;
231 	}
232 	else // we got an already fetched name here so look for it
233 	{
234 		// we have a valid document name
235 		aProp = getContentPropertyWithTitle(sCanonicURL);
236 		if(!aProp.is())
237 			aProp = getContentPropertyWithSavedAsName(sCanonicURL);
238 		if(!aProp.is())
239 		{
240 			if(sCanonicURL.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("/")))
241 			{ // found only the scheme
242 				aProp = new ContentProperties();
243 				aProp->m_sDocumentId = "/";
244 				aProp->m_sTitle = sCanonicURL;
245 				aProp->m_bIsFolder = sal_True;
246 				aProp->m_bIsDocument = !aProp->m_bIsFolder;
247 				m_aContents.insert(ContentsMap::value_type(aProp->m_sDocumentId,aProp));
248 			}
249 			else
250 				aProp = queryContentProperty(sCanonicURL);
251 		}
252 	}
253 	if(!aProp.is())
254 		throw ucb::IllegalIdentifierException();
255 
256 	xContent = new Content( m_xSMgr, this, xCanonicId ,aProp);
257     registerNewContent( xContent );
258 
259 	if ( !xContent->getIdentifier().is() )
260         throw ucb::IllegalIdentifierException();
261 
262 	return xContent;
263 }
264 // -----------------------------------------------------------------------------
265 void ContentProvider::closeDocument(const ::rtl::OString& _sDocumentId)
266 {
267 	ContentsMap::iterator aIter = m_aContents.find(_sDocumentId);
268 	if(aIter != m_aContents.end())
269 	{
270 		DWORD dwFlags = ODM_SILENT;
271 		ODMSTATUS odm = NODMCloseDocEx(	ContentProvider::getHandle(),
272 										const_cast<sal_Char*>(_sDocumentId.getStr()),
273 										&dwFlags,
274 										0xFFFFFFFF,
275 										0xFFFFFFFF,
276 										NULL,
277 										0);
278 		OSL_ENSURE(odm == ODM_SUCCESS,"Error while closing a document!");
279 		if(odm == ODM_SUCCESS)
280 			aIter->second->m_bIsOpen = sal_False;
281 	}
282 }
283 // -----------------------------------------------------------------------------
284 void ContentProvider::saveDocument(const ::rtl::OString& _sDocumentId)
285 {
286 	ContentsMap::iterator aIter = m_aContents.find(_sDocumentId);
287 	if(aIter != m_aContents.end())
288 	{
289 		sal_Char* lpszDocId = new sal_Char[ODM_DOCID_MAX];
290 		DWORD dwFlags = ODM_SILENT;
291 		ODMSTATUS odm = NODMSaveDocEx(getHandle(),
292 									const_cast<sal_Char*>(_sDocumentId.getStr()),
293 									lpszDocId,
294 									&dwFlags);
295 		OSL_ENSURE(odm == ODM_SUCCESS,"Could not save document!");
296 		if(odm != ODM_SUCCESS)
297 		{
298 			delete [] lpszDocId;
299 			throw uno::Exception();
300 		}
301 		aIter->second->m_sDocumentId = rtl::OString(lpszDocId);
302 		delete [] lpszDocId;
303 	}
304 }
305 // -----------------------------------------------------------------------------
306 util::Date toDate(const ::rtl::OString& _sSQLString)
307 {
308 	sal_uInt16	nYear	= 0,
309 				nMonth	= 0,
310 				nDay	= 0;
311 	nYear	= (sal_uInt16)_sSQLString.copy(0,4).toInt32();
312 	nMonth	= (sal_uInt16)_sSQLString.copy(4,2).toInt32();
313 	nDay	= (sal_uInt16)_sSQLString.copy(6,2).toInt32();
314 
315 	return util::Date(nDay,nMonth,nYear);
316 }
317 //-----------------------------------------------------------------------------
318 util::Time toTime(const ::rtl::OString& _sSQLString)
319 {
320 	sal_uInt16	nHour	= 0,
321 				nMinute	= 0,
322 				nSecond	= 0;
323 	nHour	= (sal_uInt16)_sSQLString.copy(8,2).toInt32();
324 	nMinute = (sal_uInt16)_sSQLString.copy(10,2).toInt32();
325 	nSecond = (sal_uInt16)_sSQLString.copy(12,2).toInt32();
326 
327 	return util::Time(0,nHour,nMinute,nSecond);
328 }
329 //-----------------------------------------------------------------------------
330 util::DateTime toDateTime(const ::rtl::OString& _sSQLString)
331 {
332 	util::Date aDate = toDate(_sSQLString);
333 	util::Time aTime = toTime(_sSQLString);
334 
335 	return util::DateTime(0,aTime.Seconds,aTime.Minutes,aTime.Hours,aDate.Day,aDate.Month,aDate.Year);
336 }
337 // -----------------------------------------------------------------------------
338 void ContentProvider::fillDocumentProperties(const ::rtl::Reference<ContentProperties>& _rProp)
339 {
340 	// read some properties from the DMS
341 	sal_Char* lpszDocInfo = new sal_Char[ODM_DOCID_MAX];
342 	sal_Char* pDocId = const_cast<sal_Char*>(_rProp->m_sDocumentId.getStr());
343 
344 	// read the create date of the document
345 	ODMSTATUS odm = NODMGetDocInfo(	getHandle(),
346 									pDocId,
347 									ODM_CREATEDDATE,
348 									lpszDocInfo,
349 									ODM_DOCID_MAX);
350 	if(odm == ODM_SUCCESS)
351 		_rProp->m_aDateCreated = toDateTime(::rtl::OString(lpszDocInfo));
352 
353 	// read the modified date of the document
354 	odm = NODMGetDocInfo(	getHandle(),
355 							pDocId,
356 							ODM_MODIFYDATE,
357 							lpszDocInfo,
358 							ODM_DOCID_MAX);
359 	if(odm == ODM_SUCCESS)
360 		_rProp->m_aDateModified = toDateTime(::rtl::OString(lpszDocInfo));
361 
362 	// read the title of the document
363 	odm = NODMGetDocInfo(	getHandle(),
364 							pDocId,
365 							ODM_TITLETEXT,
366 							lpszDocInfo,
367 							ODM_DOCID_MAX);
368 	if(odm == ODM_SUCCESS)
369 		_rProp->m_sTitle = ::rtl::OStringToOUString(rtl::OString(lpszDocInfo),RTL_TEXTENCODING_ASCII_US);
370 
371 	// read the name of the document
372 	odm = NODMGetDocInfo(	getHandle(),
373 							pDocId,
374 							ODM_NAME,
375 							lpszDocInfo,
376 							ODM_DOCID_MAX);
377 	if(odm == ODM_SUCCESS)
378 		_rProp->m_sDocumentName = ::rtl::OStringToOUString(rtl::OString(lpszDocInfo),RTL_TEXTENCODING_ASCII_US);
379 
380 	// read the author of the document
381 	odm = NODMGetDocInfo(	getHandle(),
382 							pDocId,
383 							ODM_AUTHOR,
384 							lpszDocInfo,
385 							ODM_DOCID_MAX);
386 	if(odm == ODM_SUCCESS)
387 		_rProp->m_sAuthor = ::rtl::OStringToOUString(rtl::OString(lpszDocInfo),RTL_TEXTENCODING_ASCII_US);
388 
389 	// read the subject of the document
390 	odm = NODMGetDocInfo(	getHandle(),
391 							pDocId,
392 							ODM_SUBJECT,
393 							lpszDocInfo,
394 							ODM_DOCID_MAX);
395 	if(odm == ODM_SUCCESS)
396 		_rProp->m_sSubject = ::rtl::OStringToOUString(rtl::OString(lpszDocInfo),RTL_TEXTENCODING_ASCII_US);
397 
398 	// read the keywords of the document
399 	odm = NODMGetDocInfo(	getHandle(),
400 							pDocId,
401 							ODM_KEYWORDS,
402 							lpszDocInfo,
403 							ODM_DOCID_MAX);
404 	if(odm == ODM_SUCCESS)
405 		_rProp->m_sKeywords = ::rtl::OStringToOUString(rtl::OString(lpszDocInfo),RTL_TEXTENCODING_ASCII_US);
406 
407 /*
408 	odm = NODMGetDocInfo(	getHandle(),
409 									const_cast<sal_Char*>(_rProp->m_sDocumentId.getStr()),
410 									ODM_URL,
411 									lpszDocInfo,
412 									ODM_DOCID_MAX);
413 */
414 	delete [] lpszDocInfo;
415 }
416 // -----------------------------------------------------------------------------
417 void ContentProvider::append(const ::rtl::Reference<ContentProperties>& _rProp)
418 {
419 	// now fill some more properties
420 	fillDocumentProperties(_rProp);
421 	// and append them
422 	m_aContents.insert(ContentsMap::value_type(_rProp->m_sDocumentId,_rProp));
423 }
424 // -----------------------------------------------------------------------------
425 ::rtl::Reference<ContentProperties> ContentProvider::queryContentProperty(const ::rtl::OUString& _sDocumentName)
426 {
427 	::rtl::Reference<ContentProperties> aReturn;
428 	sal_Char* lpszDMSList	= new sal_Char[ODM_DMSID_MAX];
429 
430 	ODMSTATUS odm = NODMGetDMS(ODMA_ODMA_REGNAME, lpszDMSList);
431 	if(odm == ODM_SUCCESS)
432 	{
433 		sal_Char* pQueryId = new sal_Char[ODM_QUERYID_MAX];
434 		lpszDMSList[strlen(lpszDMSList)+1] = '\0';
435 
436 		::rtl::OString sTitleText(::rtl::OUStringToOString(_sDocumentName,RTL_TEXTENCODING_ASCII_US));
437 		::rtl::OString sQuery("SELECT ODM_DOCID, ODM_NAME WHERE ODM_TITLETEXT = '");
438 		sQuery += sTitleText;
439 		sQuery += "'";
440 
441 		DWORD dwFlags = ODM_SPECIFIC;
442 		odm = NODMQueryExecute(getHandle(), sQuery,dwFlags, lpszDMSList, pQueryId );
443 		if(odm == ODM_SUCCESS)
444 		{
445 			sal_uInt16 nCount		= 10;
446 			sal_uInt16 nMaxCount	= 10;
447 			sal_Char* lpszDocId		= new sal_Char[ODM_DOCID_MAX * nMaxCount];
448 			sal_Char* lpszDocName	= new sal_Char[ODM_NAME_MAX * nMaxCount];
449 			sal_Char* lpszDocInfo	= new sal_Char[ODM_DOCID_MAX];
450 
451 			::rtl::OUString sContentType(RTL_CONSTASCII_USTRINGPARAM(ODMA_CONTENT_TYPE));
452 			do
453 			{
454 				if(nCount >= nMaxCount)
455 				{
456 					// get the result
457 					nCount = nMaxCount;
458 					odm = NODMQueryGetResults(getHandle(), pQueryId,lpszDocId, lpszDocName, ODM_NAME_MAX, (WORD*)&nCount);
459 				}
460 				if(odm == ODM_SUCCESS)
461 					for(sal_uInt16 i = 0; i < nCount; ++i)
462 					{
463 						odm = NODMGetDocInfo(	getHandle(),
464 												&lpszDocId[ODM_DOCID_MAX*i],
465 												ODM_TITLETEXT,
466 												lpszDocInfo,
467 												ODM_DOCID_MAX);
468 						if( odm == ODM_SUCCESS && sTitleText == ::rtl::OString(lpszDocInfo))
469 						{
470 							aReturn = new ContentProperties();
471 							aReturn->m_sDocumentName	= ::rtl::OStringToOUString(rtl::OString(&lpszDocName[ODM_NAME_MAX*i]),RTL_TEXTENCODING_ASCII_US);
472 							aReturn->m_sDocumentId	= ::rtl::OString(&lpszDocId[ODM_DOCID_MAX*i]);
473 							aReturn->m_sContentType	= sContentType;
474 							append(aReturn);
475 							nCount = 0; // break condition from outer loop
476 							break;
477 						}
478 					}
479 			}
480 			while(nCount > nMaxCount);
481 
482 			delete [] lpszDocInfo;
483 			delete [] lpszDocId;
484 			delete [] lpszDocName;
485 		}
486 
487 		// now close the query
488 		odm = NODMQueryClose(ContentProvider::getHandle(), pQueryId);
489 		delete [] pQueryId;
490 	}
491 	delete [] lpszDMSList;
492 
493 
494 	return aReturn;
495 }
496 // -----------------------------------------------------------------------------
497 ::rtl::Reference<ContentProperties> ContentProvider::getContentProperty(const ::rtl::OUString& _sName,
498 																   const ContentPropertiesMemberFunctor& _aFunctor) const
499 {
500 	::rtl::Reference<ContentProperties> aReturn;
501 	ContentsMap::const_iterator aFind = ::std::find_if(	m_aContents.begin(),
502 														m_aContents.end(),
503 														::std::compose1(
504 															::std::bind2nd(_aFunctor,_sName),
505 															::std::select2nd<ContentsMap::value_type>()
506 														)
507 													);
508 	if(aFind != m_aContents.end())
509 		aReturn = aFind->second;
510 	return aReturn;
511 }
512 // -----------------------------------------------------------------------------
513 ::rtl::Reference<ContentProperties> ContentProvider::getContentPropertyWithSavedAsName(const ::rtl::OUString& _sSaveAsName) const
514 {
515 	ContentPropertiesMemberFunctor aFunc(::std::mem_fun(&ContentProperties::getSavedAsName));
516 	return getContentProperty(_sSaveAsName,aFunc);
517 }
518 // -----------------------------------------------------------------------------
519 ::rtl::Reference<ContentProperties> ContentProvider::getContentPropertyWithTitle(const ::rtl::OUString& _sTitle) const
520 {
521 	ContentPropertiesMemberFunctor aFunc(::std::mem_fun(&ContentProperties::getTitle));
522 	return getContentProperty(_sTitle,aFunc);
523 }
524 // -----------------------------------------------------------------------------
525 ::rtl::OUString ContentProvider::openDoc(const ::rtl::Reference<ContentProperties>& _rProp)  throw (uno::Exception)
526 {
527 	OSL_ENSURE(_rProp.is(),"No valid content properties!");
528 	if(!_rProp->m_bIsOpen)
529 	{
530 		sal_Char *pFileName = new sal_Char[ODM_FILENAME_MAX];
531 
532 		DWORD dwFlag = ODM_MODIFYMODE | ODM_SILENT;
533 		ODMSTATUS odm = NODMOpenDoc(getHandle(), dwFlag, const_cast<sal_Char*>(_rProp->m_sDocumentId.getStr()), pFileName);
534 		switch(odm)
535 		{
536 			case ODM_E_INUSE:
537 				dwFlag = ODM_VIEWMODE;
538 				if( NODMOpenDoc(getHandle(), dwFlag, const_cast<sal_Char*>(_rProp->m_sDocumentId.getStr()), pFileName) != ODM_SUCCESS)
539 					break;
540 				// else run through
541 			case ODM_SUCCESS:
542 				::osl::FileBase::getFileURLFromSystemPath(::rtl::OStringToOUString(rtl::OString(pFileName),RTL_TEXTENCODING_ASCII_US)
543 															,_rProp->m_sFileURL);
544 				_rProp->m_bIsOpen = sal_True;
545 				break;
546 			default:
547 				delete [] pFileName;
548 				throw uno::Exception();  // TODO give a more precise error message here
549 		}
550 
551 		delete [] pFileName;
552 	}
553 	return _rProp->m_sFileURL;
554 }
555 // -----------------------------------------------------------------------------
556 ::rtl::OUString ContentProvider::convertURL(const ::rtl::OUString& _sCanonicURL)
557 {
558 	sal_Int32 nPos = 0;
559 	// check if url starts with odma
560 	if(_sCanonicURL.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM(ODMA_URL_SCHEME_SHORT ODMA_URL_SHORT)))
561 	{ // URL starts with odma:// so we have to remove this
562 		nPos = ODMA_URL_SHORT_LGTH;
563 	}
564 	else if(_sCanonicURL.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM(ODMA_URL_SCHEME ODMA_URL_SHORT)))
565 	{ // URL starts with vnd.sun.star.odma:/// so we have to remove this
566 		nPos = ODMA_URL_LGTH;
567 	}
568 
569 	::rtl::OUString sCanonicURL = _sCanonicURL;
570 	// now check what formats we allow
571 	if(nPos == _sCanonicURL.getLength()) // only ask for root entry
572 		sCanonicURL = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/"));
573 
574 	if(nPos < sCanonicURL.getLength())
575 	{
576 		sCanonicURL = sCanonicURL.copy(nPos);
577 		sCanonicURL = rtl::Uri::decode(sCanonicURL,rtl_UriDecodeWithCharset,RTL_TEXTENCODING_UTF8);
578 	}
579 	if(sCanonicURL.getLength() > 1 && sCanonicURL.getStr()[0] == sal_Unicode('/'))
580 	{
581 		sCanonicURL = sCanonicURL.copy(1);
582 		if(sCanonicURL.getLength() == 1 && sCanonicURL.getStr()[0] == sal_Unicode('.'))
583 			sCanonicURL = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/"));
584 	}
585 	return sCanonicURL;
586 }
587 // -----------------------------------------------------------------------------
588 sal_Bool ContentProvider::deleteDocument(const ::rtl::Reference<ContentProperties>& _rProp)
589 {
590 	closeDocument(_rProp->m_sDocumentId);
591 	ODMSTATUS odm = NODMActivate(ContentProvider::getHandle(),
592 								 ODM_DELETE,
593 								 const_cast< sal_Char*>(_rProp->m_sDocumentId.getStr()));
594 	if(odm == ODM_SUCCESS)
595 		m_aContents.erase(_rProp->m_sDocumentId);
596 
597 	return odm == ODM_SUCCESS;
598 }
599 // -----------------------------------------------------------------------------
600