makefiles: Generate the config.status dependency as part of the makefile dependencies.
[wine/multimedia.git] / dlls / hhctrl.ocx / index.c
blobdd61fe3fa3c9fcec5e459d1fc2fe7baa5ad18d27
1 /*
2 * Copyright 2007 Jacek Caban for CodeWeavers
3 * Copyright 2010 Erich Hoover
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #define NONAMELESSUNION
21 #define NONAMELESSSTRUCT
23 #include "hhctrl.h"
24 #include "stream.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp);
30 /* Fill the TreeView object corresponding to the Index items */
31 static void fill_index_tree(HWND hwnd, IndexItem *item)
33 int index = 0;
34 LVITEMW lvi;
36 while(item) {
37 TRACE("tree debug: %s\n", debugstr_w(item->keyword));
39 memset(&lvi, 0, sizeof(lvi));
40 lvi.iItem = index++;
41 lvi.mask = LVIF_TEXT|LVIF_PARAM;
42 lvi.cchTextMax = strlenW(item->keyword)+1;
43 lvi.pszText = item->keyword;
44 lvi.lParam = (LPARAM)item;
45 item->id = (HTREEITEM)SendMessageW(hwnd, LVM_INSERTITEMW, 0, (LPARAM)&lvi);
46 item = item->next;
50 /* Parse the attributes correspond to a list item, including sub-topics.
52 * Each list item has, at minimum, a param of type "keyword" and two
53 * parameters corresponding to a "sub-topic." For each sub-topic there
54 * must be a "name" param and a "local" param, if there is only one
55 * sub-topic then there isn't really a sub-topic, the index will jump
56 * directly to the requested item.
58 static void parse_index_obj_node_param(IndexItem *item, const char *text)
60 const char *ptr;
61 LPWSTR *param;
62 int len, wlen;
64 ptr = get_attr(text, "name", &len);
65 if(!ptr) {
66 WARN("name attr not found\n");
67 return;
70 /* Allocate a new sub-item, either on the first run or whenever a
71 * sub-topic has filled out both the "name" and "local" params.
73 if(item->itemFlags == 0x11 && (!strncasecmp("name", ptr, len) || !strncasecmp("local", ptr, len))) {
74 item->nItems++;
75 item->items = heap_realloc(item->items, sizeof(IndexSubItem)*item->nItems);
76 item->items[item->nItems-1].name = NULL;
77 item->items[item->nItems-1].local = NULL;
78 item->itemFlags = 0x00;
80 if(!strncasecmp("keyword", ptr, len)) {
81 param = &item->keyword;
82 }else if(!strncasecmp("name", ptr, len)) {
83 item->itemFlags |= 0x01;
84 param = &item->items[item->nItems-1].name;
85 }else if(!strncasecmp("local", ptr, len)) {
86 item->itemFlags |= 0x10;
87 param = &item->items[item->nItems-1].local;
88 }else {
89 WARN("unhandled param %s\n", debugstr_an(ptr, len));
90 return;
93 ptr = get_attr(text, "value", &len);
94 if(!ptr) {
95 WARN("value attr not found\n");
96 return;
99 wlen = MultiByteToWideChar(CP_ACP, 0, ptr, len, NULL, 0);
100 *param = heap_alloc((wlen+1)*sizeof(WCHAR));
101 MultiByteToWideChar(CP_ACP, 0, ptr, len, *param, wlen);
102 (*param)[wlen] = 0;
105 /* Parse the object tag corresponding to a list item.
107 * At this step we look for all of the "param" child tags, using this information
108 * to build up the information about the list item. When we reach the </object>
109 * tag we know that we've finished parsing this list item.
111 static IndexItem *parse_index_sitemap_object(HHInfo *info, stream_t *stream)
113 strbuf_t node, node_name;
114 IndexItem *item;
116 strbuf_init(&node);
117 strbuf_init(&node_name);
119 item = heap_alloc_zero(sizeof(IndexItem));
120 item->nItems = 0;
121 item->items = heap_alloc_zero(0);
122 item->itemFlags = 0x11;
124 while(next_node(stream, &node)) {
125 get_node_name(&node, &node_name);
127 TRACE("%s\n", node.buf);
129 if(!strcasecmp(node_name.buf, "param")) {
130 parse_index_obj_node_param(item, node.buf);
131 }else if(!strcasecmp(node_name.buf, "/object")) {
132 break;
133 }else {
134 WARN("Unhandled tag! %s\n", node_name.buf);
137 strbuf_zero(&node);
140 strbuf_free(&node);
141 strbuf_free(&node_name);
143 return item;
146 /* Parse the HTML list item node corresponding to a specific help entry.
148 * At this stage we look for the only child tag we expect to find under
149 * the list item: the <OBJECT> tag. We also only expect to find object
150 * tags with the "type" attribute set to "text/sitemap".
152 static IndexItem *parse_li(HHInfo *info, stream_t *stream)
154 strbuf_t node, node_name;
155 IndexItem *ret = NULL;
157 strbuf_init(&node);
158 strbuf_init(&node_name);
160 while(next_node(stream, &node)) {
161 get_node_name(&node, &node_name);
163 TRACE("%s\n", node.buf);
165 if(!strcasecmp(node_name.buf, "object")) {
166 const char *ptr;
167 int len;
169 static const char sz_text_sitemap[] = "text/sitemap";
171 ptr = get_attr(node.buf, "type", &len);
173 if(ptr && len == sizeof(sz_text_sitemap)-1
174 && !memcmp(ptr, sz_text_sitemap, len)) {
175 ret = parse_index_sitemap_object(info, stream);
176 break;
178 }else {
179 WARN("Unhandled tag! %s\n", node_name.buf);
182 strbuf_zero(&node);
185 strbuf_free(&node);
186 strbuf_free(&node_name);
188 return ret;
191 /* Parse the HTML Help page corresponding to all of the Index items.
193 * At this high-level stage we locate out each HTML list item tag.
194 * Since there is no end-tag for the <LI> item, we must hope that
195 * the <LI> entry is parsed correctly or tags might get lost.
197 static void parse_hhindex(HHInfo *info, IStream *str, IndexItem *item)
199 stream_t stream;
200 strbuf_t node, node_name;
202 strbuf_init(&node);
203 strbuf_init(&node_name);
205 stream_init(&stream, str);
207 while(next_node(&stream, &node)) {
208 get_node_name(&node, &node_name);
210 TRACE("%s\n", node.buf);
212 if(!strcasecmp(node_name.buf, "li")) {
213 item->next = parse_li(info, &stream);
214 item->next->merge = item->merge;
215 item = item->next;
216 }else {
217 WARN("Unhandled tag! %s\n", node_name.buf);
220 strbuf_zero(&node);
223 strbuf_free(&node);
224 strbuf_free(&node_name);
227 /* Initialize the HTML Help Index tab */
228 void InitIndex(HHInfo *info)
230 IStream *stream;
232 info->index = heap_alloc_zero(sizeof(IndexItem));
233 info->index->nItems = 0;
234 SetChmPath(&info->index->merge, info->pCHMInfo->szFile, info->WinType.pszIndex);
236 stream = GetChmStream(info->pCHMInfo, info->pCHMInfo->szFile, &info->index->merge);
237 if(!stream) {
238 TRACE("Could not get index stream\n");
239 return;
242 parse_hhindex(info, stream, info->index);
243 IStream_Release(stream);
245 fill_index_tree(info->tabs[TAB_INDEX].hwnd, info->index->next);
248 /* Free all of the Index items, including all of the "sub-items" that
249 * correspond to different sub-topics.
251 void ReleaseIndex(HHInfo *info)
253 IndexItem *item = info->index, *next;
254 int i;
256 /* Note: item->merge is identical for all items, only free once */
257 heap_free(item->merge.chm_file);
258 heap_free(item->merge.chm_index);
259 while(item) {
260 next = item->next;
262 heap_free(item->keyword);
263 for(i=0;i<item->nItems;i++) {
264 heap_free(item->items[i].name);
265 heap_free(item->items[i].local);
267 heap_free(item->items);
269 item = next;