Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygensearch.c
Go to the documentation of this file.
00001 /* 00002 * Copyright 2010 Erich Hoover 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2.1 of the License, or (at your option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public 00015 * License along with this library; if not, write to the Free Software 00016 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00017 */ 00018 00019 #define NONAMELESSUNION 00020 #define NONAMELESSSTRUCT 00021 00022 #include "hhctrl.h" 00023 #include "stream.h" 00024 00025 #include "wine/debug.h" 00026 00027 WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp); 00028 00029 static SearchItem *SearchCHM_Folder(SearchItem *item, IStorage *pStorage, 00030 const WCHAR *folder, const char *needle); 00031 00032 /* Allocate a ListView entry for a search result. */ 00033 static SearchItem *alloc_search_item(WCHAR *title, const WCHAR *filename) 00034 { 00035 int filename_len = filename ? (strlenW(filename)+1)*sizeof(WCHAR) : 0; 00036 SearchItem *item; 00037 00038 item = heap_alloc_zero(sizeof(SearchItem)); 00039 if(filename) 00040 { 00041 item->filename = heap_alloc(filename_len); 00042 memcpy(item->filename, filename, filename_len); 00043 } 00044 item->title = title; /* Already allocated */ 00045 00046 return item; 00047 } 00048 00049 /* Fill the ListView object corresponding to the found Search tab items */ 00050 static void fill_search_tree(HWND hwndList, SearchItem *item) 00051 { 00052 int index = 0; 00053 LVITEMW lvi; 00054 00055 SendMessageW(hwndList, LVM_DELETEALLITEMS, 0, 0); 00056 while(item) { 00057 TRACE("list debug: %s\n", debugstr_w(item->filename)); 00058 00059 memset(&lvi, 0, sizeof(lvi)); 00060 lvi.iItem = index++; 00061 lvi.mask = LVIF_TEXT|LVIF_PARAM; 00062 lvi.cchTextMax = strlenW(item->title)+1; 00063 lvi.pszText = item->title; 00064 lvi.lParam = (LPARAM)item; 00065 item->id = (HTREEITEM)SendMessageW(hwndList, LVM_INSERTITEMW, 0, (LPARAM)&lvi); 00066 item = item->next; 00067 } 00068 } 00069 00070 /* Search the CHM storage stream (an HTML file) for the requested text. 00071 * 00072 * Before searching the HTML file all HTML tags are removed so that only 00073 * the content of the document is scanned. If the search string is found 00074 * then the title of the document is returned. 00075 */ 00076 static WCHAR *SearchCHM_File(IStorage *pStorage, const WCHAR *file, const char *needle) 00077 { 00078 char *buffer = heap_alloc(BLOCK_SIZE); 00079 strbuf_t content, node, node_name; 00080 IStream *temp_stream = NULL; 00081 DWORD i, buffer_size = 0; 00082 WCHAR *title = NULL; 00083 BOOL found = FALSE; 00084 stream_t stream; 00085 HRESULT hres; 00086 00087 hres = IStorage_OpenStream(pStorage, file, NULL, STGM_READ, 0, &temp_stream); 00088 if(FAILED(hres)) { 00089 FIXME("Could not open '%s' stream: %08x\n", debugstr_w(file), hres); 00090 goto cleanup; 00091 } 00092 00093 strbuf_init(&node); 00094 strbuf_init(&content); 00095 strbuf_init(&node_name); 00096 00097 stream_init(&stream, temp_stream); 00098 00099 /* Remove all HTML formatting and record the title */ 00100 while(next_node(&stream, &node)) { 00101 get_node_name(&node, &node_name); 00102 00103 if(next_content(&stream, &content) && content.len > 1) 00104 { 00105 char *text = &content.buf[1]; 00106 int textlen = content.len-1; 00107 00108 if(!strcasecmp(node_name.buf, "title")) 00109 { 00110 int wlen = MultiByteToWideChar(CP_ACP, 0, text, textlen, NULL, 0); 00111 title = heap_alloc((wlen+1)*sizeof(WCHAR)); 00112 MultiByteToWideChar(CP_ACP, 0, text, textlen, title, wlen); 00113 title[wlen] = 0; 00114 } 00115 00116 buffer = heap_realloc(buffer, buffer_size + textlen + 1); 00117 memcpy(&buffer[buffer_size], text, textlen); 00118 buffer[buffer_size + textlen] = '\0'; 00119 buffer_size += textlen; 00120 } 00121 00122 strbuf_zero(&node); 00123 strbuf_zero(&content); 00124 } 00125 00126 /* Convert the buffer to lower case for comparison against the 00127 * requested text (already in lower case). 00128 */ 00129 for(i=0;i<buffer_size;i++) 00130 buffer[i] = tolower(buffer[i]); 00131 00132 /* Search the decoded buffer for the requested text */ 00133 if(strstr(buffer, needle)) 00134 found = TRUE; 00135 00136 strbuf_free(&node); 00137 strbuf_free(&content); 00138 strbuf_free(&node_name); 00139 00140 cleanup: 00141 heap_free(buffer); 00142 if(temp_stream) 00143 IStream_Release(temp_stream); 00144 if(!found) 00145 { 00146 heap_free(title); 00147 return NULL; 00148 } 00149 return title; 00150 } 00151 00152 /* Search all children of a CHM storage object for the requested text and 00153 * return the last found search item. 00154 */ 00155 static SearchItem *SearchCHM_Storage(SearchItem *item, IStorage *pStorage, 00156 const char *needle) 00157 { 00158 const WCHAR szHTMext[] = {'.','h','t','m',0}; 00159 IEnumSTATSTG *elem = NULL; 00160 WCHAR *filename = NULL; 00161 STATSTG entries; 00162 HRESULT hres; 00163 ULONG retr; 00164 00165 hres = IStorage_EnumElements(pStorage, 0, NULL, 0, &elem); 00166 if(hres != S_OK) 00167 { 00168 FIXME("Could not enumerate '/' storage elements: %08x\n", hres); 00169 return NULL; 00170 } 00171 while (IEnumSTATSTG_Next(elem, 1, &entries, &retr) == NOERROR) 00172 { 00173 switch(entries.type) { 00174 case STGTY_STORAGE: 00175 item = SearchCHM_Folder(item, pStorage, entries.pwcsName, needle); 00176 break; 00177 case STGTY_STREAM: 00178 filename = entries.pwcsName; 00179 while(strchrW(filename, '/')) 00180 filename = strchrW(filename, '/')+1; 00181 if(strstrW(filename, szHTMext)) 00182 { 00183 WCHAR *title = SearchCHM_File(pStorage, filename, needle); 00184 00185 if(title) 00186 { 00187 item->next = alloc_search_item(title, entries.pwcsName); 00188 item = item->next; 00189 } 00190 } 00191 break; 00192 default: 00193 FIXME("Unhandled IStorage stream element.\n"); 00194 } 00195 } 00196 return item; 00197 } 00198 00199 /* Open a CHM storage object (folder) by name and find all items with 00200 * the requested text. The last found item is returned. 00201 */ 00202 static SearchItem *SearchCHM_Folder(SearchItem *item, IStorage *pStorage, 00203 const WCHAR *folder, const char *needle) 00204 { 00205 IStorage *temp_storage = NULL; 00206 HRESULT hres; 00207 00208 hres = IStorage_OpenStorage(pStorage, folder, NULL, STGM_READ, NULL, 0, &temp_storage); 00209 if(FAILED(hres)) 00210 { 00211 FIXME("Could not open '%s' storage object: %08x\n", debugstr_w(folder), hres); 00212 return NULL; 00213 } 00214 item = SearchCHM_Storage(item, temp_storage, needle); 00215 00216 IStorage_Release(temp_storage); 00217 return item; 00218 } 00219 00220 /* Search the entire CHM file for the requested text and add all of 00221 * the found items to a ListView for the user to choose the item 00222 * they want. 00223 */ 00224 void InitSearch(HHInfo *info, const char *needle) 00225 { 00226 CHMInfo *chm = info->pCHMInfo; 00227 SearchItem *root_item = alloc_search_item(NULL, NULL); 00228 00229 SearchCHM_Storage(root_item, chm->pStorage, needle); 00230 fill_search_tree(info->search.hwndList, root_item->next); 00231 if(info->search.root) 00232 ReleaseSearch(info); 00233 info->search.root = root_item; 00234 } 00235 00236 /* Free all of the found Search items. */ 00237 void ReleaseSearch(HHInfo *info) 00238 { 00239 SearchItem *item = info->search.root; 00240 00241 info->search.root = NULL; 00242 while(item) { 00243 heap_free(item->filename); 00244 item = item->next; 00245 } 00246 } Generated on Fri May 25 2012 04:21:59 for ReactOS by
1.7.6.1
|