Bump version to 5.0-14
[LibreOffice.git] / shell / source / win32 / shlxthandler / ooofilt / ooofilt.cxx
blobfbc38528430c714425091321d6320c327943e898
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
22 // File: ooofilt.cxx
23 // Contents: Filter Implementation for OpenOffice.Org Document using
24 // Indexing Service
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
28 // to be filtered.
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
49 #if defined _MSC_VER
50 #pragma warning(push, 1)
51 #endif
52 #include <windows.h>
53 #if defined _MSC_VER
54 #pragma warning(pop)
55 #endif
56 #include <string.h>
57 #include <filter.h>
58 #include <filterr.h>
59 #include <ntquery.h>
60 #include "assert.h"
61 #include "ooofilt.hxx"
62 #include <objidl.h>
63 #include <stdio.h>
64 #include "propspec.hxx"
65 #ifdef __MINGW32__
66 #include <algorithm>
67 using ::std::min;
68 #endif
70 #include "internal/stream_helper.hxx"
72 //C-------------------------------------------------------------------------
73 // Class: COooFilter
74 // Summary: Implements LibreOffice filter class
76 //M-------------------------------------------------------------------------
77 // Method: COooFilter::COooFilter
78 // Summary: Class constructor
79 // Arguments: void
80 // Purpose: Manages global instance count
82 COooFilter::COooFilter() :
83 m_lRefs(1),
84 m_pContentReader(NULL),
85 m_pMetaInfoReader(NULL),
86 m_eState(FilteringContent),
87 m_ulUnicodeBufferLen(0),
88 m_ulUnicodeCharsRead(0),
89 m_ulPropertyNum(0),
90 m_ulCurrentPropertyNum(0),
91 m_ulChunkID(1),
92 m_fContents(FALSE),
93 m_fEof(FALSE),
94 m_ChunkPosition(0),
95 m_cAttributes(0),
96 m_pAttributes(0),
97 m_pStream(NULL)
100 InterlockedIncrement( &g_lInstances );
102 //M-------------------------------------------------------------------------
103 // Method: COooFilter::~COooFilter
104 // Summary: Class destructor
105 // Arguments: void
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;
116 if (m_pStream)
117 delete m_pStream;
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
126 // ppvObject
127 // [out] Address that receives requested interface pointer
128 // Returns: S_OK
129 // Interface is supported
130 // E_NOINTERFACE
131 // Interface is not supported
133 SCODE STDMETHODCALLTYPE COooFilter::QueryInterface(
134 REFIID riid,
135 void ** ppvObject)
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;
148 else
150 *ppvObject = NULL;
151 return E_NOINTERFACE;
153 *ppvObject = (void *)pUnkTemp;
154 pUnkTemp->AddRef();
155 return S_OK;
157 //M-------------------------------------------------------------------------
158 // Method: COooFilter::AddRef (IUnknown::AddRef)
159 // Summary: Increments interface refcount
160 // Arguments: void
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
170 // Arguments: void
171 // Returns: Value of decremented interface refcount
173 ULONG STDMETHODCALLTYPE COooFilter::Release()
175 ULONG ulTmp = InterlockedDecrement( &m_lRefs );
177 if ( 0 == ulTmp )
178 delete this;
179 return ulTmp;
181 //M-------------------------------------------------------------------------
182 // Method: COooFilter::Init (IFilter::Init)
183 // Summary: Initializes LibreOffice filter instance
184 // Arguments: grfFlags
185 // [in] Flags for filter behavior
186 // cAttributes
187 // [in] Number attributes in array aAttributes
188 // aAttributes
189 // [in] Array of requested attribute strings
190 // pFlags
191 // [out] Pointer to return flags for additional properties
192 // Returns: S_OK
193 // Initialization succeeded
194 // E_FAIL
195 // File not previously loaded
196 // E_INVALIDARG
197 // Count and contents of attributes do not agree
198 // FILTER_E_ACCESS
199 // Unable to access file to be filtered
200 // FILTER_E_PASSWORD
201 // (not implemented)
203 const int COUNT_ATTRIBUTES = 5;
205 SCODE STDMETHODCALLTYPE COooFilter::Init(
206 ULONG grfFlags,
207 ULONG cAttributes,
208 FULLPROPSPEC const * aAttributes,
209 ULONG * pFlags)
211 // Enumerate OLE properties, since any NTFS file can have them
212 *pFlags = IFILTER_FLAGS_OLE_PROPERTIES;
215 m_fContents = FALSE;
216 m_ulPropertyNum = 0;
217 m_ulCurrentPropertyNum = 0;
218 if ( m_cAttributes > 0 )
220 delete[] m_pAttributes;
221 m_pAttributes = 0;
222 m_cAttributes = 0;
224 if( 0 < cAttributes )
226 // Filter properties specified in aAttributes
227 if ( 0 == aAttributes )
228 return E_INVALIDARG;
229 m_pAttributes = new CFullPropSpec[cAttributes];
230 m_cAttributes = cAttributes;
231 // Is caller want to filter contents?
232 CFullPropSpec *pAttrib = (CFullPropSpec *) aAttributes;
233 ULONG ulNumAttr;
234 for ( ulNumAttr = 0 ; ulNumAttr < cAttributes; ulNumAttr++ )
236 if ( pAttrib[ulNumAttr].IsPropertyPropid() &&
237 pAttrib[ulNumAttr].GetPropertyPropid() == PID_STG_CONTENTS &&
238 pAttrib[ulNumAttr].GetPropSet() == guidStorage )
240 m_fContents = TRUE;
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
249 m_fContents = TRUE;
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
267 m_fContents = TRUE;
269 else
270 m_fContents = FALSE;
271 // Re-initialize
272 if ( m_fContents )
274 m_fEof = FALSE;
275 m_eState = FilteringContent;
276 m_ulUnicodeCharsRead = 0;
277 m_ChunkPosition = 0;
279 else
281 m_fEof = TRUE;
282 m_eState = FilteringProperty;
284 m_ulChunkID = 1;
286 catch (const std::exception&)
288 return E_FAIL;
291 return S_OK;
293 //M-------------------------------------------------------------------------
294 // Method: COooFilter::GetChunk (IFilter::GetChunk)
295 // Summary: Gets the next chunk
296 // Arguments: ppStat
297 // [out] Pointer to description of current chunk
298 // Returns: S_OK
299 // Chunk was successfully retrieved
300 // E_FAIL
301 // Character conversion failed
302 // FILTER_E_ACCESS
303 // General access failure occurred
304 // FILTER_E_END_OF_CHUNKS
305 // Previous chunk was the last chunk
306 // FILTER_E_EMBEDDING_UNAVAILABLE
307 // (not implemented)
308 // FILTER_E_LINK_UNAVAILABLE
309 // (not implemented)
310 // FILTER_E_PASSWORD
311 // (not implemented)
313 SCODE STDMETHODCALLTYPE COooFilter::GetChunk(STAT_CHUNK * pStat)
315 for(;;)
317 switch ( m_eState )
319 case FilteringContent:
321 // Read Unicodes from buffer.
322 if( m_ChunkPosition == m_pContentReader ->getChunkBuffer().size() )
324 m_ulUnicodeBufferLen=0;
325 m_fEof = TRUE;
328 if ( !m_fContents || m_fEof )
330 m_eState = FilteringProperty;
331 continue;
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;
348 m_ulChunkID++;
349 m_ChunkPosition++;
350 return S_OK;
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 )
365 m_ulPropertyNum++;
366 else
367 break;
369 if ( m_ulPropertyNum == m_cAttributes)
370 return FILTER_E_END_OF_CHUNKS;
371 else
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;
385 m_ulPropertyNum++;
386 m_ulChunkID++;
387 return S_OK;
390 default:
391 return E_FAIL;
392 }//switch(...)
393 }//for(;;)
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
401 // awcBuffer
402 // [out] Pointer to buffer to receive UNICODE text
403 // Returns: S_OK
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)
412 switch ( m_eState )
414 case FilteringProperty:
415 return FILTER_E_NO_TEXT;
416 case FilteringContent:
418 if ( !m_fContents || 0 == m_ulUnicodeBufferLen )
420 *pcwcBuffer = 0;
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;
435 return S_OK;
437 default:
438 return E_FAIL;
441 //M-------------------------------------------------------------------------
442 // Method: GetMetaInfoNameFromPropertyId
443 // Summary: helper function to convert PropertyID into respective
444 // MetaInfo names.
445 // Arguments: ulPropID
446 // [in] property ID
447 // Returns: corresponding metainfo names.
450 ::std::wstring GetMetaInfoNameFromPropertyId( ULONG ulPropID )
452 switch ( 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
468 // Always
469 // FILTER_E_NO_MORE_VALUES
470 // (not implemented)
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) );
482 if ( pPropVar == 0 )
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;
499 return S_OK;
501 else
502 return E_FAIL;
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
509 // riid
510 // [in] Reference IID of specified interface
511 // ppunk
512 // [out] Address that receives requested interface pointer
513 // Returns: E_NOTIMPL
514 // Always
515 // FILTER_W_REGION_CLIPPED
516 // (not implemented)
519 SCODE STDMETHODCALLTYPE COooFilter::BindRegion(
520 FILTERREGION /*origPos*/,
521 REFIID /*riid*/,
522 void ** /*ppunk*/)
524 // BindRegion is currently reserved for future use
525 return E_NOTIMPL;
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
532 // Returns: S_OK
533 // Always
534 // E_FAIL
535 // (not implemented)
537 SCODE STDMETHODCALLTYPE COooFilter::GetClassID(CLSID * pClassID)
539 *pClassID = CLSID_COooFilter;
540 return S_OK;
542 //M-------------------------------------------------------------------------
543 // Method: COooFilter::IsDirty (IPersistFile::IsDirty)
544 // Summary: Checks whether file has changed since last save
545 // Arguments: void
546 // Returns: S_FALSE
547 // Always
548 // S_OK
549 // (not implemented)
551 SCODE STDMETHODCALLTYPE COooFilter::IsDirty()
553 // File is opened read-only and never changes
554 return S_FALSE;
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
562 // dwMode
563 // [in] Access mode to open the file
564 // Returns: S_OK
565 // File was successfully loaded
566 // E_OUTOFMEMORY
567 // File could not be loaded due to insufficient memory
568 // E_FAIL
569 // (not implemented)
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&)
589 return E_FAIL;
591 return S_OK;
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
599 // fRemember
600 // [in] Whether the saved copy is made the current file
601 // Returns: E_FAIL
602 // Always
603 // S_OK
604 // (not implemented)
606 SCODE STDMETHODCALLTYPE COooFilter::Save(LPCWSTR /*pszFileName*/, BOOL /*fRemember*/)
608 // File is opened read-only; saving it is an error
609 return E_FAIL;
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
617 // Returns: S_OK
618 // Always
620 SCODE STDMETHODCALLTYPE COooFilter::SaveCompleted(LPCWSTR /*pszFileName*/)
622 // File is opened read-only, so "save" is always finished
623 return S_OK;
626 //M-------------------------------------------------------------------------
627 // Method: COooFilter::Load (IPersistStream::Load)
628 // Summary: Initializes an object from the stream where it was previously saved
629 // Arguments: pStm
630 // [in] Pointer to stream from which object should be loaded
631 // Returns: S_OK
632 // E_OUTOFMEMORY
633 // E_FAIL
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&)
650 return E_FAIL;
652 return S_OK;
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*/)
664 return E_NOTIMPL;
667 //M-------------------------------------------------------------------------
668 // Method: COooFilter::Save (IPersistStream::Save)
669 // Summary: Save object to specified stream
670 // Arguments: pStm
671 // [in] Pointer to stream
672 // fClearDirty
673 // [in] Indicates whether to clear dirty flag
674 // Returns: E_NOTIMPL
676 SCODE STDMETHODCALLTYPE COooFilter::Save(IStream * /*pStm*/, BOOL )
678 return E_NOTIMPL;
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
687 // Returns: S_OK
688 // A valid absolute path was successfully returned
689 // S_FALSE
690 // (not implemented)
691 // E_OUTOFMEMORY
692 // Operation failed due to insufficient memory
693 // E_FAIL
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 )
700 return E_FAIL;
701 else
702 *ppszFileName = (LPWSTR)m_pwszFileName.c_str();
703 return S_OK;
706 //M-------------------------------------------------------------------------
707 // Method: COooFilterCF::COooFilterCF
708 // Summary: Class factory constructor
709 // Arguments: void
710 // Purpose: Manages global instance count
712 COooFilterCF::COooFilterCF() :
713 m_lRefs(1)
715 InterlockedIncrement( &g_lInstances );
717 //M-------------------------------------------------------------------------
718 // Method: COooFilterCF::~COooFilterCF
719 // Summary: Class factory destructor
720 // Arguments: void
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
730 // Arguments: riid
731 // [in] Reference IID of requested interface
732 // ppvObject
733 // [out] Address that receives requested interface pointer
734 // Returns: S_OK
735 // Interface is supported
736 // E_NOINTERFACE
737 // Interface is not supported
739 SCODE STDMETHODCALLTYPE COooFilterCF::QueryInterface(REFIID riid, void ** ppvObject)
741 IUnknown *pUnkTemp;
743 if ( IID_IClassFactory == riid )
744 pUnkTemp = (IUnknown *)(IClassFactory *)this;
745 else if ( IID_IUnknown == riid )
746 pUnkTemp = (IUnknown *)this;
747 else
749 *ppvObject = NULL;
750 return E_NOINTERFACE;
752 *ppvObject = (void *)pUnkTemp;
753 pUnkTemp->AddRef();
754 return S_OK;
756 //M-------------------------------------------------------------------------
757 // Method: COooFilterCF::AddRef (IUknown::AddRef)
758 // Summary: Increments interface refcount
759 // Arguments: void
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
769 // Arguments: void
770 // Returns: Value of decremented refcount
772 ULONG STDMETHODCALLTYPE COooFilterCF::Release()
774 ULONG ulTmp = InterlockedDecrement( &m_lRefs );
776 if ( 0 == ulTmp )
777 delete this;
778 return ulTmp;
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
785 // riid
786 // [in] Reference IID of requested interface
787 // ppvObject
788 // [out] Address that receives requested interface pointer
789 // Returns: S_OK
790 // LibreOffice filter object was successfully created
791 // CLASS_E_NOAGGREGATION
792 // pUnkOuter parameter was non-NULL
793 // E_NOINTERFACE
794 // (not implemented)
795 // E_OUTOFMEMORY
796 // LibreOffice filter object could not be created
797 // due to insufficient memory
798 // E_UNEXPECTED
799 // Unsuccessful due to an unexpected condition
801 SCODE STDMETHODCALLTYPE COooFilterCF::CreateInstance(
802 IUnknown * pUnkOuter,
803 REFIID riid,
804 void * * ppvObject)
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
813 pIUnk->Release();
815 else
817 delete pIUnk;
818 return E_UNEXPECTED;
820 return S_OK;
823 //M-------------------------------------------------------------------------
824 // Method: COooFilterCF::LockServer (IClassFactory::LockServer)
825 // Summary: Forces/allows filter class to remain loaded/be unloaded
826 // Arguments: fLock
827 // [in] TRUE to lock, FALSE to unlock
828 // Returns: S_OK
829 // Always
830 // E_FAIL
831 // (not implemented)
832 // E_OUTOFMEMORY
833 // (not implemented)
834 // E_UNEXPECTED
835 // (not implemented)
837 SCODE STDMETHODCALLTYPE COooFilterCF::LockServer(BOOL fLock)
839 if( fLock )
840 InterlockedIncrement( &g_lInstances );
841 else
842 InterlockedDecrement( &g_lInstances );
843 return S_OK;
845 //+-------------------------------------------------------------------------
846 // DLL: ooofilt.dll
847 // Summary: Implements Dynamic Link Library functions for LibreOffice filter
849 //F-------------------------------------------------------------------------
850 // Function: DllMain
851 // Summary: Called from C-Runtime on process/thread attach/detach
852 // Arguments: hInstance
853 // [in] Handle to the DLL
854 // fdwReason
855 // [in] Reason for calling DLL entry point
856 // lpReserve
857 // [in] Details of DLL initialization and cleanup
858 // Returns: TRUE
859 // Always
861 extern "C" BOOL WINAPI DllMain(
862 HINSTANCE hInstance,
863 DWORD fdwReason,
864 LPVOID /*lpvReserved*/
867 if ( DLL_PROCESS_ATTACH == fdwReason )
868 DisableThreadLibraryCalls( hInstance );
869 return TRUE;
871 //F-------------------------------------------------------------------------
872 // Function: DllGetClassObject
873 // Summary: Create LibreOffice filter class factory object
874 // Arguments: cid
875 // [in] Class ID of class that class factory creates
876 // iid
877 // [in] Reference IID of requested class factory interface
878 // ppvObj
879 // [out] Address that receives requested interface pointer
880 // Returns: S_OK
881 // Class factory object was created successfully
882 // CLASS_E_CLASSNOTAVAILABLE
883 // DLL does not support the requested class
884 // E_INVALIDARG
885 // (not implemented
886 // E_OUTOFMEMORY
887 // Insufficient memory to create the class factory object
888 // E_UNEXPECTED
889 // Unsuccessful due to an unexpected condition
891 extern "C" SCODE STDMETHODCALLTYPE DllGetClassObject(
892 REFCLSID cid,
893 REFIID iid,
894 void ** ppvObj
897 COooFilterCF* pImpl = 0;
898 IUnknown *pResult = 0;
900 if ( CLSID_COooFilter == cid )
902 pImpl = new COooFilterCF;
903 pResult = (IUnknown *) pImpl;
905 else
906 return CLASS_E_CLASSNOTAVAILABLE;
907 if( SUCCEEDED( pResult->QueryInterface( iid, ppvObj ) ) )
908 // Release extra refcount from QueryInterface
909 pResult->Release();
910 else
912 delete pImpl;
913 return E_UNEXPECTED;
915 return S_OK;
917 //F-------------------------------------------------------------------------
918 // Function: DllCanUnloadNow
919 // Summary: Indicates whether it is possible to unload DLL
920 // Arguments: void
921 // Returns: S_OK
922 // DLL can be unloaded now
923 // S_FALSE
924 // DLL must remain loaded
926 extern "C" SCODE STDMETHODCALLTYPE DllCanUnloadNow()
928 if ( 0 >= g_lInstances )
929 return S_OK;
930 else
931 return S_FALSE;
933 //F-------------------------------------------------------------------------
934 // Function: DllRegisterServer
935 // DllUnregisterServer
936 // Summary: Registers and unregisters DLL server
937 // Returns: DllRegisterServer
938 // S_OK
939 // Registration was successful
940 // SELFREG_E_CLASS
941 // Registration was unsuccessful
942 // SELFREG_E_TYPELIB
943 // (not implemented)
944 // E_OUTOFMEMORY
945 // (not implemented)
946 // E_UNEXPECTED
947 // (not implemented)
948 // DllUnregisterServer
949 // S_OK
950 // Unregistration was successful
951 // S_FALSE
952 // Unregistration was successful, but other
953 // entries still exist for the DLL's classes
954 // SELFREG_E_CLASS
955 // (not implemented)
956 // SELFREG_E_TYPELIB
957 // (not implemented)
958 // E_OUTOFMEMORY
959 // (not implemented)
960 // E_UNEXPECTED
961 // (not implemented)
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"))
1013 return E_FAIL;
1015 ClsidEntry = CLSID_GUID_INPROC_ENTRY;
1016 SubstitutePlaceholder(ClsidEntry, GUID_PLACEHOLDER, ClsidToString(FilterGuid));
1018 if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), "", FilePath))
1019 return E_FAIL;
1021 if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), "ThreadingModel", "Both"))
1022 return E_FAIL;
1024 return S_OK;
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"))
1041 return E_FAIL;
1043 // Add missing entry
1044 std::string ClsidEntry_Persist_Entry = CLSID_PERSIST_ENTRY;
1045 SubstitutePlaceholder(ClsidEntry_Persist_Entry,
1046 GUID_PLACEHOLDER,
1047 ClsidToString(PersistentGuid));
1049 if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry_Persist_Entry.c_str(), "", ClsidToString(PersistentGuid).c_str()))
1050 return E_FAIL;
1052 std::string ClsidEntry_Persist_Addin = CLSID_GUID_PERSIST_ADDIN_ENTRY;
1053 SubstitutePlaceholder(ClsidEntry_Persist_Addin,
1054 GUID_PLACEHOLDER,
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() ))
1061 return E_FAIL;
1063 return S_OK;
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)))
1086 return E_FAIL;
1088 if (FAILED(RegisterPersistentHandler(CLSID_FILTER_HANDLER, CLSID_PERSISTENT_HANDLER )))
1089 return E_FAIL;
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()))
1102 return E_FAIL;
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,
1116 GUID_PLACEHOLDER,
1117 extCLSID);
1119 if (!SetRegistryKey(HKEY_CLASSES_ROOT,
1120 ClsidEntry_CLSID_Persist.c_str(),
1122 ClsidToString(CLSID_PERSISTENT_HANDLER).c_str() ))
1123 return E_FAIL;
1128 return S_OK;
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,
1155 GUID_PLACEHOLDER,
1156 extCLSID);
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
1169 // each time.
1171 HRESULT AddOrRemoveDllsToRegisterList( const ::std::string & DllPath, bool isAdd )
1173 char DllsToRegisterList[4096];
1174 if (QueryRegistryKey(HKEY_LOCAL_MACHINE,
1175 INDEXING_FILTER_DLLSTOREGISTER,
1176 "DLLsToRegister",
1177 DllsToRegisterList,
1178 4096))
1180 char * pChar = DllsToRegisterList;
1181 for ( ; *pChar != '\0' || *(pChar +1) != '\0'; pChar++)
1182 if ( *pChar == '\0')
1183 *pChar = ';';
1184 *pChar = ';';
1185 *(pChar+1) = '\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 );
1192 else
1193 return S_OK;
1195 pChar = DllsToRegisterList;
1196 for ( size_t nChar = 0; nChar < DllList.length(); pChar++,nChar++)
1198 if ( DllList[nChar] == ';')
1199 *pChar = '\0';
1200 else
1201 *pChar = DllList[nChar];
1203 *pChar = *( pChar+1 ) ='\0';
1205 HKEY hSubKey;
1206 char dummy[] = "";
1207 int rc = RegCreateKeyExA(HKEY_LOCAL_MACHINE,
1208 INDEXING_FILTER_DLLSTOREGISTER,
1210 dummy,
1211 REG_OPTION_NON_VOLATILE,
1212 KEY_WRITE,
1214 &hSubKey,
1217 if (ERROR_SUCCESS == rc)
1219 rc = RegSetValueExA( hSubKey,
1220 "DLLsToRegister",
1222 REG_MULTI_SZ,
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;
1232 return S_OK;
1235 } // namespace /* private */
1237 STDAPI DllRegisterServer()
1239 return S_OK;
1244 STDAPI DllUnregisterServer()
1246 return S_OK;
1249 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */