1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
23 // Contents: Filter Implementation for OpenOffice.Org Document using
25 // Summary: The LibreOffice filter reads OpenOffice.org XML files (with
26 // the extension .sxw .sxi, etc) and ODF files and extract
27 // their content, author, keywords,subject,comments and title
30 // Platform: Windows 2000, Windows XP
32 #include "internal/contentreader.hxx"
33 #include "internal/metainforeader.hxx"
34 #include "internal/registry.hxx"
35 #include "internal/fileextensions.hxx"
38 // Include file Purpose
39 // windows.h Win32 declarations
40 // string.h string wstring declarations
41 // filter.h IFilter interface declarations
42 // filterr.h FACILITY_ITF error definitions for IFilter
43 // ntquery.h Indexing Service declarations
44 // assert.h assertion function.
45 // ooofilt.hxx LibreOffice filter declarations
46 // propspec.hxx PROPSPEC
50 #pragma warning(push, 1)
61 #include "ooofilt.hxx"
64 #include "propspec.hxx"
70 #include "internal/stream_helper.hxx"
72 //C-------------------------------------------------------------------------
74 // Summary: Implements LibreOffice filter class
76 //M-------------------------------------------------------------------------
77 // Method: COooFilter::COooFilter
78 // Summary: Class constructor
80 // Purpose: Manages global instance count
82 COooFilter::COooFilter() :
84 m_pContentReader(NULL
),
85 m_pMetaInfoReader(NULL
),
86 m_eState(FilteringContent
),
87 m_ulUnicodeBufferLen(0),
88 m_ulUnicodeCharsRead(0),
90 m_ulCurrentPropertyNum(0),
100 InterlockedIncrement( &g_lInstances
);
102 //M-------------------------------------------------------------------------
103 // Method: COooFilter::~COooFilter
104 // Summary: Class destructor
106 // Purpose: Manages global instance count and file handle
108 COooFilter::~COooFilter()
110 delete [] m_pAttributes
;
112 if (m_pContentReader
)
113 delete m_pContentReader
;
114 if (m_pMetaInfoReader
)
115 delete m_pMetaInfoReader
;
119 InterlockedDecrement( &g_lInstances
);
122 //M-------------------------------------------------------------------------
123 // Method: COooFilter::QueryInterface (IUnknown::QueryInterface)
124 // Summary: Queries for requested interface // Arguments: riid
125 // [in] Reference IID of requested interface
127 // [out] Address that receives requested interface pointer
129 // Interface is supported
131 // Interface is not supported
133 SCODE STDMETHODCALLTYPE
COooFilter::QueryInterface(
137 IUnknown
*pUnkTemp
= 0;
138 if ( IID_IFilter
== riid
)
139 pUnkTemp
= (IUnknown
*)(IFilter
*)this;
140 else if ( IID_IPersistFile
== riid
)
141 pUnkTemp
= (IUnknown
*)(IPersistFile
*)this;
142 else if ( IID_IPersist
== riid
)
143 pUnkTemp
= (IUnknown
*)(IPersist
*)(IPersistFile
*)this;
144 else if (IID_IPersistStream
== riid
)
145 pUnkTemp
= (IUnknown
*)(IPersistStream
*)this;
146 else if ( IID_IUnknown
== riid
)
147 pUnkTemp
= (IUnknown
*)(IPersist
*)(IPersistFile
*)this;
151 return E_NOINTERFACE
;
153 *ppvObject
= (void *)pUnkTemp
;
157 //M-------------------------------------------------------------------------
158 // Method: COooFilter::AddRef (IUnknown::AddRef)
159 // Summary: Increments interface refcount
161 // Returns: Value of incremented interface refcount
163 ULONG STDMETHODCALLTYPE
COooFilter::AddRef()
165 return InterlockedIncrement( &m_lRefs
);
167 //M-------------------------------------------------------------------------
168 // Method: COooFilter::Release (IUnknown::Release)
169 // Summary: Decrements interface refcount, deleting if unreferenced
171 // Returns: Value of decremented interface refcount
173 ULONG STDMETHODCALLTYPE
COooFilter::Release()
175 ULONG ulTmp
= InterlockedDecrement( &m_lRefs
);
181 //M-------------------------------------------------------------------------
182 // Method: COooFilter::Init (IFilter::Init)
183 // Summary: Initializes LibreOffice filter instance
184 // Arguments: grfFlags
185 // [in] Flags for filter behavior
187 // [in] Number attributes in array aAttributes
189 // [in] Array of requested attribute strings
191 // [out] Pointer to return flags for additional properties
193 // Initialization succeeded
195 // File not previously loaded
197 // Count and contents of attributes do not agree
199 // Unable to access file to be filtered
203 const int COUNT_ATTRIBUTES
= 5;
205 SCODE STDMETHODCALLTYPE
COooFilter::Init(
208 FULLPROPSPEC
const * aAttributes
,
211 // Enumerate OLE properties, since any NTFS file can have them
212 *pFlags
= IFILTER_FLAGS_OLE_PROPERTIES
;
217 m_ulCurrentPropertyNum
= 0;
218 if ( m_cAttributes
> 0 )
220 delete[] m_pAttributes
;
224 if( 0 < cAttributes
)
226 // Filter properties specified in aAttributes
227 if ( 0 == aAttributes
)
229 m_pAttributes
= new CFullPropSpec
[cAttributes
];
230 m_cAttributes
= cAttributes
;
231 // Is caller want to filter contents?
232 CFullPropSpec
*pAttrib
= (CFullPropSpec
*) aAttributes
;
234 for ( ulNumAttr
= 0 ; ulNumAttr
< cAttributes
; ulNumAttr
++ )
236 if ( pAttrib
[ulNumAttr
].IsPropertyPropid() &&
237 pAttrib
[ulNumAttr
].GetPropertyPropid() == PID_STG_CONTENTS
&&
238 pAttrib
[ulNumAttr
].GetPropSet() == guidStorage
)
242 // save the requested properties.
243 m_pAttributes
[ulNumAttr
] = pAttrib
[ulNumAttr
];
246 else if ( grfFlags
& IFILTER_INIT_APPLY_INDEX_ATTRIBUTES
)
248 // Filter contents and all pseudo-properties
251 m_pAttributes
= new CFullPropSpec
[COUNT_ATTRIBUTES
];
252 m_cAttributes
= COUNT_ATTRIBUTES
;
253 m_pAttributes
[0].SetPropSet( FMTID_SummaryInformation
);
254 m_pAttributes
[0].SetProperty( PIDSI_AUTHOR
);
255 m_pAttributes
[1].SetPropSet( FMTID_SummaryInformation
);
256 m_pAttributes
[1].SetProperty( PIDSI_TITLE
);
257 m_pAttributes
[2].SetPropSet( FMTID_SummaryInformation
);
258 m_pAttributes
[2].SetProperty( PIDSI_SUBJECT
);
259 m_pAttributes
[3].SetPropSet( FMTID_SummaryInformation
);
260 m_pAttributes
[3].SetProperty( PIDSI_KEYWORDS
);
261 m_pAttributes
[4].SetPropSet( FMTID_SummaryInformation
);
262 m_pAttributes
[4].SetProperty( PIDSI_COMMENTS
);
264 else if ( 0 == grfFlags
)
266 // Filter only contents
275 m_eState
= FilteringContent
;
276 m_ulUnicodeCharsRead
= 0;
282 m_eState
= FilteringProperty
;
286 catch (const std::exception
&)
293 //M-------------------------------------------------------------------------
294 // Method: COooFilter::GetChunk (IFilter::GetChunk)
295 // Summary: Gets the next chunk
297 // [out] Pointer to description of current chunk
299 // Chunk was successfully retrieved
301 // Character conversion failed
303 // General access failure occurred
304 // FILTER_E_END_OF_CHUNKS
305 // Previous chunk was the last chunk
306 // FILTER_E_EMBEDDING_UNAVAILABLE
308 // FILTER_E_LINK_UNAVAILABLE
313 SCODE STDMETHODCALLTYPE
COooFilter::GetChunk(STAT_CHUNK
* pStat
)
319 case FilteringContent
:
321 // Read Unicodes from buffer.
322 if( m_ChunkPosition
== m_pContentReader
->getChunkBuffer().size() )
324 m_ulUnicodeBufferLen
=0;
328 if ( !m_fContents
|| m_fEof
)
330 m_eState
= FilteringProperty
;
333 m_pwsBuffer
= m_pContentReader
-> getChunkBuffer()[m_ChunkPosition
].second
;
334 m_ulUnicodeBufferLen
= static_cast<ULONG
>(m_pwsBuffer
.length());
335 DWORD ChunkLCID
= LocaleSetToLCID( m_pContentReader
-> getChunkBuffer()[m_ChunkPosition
].first
);
336 // Set chunk description
337 pStat
->idChunk
= m_ulChunkID
;
338 pStat
->breakType
= CHUNK_NO_BREAK
;
339 pStat
->flags
= CHUNK_TEXT
;
340 pStat
->locale
= ChunkLCID
;
341 pStat
->attribute
.guidPropSet
= guidStorage
;
342 pStat
->attribute
.psProperty
.ulKind
= PRSPEC_PROPID
;
343 pStat
->attribute
.psProperty
.propid
= PID_STG_CONTENTS
;
344 pStat
->idChunkSource
= m_ulChunkID
;
345 pStat
->cwcStartSource
= 0;
346 pStat
->cwcLenSource
= 0;
347 m_ulUnicodeCharsRead
= 0;
352 case FilteringProperty
:
354 if ( m_cAttributes
== 0 )
355 return FILTER_E_END_OF_CHUNKS
;
356 while( !( ( m_pAttributes
[m_ulPropertyNum
].IsPropertyPropid() ) &&
357 ( m_pAttributes
[m_ulPropertyNum
].GetPropSet() == FMTID_SummaryInformation
) )||
358 ( ( m_pAttributes
[m_ulPropertyNum
].GetPropertyPropid() != PIDSI_AUTHOR
) &&
359 ( m_pAttributes
[m_ulPropertyNum
].GetPropertyPropid() != PIDSI_TITLE
) &&
360 ( m_pAttributes
[m_ulPropertyNum
].GetPropertyPropid() != PIDSI_SUBJECT
) &&
361 ( m_pAttributes
[m_ulPropertyNum
].GetPropertyPropid() != PIDSI_KEYWORDS
) &&
362 ( m_pAttributes
[m_ulPropertyNum
].GetPropertyPropid() != PIDSI_COMMENTS
) ) )
364 if ( m_ulPropertyNum
< m_cAttributes
)
369 if ( m_ulPropertyNum
== m_cAttributes
)
370 return FILTER_E_END_OF_CHUNKS
;
373 // Set chunk description
374 pStat
->idChunk
= m_ulChunkID
;
375 pStat
->breakType
= CHUNK_EOS
;
376 pStat
->flags
= CHUNK_VALUE
;
377 pStat
->locale
= GetSystemDefaultLCID();
378 pStat
->attribute
.guidPropSet
= FMTID_SummaryInformation
;
379 pStat
->attribute
.psProperty
.ulKind
= PRSPEC_PROPID
;
380 pStat
->attribute
.psProperty
.propid
= m_pAttributes
[m_ulPropertyNum
].GetPropertyPropid();
381 pStat
->idChunkSource
= m_ulChunkID
;
382 pStat
->cwcStartSource
= 0;
383 pStat
->cwcLenSource
= 0;
384 m_ulCurrentPropertyNum
= m_ulPropertyNum
;
395 //M-------------------------------------------------------------------------
396 // Method: COooFilter::GetText (IFilter::GetText)
397 // Summary: Retrieves UNICODE text for index
398 // Arguments: pcwcBuffer
399 // [in] Pointer to size of UNICODE buffer
400 // [out] Pointer to count of UNICODE characters returned
402 // [out] Pointer to buffer to receive UNICODE text
404 // Text successfully retrieved, but text remains in chunk
405 // FILTER_E_NO_MORE_TEXT
406 // All of the text in the current chunk has been returned
407 // FILTER_S_LAST_TEXT
408 // Next call to GetText will return FILTER_E_NO_MORE_TEXT
410 SCODE STDMETHODCALLTYPE
COooFilter::GetText(ULONG
* pcwcBuffer
, WCHAR
* awcBuffer
)
414 case FilteringProperty
:
415 return FILTER_E_NO_TEXT
;
416 case FilteringContent
:
418 if ( !m_fContents
|| 0 == m_ulUnicodeBufferLen
)
421 return FILTER_E_NO_MORE_TEXT
;
423 // Copy UNICODE characters in chunk buffer to output UNICODE buffer
424 ULONG ulToCopy
= min( *pcwcBuffer
, m_ulUnicodeBufferLen
- m_ulUnicodeCharsRead
);
425 ZeroMemory(awcBuffer
, sizeof(awcBuffer
));
426 wmemcpy( awcBuffer
, m_pwsBuffer
.c_str() + m_ulUnicodeCharsRead
, ulToCopy
);
427 m_ulUnicodeCharsRead
+= ulToCopy
;
428 *pcwcBuffer
= ulToCopy
;
429 if ( m_ulUnicodeBufferLen
== m_ulUnicodeCharsRead
)
431 m_ulUnicodeCharsRead
= 0;
432 m_ulUnicodeBufferLen
= 0;
433 return FILTER_S_LAST_TEXT
;
441 //M-------------------------------------------------------------------------
442 // Method: GetMetaInfoNameFromPropertyId
443 // Summary: helper function to convert PropertyID into respective
445 // Arguments: ulPropID
447 // Returns: corresponding metainfo names.
450 ::std::wstring
GetMetaInfoNameFromPropertyId( ULONG ulPropID
)
454 case PIDSI_AUTHOR
: return META_INFO_AUTHOR
;
455 case PIDSI_TITLE
: return META_INFO_TITLE
;
456 case PIDSI_SUBJECT
: return META_INFO_SUBJECT
;
457 case PIDSI_KEYWORDS
: return META_INFO_KEYWORDS
;
458 case PIDSI_COMMENTS
: return META_INFO_DESCRIPTION
;
459 default: return EMPTY_STRING
;
462 //M-------------------------------------------------------------------------
463 // Method: COooFilter::GetValue (IFilter::GetValue)
464 // Summary: Retrieves properites for index
465 // Arguments: ppPropValue
466 // [out] Address that receives pointer to property value
467 // Returns: FILTER_E_NO_VALUES
469 // FILTER_E_NO_MORE_VALUES
473 SCODE STDMETHODCALLTYPE
COooFilter::GetValue(PROPVARIANT
** ppPropValue
)
475 if (m_eState
== FilteringContent
)
476 return FILTER_E_NO_VALUES
;
477 else if (m_eState
== FilteringProperty
)
479 if ( m_cAttributes
== 0 || ( m_ulCurrentPropertyNum
== m_ulPropertyNum
) )
480 return FILTER_E_NO_MORE_VALUES
;
481 PROPVARIANT
*pPropVar
= (PROPVARIANT
*) CoTaskMemAlloc( sizeof (PROPVARIANT
) );
483 return E_OUTOFMEMORY
;
484 ::std::wstring wsTagName
= GetMetaInfoNameFromPropertyId( m_pAttributes
[m_ulCurrentPropertyNum
].GetPropertyPropid() );
485 if ( wsTagName
== EMPTY_STRING
)
486 return FILTER_E_NO_VALUES
;
487 ::std::wstring wsTagData
= m_pMetaInfoReader
->getTagData(wsTagName
);
488 pPropVar
->vt
= VT_LPWSTR
;
489 size_t cw
= wsTagData
.length() + 1; // reserve one for the '\0'
490 pPropVar
->pwszVal
= static_cast<WCHAR
*>( CoTaskMemAlloc(cw
*sizeof(WCHAR
)) );
491 if (pPropVar
->pwszVal
== 0)
493 CoTaskMemFree(pPropVar
);
494 return E_OUTOFMEMORY
;
496 wmemcpy(pPropVar
->pwszVal
, wsTagData
.c_str(), cw
);
497 *ppPropValue
= pPropVar
;
498 m_ulCurrentPropertyNum
= m_ulPropertyNum
;
504 //M-------------------------------------------------------------------------
505 // Method: COooFilter::BindRegion (IFilter::BindRegion)
506 // Summary: Creates moniker or other interface for indicated text
507 // Arguments: origPos
508 // [in] Description of text location and extent
510 // [in] Reference IID of specified interface
512 // [out] Address that receives requested interface pointer
513 // Returns: E_NOTIMPL
515 // FILTER_W_REGION_CLIPPED
519 SCODE STDMETHODCALLTYPE
COooFilter::BindRegion(
520 FILTERREGION
/*origPos*/,
524 // BindRegion is currently reserved for future use
527 //M-------------------------------------------------------------------------
528 // Method: COooFilter::GetClassID (IPersist::GetClassID)
529 // Summary: Retrieves the class id of the filter class
530 // Arguments: pClassID
531 // [out] Pointer to the class ID of the filter
537 SCODE STDMETHODCALLTYPE
COooFilter::GetClassID(CLSID
* pClassID
)
539 *pClassID
= CLSID_COooFilter
;
542 //M-------------------------------------------------------------------------
543 // Method: COooFilter::IsDirty (IPersistFile::IsDirty)
544 // Summary: Checks whether file has changed since last save
551 SCODE STDMETHODCALLTYPE
COooFilter::IsDirty()
553 // File is opened read-only and never changes
556 //M-------------------------------------------------------------------------
557 // Method: COooFilter::Load (IPersistFile::Load)
558 // Summary: Opens and initializes the specified file
559 // Arguments: pszFileName
560 // [in] Pointer to zero-terminated string
561 // of absolute path of file to open
563 // [in] Access mode to open the file
565 // File was successfully loaded
567 // File could not be loaded due to insufficient memory
571 SCODE STDMETHODCALLTYPE
COooFilter::Load(LPCWSTR pszFileName
, DWORD
/*dwMode*/)
573 // Load just sets the filename for GetChunk to read and ignores the mode
574 m_pwszFileName
= getShortPathName( pszFileName
);
576 // Open the file previously specified in call to IPersistFile::Load and get content.
579 if (m_pMetaInfoReader
)
580 delete m_pMetaInfoReader
;
581 m_pMetaInfoReader
= new CMetaInfoReader(WStringToString(m_pwszFileName
));
583 if (m_pContentReader
)
584 delete m_pContentReader
;
585 m_pContentReader
= new CContentReader(WStringToString(m_pwszFileName
), m_pMetaInfoReader
->getDefaultLocale());
587 catch (const std::exception
&)
593 //M-------------------------------------------------------------------------
594 // Method: COooFilter::Save (IPersistFile::Save)
595 // Summary: Saves a copy of the current file being filtered
596 // Arguments: pszFileName
597 // [in] Pointer to zero-terminated string of
598 // absolute path of where to save file
600 // [in] Whether the saved copy is made the current file
606 SCODE STDMETHODCALLTYPE
COooFilter::Save(LPCWSTR
/*pszFileName*/, BOOL
/*fRemember*/)
608 // File is opened read-only; saving it is an error
611 //M-------------------------------------------------------------------------
612 // Method: COooFilter::SaveCompleted (IPersistFile::SaveCompleted)
613 // Summary: Determines whether a file save is completed
614 // Arguments: pszFileName
615 // [in] Pointer to zero-terminated string of
616 // absolute path where file was previously saved
620 SCODE STDMETHODCALLTYPE
COooFilter::SaveCompleted(LPCWSTR
/*pszFileName*/)
622 // File is opened read-only, so "save" is always finished
626 //M-------------------------------------------------------------------------
627 // Method: COooFilter::Load (IPersistStream::Load)
628 // Summary: Initializes an object from the stream where it was previously saved
630 // [in] Pointer to stream from which object should be loaded
635 SCODE STDMETHODCALLTYPE
COooFilter::Load(IStream
*pStm
)
637 m_pStream
= new BufferStream(pStm
);
640 if (m_pMetaInfoReader
)
641 delete m_pMetaInfoReader
;
642 m_pMetaInfoReader
= new CMetaInfoReader(m_pStream
);
644 if (m_pContentReader
)
645 delete m_pContentReader
;
646 m_pContentReader
= new CContentReader(m_pStream
, m_pMetaInfoReader
->getDefaultLocale());
648 catch (const std::exception
&)
655 //M-------------------------------------------------------------------------
656 // Method: COooFilter::GetSizeMax (IPersistStream::GetSizeMax)
657 // Summary: Returns the size in bytes of the stream neede to save the object.
658 // Arguments: pcbSize
659 // [out] Pointer to a 64 bit unsigned int indicating the size needed
660 // Returns: E_NOTIMPL
662 SCODE STDMETHODCALLTYPE
COooFilter::GetSizeMax(ULARGE_INTEGER
* /*pcbSize*/)
667 //M-------------------------------------------------------------------------
668 // Method: COooFilter::Save (IPersistStream::Save)
669 // Summary: Save object to specified stream
671 // [in] Pointer to stream
673 // [in] Indicates whether to clear dirty flag
674 // Returns: E_NOTIMPL
676 SCODE STDMETHODCALLTYPE
COooFilter::Save(IStream
* /*pStm*/, BOOL
)
681 //M-------------------------------------------------------------------------
682 // Method: COooFilter::GetCurFile (IPersistFile::GetCurFile)
683 // Summary: Returns a copy of the current file name
684 // Arguments: ppszFileName
685 // [out] Address to receive pointer to zero-terminated
686 // string for absolute path to current file
688 // A valid absolute path was successfully returned
692 // Operation failed due to insufficient memory
694 // Operation failed due to some reason
695 // other than insufficient memory
697 SCODE STDMETHODCALLTYPE
COooFilter::GetCurFile(LPWSTR
* ppszFileName
)
699 if ( EMPTY_STRING
== m_pwszFileName
)
702 *ppszFileName
= (LPWSTR
)m_pwszFileName
.c_str();
706 //M-------------------------------------------------------------------------
707 // Method: COooFilterCF::COooFilterCF
708 // Summary: Class factory constructor
710 // Purpose: Manages global instance count
712 COooFilterCF::COooFilterCF() :
715 InterlockedIncrement( &g_lInstances
);
717 //M-------------------------------------------------------------------------
718 // Method: COooFilterCF::~COooFilterCF
719 // Summary: Class factory destructor
721 // Purpose: Manages global instance count
723 COooFilterCF::~COooFilterCF()
725 InterlockedDecrement( &g_lInstances
);
727 //M-------------------------------------------------------------------------
728 // Method: COooFilterCF::QueryInterface (IUnknown::QueryInterface)
729 // Summary: Queries for requested interface
731 // [in] Reference IID of requested interface
733 // [out] Address that receives requested interface pointer
735 // Interface is supported
737 // Interface is not supported
739 SCODE STDMETHODCALLTYPE
COooFilterCF::QueryInterface(REFIID riid
, void ** ppvObject
)
743 if ( IID_IClassFactory
== riid
)
744 pUnkTemp
= (IUnknown
*)(IClassFactory
*)this;
745 else if ( IID_IUnknown
== riid
)
746 pUnkTemp
= (IUnknown
*)this;
750 return E_NOINTERFACE
;
752 *ppvObject
= (void *)pUnkTemp
;
756 //M-------------------------------------------------------------------------
757 // Method: COooFilterCF::AddRef (IUknown::AddRef)
758 // Summary: Increments interface refcount
760 // Returns: Value of incremented interface refcount
762 ULONG STDMETHODCALLTYPE
COooFilterCF::AddRef()
764 return InterlockedIncrement( &m_lRefs
);
766 //M-------------------------------------------------------------------------
767 // Method: COooFilterCF::Release (IUnknown::Release)
768 // Summary: Decrements interface refcount, deleting if unreferenced
770 // Returns: Value of decremented refcount
772 ULONG STDMETHODCALLTYPE
COooFilterCF::Release()
774 ULONG ulTmp
= InterlockedDecrement( &m_lRefs
);
780 //M-------------------------------------------------------------------------
781 // Method: COooFilterCF::CreateInstance (IClassFactory::CreateInstance)
782 // Summary: Creates new LibreOffice filter object
783 // Arguments: pUnkOuter
784 // [in] Pointer to IUnknown interface of aggregating object
786 // [in] Reference IID of requested interface
788 // [out] Address that receives requested interface pointer
790 // LibreOffice filter object was successfully created
791 // CLASS_E_NOAGGREGATION
792 // pUnkOuter parameter was non-NULL
796 // LibreOffice filter object could not be created
797 // due to insufficient memory
799 // Unsuccessful due to an unexpected condition
801 SCODE STDMETHODCALLTYPE
COooFilterCF::CreateInstance(
802 IUnknown
* pUnkOuter
,
806 COooFilter
*pIUnk
= 0;
807 if ( 0 != pUnkOuter
)
808 return CLASS_E_NOAGGREGATION
;
809 pIUnk
= new COooFilter();
810 if ( SUCCEEDED( pIUnk
->QueryInterface( riid
, ppvObject
) ) )
812 // Release extra refcount from QueryInterface
823 //M-------------------------------------------------------------------------
824 // Method: COooFilterCF::LockServer (IClassFactory::LockServer)
825 // Summary: Forces/allows filter class to remain loaded/be unloaded
827 // [in] TRUE to lock, FALSE to unlock
837 SCODE STDMETHODCALLTYPE
COooFilterCF::LockServer(BOOL fLock
)
840 InterlockedIncrement( &g_lInstances
);
842 InterlockedDecrement( &g_lInstances
);
845 //+-------------------------------------------------------------------------
847 // Summary: Implements Dynamic Link Library functions for LibreOffice filter
849 //F-------------------------------------------------------------------------
851 // Summary: Called from C-Runtime on process/thread attach/detach
852 // Arguments: hInstance
853 // [in] Handle to the DLL
855 // [in] Reason for calling DLL entry point
857 // [in] Details of DLL initialization and cleanup
861 extern "C" BOOL WINAPI
DllMain(
864 LPVOID
/*lpvReserved*/
867 if ( DLL_PROCESS_ATTACH
== fdwReason
)
868 DisableThreadLibraryCalls( hInstance
);
871 //F-------------------------------------------------------------------------
872 // Function: DllGetClassObject
873 // Summary: Create LibreOffice filter class factory object
875 // [in] Class ID of class that class factory creates
877 // [in] Reference IID of requested class factory interface
879 // [out] Address that receives requested interface pointer
881 // Class factory object was created successfully
882 // CLASS_E_CLASSNOTAVAILABLE
883 // DLL does not support the requested class
887 // Insufficient memory to create the class factory object
889 // Unsuccessful due to an unexpected condition
891 extern "C" SCODE STDMETHODCALLTYPE
DllGetClassObject(
897 COooFilterCF
* pImpl
= 0;
898 IUnknown
*pResult
= 0;
900 if ( CLSID_COooFilter
== cid
)
902 pImpl
= new COooFilterCF
;
903 pResult
= (IUnknown
*) pImpl
;
906 return CLASS_E_CLASSNOTAVAILABLE
;
907 if( SUCCEEDED( pResult
->QueryInterface( iid
, ppvObj
) ) )
908 // Release extra refcount from QueryInterface
917 //F-------------------------------------------------------------------------
918 // Function: DllCanUnloadNow
919 // Summary: Indicates whether it is possible to unload DLL
922 // DLL can be unloaded now
924 // DLL must remain loaded
926 extern "C" SCODE STDMETHODCALLTYPE
DllCanUnloadNow()
928 if ( 0 >= g_lInstances
)
933 //F-------------------------------------------------------------------------
934 // Function: DllRegisterServer
935 // DllUnregisterServer
936 // Summary: Registers and unregisters DLL server
937 // Returns: DllRegisterServer
939 // Registration was successful
941 // Registration was unsuccessful
948 // DllUnregisterServer
950 // Unregistration was successful
952 // Unregistration was successful, but other
953 // entries still exist for the DLL's classes
965 //F-------------------------------------------------------------------------
966 // helper functions to register the Indexing Service.
969 namespace /* private */
971 const char* GUID_PLACEHOLDER
= "{GUID}";
972 const char* GUID_PERSIST_PLACEHOLDER
= "{GUIDPERSIST}";
973 const char* EXTENSION_PLACEHOLDER
= "{EXT}";
975 const char* CLSID_GUID_INPROC_ENTRY
= "CLSID\\{GUID}\\InProcServer32";
976 const char* CLSID_GUID_ENTRY
= "CLSID\\{GUID}";
977 const char* CLSID_GUID_PERSIST_ADDIN_ENTRY
= "CLSID\\{GUID}\\PersistentAddinsRegistered\\{GUIDPERSIST}";
978 const char* CLSID_PERSIST_ENTRY
= "CLSID\\{GUID}\\PersistentHandler";
979 const char* EXT_PERSIST_ENTRY
= "{EXT}\\PersistentHandler";
981 const char* INDEXING_FILTER_DLLSTOREGISTER
= "SYSTEM\\CurrentControlSet\\Control\\ContentIndex";
984 // "String Placeholder" ->
985 // "String Replacement"
988 void SubstitutePlaceholder(std::string
& String
, const std::string
& Placeholder
, const std::string
& Replacement
)
990 std::string::size_type idx
= String
.find(Placeholder
);
991 std::string::size_type len
= Placeholder
.length();
993 while (std::string::npos
!= idx
)
995 String
.replace(idx
, len
, Replacement
);
996 idx
= String
.find(Placeholder
);
1001 // Make the registry entry and set Filter Handler
1002 // HKCR\CLSID\{7BC0E710-5703-45be-A29D-5D46D8B39262} = LibreOffice Filter
1003 // InProcServer32 (Default) = Path\ooofilt.dll
1004 // ThreadingModel = Both
1007 HRESULT
RegisterFilterHandler(const char* FilePath
, const CLSID
& FilterGuid
)
1009 std::string ClsidEntry
= CLSID_GUID_ENTRY
;
1010 SubstitutePlaceholder(ClsidEntry
, GUID_PLACEHOLDER
, ClsidToString(FilterGuid
));
1012 if (!SetRegistryKey(HKEY_CLASSES_ROOT
, ClsidEntry
.c_str(), "", "LibreOffice Filter"))
1015 ClsidEntry
= CLSID_GUID_INPROC_ENTRY
;
1016 SubstitutePlaceholder(ClsidEntry
, GUID_PLACEHOLDER
, ClsidToString(FilterGuid
));
1018 if (!SetRegistryKey(HKEY_CLASSES_ROOT
, ClsidEntry
.c_str(), "", FilePath
))
1021 if (!SetRegistryKey(HKEY_CLASSES_ROOT
, ClsidEntry
.c_str(), "ThreadingModel", "Both"))
1028 // Make the registry entry and set Persistent Handler
1029 // HKCR\CLSID\{7BC0E713-5703-45be-A29D-5D46D8B39262} = LibreOffice Persistent Handler
1030 // PersistentAddinsRegistered
1031 // {89BCB740-6119-101A-BCB7-00DD010655AF} = {7BC0E710-5703-45be-A29D-5D46D8B39262}
1034 HRESULT
RegisterPersistentHandler(const CLSID
& FilterGuid
, const CLSID
& PersistentGuid
)
1036 std::string ClsidEntry_Persist
= CLSID_GUID_ENTRY
;
1037 SubstitutePlaceholder(ClsidEntry_Persist
, GUID_PLACEHOLDER
, ClsidToString(PersistentGuid
));
1040 if (!SetRegistryKey(HKEY_CLASSES_ROOT
, ClsidEntry_Persist
.c_str(), "", "LibreOffice Persistent Handler"))
1043 // Add missing entry
1044 std::string ClsidEntry_Persist_Entry
= CLSID_PERSIST_ENTRY
;
1045 SubstitutePlaceholder(ClsidEntry_Persist_Entry
,
1047 ClsidToString(PersistentGuid
));
1049 if (!SetRegistryKey(HKEY_CLASSES_ROOT
, ClsidEntry_Persist_Entry
.c_str(), "", ClsidToString(PersistentGuid
).c_str()))
1052 std::string ClsidEntry_Persist_Addin
= CLSID_GUID_PERSIST_ADDIN_ENTRY
;
1053 SubstitutePlaceholder(ClsidEntry_Persist_Addin
,
1055 ClsidToString(PersistentGuid
));
1056 SubstitutePlaceholder(ClsidEntry_Persist_Addin
,
1057 GUID_PERSIST_PLACEHOLDER
,
1058 ClsidToString(CLSID_PERSISTENT_HANDLER_ADDIN
));
1060 if (!SetRegistryKey(HKEY_CLASSES_ROOT
, ClsidEntry_Persist_Addin
.c_str(), "", ClsidToString(FilterGuid
).c_str() ))
1067 // Unregister Filter Handler or persistent handler
1070 HRESULT
UnregisterHandler(const CLSID
& Guid
)
1072 std::string tmp
= "CLSID\\";
1073 tmp
+= ClsidToString(Guid
);
1074 return DeleteRegistryKey(HKEY_CLASSES_ROOT
, tmp
.c_str()) ? S_OK
: E_FAIL
;
1078 // Register Indexing Service ext and class.
1079 // HKCR\{EXT}\PersistentHandler = {7BC0E713-5703-45be-A29D-5D46D8B39262}
1080 // HKCR\{GUID\PersistentHandler = {7BC0E713-5703-45be-A29D-5D46D8B39262}
1083 HRESULT
RegisterSearchHandler(const char* ModuleFileName
)
1085 if (FAILED(RegisterFilterHandler(ModuleFileName
, CLSID_FILTER_HANDLER
)))
1088 if (FAILED(RegisterPersistentHandler(CLSID_FILTER_HANDLER
, CLSID_PERSISTENT_HANDLER
)))
1091 std::string sExtPersistEntry
;
1093 for(size_t i
= 0; i
< OOFileExtensionTableSize
; i
++)
1095 // first, register extension.
1096 sExtPersistEntry
= EXT_PERSIST_ENTRY
;
1097 SubstitutePlaceholder(sExtPersistEntry
, EXTENSION_PLACEHOLDER
, OOFileExtensionTable
[i
].ExtensionAnsi
);
1098 if (!SetRegistryKey(HKEY_CLASSES_ROOT
,
1099 sExtPersistEntry
.c_str(),
1101 ClsidToString(CLSID_PERSISTENT_HANDLER
).c_str()))
1104 // second, register class.
1105 char extClassName
[MAX_PATH
];
1106 if (QueryRegistryKey(HKEY_CLASSES_ROOT
, OOFileExtensionTable
[i
].ExtensionAnsi
, "", extClassName
,MAX_PATH
))
1108 ::std::string
extCLSIDName( extClassName
);
1109 extCLSIDName
+= "\\CLSID";
1110 char extCLSID
[MAX_PATH
];
1112 if (QueryRegistryKey( HKEY_CLASSES_ROOT
, extCLSIDName
.c_str(), "", extCLSID
, MAX_PATH
))
1114 std::string ClsidEntry_CLSID_Persist
= CLSID_PERSIST_ENTRY
;
1115 SubstitutePlaceholder(ClsidEntry_CLSID_Persist
,
1119 if (!SetRegistryKey(HKEY_CLASSES_ROOT
,
1120 ClsidEntry_CLSID_Persist
.c_str(),
1122 ClsidToString(CLSID_PERSISTENT_HANDLER
).c_str() ))
1131 // Register Indexing Service ext and class.
1132 HRESULT
UnregisterSearchHandler()
1134 std::string sExtPersistEntry
;
1136 for (size_t i
= 0; i
< OOFileExtensionTableSize
; i
++)
1138 // first, unregister extension
1139 sExtPersistEntry
= EXT_PERSIST_ENTRY
;
1140 SubstitutePlaceholder(sExtPersistEntry
, EXTENSION_PLACEHOLDER
, OOFileExtensionTable
[i
].ExtensionAnsi
);
1141 DeleteRegistryKey(HKEY_CLASSES_ROOT
, sExtPersistEntry
.c_str());
1143 // second, unregister class
1144 char extClassName
[MAX_PATH
];
1145 if (QueryRegistryKey(HKEY_CLASSES_ROOT
, OOFileExtensionTable
[i
].ExtensionAnsi
, "", extClassName
,MAX_PATH
))
1147 ::std::string
extCLSIDName( extClassName
);
1148 extCLSIDName
+= "\\CLSID";
1149 char extCLSID
[MAX_PATH
];
1151 if (QueryRegistryKey( HKEY_CLASSES_ROOT
, extCLSIDName
.c_str(), "", extCLSID
, MAX_PATH
))
1153 std::string ClsidEntry_CLSID_Persist
= CLSID_PERSIST_ENTRY
;
1154 SubstitutePlaceholder(ClsidEntry_CLSID_Persist
,
1158 DeleteRegistryKey(HKEY_CLASSES_ROOT
, ClsidEntry_CLSID_Persist
.c_str());
1163 return ((UnregisterHandler(CLSID_FILTER_HANDLER
)==S_OK
) && (UnregisterHandler(CLSID_PERSISTENT_HANDLER
)==S_OK
))?S_OK
:E_FAIL
;
1167 // add or remove an entry to DllsToRegister entry of Indexing
1168 // Filter to let Indexing Service register our filter automatically
1171 HRESULT
AddOrRemoveDllsToRegisterList( const ::std::string
& DllPath
, bool isAdd
)
1173 char DllsToRegisterList
[4096];
1174 if (QueryRegistryKey(HKEY_LOCAL_MACHINE
,
1175 INDEXING_FILTER_DLLSTOREGISTER
,
1180 char * pChar
= DllsToRegisterList
;
1181 for ( ; *pChar
!= '\0' || *(pChar
+1) != '\0'; pChar
++)
1182 if ( *pChar
== '\0')
1187 ::std::string
DllList(DllsToRegisterList
);
1188 if ( ( isAdd
)&&( DllList
.find( DllPath
) == ::std::string::npos
) )
1189 DllList
.append( DllPath
);
1190 else if ( ( !isAdd
)&&( DllList
.find( DllPath
) != ::std::string::npos
) )
1191 DllList
.erase( DllList
.find( DllPath
)-1, DllPath
.length()+1 );
1195 pChar
= DllsToRegisterList
;
1196 for ( size_t nChar
= 0; nChar
< DllList
.length(); pChar
++,nChar
++)
1198 if ( DllList
[nChar
] == ';')
1201 *pChar
= DllList
[nChar
];
1203 *pChar
= *( pChar
+1 ) ='\0';
1207 int rc
= RegCreateKeyExA(HKEY_LOCAL_MACHINE
,
1208 INDEXING_FILTER_DLLSTOREGISTER
,
1211 REG_OPTION_NON_VOLATILE
,
1217 if (ERROR_SUCCESS
== rc
)
1219 rc
= RegSetValueExA( hSubKey
,
1223 reinterpret_cast<const BYTE
*>(DllsToRegisterList
),
1224 static_cast<DWORD
>(DllList
.length() + 2));
1226 RegCloseKey(hSubKey
);
1229 return (ERROR_SUCCESS
== rc
)?S_OK
:E_FAIL
;
1235 } // namespace /* private */
1237 STDAPI
DllRegisterServer()
1244 STDAPI
DllUnregisterServer()
1249 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */