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