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_shell.hxx"
30 
31 //--------------------------------------------------------------------------
32 //  File:       ooofilt.cxx
33 //
34 //  Contents:   Filter Implementation for OpenOffice.Org Document using
35 //              Indexing Service
36 //
37 //  Summary:    The OpenOffice.org filter reads OpenOffice.org files (with the
38 //              extension .sxw .sxi, etc) and extract their content, author,
39 //              keywords,subject,comments and title to be filtered.
40 //
41 //  Platform:   Windows 2000, Windows XP
42 //
43 //--------------------------------------------------------------------------
44 #include "internal/contentreader.hxx"
45 #include "internal/metainforeader.hxx"
46 //#include "internal/utilities.hxx"
47 #include "internal/registry.hxx"
48 #include "internal/fileextensions.hxx"
49 
50 //--------------------------------------------------------------------------
51 //
52 //  Include file    Purpose
53 //
54 //  windows.h       Win32 declarations
55 //  string.h        string wstring declarations
56 //  filter.h        IFilter interface declarations
57 //  filterr.h       FACILITY_ITF error definitions for IFilter
58 //  ntquery.h       Indexing Service declarations
59 //  assert.h        assertion function.
60 //  ooofilt.hxx     OpenOffice.org filter declarations
61 //  propspec.hxx    PROPSPEC
62 //
63 //--------------------------------------------------------------------------
64 
65 #if defined _MSC_VER
66 #pragma warning(push, 1)
67 #endif
68 #include <windows.h>
69 #if defined _MSC_VER
70 #pragma warning(pop)
71 #endif
72 #include <string.h>
73 #include <filter.h>
74 #include <filterr.h>
75 #include <ntquery.h>
76 #include "assert.h"
77 #include "ooofilt.hxx"
78 #include <objidl.h>
79 #include <stdio.h>
80 #include "propspec.hxx"
81 #ifdef __MINGW32__
82 #include <algorithm>
83 using ::std::min;
84 #endif
85 
86 #include "internal/stream_helper.hxx"
87 
88 //C-------------------------------------------------------------------------
89 //
90 //  Class:      COooFilter
91 //
92 //  Summary:    Implements OpenOffice.org filter class
93 //
94 //--------------------------------------------------------------------------
95 //M-------------------------------------------------------------------------
96 //
97 //  Method:     COooFilter::COooFilter
98 //
99 //  Summary:    Class constructor
100 //
101 //  Arguments:  void
102 //
103 //  Purpose:    Manages global instance count
104 //
105 //--------------------------------------------------------------------------
106 COooFilter::COooFilter() :
107     m_lRefs(1),
108     m_pContentReader(NULL),
109     m_pMetaInfoReader(NULL),
110     m_eState(FilteringContent),
111     m_ulUnicodeBufferLen(0),
112     m_ulUnicodeCharsRead(0),
113     m_ulPropertyNum(0),
114     m_ulCurrentPropertyNum(0),
115     m_ulChunkID(1),
116     m_fContents(FALSE),
117     m_fEof(FALSE),
118     m_ChunkPosition(0),
119     m_cAttributes(0),
120     m_pAttributes(0),
121 	m_pStream(NULL)
122 
123 {
124     InterlockedIncrement( &g_lInstances );
125 }
126 //M-------------------------------------------------------------------------
127 //
128 //  Method:     COooFilter::~COooFilter
129 //
130 //  Summary:    Class destructor
131 //
132 //  Arguments:  void
133 //
134 //  Purpose:    Manages global instance count and file handle
135 //
136 //--------------------------------------------------------------------------
137 COooFilter::~COooFilter()
138 {
139     delete [] m_pAttributes;
140 
141     if (m_pContentReader)
142         delete m_pContentReader;
143     if (m_pMetaInfoReader)
144         delete m_pMetaInfoReader;
145 
146     InterlockedDecrement( &g_lInstances );
147 }
148 
149 //M-------------------------------------------------------------------------
150 //
151 //  Method:     COooFilter::QueryInterface      (IUnknown::QueryInterface)
152 //
153 //  Summary:    Queries for requested interface
154 //
155 //  Arguments:  riid
156 //              [in] Reference IID of requested interface
157 //              ppvObject
158 //              [out] Address that receives requested interface pointer
159 //
160 //  Returns:    S_OK
161 //              Interface is supported
162 //              E_NOINTERFACE
163 //              Interface is not supported
164 //
165 //--------------------------------------------------------------------------
166 SCODE STDMETHODCALLTYPE COooFilter::QueryInterface(
167     REFIID riid,
168     void  ** ppvObject)
169 {
170     IUnknown *pUnkTemp = 0;
171     if ( IID_IFilter == riid )
172         pUnkTemp = (IUnknown *)(IFilter *)this;
173     else if ( IID_IPersistFile == riid )
174         pUnkTemp = (IUnknown *)(IPersistFile *)this;
175     else if ( IID_IPersist == riid )
176         pUnkTemp = (IUnknown *)(IPersist *)(IPersistFile *)this;
177 	else if (IID_IPersistStream == riid)
178 		pUnkTemp = (IUnknown *)(IPersistStream *)this;
179     else if ( IID_IUnknown == riid )
180         pUnkTemp = (IUnknown *)(IPersist *)(IPersistFile *)this;
181     else
182     {
183         *ppvObject = NULL;
184         return E_NOINTERFACE;
185     }
186     *ppvObject = (void  *)pUnkTemp;
187     pUnkTemp->AddRef();
188     return S_OK;
189 }
190 //M-------------------------------------------------------------------------
191 //
192 //  Method:     COooFilter::AddRef              (IUnknown::AddRef)
193 //
194 //  Summary:    Increments interface refcount
195 //
196 //  Arguments:  void
197 //
198 //  Returns:    Value of incremented interface refcount
199 //
200 //--------------------------------------------------------------------------
201 ULONG STDMETHODCALLTYPE COooFilter::AddRef()
202 {
203     return InterlockedIncrement( &m_lRefs );
204 }
205 //M-------------------------------------------------------------------------
206 //
207 //  Method:     COooFilter::Release             (IUnknown::Release)
208 //
209 //  Summary:    Decrements interface refcount, deleting if unreferenced
210 //
211 //  Arguments:  void
212 //
213 //  Returns:    Value of decremented interface refcount
214 //
215 //--------------------------------------------------------------------------
216 ULONG STDMETHODCALLTYPE COooFilter::Release()
217 {
218     ULONG ulTmp = InterlockedDecrement( &m_lRefs );
219 
220     if ( 0 == ulTmp )
221         delete this;
222     return ulTmp;
223 }
224 //M-------------------------------------------------------------------------
225 //
226 //  Method:     COooFilter::Init                (IFilter::Init)
227 //
228 //  Summary:    Initializes OpenOffice.org filter instance
229 //
230 //  Arguments:  grfFlags
231 //                  [in] Flags for filter behavior
232 //              cAttributes
233 //                  [in] Number attributes in array aAttributes
234 //              aAttributes
235 //                  [in] Array of requested attribute strings
236 //              pFlags
237 //                  [out] Pointer to return flags for additional properties
238 //
239 //  Returns:    S_OK
240 //                  Initialization succeeded
241 //              E_FAIL
242 //                  File not previously loaded
243 //              E_INVALIDARG
244 //                  Count and contents of attributes do not agree
245 //              FILTER_E_ACCESS
246 //                  Unable to access file to be filtered
247 //              FILTER_E_PASSWORD
248 //                  (not implemented)
249 //
250 //--------------------------------------------------------------------------
251 const int COUNT_ATTRIBUTES = 5;
252 
253 SCODE STDMETHODCALLTYPE COooFilter::Init(
254     ULONG grfFlags,
255     ULONG cAttributes,
256     FULLPROPSPEC const * aAttributes,
257     ULONG * pFlags)
258 {
259     // Enumerate OLE properties, since any NTFS file can have them
260     *pFlags = IFILTER_FLAGS_OLE_PROPERTIES;
261     try
262     {
263         m_fContents = FALSE;
264         m_ulPropertyNum = 0;
265         m_ulCurrentPropertyNum = 0;
266         if ( m_cAttributes > 0 )
267         {
268             delete[] m_pAttributes;
269             m_pAttributes = 0;
270             m_cAttributes = 0;
271         }
272         if( 0 < cAttributes )
273         {
274             // Filter properties specified in aAttributes
275             if ( 0 == aAttributes )
276                 return E_INVALIDARG;
277             m_pAttributes = new CFullPropSpec[cAttributes];
278             m_cAttributes = cAttributes;
279             // Is caller want to filter contents?
280             CFullPropSpec *pAttrib = (CFullPropSpec *) aAttributes;
281             ULONG ulNumAttr;
282             for ( ulNumAttr = 0 ; ulNumAttr < cAttributes; ulNumAttr++ )
283             {
284                 if ( pAttrib[ulNumAttr].IsPropertyPropid() &&
285                      pAttrib[ulNumAttr].GetPropertyPropid() == PID_STG_CONTENTS &&
286                      pAttrib[ulNumAttr].GetPropSet() == guidStorage )
287                 {
288                     m_fContents = TRUE;
289                 }
290                 // save the requested properties.
291                 m_pAttributes[ulNumAttr] = pAttrib[ulNumAttr];
292             }
293         }
294         else if ( grfFlags & IFILTER_INIT_APPLY_INDEX_ATTRIBUTES )
295         {
296             // Filter contents and all pseudo-properties
297             m_fContents = TRUE;
298 
299             m_pAttributes = new CFullPropSpec[COUNT_ATTRIBUTES];
300             m_cAttributes = COUNT_ATTRIBUTES;
301             m_pAttributes[0].SetPropSet( FMTID_SummaryInformation );
302             m_pAttributes[0].SetProperty( PIDSI_AUTHOR );
303             m_pAttributes[1].SetPropSet( FMTID_SummaryInformation );
304             m_pAttributes[1].SetProperty( PIDSI_TITLE );
305             m_pAttributes[2].SetPropSet( FMTID_SummaryInformation );
306             m_pAttributes[2].SetProperty( PIDSI_SUBJECT );
307             m_pAttributes[3].SetPropSet( FMTID_SummaryInformation );
308             m_pAttributes[3].SetProperty( PIDSI_KEYWORDS );
309             m_pAttributes[4].SetPropSet( FMTID_SummaryInformation );
310             m_pAttributes[4].SetProperty( PIDSI_COMMENTS );
311         }
312         else if ( 0 == grfFlags )
313         {
314             // Filter only contents
315             m_fContents = TRUE;
316         }
317         else
318             m_fContents = FALSE;
319         // Re-initialize
320         if ( m_fContents )
321         {
322             m_fEof = FALSE;
323             m_eState = FilteringContent;
324             m_ulUnicodeCharsRead = 0;
325             m_ChunkPosition = 0;
326         }
327         else
328         {
329             m_fEof = TRUE;
330             m_eState = FilteringProperty;
331         }
332         m_ulChunkID = 1;
333     }
334     catch (const std::exception&)
335     {
336         return E_FAIL;
337     }
338 
339     return S_OK;
340 }
341 //M-------------------------------------------------------------------------
342 //
343 //  Method:     COooFilter::GetChunk            (IFilter::GetChunk)
344 //
345 //  Summary:    Gets the next chunk
346 //
347 //  Arguments:  ppStat
348 //                  [out] Pointer to description of current chunk
349 //  Returns:    S_OK
350 //                  Chunk was successfully retrieved
351 //              E_FAIL
352 //                  Character conversion failed
353 //              FILTER_E_ACCESS
354 //                  General access failure occurred
355 //              FILTER_E_END_OF_CHUNKS
356 //                  Previous chunk was the last chunk
357 //              FILTER_E_EMBEDDING_UNAVAILABLE
358 //                  (not implemented)
359 //              FILTER_E_LINK_UNAVAILABLE
360 //                  (not implemented)
361 //              FILTER_E_PASSWORD
362 //                  (not implemented)
363 //
364 //--------------------------------------------------------------------------
365 SCODE STDMETHODCALLTYPE COooFilter::GetChunk(STAT_CHUNK * pStat)
366 {
367     for(;;)
368     {
369         switch ( m_eState )
370         {
371         case FilteringContent:
372         {
373             // Read Unicodes from buffer.
374             if( m_ChunkPosition == m_pContentReader ->getChunkBuffer().size() )
375             {
376                 m_ulUnicodeBufferLen=0;
377                 m_fEof = TRUE;
378             }
379 
380             if ( !m_fContents || m_fEof )
381             {
382                 m_eState = FilteringProperty;
383                 continue;
384             }
385             m_pwsBuffer = m_pContentReader -> getChunkBuffer()[m_ChunkPosition].second;
386             m_ulUnicodeBufferLen = m_pwsBuffer.length();
387             DWORD ChunkLCID = LocaleSetToLCID( m_pContentReader -> getChunkBuffer()[m_ChunkPosition].first );
388             // Set chunk description
389             pStat->idChunk   = m_ulChunkID;
390             pStat->breakType = CHUNK_NO_BREAK;
391             pStat->flags     = CHUNK_TEXT;
392             pStat->locale    = ChunkLCID;
393             pStat->attribute.guidPropSet       = guidStorage;
394             pStat->attribute.psProperty.ulKind = PRSPEC_PROPID;
395             pStat->attribute.psProperty.propid = PID_STG_CONTENTS;
396             pStat->idChunkSource  = m_ulChunkID;
397             pStat->cwcStartSource = 0;
398             pStat->cwcLenSource   = 0;
399             m_ulUnicodeCharsRead = 0;
400             m_ulChunkID++;
401             m_ChunkPosition++;
402             return S_OK;
403         }
404         case FilteringProperty:
405         {
406             if ( m_cAttributes ==  0 )
407                 return FILTER_E_END_OF_CHUNKS;
408             while(  !( ( m_pAttributes[m_ulPropertyNum].IsPropertyPropid() ) &&
409                        ( m_pAttributes[m_ulPropertyNum].GetPropSet() == FMTID_SummaryInformation ) )||
410                      ( ( m_pAttributes[m_ulPropertyNum].GetPropertyPropid() != PIDSI_AUTHOR ) &&
411                        ( m_pAttributes[m_ulPropertyNum].GetPropertyPropid() != PIDSI_TITLE ) &&
412                        ( m_pAttributes[m_ulPropertyNum].GetPropertyPropid() != PIDSI_SUBJECT ) &&
413                        ( m_pAttributes[m_ulPropertyNum].GetPropertyPropid() != PIDSI_KEYWORDS ) &&
414                        ( m_pAttributes[m_ulPropertyNum].GetPropertyPropid() != PIDSI_COMMENTS ) ) )
415             {
416                 if ( m_ulPropertyNum <  m_cAttributes )
417                     m_ulPropertyNum++;
418                 else
419                     break;
420             }
421             if ( m_ulPropertyNum ==  m_cAttributes)
422                 return FILTER_E_END_OF_CHUNKS;
423             else
424             {
425                 // Set chunk description
426                 pStat->idChunk = m_ulChunkID;
427                 pStat->breakType = CHUNK_EOS;
428                 pStat->flags = CHUNK_VALUE;
429                 pStat->locale = GetSystemDefaultLCID();
430                 pStat->attribute.guidPropSet = FMTID_SummaryInformation;
431                 pStat->attribute.psProperty.ulKind = PRSPEC_PROPID;
432                 pStat->attribute.psProperty.propid = m_pAttributes[m_ulPropertyNum].GetPropertyPropid();
433                 pStat->idChunkSource = m_ulChunkID;
434                 pStat->cwcStartSource = 0;
435                 pStat->cwcLenSource = 0;
436                 m_ulCurrentPropertyNum = m_ulPropertyNum;
437                 m_ulPropertyNum++;
438                 m_ulChunkID++;
439                 return S_OK;
440             }
441         }
442         default:
443             return E_FAIL;
444         }//switch(...)
445     }//for(;;)
446 }
447 //M-------------------------------------------------------------------------
448 //
449 //  Method:     COooFilter::GetText             (IFilter::GetText)
450 //
451 //  Summary:    Retrieves UNICODE text for index
452 //
453 //  Arguments:  pcwcBuffer
454 //                  [in] Pointer to size of UNICODE buffer
455 //                  [out] Pointer to count of UNICODE characters returned
456 //              awcBuffer
457 //                  [out] Pointer to buffer to receive UNICODE text
458 //
459 //  Returns:    S_OK
460 //                  Text successfully retrieved, but text remains in chunk
461 //              FILTER_E_NO_MORE_TEXT
462 //                  All of the text in the current chunk has been returned
463 //              FILTER_S_LAST_TEXT
464 //                  Next call to GetText will return FILTER_E_NO_MORE_TEXT
465 //
466 //--------------------------------------------------------------------------
467 SCODE STDMETHODCALLTYPE COooFilter::GetText(ULONG * pcwcBuffer, WCHAR * awcBuffer)
468 {
469     switch ( m_eState )
470     {
471     case FilteringProperty:
472         return FILTER_E_NO_TEXT;
473     case FilteringContent:
474     {
475         if ( !m_fContents || 0 == m_ulUnicodeBufferLen )
476         {
477             *pcwcBuffer = 0;
478             return FILTER_E_NO_MORE_TEXT;
479         }
480         // Copy UNICODE characters in chunk buffer to output UNICODE buffer
481         ULONG ulToCopy = min( *pcwcBuffer, m_ulUnicodeBufferLen - m_ulUnicodeCharsRead );
482         ZeroMemory(awcBuffer, sizeof(awcBuffer));
483         wmemcpy( awcBuffer, m_pwsBuffer.c_str() + m_ulUnicodeCharsRead, ulToCopy );
484         m_ulUnicodeCharsRead += ulToCopy;
485         *pcwcBuffer = ulToCopy;
486         if ( m_ulUnicodeBufferLen == m_ulUnicodeCharsRead )
487         {
488             m_ulUnicodeCharsRead = 0;
489             m_ulUnicodeBufferLen = 0;
490             return FILTER_S_LAST_TEXT;
491         }
492         return S_OK;
493     }
494     default:
495         return E_FAIL;
496     }
497 }
498 //M-------------------------------------------------------------------------
499 //
500 //  Method:     GetMetaInfoNameFromPropertyId
501 //
502 //  Summary:    helper function to convert PropertyID into respective
503 //              MetaInfo names.
504 //
505 //  Arguments:  ulPropID
506 //                  [in] property ID
507 //
508 //  Returns:    corresponding metainfo names.
509 //
510 //--------------------------------------------------------------------------
511 
512 ::std::wstring GetMetaInfoNameFromPropertyId( ULONG ulPropID )
513 {
514     switch ( ulPropID )
515     {
516         case PIDSI_AUTHOR:   return META_INFO_AUTHOR;
517         case PIDSI_TITLE:    return META_INFO_TITLE;
518         case PIDSI_SUBJECT:  return META_INFO_SUBJECT;
519         case PIDSI_KEYWORDS: return META_INFO_KEYWORDS;
520         case PIDSI_COMMENTS: return META_INFO_DESCRIPTION;
521         default:             return EMPTY_STRING;
522     }
523 }
524 //M-------------------------------------------------------------------------
525 //
526 //  Method:     COooFilter::GetValue            (IFilter::GetValue)
527 //
528 //  Summary:    Retrieves properites for index
529 //
530 //  Arguments:  ppPropValue
531 //                  [out] Address that receives pointer to property value
532 //
533 //  Returns:    FILTER_E_NO_VALUES
534 //                  Always
535 //              FILTER_E_NO_MORE_VALUES
536 //                  (not implemented)
537 //
538 //--------------------------------------------------------------------------
539 
540 SCODE STDMETHODCALLTYPE COooFilter::GetValue(PROPVARIANT ** ppPropValue)
541 {
542     if (m_eState == FilteringContent)
543         return FILTER_E_NO_VALUES;
544     else if (m_eState == FilteringProperty)
545     {
546         if ( m_cAttributes == 0 || ( m_ulCurrentPropertyNum == m_ulPropertyNum ) )
547             return FILTER_E_NO_MORE_VALUES;
548         PROPVARIANT *pPropVar = (PROPVARIANT *) CoTaskMemAlloc( sizeof (PROPVARIANT) );
549         if ( pPropVar == 0 )
550             return E_OUTOFMEMORY;
551         ::std::wstring wsTagName= GetMetaInfoNameFromPropertyId( m_pAttributes[m_ulCurrentPropertyNum].GetPropertyPropid() );
552         if ( wsTagName == EMPTY_STRING )
553             return FILTER_E_NO_VALUES;
554 		::std::wstring wsTagData = m_pMetaInfoReader->getTagData(wsTagName);
555 		pPropVar->vt = VT_LPWSTR;
556 		size_t cw = wsTagData.length() + 1; // reserve one for the '\0'
557 		pPropVar->pwszVal = static_cast<WCHAR*>( CoTaskMemAlloc(cw*sizeof(WCHAR)) );
558 		if (pPropVar->pwszVal == 0)
559 		{
560 			CoTaskMemFree(pPropVar);
561 			return E_OUTOFMEMORY;
562 		}
563 		wmemcpy(pPropVar->pwszVal, wsTagData.c_str(), cw);
564         *ppPropValue = pPropVar;
565         m_ulCurrentPropertyNum = m_ulPropertyNum;
566         return S_OK;
567     }
568     else
569         return E_FAIL;
570 }
571 //M-------------------------------------------------------------------------
572 //
573 //  Method:     COooFilter::BindRegion          (IFilter::BindRegion)
574 //
575 //  Summary:    Creates moniker or other interface for indicated text
576 //
577 //  Arguments:  origPos
578 //                  [in] Description of text location and extent
579 //              riid
580 //                  [in] Reference IID of specified interface
581 //              ppunk
582 //                  [out] Address that receives requested interface pointer
583 //
584 //  Returns:    E_NOTIMPL
585 //                  Always
586 //              FILTER_W_REGION_CLIPPED
587 //                  (not implemented)
588 //
589 //--------------------------------------------------------------------------
590 
591 SCODE STDMETHODCALLTYPE COooFilter::BindRegion(
592     FILTERREGION /*origPos*/,
593     REFIID /*riid*/,
594     void ** /*ppunk*/)
595 {
596     // BindRegion is currently reserved for future use
597     return E_NOTIMPL;
598 }
599 //M-------------------------------------------------------------------------
600 //
601 //  Method:     COooFilter::GetClassID          (IPersist::GetClassID)
602 //
603 //  Summary:    Retrieves the class id of the filter class
604 //
605 //  Arguments:  pClassID
606 //                  [out] Pointer to the class ID of the filter
607 //
608 //  Returns:    S_OK
609 //                  Always
610 //              E_FAIL
611 //                  (not implemented)
612 //--------------------------------------------------------------------------
613 SCODE STDMETHODCALLTYPE COooFilter::GetClassID(CLSID * pClassID)
614 {
615     *pClassID = CLSID_COooFilter;
616     return S_OK;
617 }
618 //M-------------------------------------------------------------------------
619 //
620 //  Method:     COooFilter::IsDirty             (IPersistFile::IsDirty)
621 //
622 //  Summary:    Checks whether file has changed since last save
623 //
624 //  Arguments:  void
625 //
626 //  Returns:    S_FALSE
627 //                  Always
628 //              S_OK
629 //                  (not implemented)
630 //
631 //--------------------------------------------------------------------------
632 SCODE STDMETHODCALLTYPE COooFilter::IsDirty()
633 {
634     // File is opened read-only and never changes
635     return S_FALSE;
636 }
637 //M-------------------------------------------------------------------------
638 //
639 //  Method:     COooFilter::Load                (IPersistFile::Load)
640 //
641 //  Summary:    Opens and initializes the specified file
642 //
643 //  Arguments:  pszFileName
644 //                  [in] Pointer to zero-terminated string
645 //                       of absolute path of file to open
646 //              dwMode
647 //                  [in] Access mode to open the file
648 //
649 //  Returns:    S_OK
650 //                  File was successfully loaded
651 //              E_OUTOFMEMORY
652 //                  File could not be loaded due to insufficient memory
653 //              E_FAIL
654 //                  (not implemented)
655 //
656 //--------------------------------------------------------------------------
657 SCODE STDMETHODCALLTYPE COooFilter::Load(LPCWSTR pszFileName, DWORD /*dwMode*/)
658 {
659     // Load just sets the filename for GetChunk to read and ignores the mode
660     m_pwszFileName = getShortPathName( pszFileName );
661 
662     // Open the file previously specified in call to IPersistFile::Load and get content.
663 	try
664     {
665         if (m_pMetaInfoReader)
666             delete m_pMetaInfoReader;
667 		m_pMetaInfoReader = new CMetaInfoReader(WStringToString(m_pwszFileName));
668 
669 		if (m_pContentReader)
670 		    delete m_pContentReader;
671 		m_pContentReader = new CContentReader(WStringToString(m_pwszFileName), m_pMetaInfoReader->getDefaultLocale());
672     }
673     catch (const std::exception&)
674     {
675         return E_FAIL;
676     }
677     return S_OK;
678 }
679 //M-------------------------------------------------------------------------
680 //
681 //  Method:     COooFilter::Save                (IPersistFile::Save)
682 //
683 //  Summary:    Saves a copy of the current file being filtered
684 //
685 //  Arguments:  pszFileName
686 //                  [in] Pointer to zero-terminated string of
687 //                       absolute path of where to save file
688 //              fRemember
689 //                  [in] Whether the saved copy is made the current file
690 //
691 //  Returns:    E_FAIL
692 //                  Always
693 //              S_OK
694 //                  (not implemented)
695 //
696 //--------------------------------------------------------------------------
697 SCODE STDMETHODCALLTYPE COooFilter::Save(LPCWSTR /*pszFileName*/, BOOL /*fRemember*/)
698 {
699     // File is opened read-only; saving it is an error
700     return E_FAIL;
701 }
702 //M-------------------------------------------------------------------------
703 //
704 //  Method:     COooFilter::SaveCompleted      (IPersistFile::SaveCompleted)
705 //
706 //  Summary:    Determines whether a file save is completed
707 //
708 //  Arguments:  pszFileName
709 //                  [in] Pointer to zero-terminated string of
710 //                       absolute path where file was previously saved
711 //
712 //  Returns:    S_OK
713 //                  Always
714 //
715 //--------------------------------------------------------------------------
716 SCODE STDMETHODCALLTYPE COooFilter::SaveCompleted(LPCWSTR /*pszFileName*/)
717 {
718     // File is opened read-only, so "save" is always finished
719     return S_OK;
720 }
721 
722 //M-------------------------------------------------------------------------
723 //
724 //  Method:     COooFilter::Load      (IPersistStream::Load)
725 //
726 //  Summary:    Initializes an object from the stream where it was previously saved
727 //
728 //  Arguments:  pStm
729 //                  [in] Pointer to stream from which object should be loaded
730 //
731 //
732 //  Returns:    S_OK
733 //				E_OUTOFMEMORY
734 //				E_FAIL
735 //
736 //
737 //--------------------------------------------------------------------------
738 SCODE STDMETHODCALLTYPE COooFilter::Load(IStream *pStm)
739 {
740 	zlib_filefunc_def z_filefunc;
741 
742     m_pStream = PrepareIStream( pStm, z_filefunc );
743 
744 	try
745     {
746         if (m_pMetaInfoReader)
747             delete m_pMetaInfoReader;
748 		m_pMetaInfoReader = new CMetaInfoReader((void*)m_pStream, &z_filefunc);
749 
750 		if (m_pContentReader)
751 		    delete m_pContentReader;
752 		m_pContentReader = new CContentReader((void*)m_pStream, m_pMetaInfoReader->getDefaultLocale(), &z_filefunc);
753     }
754     catch (const std::exception&)
755     {
756         return E_FAIL;
757     }
758     return S_OK;
759 }
760 
761 //M-------------------------------------------------------------------------
762 //
763 //  Method:     COooFilter::GetSizeMax      (IPersistStream::GetSizeMax)
764 //
765 //  Summary:    Returns the size in bytes of the stream neede to save the object.
766 //
767 //  Arguments:  pcbSize
768 //                  [out] Pointer to a 64 bit unsigned int indicating the size needed
769 //
770 //  Returns:    E_NOTIMPL
771 //
772 //
773 //--------------------------------------------------------------------------
774 SCODE STDMETHODCALLTYPE COooFilter::GetSizeMax(ULARGE_INTEGER * /*pcbSize*/)
775 {
776     //
777     return E_NOTIMPL;
778 }
779 
780 //M-------------------------------------------------------------------------
781 //
782 //  Method:     COooFilter::Save      (IPersistStream::Save)
783 //
784 //  Summary:    Save object to specified stream
785 //
786 //  Arguments:  pStm
787 //                  [in] Pointer to stream
788 //
789 //              fClearDirty
790 //					[in] Indicates whether to clear dirty flag
791 //
792 //  Returns:    E_NOTIMPL
793 //
794 //
795 //--------------------------------------------------------------------------
796 SCODE STDMETHODCALLTYPE COooFilter::Save(IStream * /*pStm*/, BOOL )
797 {
798     //
799     return E_NOTIMPL;
800 }
801 
802 //M-------------------------------------------------------------------------
803 //
804 //  Method:     COooFilter::GetCurFile          (IPersistFile::GetCurFile)
805 //
806 //  Summary:    Returns a copy of the current file name
807 //
808 //  Arguments:  ppszFileName
809 //                  [out] Address to receive pointer to zero-terminated
810 //                        string for absolute path to current file
811 //
812 //  Returns:    S_OK
813 //                  A valid absolute path was successfully returned
814 //              S_FALSE
815 //                  (not implemented)
816 //              E_OUTOFMEMORY
817 //                  Operation failed due to insufficient memory
818 //              E_FAIL
819 //                  Operation failed due to some reason
820 //                  other than insufficient memory
821 //
822 //-------------------------------------------------------------------------
823 SCODE STDMETHODCALLTYPE COooFilter::GetCurFile(LPWSTR * ppszFileName)
824 {
825     if ( EMPTY_STRING == m_pwszFileName )
826         return E_FAIL;
827     else
828         *ppszFileName = (LPWSTR)m_pwszFileName.c_str();
829     return S_OK;
830 }
831 
832 //M-------------------------------------------------------------------------
833 //
834 //  Method:     COooFilterCF::COooFilterCF
835 //
836 //  Summary:    Class factory constructor
837 //
838 //  Arguments:  void
839 //
840 //  Purpose:    Manages global instance count
841 //
842 //--------------------------------------------------------------------------
843 COooFilterCF::COooFilterCF() :
844     m_lRefs(1)
845 {
846     InterlockedIncrement( &g_lInstances );
847 }
848 //M-------------------------------------------------------------------------
849 //
850 //  Method:     COooFilterCF::~COooFilterCF
851 //
852 //  Summary:    Class factory destructor
853 //
854 //  Arguments:  void
855 //
856 //  Purpose:    Manages global instance count
857 //
858 //--------------------------------------------------------------------------
859 COooFilterCF::~COooFilterCF()
860 {
861    InterlockedDecrement( &g_lInstances );
862 }
863 //M-------------------------------------------------------------------------
864 //
865 //  Method:     COooFilterCF::QueryInterface    (IUnknown::QueryInterface)
866 //
867 //  Summary:    Queries for requested interface
868 //
869 //  Arguments:  riid
870 //                  [in] Reference IID of requested interface
871 //              ppvObject
872 //                  [out] Address that receives requested interface pointer
873 //
874 //  Returns:    S_OK
875 //                  Interface is supported
876 //              E_NOINTERFACE
877 //                  Interface is not supported
878 //
879 //--------------------------------------------------------------------------
880 SCODE STDMETHODCALLTYPE COooFilterCF::QueryInterface(REFIID riid, void  ** ppvObject)
881 {
882     IUnknown *pUnkTemp;
883 
884     if ( IID_IClassFactory == riid )
885         pUnkTemp = (IUnknown *)(IClassFactory *)this;
886     else if ( IID_IUnknown == riid )
887         pUnkTemp = (IUnknown *)this;
888     else
889     {
890         *ppvObject = NULL;
891         return E_NOINTERFACE;
892     }
893     *ppvObject = (void  *)pUnkTemp;
894     pUnkTemp->AddRef();
895     return S_OK;
896 }
897 //M-------------------------------------------------------------------------
898 //
899 //  Method:     COooFilterCF::AddRef            (IUknown::AddRef)
900 //
901 //  Summary:    Increments interface refcount
902 //
903 //  Arguments:  void
904 //
905 //  Returns:    Value of incremented interface refcount
906 //
907 //-------------------------------------------------------------------------
908 ULONG STDMETHODCALLTYPE COooFilterCF::AddRef()
909 {
910    return InterlockedIncrement( &m_lRefs );
911 }
912 //M-------------------------------------------------------------------------
913 //
914 //  Method:     COooFilterCF::Release           (IUnknown::Release)
915 //
916 //  Summary:    Decrements interface refcount, deleting if unreferenced
917 //
918 //  Arguments:  void
919 //
920 //  Returns:    Value of decremented refcount
921 //
922 //--------------------------------------------------------------------------
923 ULONG STDMETHODCALLTYPE COooFilterCF::Release()
924 {
925     ULONG ulTmp = InterlockedDecrement( &m_lRefs );
926 
927     if ( 0 == ulTmp )
928         delete this;
929     return ulTmp;
930 }
931 //M-------------------------------------------------------------------------
932 //
933 //  Method:     COooFilterCF::CreateInstance (IClassFactory::CreateInstance)
934 //
935 //  Summary:    Creates new OpenOffice.org filter object
936 //
937 //  Arguments:  pUnkOuter
938 //                  [in] Pointer to IUnknown interface of aggregating object
939 //              riid
940 //                  [in] Reference IID of requested interface
941 //              ppvObject
942 //                  [out] Address that receives requested interface pointer
943 //
944 //  Returns:    S_OK
945 //                  OpenOffice.org filter object was successfully created
946 //              CLASS_E_NOAGGREGATION
947 //                  pUnkOuter parameter was non-NULL
948 //              E_NOINTERFACE
949 //                  (not implemented)
950 //              E_OUTOFMEMORY
951 //                  OpenOffice.org filter object could not be created
952 //                  due to insufficient memory
953 //              E_UNEXPECTED
954 //                  Unsuccessful due to an unexpected condition
955 //
956 //--------------------------------------------------------------------------
957 SCODE STDMETHODCALLTYPE COooFilterCF::CreateInstance(
958     IUnknown * pUnkOuter,
959     REFIID riid,
960     void  * * ppvObject)
961 {
962     COooFilter *pIUnk = 0;
963     if ( 0 != pUnkOuter )
964         return CLASS_E_NOAGGREGATION;
965     pIUnk = new COooFilter();
966     if ( 0 != pIUnk )
967     {
968         if ( SUCCEEDED( pIUnk->QueryInterface( riid , ppvObject ) ) )
969         {
970             // Release extra refcount from QueryInterface
971             pIUnk->Release();
972         }
973         else
974         {
975             delete pIUnk;
976             return E_UNEXPECTED;
977         }
978     }
979     else
980         return E_OUTOFMEMORY;
981     return S_OK;
982 }
983 
984 //M-------------------------------------------------------------------------
985 //
986 //  Method:     COooFilterCF::LockServer        (IClassFactory::LockServer)
987 //
988 //  Summary:    Forces/allows filter class to remain loaded/be unloaded
989 //
990 //  Arguments:  fLock
991 //                  [in] TRUE to lock, FALSE to unlock
992 //
993 //  Returns:    S_OK
994 //                  Always
995 //              E_FAIL
996 //                  (not implemented)
997 //              E_OUTOFMEMORY
998 //                  (not implemented)
999 //              E_UNEXPECTED
1000 //                  (not implemented)
1001 //
1002 //--------------------------------------------------------------------------
1003 SCODE STDMETHODCALLTYPE COooFilterCF::LockServer(BOOL fLock)
1004 {
1005     if( fLock )
1006         InterlockedIncrement( &g_lInstances );
1007     else
1008         InterlockedDecrement( &g_lInstances );
1009     return S_OK;
1010 }
1011 //+-------------------------------------------------------------------------
1012 //
1013 //  DLL:        ooofilt.dll
1014 //
1015 //  Summary:    Implements Dynamic Link Library functions for OpenOffice.org filter
1016 //
1017 //--------------------------------------------------------------------------
1018 //F-------------------------------------------------------------------------
1019 //
1020 //  Function:   DllMain
1021 //
1022 //  Summary:    Called from C-Runtime on process/thread attach/detach
1023 //
1024 //  Arguments:  hInstance
1025 //                  [in] Handle to the DLL
1026 //              fdwReason
1027 //                  [in] Reason for calling DLL entry point
1028 //              lpReserve
1029 //                  [in] Details of DLL initialization and cleanup
1030 //
1031 //  Returns:    TRUE
1032 //                  Always
1033 //
1034 //--------------------------------------------------------------------------
1035 extern "C" BOOL WINAPI DllMain(
1036     HINSTANCE hInstance,
1037     DWORD     fdwReason,
1038     LPVOID    /*lpvReserved*/
1039 )
1040 {
1041    if ( DLL_PROCESS_ATTACH == fdwReason )
1042         DisableThreadLibraryCalls( hInstance );
1043     return TRUE;
1044 }
1045 //F-------------------------------------------------------------------------
1046 //
1047 //  Function:   DllGetClassObject
1048 //
1049 //  Summary:    Create OpenOffice.org filter class factory object
1050 //
1051 //  Arguments:  cid
1052 //                  [in] Class ID of class that class factory creates
1053 //              iid
1054 //                  [in] Reference IID of requested class factory interface
1055 //              ppvObj
1056 //                  [out] Address that receives requested interface pointer
1057 //
1058 //  Returns:    S_OK
1059 //                  Class factory object was created successfully
1060 //              CLASS_E_CLASSNOTAVAILABLE
1061 //                  DLL does not support the requested class
1062 //              E_INVALIDARG
1063 //                  (not implemented
1064 //              E_OUTOFMEMORY
1065 //                  Insufficient memory to create the class factory object
1066 //              E_UNEXPECTED
1067 //                  Unsuccessful due to an unexpected condition
1068 //
1069 //-------------------------------------------------------------------------
1070 extern "C" SCODE STDMETHODCALLTYPE DllGetClassObject(
1071     REFCLSID   cid,
1072     REFIID     iid,
1073     void **    ppvObj
1074 )
1075 {
1076     IUnknown *pResult = 0;
1077 
1078     if ( CLSID_COooFilter == cid )
1079         pResult = (IUnknown *) new COooFilterCF;
1080     else
1081         return CLASS_E_CLASSNOTAVAILABLE;
1082     if ( 0 != pResult )
1083     {
1084         if( SUCCEEDED( pResult->QueryInterface( iid, ppvObj ) ) )
1085             // Release extra refcount from QueryInterface
1086             pResult->Release();
1087         else
1088         {
1089             delete pResult;
1090             return E_UNEXPECTED;
1091         }
1092     }
1093     else
1094         return E_OUTOFMEMORY;
1095     return S_OK;
1096 }
1097 //F-------------------------------------------------------------------------
1098 //
1099 //  Function:   DllCanUnloadNow
1100 //
1101 //  Summary:    Indicates whether it is possible to unload DLL
1102 //
1103 //  Arguments:  void
1104 //
1105 //  Returns:    S_OK
1106 //                  DLL can be unloaded now
1107 //              S_FALSE
1108 //                  DLL must remain loaded
1109 //
1110 //--------------------------------------------------------------------------
1111 extern "C" SCODE STDMETHODCALLTYPE DllCanUnloadNow()
1112 {
1113     if ( 0 >= g_lInstances )
1114         return S_OK;
1115     else
1116         return S_FALSE;
1117 }
1118 //F-------------------------------------------------------------------------
1119 //
1120 //  Function:   DllRegisterServer
1121 //              DllUnregisterServer
1122 //
1123 //  Summary:    Registers and unregisters DLL server
1124 //
1125 //  Returns:    DllRegisterServer
1126 //                  S_OK
1127 //                      Registration was successful
1128 //                  SELFREG_E_CLASS
1129 //                      Registration was unsuccessful
1130 //                  SELFREG_E_TYPELIB
1131 //                      (not implemented)
1132 //                  E_OUTOFMEMORY
1133 //                      (not implemented)
1134 //                  E_UNEXPECTED
1135 //                      (not implemented)
1136 //              DllUnregisterServer
1137 //                  S_OK
1138 //                      Unregistration was successful
1139 //                  S_FALSE
1140 //                      Unregistration was successful, but other
1141 //                      entries still exist for the DLL's classes
1142 //                  SELFREG_E_CLASS
1143 //                      (not implemented)
1144 //                  SELFREG_E_TYPELIB
1145 //                      (not implemented)
1146 //                  E_OUTOFMEMORY
1147 //                      (not implemented)
1148 //                  E_UNEXPECTED
1149 //                      (not implemented)
1150 //
1151 //--------------------------------------------------------------------------
1152 
1153 
1154 //F-------------------------------------------------------------------------
1155 //
1156 //  helper functions to register the Indexing Service.
1157 //
1158 //--------------------------------------------------------------------------
1159 
1160 namespace /* private */
1161 {
1162 	const char* GUID_PLACEHOLDER         = "{GUID}";
1163 	const char* GUID_PERSIST_PLACEHOLDER = "{GUIDPERSIST}";
1164 	const char* EXTENSION_PLACEHOLDER    = "{EXT}";
1165 	const char* FORWARDKEY_PLACEHOLDER   = "{FWDKEY}";
1166 
1167 	const char* CLSID_GUID_INPROC_ENTRY             = "CLSID\\{GUID}\\InProcServer32";
1168 	const char* CLSID_GUID_ENTRY                    = "CLSID\\{GUID}";
1169 	const char* CLSID_GUID_PERSIST_ADDIN_ENTRY      = "CLSID\\{GUID}\\PersistentAddinsRegistered\\{GUIDPERSIST}";
1170 	const char* CLSID_PERSIST_ENTRY                 = "CLSID\\{GUID}\\PersistentHandler";
1171 	const char* EXT_PERSIST_ENTRY                   = "{EXT}\\PersistentHandler";
1172 
1173 	const char* INDEXING_FILTER_DLLSTOREGISTER      = "SYSTEM\\CurrentControlSet\\Control\\ContentIndex";
1174 
1175     //---------------------------
1176     // "String Placeholder" ->
1177     // "String Replacement"
1178     //---------------------------
1179 
1180     void SubstitutePlaceholder(std::string& String, const std::string& Placeholder, const std::string& Replacement)
1181     {
1182         std::string::size_type idx = String.find(Placeholder);
1183         std::string::size_type len = Placeholder.length();
1184 
1185         while (std::string::npos != idx)
1186         {
1187             String.replace(idx, len, Replacement);
1188             idx = String.find(Placeholder);
1189         }
1190     }
1191 
1192     //----------------------------------------------
1193     // Make the registry entry and set Filter Handler
1194     // HKCR\CLSID\{7BC0E710-5703-45be-A29D-5D46D8B39262} = OpenOffice.org Filter
1195     //		             InProcServer32	 (Default)       = Path\ooofilt.dll
1196     //			                         ThreadingModel  = Both
1197     //----------------------------------------------
1198 
1199     HRESULT RegisterFilterHandler(const char* FilePath, const CLSID& FilterGuid)
1200     {
1201         std::string ClsidEntry = CLSID_GUID_ENTRY;
1202         SubstitutePlaceholder(ClsidEntry, GUID_PLACEHOLDER, ClsidToString(FilterGuid));
1203 
1204 		if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), "", "OpenOffice.org Filter"))
1205             return E_FAIL;
1206 
1207         ClsidEntry = CLSID_GUID_INPROC_ENTRY;
1208         SubstitutePlaceholder(ClsidEntry, GUID_PLACEHOLDER, ClsidToString(FilterGuid));
1209 
1210         if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), "", FilePath))
1211             return E_FAIL;
1212 
1213         if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), "ThreadingModel", "Both"))
1214             return E_FAIL;
1215 
1216         return S_OK;
1217     }
1218 
1219     //----------------------------------------------
1220     // Make the registry entry and set Persistent Handler
1221     // HKCR\CLSID\{7BC0E713-5703-45be-A29D-5D46D8B39262}  = OpenOffice.org Persistent Handler
1222     //		PersistentAddinsRegistered
1223     //			{89BCB740-6119-101A-BCB7-00DD010655AF} = {7BC0E710-5703-45be-A29D-5D46D8B39262}
1224     //----------------------------------------------
1225 
1226     HRESULT RegisterPersistentHandler(const CLSID& FilterGuid, const CLSID& PersistentGuid)
1227     {
1228         std::string ClsidEntry_Persist = CLSID_GUID_ENTRY;
1229         SubstitutePlaceholder(ClsidEntry_Persist, GUID_PLACEHOLDER, ClsidToString(PersistentGuid));
1230 
1231 
1232 		if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry_Persist.c_str(), "", "OpenOffice.org Persistent Handler"))
1233             return E_FAIL;
1234 
1235 		// Add missing entry
1236 		std::string ClsidEntry_Persist_Entry = CLSID_PERSIST_ENTRY;
1237         SubstitutePlaceholder(ClsidEntry_Persist_Entry,
1238 			                  GUID_PLACEHOLDER,
1239 							  ClsidToString(PersistentGuid));
1240 
1241 		if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry_Persist_Entry.c_str(), "", ClsidToString(PersistentGuid).c_str()))
1242 			return E_FAIL;
1243 
1244         std::string ClsidEntry_Persist_Addin = CLSID_GUID_PERSIST_ADDIN_ENTRY;
1245         SubstitutePlaceholder(ClsidEntry_Persist_Addin,
1246 			                  GUID_PLACEHOLDER,
1247 							  ClsidToString(PersistentGuid));
1248 		SubstitutePlaceholder(ClsidEntry_Persist_Addin,
1249 			                  GUID_PERSIST_PLACEHOLDER,
1250 							  ClsidToString(CLSID_PERSISTENT_HANDLER_ADDIN));
1251 
1252         if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry_Persist_Addin.c_str(), "", ClsidToString(FilterGuid).c_str() ))
1253             return E_FAIL;
1254 
1255         return S_OK;
1256     }
1257 
1258     //---------------------------
1259     // Unregister Filter Handler or persistent handler
1260     //---------------------------
1261 
1262     HRESULT UnregisterHandler(const CLSID& Guid)
1263     {
1264         std::string tmp = "CLSID\\";
1265         tmp += ClsidToString(Guid);
1266         return DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()) ? S_OK : E_FAIL;
1267     }
1268 
1269     //---------------------------
1270     // Register Indexing Service ext and class.
1271 	// HKCR\{EXT}\PersistentHandler = {7BC0E713-5703-45be-A29D-5D46D8B39262}
1272     // HKCR\{GUID\PersistentHandler = {7BC0E713-5703-45be-A29D-5D46D8B39262}
1273     //---------------------------
1274 
1275     HRESULT RegisterSearchHandler(const char* ModuleFileName)
1276     {
1277         if (FAILED(RegisterFilterHandler(ModuleFileName, CLSID_FILTER_HANDLER)))
1278             return E_FAIL;
1279 
1280         if (FAILED(RegisterPersistentHandler(CLSID_FILTER_HANDLER, CLSID_PERSISTENT_HANDLER )))
1281             return E_FAIL;
1282 
1283         std::string sExtPersistEntry;
1284 
1285         for(size_t i = 0; i < OOFileExtensionTableSize; i++)
1286         {
1287 			// first, register extension.
1288             sExtPersistEntry = EXT_PERSIST_ENTRY;
1289             SubstitutePlaceholder(sExtPersistEntry, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi);
1290             if (!SetRegistryKey(HKEY_CLASSES_ROOT,
1291 								sExtPersistEntry.c_str(),
1292 								"",
1293 								ClsidToString(CLSID_PERSISTENT_HANDLER).c_str()))
1294                 return E_FAIL;
1295 
1296 			// second, register class.
1297 			char extClassName[MAX_PATH];
1298 			if (QueryRegistryKey(HKEY_CLASSES_ROOT, OOFileExtensionTable[i].ExtensionAnsi, "", extClassName,MAX_PATH))
1299 			{
1300 				::std::string extCLSIDName( extClassName );
1301 				extCLSIDName += "\\CLSID";
1302 				char extCLSID[MAX_PATH];
1303 
1304 				if (QueryRegistryKey( HKEY_CLASSES_ROOT, extCLSIDName.c_str(), "", extCLSID, MAX_PATH))
1305 				{
1306 					std::string ClsidEntry_CLSID_Persist = CLSID_PERSIST_ENTRY;
1307 					SubstitutePlaceholder(ClsidEntry_CLSID_Persist,
1308 										GUID_PLACEHOLDER,
1309 										extCLSID);
1310 
1311 					if (!SetRegistryKey(HKEY_CLASSES_ROOT,
1312 										ClsidEntry_CLSID_Persist.c_str(),
1313 										"",
1314 										ClsidToString(CLSID_PERSISTENT_HANDLER).c_str() ))
1315 						return E_FAIL;
1316 				}
1317 			}
1318         }
1319 
1320         return S_OK;
1321     }
1322 
1323     // Register Indexing Service ext and class.
1324     HRESULT UnregisterSearchHandler()
1325     {
1326         std::string sExtPersistEntry;
1327 
1328         for (size_t i = 0; i < OOFileExtensionTableSize; i++)
1329         {
1330 			// first, unregister extension
1331             sExtPersistEntry = EXT_PERSIST_ENTRY;
1332             SubstitutePlaceholder(sExtPersistEntry, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi);
1333             DeleteRegistryKey(HKEY_CLASSES_ROOT, sExtPersistEntry.c_str());
1334 
1335 			// second, unregister class
1336 			char extClassName[MAX_PATH];
1337 			if (QueryRegistryKey(HKEY_CLASSES_ROOT, OOFileExtensionTable[i].ExtensionAnsi, "", extClassName,MAX_PATH))
1338 			{
1339 				::std::string extCLSIDName( extClassName );
1340 				extCLSIDName += "\\CLSID";
1341 				char extCLSID[MAX_PATH];
1342 
1343 				if (QueryRegistryKey( HKEY_CLASSES_ROOT, extCLSIDName.c_str(), "", extCLSID, MAX_PATH))
1344 				{
1345 					std::string ClsidEntry_CLSID_Persist = CLSID_PERSIST_ENTRY;
1346 					SubstitutePlaceholder(ClsidEntry_CLSID_Persist,
1347 										GUID_PLACEHOLDER,
1348 										extCLSID);
1349 
1350 					DeleteRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry_CLSID_Persist.c_str());
1351 				}
1352 			}
1353 		}
1354 
1355 		return ((UnregisterHandler(CLSID_FILTER_HANDLER)==S_OK) && (UnregisterHandler(CLSID_PERSISTENT_HANDLER)==S_OK))?S_OK:E_FAIL;
1356     }
1357 
1358     //---------------------------
1359     //    add or remove an entry to DllsToRegister entry of Indexing
1360 	//    Filter to let Indexing Service register our filter automatically
1361 	//	  each time.
1362     //---------------------------
1363 	HRESULT AddOrRemoveDllsToRegisterList( const ::std::string & DllPath, bool isAdd )
1364 	{
1365 		char DllsToRegisterList[4096];
1366 		if (QueryRegistryKey(HKEY_LOCAL_MACHINE,
1367 			                 INDEXING_FILTER_DLLSTOREGISTER,
1368 							 "DLLsToRegister",
1369 							 DllsToRegisterList,
1370 							 4096))
1371 		{
1372 			char * pChar = DllsToRegisterList;
1373 			for ( ; *pChar != '\0' || *(pChar +1) != '\0'; pChar++)
1374 				if ( *pChar == '\0')
1375 					*pChar = ';';
1376 			*pChar = ';';
1377 			*(pChar+1) = '\0';
1378 
1379 			::std::string DllList(DllsToRegisterList);
1380 			if ( ( isAdd )&&( DllList.find( DllPath ) == ::std::string::npos ) )
1381 				DllList.append( DllPath );
1382 			else if ( ( !isAdd )&&( DllList.find( DllPath ) != ::std::string::npos ) )
1383 				DllList.erase( DllList.find( DllPath )-1, DllPath.length()+1 );
1384 			else
1385 				return S_OK;
1386 
1387 			pChar = DllsToRegisterList;
1388 			for ( size_t nChar = 0; nChar < DllList.length(); pChar++,nChar++)
1389 			{
1390 				if ( DllList[nChar] == ';')
1391 					*pChar = '\0';
1392 				else
1393 					*pChar = DllList[nChar];
1394 			}
1395 			*pChar = *( pChar+1 ) ='\0';
1396 
1397 			HKEY hSubKey;
1398 			int rc = RegCreateKeyExA(HKEY_LOCAL_MACHINE,
1399 									INDEXING_FILTER_DLLSTOREGISTER,
1400 									0,
1401 									"",
1402 									REG_OPTION_NON_VOLATILE,
1403 									KEY_WRITE,
1404 									0,
1405 									&hSubKey,
1406 									0);
1407 
1408 			if (ERROR_SUCCESS == rc)
1409 			{
1410 				rc = RegSetValueExA( hSubKey,
1411 									"DLLsToRegister",
1412 									0,
1413 									REG_MULTI_SZ,
1414 									reinterpret_cast<const BYTE*>(DllsToRegisterList),
1415 									DllList.length() + 2);
1416 
1417 				RegCloseKey(hSubKey);
1418 			}
1419 
1420 			return (ERROR_SUCCESS == rc)?S_OK:E_FAIL;
1421 		}
1422 
1423 		return S_OK;
1424 	}
1425 
1426 } // namespace /* private */
1427 
1428 STDAPI DllRegisterServer()
1429 {
1430     /*
1431 	TCHAR ModuleFileName[MAX_PATH];
1432 
1433 	GetModuleFileName(
1434 		GetModuleHandle(MODULE_NAME_FILTER),
1435 		ModuleFileName,
1436 		sizeof(ModuleFileName));
1437 
1438 	HRESULT hr = S_OK;
1439 
1440 
1441 // register search handler
1442 #ifdef UNICODE
1443 	if (FAILED(RegisterSearchHandler(WStringToString(ModuleFileName).c_str())))
1444 		hr = E_FAIL;
1445 	if (FAILED(AddOrRemoveDllsToRegisterList(WStringToString(ModuleFileName).c_str(), true)))
1446 		hr = E_FAIL;
1447 #else
1448     if (FAILED(RegisterSearchHandler(ModuleFileName)))
1449 		hr = E_FAIL;
1450 	if (FAILED(AddOrRemoveDllsToRegisterList(ModuleFileName, true)))
1451 		hr = E_FAIL;
1452 #endif
1453 
1454 
1455 	return hr;
1456 	*/
1457 	return S_OK;
1458 }
1459 
1460 //---------------------------
1461 //
1462 //---------------------------
1463 
1464 STDAPI DllUnregisterServer()
1465 {
1466     /*
1467 	TCHAR ModuleFileName[MAX_PATH];
1468 
1469 	GetModuleFileName(
1470 		GetModuleHandle(MODULE_NAME_FILTER),
1471 		ModuleFileName,
1472 		sizeof(ModuleFileName));
1473 
1474 	HRESULT hr = S_OK;
1475 
1476 	// unregister search handler
1477 	if (FAILED(UnregisterSearchHandler()))
1478 		hr = E_FAIL;
1479 
1480 #ifdef UNICODE
1481 	if (FAILED(AddOrRemoveDllsToRegisterList(WStringToString(ModuleFileName).c_str(),false)))
1482 		hr = E_FAIL;
1483 #else
1484 	if (FAILED(AddOrRemoveDllsToRegisterList(ModuleFileName, false)))
1485 		hr = E_FAIL;
1486 #endif
1487 
1488 	return hr;
1489 	*/
1490 	return S_OK;
1491 }
1492