Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenindex.c
Go to the documentation of this file.
00001 /* 00002 * Copyright 2007 Jacek Caban for CodeWeavers 00003 * Copyright 2010 Erich Hoover 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Lesser General Public 00007 * License as published by the Free Software Foundation; either 00008 * version 2.1 of the License, or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Lesser General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public 00016 * License along with this library; if not, write to the Free Software 00017 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00018 */ 00019 00020 #define NONAMELESSUNION 00021 #define NONAMELESSSTRUCT 00022 00023 #include "hhctrl.h" 00024 #include "stream.h" 00025 00026 #include "wine/debug.h" 00027 00028 WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp); 00029 00030 /* Fill the TreeView object corresponding to the Index items */ 00031 static void fill_index_tree(HWND hwnd, IndexItem *item) 00032 { 00033 int index = 0; 00034 LVITEMW lvi; 00035 00036 while(item) { 00037 TRACE("tree debug: %s\n", debugstr_w(item->keyword)); 00038 00039 if(!item->keyword) 00040 { 00041 FIXME("HTML Help index item has no keyword.\n"); 00042 item = item->next; 00043 continue; 00044 } 00045 memset(&lvi, 0, sizeof(lvi)); 00046 lvi.iItem = index++; 00047 lvi.mask = LVIF_TEXT|LVIF_PARAM|LVIF_INDENT; 00048 lvi.iIndent = item->indentLevel; 00049 lvi.cchTextMax = strlenW(item->keyword)+1; 00050 lvi.pszText = item->keyword; 00051 lvi.lParam = (LPARAM)item; 00052 item->id = (HTREEITEM)SendMessageW(hwnd, LVM_INSERTITEMW, 0, (LPARAM)&lvi); 00053 item = item->next; 00054 } 00055 } 00056 00057 /* Parse the attributes correspond to a list item, including sub-topics. 00058 * 00059 * Each list item has, at minimum, a param of type "keyword" and two 00060 * parameters corresponding to a "sub-topic." For each sub-topic there 00061 * must be a "name" param and a "local" param, if there is only one 00062 * sub-topic then there isn't really a sub-topic, the index will jump 00063 * directly to the requested item. 00064 */ 00065 static void parse_index_obj_node_param(IndexItem *item, const char *text) 00066 { 00067 const char *ptr; 00068 LPWSTR *param; 00069 int len, wlen; 00070 00071 ptr = get_attr(text, "name", &len); 00072 if(!ptr) { 00073 WARN("name attr not found\n"); 00074 return; 00075 } 00076 00077 /* Allocate a new sub-item, either on the first run or whenever a 00078 * sub-topic has filled out both the "name" and "local" params. 00079 */ 00080 if(item->itemFlags == 0x11 && (!strncasecmp("name", ptr, len) || !strncasecmp("local", ptr, len))) { 00081 item->nItems++; 00082 item->items = heap_realloc(item->items, sizeof(IndexSubItem)*item->nItems); 00083 item->items[item->nItems-1].name = NULL; 00084 item->items[item->nItems-1].local = NULL; 00085 item->itemFlags = 0x00; 00086 } 00087 if(!strncasecmp("keyword", ptr, len)) { 00088 param = &item->keyword; 00089 }else if(!item->keyword && !strncasecmp("name", ptr, len)) { 00090 /* Some HTML Help index files use an additional "name" parameter 00091 * rather than the "keyword" parameter. In this case, the first 00092 * occurance of the "name" parameter is the keyword. 00093 */ 00094 param = &item->keyword; 00095 }else if(!strncasecmp("name", ptr, len)) { 00096 item->itemFlags |= 0x01; 00097 param = &item->items[item->nItems-1].name; 00098 }else if(!strncasecmp("local", ptr, len)) { 00099 item->itemFlags |= 0x10; 00100 param = &item->items[item->nItems-1].local; 00101 }else { 00102 WARN("unhandled param %s\n", debugstr_an(ptr, len)); 00103 return; 00104 } 00105 00106 ptr = get_attr(text, "value", &len); 00107 if(!ptr) { 00108 WARN("value attr not found\n"); 00109 return; 00110 } 00111 00112 wlen = MultiByteToWideChar(CP_ACP, 0, ptr, len, NULL, 0); 00113 *param = heap_alloc((wlen+1)*sizeof(WCHAR)); 00114 MultiByteToWideChar(CP_ACP, 0, ptr, len, *param, wlen); 00115 (*param)[wlen] = 0; 00116 } 00117 00118 /* Parse the object tag corresponding to a list item. 00119 * 00120 * At this step we look for all of the "param" child tags, using this information 00121 * to build up the information about the list item. When we reach the </object> 00122 * tag we know that we've finished parsing this list item. 00123 */ 00124 static IndexItem *parse_index_sitemap_object(HHInfo *info, stream_t *stream) 00125 { 00126 strbuf_t node, node_name; 00127 IndexItem *item; 00128 00129 strbuf_init(&node); 00130 strbuf_init(&node_name); 00131 00132 item = heap_alloc_zero(sizeof(IndexItem)); 00133 item->nItems = 0; 00134 item->items = heap_alloc_zero(0); 00135 item->itemFlags = 0x11; 00136 00137 while(next_node(stream, &node)) { 00138 get_node_name(&node, &node_name); 00139 00140 TRACE("%s\n", node.buf); 00141 00142 if(!strcasecmp(node_name.buf, "param")) { 00143 parse_index_obj_node_param(item, node.buf); 00144 }else if(!strcasecmp(node_name.buf, "/object")) { 00145 break; 00146 }else { 00147 WARN("Unhandled tag! %s\n", node_name.buf); 00148 } 00149 00150 strbuf_zero(&node); 00151 } 00152 00153 strbuf_free(&node); 00154 strbuf_free(&node_name); 00155 00156 return item; 00157 } 00158 00159 /* Parse the HTML list item node corresponding to a specific help entry. 00160 * 00161 * At this stage we look for the only child tag we expect to find under 00162 * the list item: the <OBJECT> tag. We also only expect to find object 00163 * tags with the "type" attribute set to "text/sitemap". 00164 */ 00165 static IndexItem *parse_li(HHInfo *info, stream_t *stream) 00166 { 00167 strbuf_t node, node_name; 00168 IndexItem *ret = NULL; 00169 00170 strbuf_init(&node); 00171 strbuf_init(&node_name); 00172 00173 while(next_node(stream, &node)) { 00174 get_node_name(&node, &node_name); 00175 00176 TRACE("%s\n", node.buf); 00177 00178 if(!strcasecmp(node_name.buf, "object")) { 00179 const char *ptr; 00180 int len; 00181 00182 static const char sz_text_sitemap[] = "text/sitemap"; 00183 00184 ptr = get_attr(node.buf, "type", &len); 00185 00186 if(ptr && len == sizeof(sz_text_sitemap)-1 00187 && !memcmp(ptr, sz_text_sitemap, len)) { 00188 ret = parse_index_sitemap_object(info, stream); 00189 break; 00190 } 00191 }else { 00192 WARN("Unhandled tag! %s\n", node_name.buf); 00193 } 00194 00195 strbuf_zero(&node); 00196 } 00197 00198 strbuf_free(&node); 00199 strbuf_free(&node_name); 00200 00201 return ret; 00202 } 00203 00204 /* Parse the HTML Help page corresponding to all of the Index items. 00205 * 00206 * At this high-level stage we locate out each HTML list item tag. 00207 * Since there is no end-tag for the <LI> item, we must hope that 00208 * the <LI> entry is parsed correctly or tags might get lost. 00209 * 00210 * Within each entry it is also possible to encounter an additional 00211 * <UL> tag. When this occurs the tag indicates that the topics 00212 * contained within it are related to the parent <LI> topic and 00213 * should be inset by an indent. 00214 */ 00215 static void parse_hhindex(HHInfo *info, IStream *str, IndexItem *item) 00216 { 00217 stream_t stream; 00218 strbuf_t node, node_name; 00219 int indent_level = -1; 00220 00221 strbuf_init(&node); 00222 strbuf_init(&node_name); 00223 00224 stream_init(&stream, str); 00225 00226 while(next_node(&stream, &node)) { 00227 get_node_name(&node, &node_name); 00228 00229 TRACE("%s\n", node.buf); 00230 00231 if(!strcasecmp(node_name.buf, "li")) { 00232 item->next = parse_li(info, &stream); 00233 item->next->merge = item->merge; 00234 item = item->next; 00235 item->indentLevel = indent_level; 00236 }else if(!strcasecmp(node_name.buf, "ul")) { 00237 indent_level++; 00238 }else if(!strcasecmp(node_name.buf, "/ul")) { 00239 indent_level--; 00240 }else { 00241 WARN("Unhandled tag! %s\n", node_name.buf); 00242 } 00243 00244 strbuf_zero(&node); 00245 } 00246 00247 strbuf_free(&node); 00248 strbuf_free(&node_name); 00249 } 00250 00251 /* Initialize the HTML Help Index tab */ 00252 void InitIndex(HHInfo *info) 00253 { 00254 IStream *stream; 00255 00256 info->index = heap_alloc_zero(sizeof(IndexItem)); 00257 info->index->nItems = 0; 00258 SetChmPath(&info->index->merge, info->pCHMInfo->szFile, info->WinType.pszIndex); 00259 00260 stream = GetChmStream(info->pCHMInfo, info->pCHMInfo->szFile, &info->index->merge); 00261 if(!stream) { 00262 TRACE("Could not get index stream\n"); 00263 return; 00264 } 00265 00266 parse_hhindex(info, stream, info->index); 00267 IStream_Release(stream); 00268 00269 fill_index_tree(info->tabs[TAB_INDEX].hwnd, info->index->next); 00270 } 00271 00272 /* Free all of the Index items, including all of the "sub-items" that 00273 * correspond to different sub-topics. 00274 */ 00275 void ReleaseIndex(HHInfo *info) 00276 { 00277 IndexItem *item = info->index, *next; 00278 int i; 00279 00280 /* Note: item->merge is identical for all items, only free once */ 00281 heap_free(item->merge.chm_file); 00282 heap_free(item->merge.chm_index); 00283 while(item) { 00284 next = item->next; 00285 00286 heap_free(item->keyword); 00287 for(i=0;i<item->nItems;i++) { 00288 heap_free(item->items[i].name); 00289 heap_free(item->items[i].local); 00290 } 00291 heap_free(item->items); 00292 00293 item = next; 00294 } 00295 } Generated on Sat May 26 2012 04:22:22 for ReactOS by
1.7.6.1
|