mirror of
https://github.com/reactos/reactos.git
synced 2025-08-02 04:35:53 +00:00
[HHCTRL.OCX]
sync hhctrl.ocx to wine 1.1.40 svn path=/trunk/; revision=45990
This commit is contained in:
parent
fcaa30c541
commit
96363863d3
31 changed files with 1590 additions and 202 deletions
|
@ -21,6 +21,8 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
LANGUAGE LANG_CZECH, SUBLANG_DEFAULT
|
||||
|
||||
/* Czech strings in CP1250 */
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
LANGUAGE LANG_DANISH, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
#pragma code_page(65001)
|
||||
|
||||
LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL
|
||||
|
||||
STRINGTABLE
|
||||
|
@ -33,14 +37,14 @@ STRINGTABLE
|
|||
BEGIN
|
||||
IDTB_EXPAND "Anzeigen"
|
||||
IDTB_CONTRACT "Verstecken"
|
||||
IDTB_STOP "Stop"
|
||||
IDTB_STOP "Stopp"
|
||||
IDTB_REFRESH "Aktualisieren"
|
||||
IDTB_BACK "Zurück"
|
||||
IDTB_BACK "Zurück"
|
||||
IDTB_HOME "Startseite"
|
||||
IDTB_SYNC "Synchronisieren"
|
||||
IDTB_PRINT "Drucken"
|
||||
IDTB_OPTIONS "Einstellungen"
|
||||
IDTB_FORWARD "Vorwärts"
|
||||
IDTB_FORWARD "Vorwärts"
|
||||
IDTB_NOTES "IDTB_NOTES"
|
||||
IDTB_BROWSE_FWD "IDTB_BROWSE_FWD"
|
||||
IDTB_BROWSE_BACK "IDT_BROWSE_BACK"
|
||||
|
@ -52,7 +56,7 @@ BEGIN
|
|||
IDTB_JUMP1 "Sprung1"
|
||||
IDTB_JUMP2 "Sprung2"
|
||||
IDTB_CUSTOMIZE "Anpassen"
|
||||
IDTB_ZOOM "Vergrößern"
|
||||
IDTB_ZOOM "Vergrößern"
|
||||
IDTB_TOC_NEXT "IDTB_TOC_NEXT"
|
||||
IDTB_TOC_PREV "IDTB_TOC_PREV"
|
||||
END
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
LANGUAGE LANG_GREEK, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE
|
||||
|
@ -56,3 +58,13 @@ BEGIN
|
|||
IDTB_TOC_NEXT "IDTB_TOC_NEXT"
|
||||
IDTB_TOC_PREV "IDTB_TOC_PREV"
|
||||
END
|
||||
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_CONTENTS "&Contents"
|
||||
IDS_INDEX "I&ndex"
|
||||
IDS_SEARCH "&Search"
|
||||
IDS_FAVORITES "Favour&ites"
|
||||
END
|
||||
|
|
63
reactos/dll/win32/hhctrl.ocx/Es.rc
Normal file
63
reactos/dll/win32/hhctrl.ocx/Es.rc
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* HTML Help resources
|
||||
* Spanish Language Support
|
||||
*
|
||||
* Copyright 2010 José Manuel Ferrer Ortiz
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
/* UTF-8 */
|
||||
#pragma code_page(65001)
|
||||
|
||||
LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_CONTENTS "&Contenido"
|
||||
IDS_INDEX "Í&ndice"
|
||||
IDS_SEARCH "&Buscar"
|
||||
IDS_FAVORITES "Favor&itos"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDTB_EXPAND "Mostrar"
|
||||
IDTB_CONTRACT "Ocultar"
|
||||
IDTB_STOP "Parar"
|
||||
IDTB_REFRESH "Recargar"
|
||||
IDTB_BACK "Atrás"
|
||||
IDTB_HOME "Inicio"
|
||||
IDTB_SYNC "Sincronizar"
|
||||
IDTB_PRINT "Imprimir"
|
||||
IDTB_OPTIONS "Opciones"
|
||||
IDTB_FORWARD "Adelante"
|
||||
IDTB_NOTES "IDTB_NOTES"
|
||||
IDTB_BROWSE_FWD "IDTB_BROWSE_FWD"
|
||||
IDTB_BROWSE_BACK "IDT_BROWSE_BACK"
|
||||
IDTB_CONTENTS "IDTB_CONTENTS"
|
||||
IDTB_INDEX "IDTB_INDEX"
|
||||
IDTB_SEARCH "IDTB_SEARCH"
|
||||
IDTB_HISTORY "IDTB_HISTORY"
|
||||
IDTB_FAVORITES "IDTB_FAVORITES"
|
||||
IDTB_JUMP1 "Jump1"
|
||||
IDTB_JUMP2 "Jump2"
|
||||
IDTB_CUSTOMIZE "Personalizar"
|
||||
IDTB_ZOOM "Zoom"
|
||||
IDTB_TOC_NEXT "IDTB_TOC_NEXT"
|
||||
IDTB_TOC_PREV "IDTB_TOC_PREV"
|
||||
END
|
|
@ -19,6 +19,8 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
LANGUAGE LANG_FINNISH, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE
|
||||
|
|
|
@ -19,6 +19,11 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
/* UTF-8 */
|
||||
#pragma code_page(65001)
|
||||
|
||||
LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
|
||||
|
||||
STRINGTABLE
|
||||
|
@ -33,9 +38,9 @@ STRINGTABLE
|
|||
BEGIN
|
||||
IDTB_EXPAND "Afficher"
|
||||
IDTB_CONTRACT "Cacher"
|
||||
IDTB_STOP "Arrêter"
|
||||
IDTB_STOP "Arrêter"
|
||||
IDTB_REFRESH "A&ctualiser"
|
||||
IDTB_BACK "Précédent"
|
||||
IDTB_BACK "Précédent"
|
||||
IDTB_HOME "Sommaire"
|
||||
IDTB_SYNC "Synchroniser"
|
||||
IDTB_PRINT "Imprimer"
|
||||
|
@ -49,8 +54,8 @@ BEGIN
|
|||
IDTB_SEARCH "IDTB_SEARCH"
|
||||
IDTB_HISTORY "IDTB_HISTORY"
|
||||
IDTB_FAVORITES "IDTB_FAVORITES"
|
||||
IDTB_JUMP1 "Jump1"
|
||||
IDTB_JUMP2 "Jump2"
|
||||
IDTB_JUMP1 "Saut1"
|
||||
IDTB_JUMP2 "Saut2"
|
||||
IDTB_CUSTOMIZE "Personnaliser"
|
||||
IDTB_ZOOM "Zoom"
|
||||
IDTB_TOC_NEXT "IDTB_TOC_NEXT"
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
LANGUAGE LANG_HUNGARIAN, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
/* UTF-8 */
|
||||
#pragma code_page(65001)
|
||||
|
||||
|
@ -59,5 +61,3 @@ BEGIN
|
|||
IDTB_TOC_NEXT "IDTB_TOC_NEXT"
|
||||
IDTB_TOC_PREV "IDTB_TOC_PREV"
|
||||
END
|
||||
|
||||
#pragma code_page(default)
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
LANGUAGE LANG_DUTCH, SUBLANG_NEUTRAL
|
||||
|
||||
STRINGTABLE
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
LANGUAGE LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL
|
||||
|
||||
STRINGTABLE
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
LANGUAGE LANG_POLISH, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
LANGUAGE LANG_PORTUGUESE, SUBLANG_NEUTRAL
|
||||
|
||||
STRINGTABLE
|
||||
|
|
|
@ -19,40 +19,45 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
/* UTF-8 */
|
||||
#pragma code_page(65001)
|
||||
|
||||
LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_CONTENTS "&Содержание"
|
||||
IDS_INDEX "&Оглавление"
|
||||
IDS_SEARCH "&Поиск"
|
||||
IDS_FAVORITES "&Избранное"
|
||||
IDS_CONTENTS "&Содержание"
|
||||
IDS_INDEX "&Оглавление"
|
||||
IDS_SEARCH "&Поиск"
|
||||
IDS_FAVORITES "&Избранное"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDTB_EXPAND "Показать"
|
||||
IDTB_CONTRACT "Спрятать"
|
||||
IDTB_STOP "Остановить"
|
||||
IDTB_REFRESH "Обновить"
|
||||
IDTB_BACK "Назад"
|
||||
IDTB_HOME "В начало"
|
||||
IDTB_SYNC "Синхронизировать"
|
||||
IDTB_PRINT "Печать"
|
||||
IDTB_OPTIONS "Настройки"
|
||||
IDTB_FORWARD "Вперёд"
|
||||
IDTB_NOTES "Записки"
|
||||
IDTB_BROWSE_FWD "Просмотр вперёд"
|
||||
IDTB_BROWSE_BACK "Просмотр назад"
|
||||
IDTB_CONTENTS "Содержание"
|
||||
IDTB_INDEX "Оглавление"
|
||||
IDTB_SEARCH "Поиск"
|
||||
IDTB_HISTORY "История"
|
||||
IDTB_FAVORITES "Избранное"
|
||||
IDTB_JUMP1 "Переход 1"
|
||||
IDTB_JUMP2 "Переход 2"
|
||||
IDTB_CUSTOMIZE "Персонализовать"
|
||||
IDTB_ZOOM "Масштаб"
|
||||
IDTB_TOC_NEXT "Следующая глава"
|
||||
IDTB_TOC_PREV "Предыдущая глава"
|
||||
IDTB_EXPAND "Показать"
|
||||
IDTB_CONTRACT "Спрятать"
|
||||
IDTB_STOP "Остановить"
|
||||
IDTB_REFRESH "Обновить"
|
||||
IDTB_BACK "Назад"
|
||||
IDTB_HOME "В начало"
|
||||
IDTB_SYNC "Синхронизировать"
|
||||
IDTB_PRINT "Печать"
|
||||
IDTB_OPTIONS "Настройки"
|
||||
IDTB_FORWARD "Вперёд"
|
||||
IDTB_NOTES "Записки"
|
||||
IDTB_BROWSE_FWD "Просмотр вперёд"
|
||||
IDTB_BROWSE_BACK "Просмотр назад"
|
||||
IDTB_CONTENTS "Содержание"
|
||||
IDTB_INDEX "Оглавление"
|
||||
IDTB_SEARCH "Поиск"
|
||||
IDTB_HISTORY "История"
|
||||
IDTB_FAVORITES "Избранное"
|
||||
IDTB_JUMP1 "Переход 1"
|
||||
IDTB_JUMP2 "Переход 2"
|
||||
IDTB_CUSTOMIZE "Персонализовать"
|
||||
IDTB_ZOOM "Масштаб"
|
||||
IDTB_TOC_NEXT "Следующая глава"
|
||||
IDTB_TOC_PREV "Предыдущая глава"
|
||||
END
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
#pragma code_page(65001)
|
||||
|
||||
LANGUAGE LANG_SLOVENIAN, SUBLANG_DEFAULT
|
||||
|
@ -58,5 +60,3 @@ BEGIN
|
|||
IDTB_TOC_NEXT "IDTB_TOC_NEXT"
|
||||
IDTB_TOC_PREV "IDTB_TOC_PREV"
|
||||
END
|
||||
|
||||
#pragma code_page(default)
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
LANGUAGE LANG_SWEDISH, SUBLANG_NEUTRAL
|
||||
|
||||
STRINGTABLE
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE
|
||||
|
|
75
reactos/dll/win32/hhctrl.ocx/Uk.rc
Normal file
75
reactos/dll/win32/hhctrl.ocx/Uk.rc
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* HTML Help resources
|
||||
* Ukrainian Language Support
|
||||
*
|
||||
* Copyright 2005 James Hawkins
|
||||
* Copyright 2007 Artem Reznikov
|
||||
* Copyright 2010 Igor Paliychuk
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
/* UTF-8 */
|
||||
#pragma code_page(65001)
|
||||
|
||||
LANGUAGE LANG_UKRAINIAN, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_CONTENTS "&Зміст"
|
||||
IDS_INDEX "&Вказівник"
|
||||
IDS_SEARCH "&Пошук"
|
||||
IDS_FAVORITES "&Обране"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDTB_EXPAND "Показувати"
|
||||
IDTB_CONTRACT "Приховати"
|
||||
IDTB_STOP "Зупинити"
|
||||
IDTB_REFRESH "Оновити"
|
||||
IDTB_BACK "Назад"
|
||||
IDTB_HOME "Додому"
|
||||
IDTB_SYNC "Синхронізувати"
|
||||
IDTB_PRINT "Друк"
|
||||
IDTB_OPTIONS "Параметри"
|
||||
IDTB_FORWARD "Вперед"
|
||||
IDTB_NOTES "IDTB_NOTES"
|
||||
IDTB_BROWSE_FWD "IDTB_BROWSE_FWD"
|
||||
IDTB_BROWSE_BACK "IDT_BROWSE_BACK"
|
||||
IDTB_CONTENTS "IDTB_CONTENTS"
|
||||
IDTB_INDEX "IDTB_INDEX"
|
||||
IDTB_SEARCH "IDTB_SEARCH"
|
||||
IDTB_HISTORY "IDTB_HISTORY"
|
||||
IDTB_FAVORITES "IDTB_FAVORITES"
|
||||
IDTB_JUMP1 "Jump1"
|
||||
IDTB_JUMP2 "Jump2"
|
||||
IDTB_CUSTOMIZE "Налаштування"
|
||||
IDTB_ZOOM "Збільшення"
|
||||
IDTB_TOC_NEXT "IDTB_TOC_NEXT"
|
||||
IDTB_TOC_PREV "IDTB_TOC_PREV"
|
||||
END
|
||||
|
||||
LANGUAGE LANG_UKRAINIAN, SUBLANG_NEUTRAL
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_CONTENTS "&Зміст"
|
||||
IDS_INDEX "&Вказівник"
|
||||
IDS_SEARCH "&Пошук"
|
||||
IDS_FAVORITES "&Обране"
|
||||
END
|
|
@ -18,6 +18,8 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
/* Chinese text is encoded in UTF-8 */
|
||||
#pragma code_page(65001)
|
||||
|
||||
|
@ -96,5 +98,3 @@ BEGIN
|
|||
IDTB_TOC_NEXT "後一項"
|
||||
IDTB_TOC_PREV "前一項"
|
||||
END
|
||||
|
||||
#pragma code_page(default)
|
||||
|
|
|
@ -38,12 +38,13 @@ static LPCSTR GetChmString(CHMInfo *chm, DWORD offset)
|
|||
return NULL;
|
||||
|
||||
if(chm->strings_size <= (offset >> BLOCK_BITS)) {
|
||||
chm->strings_size = (offset >> BLOCK_BITS)+1;
|
||||
if(chm->strings)
|
||||
chm->strings = heap_realloc_zero(chm->strings,
|
||||
chm->strings_size = ((offset >> BLOCK_BITS)+1)*sizeof(char*));
|
||||
chm->strings_size*sizeof(char*));
|
||||
else
|
||||
chm->strings = heap_alloc_zero(
|
||||
chm->strings_size = ((offset >> BLOCK_BITS)+1)*sizeof(char*));
|
||||
chm->strings_size*sizeof(char*));
|
||||
|
||||
}
|
||||
|
||||
|
@ -388,7 +389,6 @@ CHMInfo *OpenCHM(LPCWSTR szFile)
|
|||
WARN("Could not open storage: %08x\n", hres);
|
||||
return CloseCHM(ret);
|
||||
}
|
||||
|
||||
hres = IStorage_OpenStream(ret->pStorage, wszSTRINGS, NULL, STGM_READ, 0,
|
||||
&ret->strings_stream);
|
||||
if(FAILED(hres)) {
|
||||
|
|
|
@ -20,13 +20,12 @@
|
|||
#define NONAMELESSSTRUCT
|
||||
|
||||
#include "hhctrl.h"
|
||||
#include "stream.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp);
|
||||
|
||||
#define BLOCK_SIZE 0x1000
|
||||
|
||||
typedef enum {
|
||||
INSERT_NEXT,
|
||||
INSERT_CHILD
|
||||
|
@ -50,134 +49,6 @@ static void free_content_item(ContentItem *item)
|
|||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char *buf;
|
||||
int size;
|
||||
int len;
|
||||
} strbuf_t;
|
||||
|
||||
static void strbuf_init(strbuf_t *buf)
|
||||
{
|
||||
buf->size = 8;
|
||||
buf->len = 0;
|
||||
buf->buf = heap_alloc(buf->size);
|
||||
}
|
||||
|
||||
static void strbuf_zero(strbuf_t *buf)
|
||||
{
|
||||
buf->len = 0;
|
||||
}
|
||||
|
||||
static void strbuf_free(strbuf_t *buf)
|
||||
{
|
||||
heap_free(buf->buf);
|
||||
}
|
||||
|
||||
static void strbuf_append(strbuf_t *buf, const char *data, int len)
|
||||
{
|
||||
if(buf->len+len > buf->size) {
|
||||
buf->size = buf->len+len;
|
||||
buf->buf = heap_realloc(buf->buf, buf->size);
|
||||
}
|
||||
|
||||
memcpy(buf->buf+buf->len, data, len);
|
||||
buf->len += len;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
IStream *str;
|
||||
char buf[BLOCK_SIZE];
|
||||
ULONG size;
|
||||
ULONG p;
|
||||
} stream_t;
|
||||
|
||||
static void stream_init(stream_t *stream, IStream *str)
|
||||
{
|
||||
memset(stream, 0, sizeof(stream_t));
|
||||
stream->str = str;
|
||||
}
|
||||
|
||||
static BOOL stream_chr(stream_t *stream, strbuf_t *buf, char c)
|
||||
{
|
||||
BOOL b = TRUE;
|
||||
ULONG i;
|
||||
|
||||
while(b) {
|
||||
for(i=stream->p; i<stream->size; i++) {
|
||||
if(stream->buf[i] == c) {
|
||||
b = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(buf && i > stream->p)
|
||||
strbuf_append(buf, stream->buf+stream->p, i-stream->p);
|
||||
stream->p = i;
|
||||
|
||||
if(stream->p == stream->size) {
|
||||
stream->p = 0;
|
||||
IStream_Read(stream->str, stream->buf, sizeof(stream->buf), &stream->size);
|
||||
if(!stream->size)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return stream->size != 0;
|
||||
}
|
||||
|
||||
static void get_node_name(strbuf_t *node, strbuf_t *name)
|
||||
{
|
||||
const char *ptr = node->buf+1;
|
||||
|
||||
strbuf_zero(name);
|
||||
|
||||
while(*ptr != '>' && !isspace(*ptr))
|
||||
ptr++;
|
||||
|
||||
strbuf_append(name, node->buf+1, ptr-node->buf-1);
|
||||
strbuf_append(name, "", 1);
|
||||
}
|
||||
|
||||
static BOOL next_node(stream_t *stream, strbuf_t *buf)
|
||||
{
|
||||
if(!stream_chr(stream, NULL, '<'))
|
||||
return FALSE;
|
||||
|
||||
if(!stream_chr(stream, buf, '>'))
|
||||
return FALSE;
|
||||
|
||||
strbuf_append(buf, ">", 2);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static const char *get_attr(const char *node, const char *name, int *len)
|
||||
{
|
||||
const char *ptr, *ptr2;
|
||||
char name_buf[32];
|
||||
int nlen;
|
||||
|
||||
nlen = strlen(name);
|
||||
memcpy(name_buf, name, nlen);
|
||||
name_buf[nlen++] = '=';
|
||||
name_buf[nlen++] = '\"';
|
||||
name_buf[nlen] = 0;
|
||||
|
||||
ptr = strstr(node, name_buf);
|
||||
if(!ptr) {
|
||||
WARN("name not found\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ptr += nlen;
|
||||
ptr2 = strchr(ptr, '\"');
|
||||
if(!ptr2)
|
||||
return NULL;
|
||||
|
||||
*len = ptr2-ptr;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void parse_obj_node_param(ContentItem *item, ContentItem *hhc_root, const char *text)
|
||||
{
|
||||
const char *ptr;
|
||||
|
|
|
@ -44,6 +44,7 @@ static LRESULT Help_OnSize(HWND hWnd);
|
|||
#define TAB_TOP_PADDING 8
|
||||
#define TAB_RIGHT_PADDING 4
|
||||
#define TAB_MARGIN 8
|
||||
#define EDIT_HEIGHT 20
|
||||
|
||||
static const WCHAR szEmpty[] = {0};
|
||||
|
||||
|
@ -320,8 +321,10 @@ static LRESULT Child_OnPaint(HWND hWnd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ResizeTabChild(HHInfo *info, HWND hwnd)
|
||||
static void ResizeTabChild(HHInfo *info, int tab)
|
||||
{
|
||||
HWND hwnd = info->tabs[tab].hwnd;
|
||||
INT width, height;
|
||||
RECT rect, tabrc;
|
||||
DWORD cnt;
|
||||
|
||||
|
@ -333,9 +336,47 @@ static void ResizeTabChild(HHInfo *info, HWND hwnd)
|
|||
rect.top = TAB_TOP_PADDING + cnt*(tabrc.bottom-tabrc.top) + TAB_MARGIN;
|
||||
rect.right -= TAB_RIGHT_PADDING + TAB_MARGIN;
|
||||
rect.bottom -= TAB_MARGIN;
|
||||
width = rect.right-rect.left;
|
||||
height = rect.bottom-rect.top;
|
||||
|
||||
SetWindowPos(hwnd, NULL, rect.left, rect.top, rect.right-rect.left,
|
||||
rect.bottom-rect.top, SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
SetWindowPos(hwnd, NULL, rect.left, rect.top, width, height,
|
||||
SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
|
||||
switch (tab)
|
||||
{
|
||||
case TAB_INDEX: {
|
||||
int scroll_width = GetSystemMetrics(SM_CXVSCROLL);
|
||||
int border_width = GetSystemMetrics(SM_CXBORDER);
|
||||
int edge_width = GetSystemMetrics(SM_CXEDGE);
|
||||
|
||||
/* Resize the tab widget column to perfectly fit the tab window and
|
||||
* leave sufficient space for the scroll widget.
|
||||
*/
|
||||
SendMessageW(info->tabs[TAB_INDEX].hwnd, LVM_SETCOLUMNWIDTH, 0,
|
||||
width-scroll_width-2*border_width-2*edge_width);
|
||||
|
||||
break;
|
||||
}
|
||||
case TAB_SEARCH: {
|
||||
int scroll_width = GetSystemMetrics(SM_CXVSCROLL);
|
||||
int border_width = GetSystemMetrics(SM_CXBORDER);
|
||||
int edge_width = GetSystemMetrics(SM_CXEDGE);
|
||||
int top_pos = 0;
|
||||
|
||||
SetWindowPos(info->search.hwndEdit, NULL, 0, top_pos, width,
|
||||
EDIT_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
top_pos += EDIT_HEIGHT + TAB_MARGIN;
|
||||
SetWindowPos(info->search.hwndList, NULL, 0, top_pos, width,
|
||||
height-top_pos, SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
/* Resize the tab widget column to perfectly fit the tab window and
|
||||
* leave sufficient space for the scroll widget.
|
||||
*/
|
||||
SendMessageW(info->search.hwndList, LVM_SETCOLUMNWIDTH, 0,
|
||||
width-scroll_width-2*border_width-2*edge_width);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static LRESULT Child_OnSize(HWND hwnd)
|
||||
|
@ -351,7 +392,8 @@ static LRESULT Child_OnSize(HWND hwnd)
|
|||
rect.right - TAB_RIGHT_PADDING,
|
||||
rect.bottom - TAB_TOP_PADDING, SWP_NOMOVE);
|
||||
|
||||
ResizeTabChild(info, info->tabs[TAB_CONTENTS].hwnd);
|
||||
ResizeTabChild(info, TAB_CONTENTS);
|
||||
ResizeTabChild(info, TAB_INDEX);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -375,29 +417,101 @@ static LRESULT OnTabChange(HWND hwnd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static LRESULT OnTopicChange(HWND hwnd, ContentItem *item)
|
||||
static LRESULT OnTopicChange(HHInfo *info, void *user_data)
|
||||
{
|
||||
HHInfo *info = (HHInfo*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
|
||||
LPCWSTR chmfile = NULL;
|
||||
ContentItem *iter = item;
|
||||
LPCWSTR chmfile = NULL, name = NULL, local = NULL;
|
||||
ContentItem *citer;
|
||||
SearchItem *siter;
|
||||
IndexItem *iiter;
|
||||
|
||||
if(!item || !info)
|
||||
if(!user_data || !info)
|
||||
return 0;
|
||||
|
||||
TRACE("name %s loal %s\n", debugstr_w(item->name), debugstr_w(item->local));
|
||||
|
||||
while(iter) {
|
||||
if(iter->merge.chm_file) {
|
||||
chmfile = iter->merge.chm_file;
|
||||
break;
|
||||
switch (info->current_tab)
|
||||
{
|
||||
case TAB_CONTENTS:
|
||||
citer = (ContentItem *) user_data;
|
||||
name = citer->name;
|
||||
local = citer->local;
|
||||
while(citer) {
|
||||
if(citer->merge.chm_file) {
|
||||
chmfile = citer->merge.chm_file;
|
||||
break;
|
||||
}
|
||||
citer = citer->parent;
|
||||
}
|
||||
iter = iter->parent;
|
||||
break;
|
||||
case TAB_INDEX:
|
||||
iiter = (IndexItem *) user_data;
|
||||
if(iiter->nItems == 0) {
|
||||
FIXME("No entries for this item!\n");
|
||||
return 0;
|
||||
}
|
||||
if(iiter->nItems > 1) {
|
||||
int i = 0;
|
||||
LVITEMW lvi;
|
||||
|
||||
SendMessageW(info->popup.hwndList, LVM_DELETEALLITEMS, 0, 0);
|
||||
for(i=0;i<iiter->nItems;i++) {
|
||||
IndexSubItem *item = &iiter->items[i];
|
||||
WCHAR *name = iiter->keyword;
|
||||
|
||||
if(item->name)
|
||||
name = item->name;
|
||||
memset(&lvi, 0, sizeof(lvi));
|
||||
lvi.iItem = i;
|
||||
lvi.mask = LVIF_TEXT|LVIF_PARAM;
|
||||
lvi.cchTextMax = strlenW(name)+1;
|
||||
lvi.pszText = name;
|
||||
lvi.lParam = (LPARAM) item;
|
||||
SendMessageW(info->popup.hwndList, LVM_INSERTITEMW, 0, (LPARAM)&lvi);
|
||||
}
|
||||
ShowWindow(info->popup.hwndPopup, SW_SHOW);
|
||||
return 0;
|
||||
}
|
||||
name = iiter->items[0].name;
|
||||
local = iiter->items[0].local;
|
||||
chmfile = iiter->merge.chm_file;
|
||||
break;
|
||||
case TAB_SEARCH:
|
||||
siter = (SearchItem *) user_data;
|
||||
name = siter->filename;
|
||||
local = siter->filename;
|
||||
chmfile = info->pCHMInfo->szFile;
|
||||
break;
|
||||
default:
|
||||
FIXME("Unhandled operation for this tab!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
NavigateToChm(info, chmfile, item->local);
|
||||
if(!chmfile)
|
||||
{
|
||||
FIXME("No help file found for this item!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
TRACE("name %s loal %s\n", debugstr_w(name), debugstr_w(local));
|
||||
|
||||
NavigateToChm(info, chmfile, local);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Capture the Enter/Return key and send it up to Child_WndProc as an NM_RETURN message */
|
||||
static LRESULT CALLBACK EditChild_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
WNDPROC editWndProc = (WNDPROC)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
|
||||
|
||||
if(message == WM_KEYUP && wParam == VK_RETURN)
|
||||
{
|
||||
NMHDR nmhdr;
|
||||
|
||||
nmhdr.hwndFrom = hWnd;
|
||||
nmhdr.code = NM_RETURN;
|
||||
SendMessageW(GetParent(GetParent(hWnd)), WM_NOTIFY, wParam, (LPARAM)&nmhdr);
|
||||
}
|
||||
return editWndProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK Child_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (message)
|
||||
|
@ -407,12 +521,71 @@ static LRESULT CALLBACK Child_WndProc(HWND hWnd, UINT message, WPARAM wParam, LP
|
|||
case WM_SIZE:
|
||||
return Child_OnSize(hWnd);
|
||||
case WM_NOTIFY: {
|
||||
HHInfo *info = (HHInfo*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
|
||||
NMHDR *nmhdr = (NMHDR*)lParam;
|
||||
|
||||
switch(nmhdr->code) {
|
||||
case TCN_SELCHANGE:
|
||||
return OnTabChange(hWnd);
|
||||
case TVN_SELCHANGEDW:
|
||||
return OnTopicChange(hWnd, (ContentItem*)((NMTREEVIEWW *)lParam)->itemNew.lParam);
|
||||
return OnTopicChange(info, (void*)((NMTREEVIEWW *)lParam)->itemNew.lParam);
|
||||
case NM_DBLCLK:
|
||||
if(!info)
|
||||
return 0;
|
||||
switch(info->current_tab)
|
||||
{
|
||||
case TAB_INDEX:
|
||||
return OnTopicChange(info, (void*)((NMITEMACTIVATE *)lParam)->lParam);
|
||||
case TAB_SEARCH:
|
||||
return OnTopicChange(info, (void*)((NMITEMACTIVATE *)lParam)->lParam);
|
||||
}
|
||||
break;
|
||||
case NM_RETURN:
|
||||
if(!info)
|
||||
return 0;
|
||||
switch(info->current_tab) {
|
||||
case TAB_INDEX: {
|
||||
HWND hwndList = info->tabs[TAB_INDEX].hwnd;
|
||||
LVITEMW lvItem;
|
||||
|
||||
lvItem.iItem = (int) SendMessageW(hwndList, LVM_GETSELECTIONMARK, 0, 0);
|
||||
lvItem.mask = TVIF_PARAM;
|
||||
SendMessageW(hwndList, LVM_GETITEMW, 0, (LPARAM)&lvItem);
|
||||
OnTopicChange(info, (void*) lvItem.lParam);
|
||||
return 0;
|
||||
}
|
||||
case TAB_SEARCH: {
|
||||
if(nmhdr->hwndFrom == info->search.hwndEdit) {
|
||||
char needle[100];
|
||||
DWORD i, len;
|
||||
|
||||
len = GetWindowTextA(info->search.hwndEdit, needle, sizeof(needle));
|
||||
if(!len)
|
||||
{
|
||||
FIXME("Unable to get search text.\n");
|
||||
return 0;
|
||||
}
|
||||
/* Convert the requested text for comparison later against the
|
||||
* lower case version of HTML file contents.
|
||||
*/
|
||||
for(i=0;i<len;i++)
|
||||
needle[i] = tolower(needle[i]);
|
||||
InitSearch(info, needle);
|
||||
return 0;
|
||||
}else if(nmhdr->hwndFrom == info->search.hwndList) {
|
||||
HWND hwndList = info->search.hwndList;
|
||||
LVITEMW lvItem;
|
||||
|
||||
lvItem.iItem = (int) SendMessageW(hwndList, LVM_GETSELECTIONMARK, 0, 0);
|
||||
lvItem.mask = TVIF_PARAM;
|
||||
SendMessageW(hwndList, LVM_GETITEMW, 0, (LPARAM)&lvItem);
|
||||
OnTopicChange(info, (void*) lvItem.lParam);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -729,6 +902,8 @@ static BOOL HH_AddHTMLPane(HHInfo *pHHInfo)
|
|||
|
||||
static BOOL AddContentTab(HHInfo *info)
|
||||
{
|
||||
if(info->tabs[TAB_CONTENTS].id == -1)
|
||||
return TRUE; /* No "Contents" tab */
|
||||
info->tabs[TAB_CONTENTS].hwnd = CreateWindowExW(WS_EX_CLIENTEDGE, WC_TREEVIEWW,
|
||||
szEmpty, WS_CHILD | WS_BORDER | 0x25, 50, 50, 100, 100,
|
||||
info->WinType.hwndNavigation, NULL, hhctrl_hinstance, NULL);
|
||||
|
@ -737,12 +912,293 @@ static BOOL AddContentTab(HHInfo *info)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
ResizeTabChild(info, info->tabs[TAB_CONTENTS].hwnd);
|
||||
ResizeTabChild(info, TAB_CONTENTS);
|
||||
ShowWindow(info->tabs[TAB_CONTENTS].hwnd, SW_SHOW);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL AddIndexTab(HHInfo *info)
|
||||
{
|
||||
char hidden_column[] = "Column";
|
||||
LVCOLUMNA lvc;
|
||||
|
||||
if(info->tabs[TAB_INDEX].id == -1)
|
||||
return TRUE; /* No "Index" tab */
|
||||
info->tabs[TAB_INDEX].hwnd = CreateWindowExW(WS_EX_CLIENTEDGE, WC_LISTVIEWW,
|
||||
szEmpty, WS_CHILD | WS_BORDER | LVS_SINGLESEL | LVS_REPORT | LVS_NOCOLUMNHEADER, 50, 50, 100, 100,
|
||||
info->WinType.hwndNavigation, NULL, hhctrl_hinstance, NULL);
|
||||
if(!info->tabs[TAB_INDEX].hwnd) {
|
||||
ERR("Could not create ListView control\n");
|
||||
return FALSE;
|
||||
}
|
||||
memset(&lvc, 0, sizeof(lvc));
|
||||
lvc.mask = LVCF_TEXT;
|
||||
lvc.pszText = hidden_column;
|
||||
if(SendMessageW(info->tabs[TAB_INDEX].hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM) &lvc) == -1)
|
||||
{
|
||||
ERR("Could not create ListView column\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ResizeTabChild(info, TAB_INDEX);
|
||||
ShowWindow(info->tabs[TAB_INDEX].hwnd, SW_HIDE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL AddSearchTab(HHInfo *info)
|
||||
{
|
||||
HWND hwndList, hwndEdit, hwndContainer;
|
||||
char hidden_column[] = "Column";
|
||||
WNDPROC editWndProc;
|
||||
LVCOLUMNA lvc;
|
||||
|
||||
if(info->tabs[TAB_SEARCH].id == -1)
|
||||
return TRUE; /* No "Search" tab */
|
||||
hwndContainer = CreateWindowExW(WS_EX_CONTROLPARENT, szChildClass, szEmpty,
|
||||
WS_CHILD, 0, 0, 0, 0, info->WinType.hwndNavigation,
|
||||
NULL, hhctrl_hinstance, NULL);
|
||||
if(!hwndContainer) {
|
||||
ERR("Could not create search window container control.\n");
|
||||
return FALSE;
|
||||
}
|
||||
hwndEdit = CreateWindowExW(WS_EX_CLIENTEDGE, WC_EDITW, szEmpty, WS_CHILD
|
||||
| WS_VISIBLE | ES_LEFT | SS_NOTIFY, 0, 0, 0, 0,
|
||||
hwndContainer, NULL, hhctrl_hinstance, NULL);
|
||||
if(!hwndEdit) {
|
||||
ERR("Could not create search ListView control.\n");
|
||||
return FALSE;
|
||||
}
|
||||
if(SendMessageW(hwndEdit, WM_SETFONT, (WPARAM) info->hFont, (LPARAM) FALSE) == -1)
|
||||
{
|
||||
ERR("Could not set font for edit control.\n");
|
||||
return FALSE;
|
||||
}
|
||||
editWndProc = (WNDPROC) SetWindowLongPtrW(hwndEdit, GWLP_WNDPROC, (LONG_PTR)EditChild_WndProc);
|
||||
if(!editWndProc) {
|
||||
ERR("Could not redirect messages for edit control.\n");
|
||||
return FALSE;
|
||||
}
|
||||
SetWindowLongPtrW(hwndEdit, GWLP_USERDATA, (LONG_PTR)editWndProc);
|
||||
hwndList = CreateWindowExW(WS_EX_CLIENTEDGE, WC_LISTVIEWW, szEmpty,
|
||||
WS_CHILD | WS_VISIBLE | WS_BORDER | LVS_SINGLESEL
|
||||
| LVS_REPORT | LVS_NOCOLUMNHEADER, 0, 0, 0, 0,
|
||||
hwndContainer, NULL, hhctrl_hinstance, NULL);
|
||||
if(!hwndList) {
|
||||
ERR("Could not create search ListView control.\n");
|
||||
return FALSE;
|
||||
}
|
||||
memset(&lvc, 0, sizeof(lvc));
|
||||
lvc.mask = LVCF_TEXT;
|
||||
lvc.pszText = hidden_column;
|
||||
if(SendMessageW(hwndList, LVM_INSERTCOLUMNA, 0, (LPARAM) &lvc) == -1)
|
||||
{
|
||||
ERR("Could not create ListView column\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
info->search.hwndEdit = hwndEdit;
|
||||
info->search.hwndList = hwndList;
|
||||
info->search.hwndContainer = hwndContainer;
|
||||
info->tabs[TAB_SEARCH].hwnd = hwndContainer;
|
||||
|
||||
SetWindowLongPtrW(hwndContainer, GWLP_USERDATA, (LONG_PTR)info);
|
||||
|
||||
ResizeTabChild(info, TAB_SEARCH);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* The Index tab's sub-topic popup */
|
||||
|
||||
static void ResizePopupChild(HHInfo *info)
|
||||
{
|
||||
int scroll_width = GetSystemMetrics(SM_CXVSCROLL);
|
||||
int border_width = GetSystemMetrics(SM_CXBORDER);
|
||||
int edge_width = GetSystemMetrics(SM_CXEDGE);
|
||||
INT width, height;
|
||||
RECT rect;
|
||||
|
||||
if(!info)
|
||||
return;
|
||||
|
||||
GetClientRect(info->popup.hwndPopup, &rect);
|
||||
SetWindowPos(info->popup.hwndCallback, HWND_TOP, 0, 0,
|
||||
rect.right, rect.bottom, SWP_NOMOVE);
|
||||
|
||||
rect.left = TAB_MARGIN;
|
||||
rect.top = TAB_TOP_PADDING + TAB_MARGIN;
|
||||
rect.right -= TAB_RIGHT_PADDING + TAB_MARGIN;
|
||||
rect.bottom -= TAB_MARGIN;
|
||||
width = rect.right-rect.left;
|
||||
height = rect.bottom-rect.top;
|
||||
|
||||
SetWindowPos(info->popup.hwndList, NULL, rect.left, rect.top, width, height,
|
||||
SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
|
||||
SendMessageW(info->popup.hwndList, LVM_SETCOLUMNWIDTH, 0,
|
||||
width-scroll_width-2*border_width-2*edge_width);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK HelpPopup_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
HHInfo *info = (HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WM_SIZE:
|
||||
ResizePopupChild(info);
|
||||
return 0;
|
||||
case WM_DESTROY:
|
||||
DestroyWindow(hWnd);
|
||||
return 0;
|
||||
case WM_CLOSE:
|
||||
ShowWindow(hWnd, SW_HIDE);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return DefWindowProcW(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK PopupChild_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_NOTIFY: {
|
||||
NMHDR *nmhdr = (NMHDR*)lParam;
|
||||
switch(nmhdr->code)
|
||||
{
|
||||
case NM_DBLCLK: {
|
||||
HHInfo *info = (HHInfo*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
|
||||
IndexSubItem *iter;
|
||||
|
||||
if(info == 0 || lParam == 0)
|
||||
return 0;
|
||||
iter = (IndexSubItem*) ((NMITEMACTIVATE *)lParam)->lParam;
|
||||
if(iter == 0)
|
||||
return 0;
|
||||
NavigateToChm(info, info->index->merge.chm_file, iter->local);
|
||||
ShowWindow(info->popup.hwndPopup, SW_HIDE);
|
||||
return 0;
|
||||
}
|
||||
case NM_RETURN: {
|
||||
HHInfo *info = (HHInfo*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
|
||||
IndexSubItem *iter;
|
||||
LVITEMW lvItem;
|
||||
|
||||
if(info == 0)
|
||||
return 0;
|
||||
|
||||
lvItem.iItem = (int) SendMessageW(info->popup.hwndList, LVM_GETSELECTIONMARK, 0, 0);
|
||||
lvItem.mask = TVIF_PARAM;
|
||||
SendMessageW(info->popup.hwndList, LVM_GETITEMW, 0, (LPARAM)&lvItem);
|
||||
iter = (IndexSubItem*) lvItem.lParam;
|
||||
NavigateToChm(info, info->index->merge.chm_file, iter->local);
|
||||
ShowWindow(info->popup.hwndPopup, SW_HIDE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return DefWindowProcW(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BOOL AddIndexPopup(HHInfo *info)
|
||||
{
|
||||
static const WCHAR szPopupChildClass[] = {'H','H',' ','P','o','p','u','p',' ','C','h','i','l','d',0};
|
||||
static const WCHAR windowCaptionW[] = {'S','e','l','e','c','t',' ','T','o','p','i','c',':',0};
|
||||
static const WCHAR windowClassW[] = {'H','H',' ','P','o','p','u','p',0};
|
||||
HWND hwndList, hwndPopup, hwndCallback;
|
||||
char hidden_column[] = "Column";
|
||||
WNDCLASSEXW wcex;
|
||||
LVCOLUMNA lvc;
|
||||
|
||||
if(info->tabs[TAB_INDEX].id == -1)
|
||||
return TRUE; /* No "Index" tab */
|
||||
|
||||
wcex.cbSize = sizeof(WNDCLASSEXW);
|
||||
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wcex.lpfnWndProc = HelpPopup_WndProc;
|
||||
wcex.cbClsExtra = 0;
|
||||
wcex.cbWndExtra = 0;
|
||||
wcex.hInstance = hhctrl_hinstance;
|
||||
wcex.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
|
||||
wcex.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
|
||||
wcex.hbrBackground = (HBRUSH)(COLOR_MENU + 1);
|
||||
wcex.lpszMenuName = NULL;
|
||||
wcex.lpszClassName = windowClassW;
|
||||
wcex.hIconSm = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
|
||||
RegisterClassExW(&wcex);
|
||||
|
||||
wcex.cbSize = sizeof(WNDCLASSEXW);
|
||||
wcex.style = 0;
|
||||
wcex.lpfnWndProc = PopupChild_WndProc;
|
||||
wcex.cbClsExtra = 0;
|
||||
wcex.cbWndExtra = 0;
|
||||
wcex.hInstance = hhctrl_hinstance;
|
||||
wcex.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
|
||||
wcex.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
|
||||
wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
|
||||
wcex.lpszMenuName = NULL;
|
||||
wcex.lpszClassName = szPopupChildClass;
|
||||
wcex.hIconSm = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
|
||||
RegisterClassExW(&wcex);
|
||||
|
||||
hwndPopup = CreateWindowExW(WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_APPWINDOW
|
||||
| WS_EX_WINDOWEDGE | WS_EX_RIGHTSCROLLBAR,
|
||||
windowClassW, windowCaptionW, WS_POPUPWINDOW
|
||||
| WS_OVERLAPPEDWINDOW | WS_VISIBLE
|
||||
| WS_CLIPSIBLINGS | WS_CLIPCHILDREN, CW_USEDEFAULT,
|
||||
CW_USEDEFAULT, 300, 200, info->WinType.hwndHelp,
|
||||
NULL, hhctrl_hinstance, NULL);
|
||||
if (!hwndPopup)
|
||||
return FALSE;
|
||||
|
||||
hwndCallback = CreateWindowExW(WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
|
||||
szPopupChildClass, szEmpty, WS_CHILDWINDOW | WS_VISIBLE,
|
||||
0, 0, 0, 0,
|
||||
hwndPopup, NULL, hhctrl_hinstance, NULL);
|
||||
if (!hwndCallback)
|
||||
return FALSE;
|
||||
|
||||
ShowWindow(hwndPopup, SW_HIDE);
|
||||
hwndList = CreateWindowExW(WS_EX_CLIENTEDGE, WC_LISTVIEWW, szEmpty,
|
||||
WS_CHILD | WS_BORDER | LVS_SINGLESEL | LVS_REPORT
|
||||
| LVS_NOCOLUMNHEADER, 50, 50, 100, 100,
|
||||
hwndCallback, NULL, hhctrl_hinstance, NULL);
|
||||
if(!hwndList) {
|
||||
ERR("Could not create popup ListView control\n");
|
||||
return FALSE;
|
||||
}
|
||||
memset(&lvc, 0, sizeof(lvc));
|
||||
lvc.mask = LVCF_TEXT;
|
||||
lvc.pszText = hidden_column;
|
||||
if(SendMessageW(hwndList, LVM_INSERTCOLUMNA, 0, (LPARAM) &lvc) == -1)
|
||||
{
|
||||
ERR("Could not create popup ListView column\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
info->popup.hwndCallback = hwndCallback;
|
||||
info->popup.hwndPopup = hwndPopup;
|
||||
info->popup.hwndList = hwndList;
|
||||
SetWindowLongPtrW(hwndPopup, GWLP_USERDATA, (LONG_PTR)info);
|
||||
SetWindowLongPtrW(hwndCallback, GWLP_USERDATA, (LONG_PTR)info);
|
||||
|
||||
ResizePopupChild(info);
|
||||
ShowWindow(hwndList, SW_SHOW);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Viewer Window */
|
||||
|
||||
static LRESULT Help_OnSize(HWND hWnd)
|
||||
|
@ -918,7 +1374,17 @@ static BOOL CreateViewer(HHInfo *pHHInfo)
|
|||
if (!AddContentTab(pHHInfo))
|
||||
return FALSE;
|
||||
|
||||
if (!AddIndexTab(pHHInfo))
|
||||
return FALSE;
|
||||
|
||||
if (!AddIndexPopup(pHHInfo))
|
||||
return FALSE;
|
||||
|
||||
if (!AddSearchTab(pHHInfo))
|
||||
return FALSE;
|
||||
|
||||
InitContent(pHHInfo);
|
||||
InitIndex(pHHInfo);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -947,6 +1413,8 @@ void ReleaseHelpViewer(HHInfo *info)
|
|||
|
||||
ReleaseWebBrowser(info);
|
||||
ReleaseContent(info);
|
||||
ReleaseIndex(info);
|
||||
ReleaseSearch(info);
|
||||
|
||||
if(info->WinType.hwndHelp)
|
||||
DestroyWindow(info->WinType.hwndHelp);
|
||||
|
@ -958,6 +1426,13 @@ void ReleaseHelpViewer(HHInfo *info)
|
|||
HHInfo *CreateHelpViewer(LPCWSTR filename)
|
||||
{
|
||||
HHInfo *info = heap_alloc_zero(sizeof(HHInfo));
|
||||
int i;
|
||||
|
||||
/* Set the invalid tab ID (-1) as the default value for all
|
||||
* of the tabs, this matches a failed TCM_INSERTITEM call.
|
||||
*/
|
||||
for(i=0;i<sizeof(info->tabs)/sizeof(HHTab);i++)
|
||||
info->tabs[i].id = -1;
|
||||
|
||||
OleInitialize(NULL);
|
||||
|
||||
|
|
|
@ -272,12 +272,41 @@ HWND WINAPI HtmlHelpA(HWND caller, LPCSTR filename, UINT command, DWORD_PTR data
|
|||
int WINAPI doWinMain(HINSTANCE hInstance, LPSTR szCmdLine)
|
||||
{
|
||||
MSG msg;
|
||||
int len, buflen;
|
||||
int len, buflen, mapid = -1;
|
||||
WCHAR *filename;
|
||||
char *endq = NULL;
|
||||
|
||||
hh_process = TRUE;
|
||||
|
||||
/* Parse command line option of the HTML Help command.
|
||||
*
|
||||
* Note: The only currently handled action is "mapid",
|
||||
* which corresponds to opening a specific page.
|
||||
*/
|
||||
while(*szCmdLine == '-')
|
||||
{
|
||||
LPSTR space, ptr;
|
||||
|
||||
ptr = szCmdLine + 1;
|
||||
space = strchr(ptr, ' ');
|
||||
if(!strncmp(ptr, "mapid", space-ptr))
|
||||
{
|
||||
char idtxt[10];
|
||||
|
||||
ptr += strlen("mapid")+1;
|
||||
space = strchr(ptr, ' ');
|
||||
memcpy(idtxt, ptr, space-ptr);
|
||||
idtxt[space-ptr] = '\0';
|
||||
mapid = atoi(idtxt);
|
||||
szCmdLine = space+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
FIXME("Unhandled HTML Help command line parameter! (%.*s)\n", space-szCmdLine, szCmdLine);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: Check szCmdLine for bad arguments */
|
||||
if (*szCmdLine == '\"')
|
||||
endq = strchr(++szCmdLine, '\"');
|
||||
|
@ -291,7 +320,11 @@ int WINAPI doWinMain(HINSTANCE hInstance, LPSTR szCmdLine)
|
|||
MultiByteToWideChar(CP_ACP, 0, szCmdLine, len, filename, buflen);
|
||||
filename[buflen-1] = 0;
|
||||
|
||||
HtmlHelpW(GetDesktopWindow(), filename, HH_DISPLAY_TOPIC, 0);
|
||||
/* Open a specific help topic */
|
||||
if(mapid != -1)
|
||||
HtmlHelpW(GetDesktopWindow(), filename, HH_HELP_CONTEXT, mapid);
|
||||
else
|
||||
HtmlHelpW(GetDesktopWindow(), filename, HH_DISPLAY_TOPIC, 0);
|
||||
|
||||
heap_free(filename);
|
||||
|
||||
|
|
|
@ -65,11 +65,37 @@ typedef struct ContentItem {
|
|||
ChmPath merge;
|
||||
} ContentItem;
|
||||
|
||||
typedef struct IndexSubItem {
|
||||
LPWSTR name;
|
||||
LPWSTR local;
|
||||
} IndexSubItem;
|
||||
|
||||
typedef struct IndexItem {
|
||||
struct IndexItem *next;
|
||||
|
||||
HTREEITEM id;
|
||||
LPWSTR keyword;
|
||||
ChmPath merge;
|
||||
|
||||
int nItems;
|
||||
int itemFlags;
|
||||
int indentLevel;
|
||||
IndexSubItem *items;
|
||||
} IndexItem;
|
||||
|
||||
typedef struct SearchItem {
|
||||
struct SearchItem *next;
|
||||
|
||||
HTREEITEM id;
|
||||
LPWSTR title;
|
||||
LPWSTR filename;
|
||||
} SearchItem;
|
||||
|
||||
typedef struct CHMInfo
|
||||
{
|
||||
IITStorage *pITStorage;
|
||||
IStorage *pStorage;
|
||||
LPCWSTR szFile;
|
||||
WCHAR *szFile;
|
||||
|
||||
IStream *strings_stream;
|
||||
char **strings;
|
||||
|
@ -90,6 +116,19 @@ typedef struct {
|
|||
DWORD id;
|
||||
} HHTab;
|
||||
|
||||
typedef struct {
|
||||
HWND hwndList;
|
||||
HWND hwndPopup;
|
||||
HWND hwndCallback;
|
||||
} IndexPopup;
|
||||
|
||||
typedef struct {
|
||||
SearchItem *root;
|
||||
HWND hwndEdit;
|
||||
HWND hwndList;
|
||||
HWND hwndContainer;
|
||||
} SearchTab;
|
||||
|
||||
typedef struct {
|
||||
IOleClientSite *client_site;
|
||||
IWebBrowser2 *web_browser;
|
||||
|
@ -111,6 +150,9 @@ typedef struct {
|
|||
|
||||
CHMInfo *pCHMInfo;
|
||||
ContentItem *content;
|
||||
IndexItem *index;
|
||||
IndexPopup popup;
|
||||
SearchTab search;
|
||||
HWND hwndTabCtrl;
|
||||
HWND hwndSizeBar;
|
||||
HFONT hFont;
|
||||
|
@ -127,6 +169,9 @@ void DoPageAction(HHInfo*,DWORD);
|
|||
void InitContent(HHInfo*);
|
||||
void ReleaseContent(HHInfo*);
|
||||
|
||||
void InitIndex(HHInfo*);
|
||||
void ReleaseIndex(HHInfo*);
|
||||
|
||||
CHMInfo *OpenCHM(LPCWSTR szFile);
|
||||
BOOL LoadWinTypeFromCHM(HHInfo *info);
|
||||
CHMInfo *CloseCHM(CHMInfo *pCHMInfo);
|
||||
|
@ -139,6 +184,9 @@ void ReleaseHelpViewer(HHInfo*);
|
|||
BOOL NavigateToUrl(HHInfo*,LPCWSTR);
|
||||
BOOL NavigateToChm(HHInfo*,LPCWSTR,LPCWSTR);
|
||||
|
||||
void InitSearch(HHInfo *info, const char *needle);
|
||||
void ReleaseSearch(HHInfo *info);
|
||||
|
||||
/* memory allocation functions */
|
||||
|
||||
static inline void * __WINE_ALLOC_SIZE(1) heap_alloc(size_t len)
|
||||
|
|
|
@ -31,20 +31,25 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
|||
|
||||
#include "Cs.rc"
|
||||
#include "Da.rc"
|
||||
#include "De.rc"
|
||||
#include "El.rc"
|
||||
#include "En.rc"
|
||||
#include "Fr.rc"
|
||||
#include "Fi.rc"
|
||||
#include "Hu.rc"
|
||||
#include "Ko.rc"
|
||||
#include "Lt.rc"
|
||||
#include "Nl.rc"
|
||||
#include "No.rc"
|
||||
#include "Pl.rc"
|
||||
#include "Pt.rc"
|
||||
#include "Ru.rc"
|
||||
#include "Si.rc"
|
||||
#include "Sv.rc"
|
||||
#include "Tr.rc"
|
||||
|
||||
/* UTF-8 */
|
||||
#include "De.rc"
|
||||
#include "Es.rc"
|
||||
#include "Fr.rc"
|
||||
#include "Lt.rc"
|
||||
#include "Ru.rc"
|
||||
#include "Si.rc"
|
||||
#include "Uk.rc"
|
||||
#include "Zh.rc"
|
||||
|
||||
|
|
295
reactos/dll/win32/hhctrl.ocx/index.c
Normal file
295
reactos/dll/win32/hhctrl.ocx/index.c
Normal file
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
* Copyright 2007 Jacek Caban for CodeWeavers
|
||||
* Copyright 2010 Erich Hoover
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#define NONAMELESSUNION
|
||||
#define NONAMELESSSTRUCT
|
||||
|
||||
#include "hhctrl.h"
|
||||
#include "stream.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp);
|
||||
|
||||
/* Fill the TreeView object corresponding to the Index items */
|
||||
static void fill_index_tree(HWND hwnd, IndexItem *item)
|
||||
{
|
||||
int index = 0;
|
||||
LVITEMW lvi;
|
||||
|
||||
while(item) {
|
||||
TRACE("tree debug: %s\n", debugstr_w(item->keyword));
|
||||
|
||||
if(!item->keyword)
|
||||
{
|
||||
FIXME("HTML Help index item has no keyword.\n");
|
||||
item = item->next;
|
||||
continue;
|
||||
}
|
||||
memset(&lvi, 0, sizeof(lvi));
|
||||
lvi.iItem = index++;
|
||||
lvi.mask = LVIF_TEXT|LVIF_PARAM|LVIF_INDENT;
|
||||
lvi.iIndent = item->indentLevel;
|
||||
lvi.cchTextMax = strlenW(item->keyword)+1;
|
||||
lvi.pszText = item->keyword;
|
||||
lvi.lParam = (LPARAM)item;
|
||||
item->id = (HTREEITEM)SendMessageW(hwnd, LVM_INSERTITEMW, 0, (LPARAM)&lvi);
|
||||
item = item->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse the attributes correspond to a list item, including sub-topics.
|
||||
*
|
||||
* Each list item has, at minimum, a param of type "keyword" and two
|
||||
* parameters corresponding to a "sub-topic." For each sub-topic there
|
||||
* must be a "name" param and a "local" param, if there is only one
|
||||
* sub-topic then there isn't really a sub-topic, the index will jump
|
||||
* directly to the requested item.
|
||||
*/
|
||||
static void parse_index_obj_node_param(IndexItem *item, const char *text)
|
||||
{
|
||||
const char *ptr;
|
||||
LPWSTR *param;
|
||||
int len, wlen;
|
||||
|
||||
ptr = get_attr(text, "name", &len);
|
||||
if(!ptr) {
|
||||
WARN("name attr not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Allocate a new sub-item, either on the first run or whenever a
|
||||
* sub-topic has filled out both the "name" and "local" params.
|
||||
*/
|
||||
if(item->itemFlags == 0x11 && (!strncasecmp("name", ptr, len) || !strncasecmp("local", ptr, len))) {
|
||||
item->nItems++;
|
||||
item->items = heap_realloc(item->items, sizeof(IndexSubItem)*item->nItems);
|
||||
item->items[item->nItems-1].name = NULL;
|
||||
item->items[item->nItems-1].local = NULL;
|
||||
item->itemFlags = 0x00;
|
||||
}
|
||||
if(!strncasecmp("keyword", ptr, len)) {
|
||||
param = &item->keyword;
|
||||
}else if(!item->keyword && !strncasecmp("name", ptr, len)) {
|
||||
/* Some HTML Help index files use an additional "name" parameter
|
||||
* rather than the "keyword" parameter. In this case, the first
|
||||
* occurance of the "name" parameter is the keyword.
|
||||
*/
|
||||
param = &item->keyword;
|
||||
}else if(!strncasecmp("name", ptr, len)) {
|
||||
item->itemFlags |= 0x01;
|
||||
param = &item->items[item->nItems-1].name;
|
||||
}else if(!strncasecmp("local", ptr, len)) {
|
||||
item->itemFlags |= 0x10;
|
||||
param = &item->items[item->nItems-1].local;
|
||||
}else {
|
||||
WARN("unhandled param %s\n", debugstr_an(ptr, len));
|
||||
return;
|
||||
}
|
||||
|
||||
ptr = get_attr(text, "value", &len);
|
||||
if(!ptr) {
|
||||
WARN("value attr not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
wlen = MultiByteToWideChar(CP_ACP, 0, ptr, len, NULL, 0);
|
||||
*param = heap_alloc((wlen+1)*sizeof(WCHAR));
|
||||
MultiByteToWideChar(CP_ACP, 0, ptr, len, *param, wlen);
|
||||
(*param)[wlen] = 0;
|
||||
}
|
||||
|
||||
/* Parse the object tag corresponding to a list item.
|
||||
*
|
||||
* At this step we look for all of the "param" child tags, using this information
|
||||
* to build up the information about the list item. When we reach the </object>
|
||||
* tag we know that we've finished parsing this list item.
|
||||
*/
|
||||
static IndexItem *parse_index_sitemap_object(HHInfo *info, stream_t *stream)
|
||||
{
|
||||
strbuf_t node, node_name;
|
||||
IndexItem *item;
|
||||
|
||||
strbuf_init(&node);
|
||||
strbuf_init(&node_name);
|
||||
|
||||
item = heap_alloc_zero(sizeof(IndexItem));
|
||||
item->nItems = 0;
|
||||
item->items = heap_alloc_zero(0);
|
||||
item->itemFlags = 0x11;
|
||||
|
||||
while(next_node(stream, &node)) {
|
||||
get_node_name(&node, &node_name);
|
||||
|
||||
TRACE("%s\n", node.buf);
|
||||
|
||||
if(!strcasecmp(node_name.buf, "param")) {
|
||||
parse_index_obj_node_param(item, node.buf);
|
||||
}else if(!strcasecmp(node_name.buf, "/object")) {
|
||||
break;
|
||||
}else {
|
||||
WARN("Unhandled tag! %s\n", node_name.buf);
|
||||
}
|
||||
|
||||
strbuf_zero(&node);
|
||||
}
|
||||
|
||||
strbuf_free(&node);
|
||||
strbuf_free(&node_name);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/* Parse the HTML list item node corresponding to a specific help entry.
|
||||
*
|
||||
* At this stage we look for the only child tag we expect to find under
|
||||
* the list item: the <OBJECT> tag. We also only expect to find object
|
||||
* tags with the "type" attribute set to "text/sitemap".
|
||||
*/
|
||||
static IndexItem *parse_li(HHInfo *info, stream_t *stream)
|
||||
{
|
||||
strbuf_t node, node_name;
|
||||
IndexItem *ret = NULL;
|
||||
|
||||
strbuf_init(&node);
|
||||
strbuf_init(&node_name);
|
||||
|
||||
while(next_node(stream, &node)) {
|
||||
get_node_name(&node, &node_name);
|
||||
|
||||
TRACE("%s\n", node.buf);
|
||||
|
||||
if(!strcasecmp(node_name.buf, "object")) {
|
||||
const char *ptr;
|
||||
int len;
|
||||
|
||||
static const char sz_text_sitemap[] = "text/sitemap";
|
||||
|
||||
ptr = get_attr(node.buf, "type", &len);
|
||||
|
||||
if(ptr && len == sizeof(sz_text_sitemap)-1
|
||||
&& !memcmp(ptr, sz_text_sitemap, len)) {
|
||||
ret = parse_index_sitemap_object(info, stream);
|
||||
break;
|
||||
}
|
||||
}else {
|
||||
WARN("Unhandled tag! %s\n", node_name.buf);
|
||||
}
|
||||
|
||||
strbuf_zero(&node);
|
||||
}
|
||||
|
||||
strbuf_free(&node);
|
||||
strbuf_free(&node_name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Parse the HTML Help page corresponding to all of the Index items.
|
||||
*
|
||||
* At this high-level stage we locate out each HTML list item tag.
|
||||
* Since there is no end-tag for the <LI> item, we must hope that
|
||||
* the <LI> entry is parsed correctly or tags might get lost.
|
||||
*
|
||||
* Within each entry it is also possible to encounter an additional
|
||||
* <UL> tag. When this occurs the tag indicates that the topics
|
||||
* contained within it are related to the parent <LI> topic and
|
||||
* should be inset by an indent.
|
||||
*/
|
||||
static void parse_hhindex(HHInfo *info, IStream *str, IndexItem *item)
|
||||
{
|
||||
stream_t stream;
|
||||
strbuf_t node, node_name;
|
||||
int indent_level = -1;
|
||||
|
||||
strbuf_init(&node);
|
||||
strbuf_init(&node_name);
|
||||
|
||||
stream_init(&stream, str);
|
||||
|
||||
while(next_node(&stream, &node)) {
|
||||
get_node_name(&node, &node_name);
|
||||
|
||||
TRACE("%s\n", node.buf);
|
||||
|
||||
if(!strcasecmp(node_name.buf, "li")) {
|
||||
item->next = parse_li(info, &stream);
|
||||
item->next->merge = item->merge;
|
||||
item = item->next;
|
||||
item->indentLevel = indent_level;
|
||||
}else if(!strcasecmp(node_name.buf, "ul")) {
|
||||
indent_level++;
|
||||
}else if(!strcasecmp(node_name.buf, "/ul")) {
|
||||
indent_level--;
|
||||
}else {
|
||||
WARN("Unhandled tag! %s\n", node_name.buf);
|
||||
}
|
||||
|
||||
strbuf_zero(&node);
|
||||
}
|
||||
|
||||
strbuf_free(&node);
|
||||
strbuf_free(&node_name);
|
||||
}
|
||||
|
||||
/* Initialize the HTML Help Index tab */
|
||||
void InitIndex(HHInfo *info)
|
||||
{
|
||||
IStream *stream;
|
||||
|
||||
info->index = heap_alloc_zero(sizeof(IndexItem));
|
||||
info->index->nItems = 0;
|
||||
SetChmPath(&info->index->merge, info->pCHMInfo->szFile, info->WinType.pszIndex);
|
||||
|
||||
stream = GetChmStream(info->pCHMInfo, info->pCHMInfo->szFile, &info->index->merge);
|
||||
if(!stream) {
|
||||
TRACE("Could not get index stream\n");
|
||||
return;
|
||||
}
|
||||
|
||||
parse_hhindex(info, stream, info->index);
|
||||
IStream_Release(stream);
|
||||
|
||||
fill_index_tree(info->tabs[TAB_INDEX].hwnd, info->index->next);
|
||||
}
|
||||
|
||||
/* Free all of the Index items, including all of the "sub-items" that
|
||||
* correspond to different sub-topics.
|
||||
*/
|
||||
void ReleaseIndex(HHInfo *info)
|
||||
{
|
||||
IndexItem *item = info->index, *next;
|
||||
int i;
|
||||
|
||||
/* Note: item->merge is identical for all items, only free once */
|
||||
heap_free(item->merge.chm_file);
|
||||
heap_free(item->merge.chm_index);
|
||||
while(item) {
|
||||
next = item->next;
|
||||
|
||||
heap_free(item->keyword);
|
||||
for(i=0;i<item->nItems;i++) {
|
||||
heap_free(item->items[i].name);
|
||||
heap_free(item->items[i].local);
|
||||
}
|
||||
heap_free(item->items);
|
||||
|
||||
item = next;
|
||||
}
|
||||
}
|
246
reactos/dll/win32/hhctrl.ocx/search.c
Normal file
246
reactos/dll/win32/hhctrl.ocx/search.c
Normal file
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* Copyright 2010 Erich Hoover
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#define NONAMELESSUNION
|
||||
#define NONAMELESSSTRUCT
|
||||
|
||||
#include "hhctrl.h"
|
||||
#include "stream.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp);
|
||||
|
||||
static SearchItem *SearchCHM_Folder(SearchItem *item, IStorage *pStorage,
|
||||
const WCHAR *folder, const char *needle);
|
||||
|
||||
/* Allocate a ListView entry for a search result. */
|
||||
static SearchItem *alloc_search_item(WCHAR *title, const WCHAR *filename)
|
||||
{
|
||||
int filename_len = filename ? (strlenW(filename)+1)*sizeof(WCHAR) : 0;
|
||||
SearchItem *item;
|
||||
|
||||
item = heap_alloc_zero(sizeof(SearchItem));
|
||||
if(filename)
|
||||
{
|
||||
item->filename = heap_alloc(filename_len);
|
||||
memcpy(item->filename, filename, filename_len);
|
||||
}
|
||||
item->title = title; /* Already allocated */
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/* Fill the ListView object corresponding to the found Search tab items */
|
||||
static void fill_search_tree(HWND hwndList, SearchItem *item)
|
||||
{
|
||||
int index = 0;
|
||||
LVITEMW lvi;
|
||||
|
||||
SendMessageW(hwndList, LVM_DELETEALLITEMS, 0, 0);
|
||||
while(item) {
|
||||
TRACE("list debug: %s\n", debugstr_w(item->filename));
|
||||
|
||||
memset(&lvi, 0, sizeof(lvi));
|
||||
lvi.iItem = index++;
|
||||
lvi.mask = LVIF_TEXT|LVIF_PARAM;
|
||||
lvi.cchTextMax = strlenW(item->title)+1;
|
||||
lvi.pszText = item->title;
|
||||
lvi.lParam = (LPARAM)item;
|
||||
item->id = (HTREEITEM)SendMessageW(hwndList, LVM_INSERTITEMW, 0, (LPARAM)&lvi);
|
||||
item = item->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Search the CHM storage stream (an HTML file) for the requested text.
|
||||
*
|
||||
* Before searching the HTML file all HTML tags are removed so that only
|
||||
* the content of the document is scanned. If the search string is found
|
||||
* then the title of the document is returned.
|
||||
*/
|
||||
static WCHAR *SearchCHM_File(IStorage *pStorage, const WCHAR *file, const char *needle)
|
||||
{
|
||||
char *buffer = heap_alloc(BLOCK_SIZE);
|
||||
strbuf_t content, node, node_name;
|
||||
IStream *temp_stream = NULL;
|
||||
DWORD i, buffer_size = 0;
|
||||
WCHAR *title = NULL;
|
||||
BOOL found = FALSE;
|
||||
stream_t stream;
|
||||
HRESULT hres;
|
||||
|
||||
hres = IStorage_OpenStream(pStorage, file, NULL, STGM_READ, 0, &temp_stream);
|
||||
if(FAILED(hres)) {
|
||||
FIXME("Could not open '%s' stream: %08x\n", debugstr_w(file), hres);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
strbuf_init(&node);
|
||||
strbuf_init(&content);
|
||||
strbuf_init(&node_name);
|
||||
|
||||
stream_init(&stream, temp_stream);
|
||||
|
||||
/* Remove all HTML formatting and record the title */
|
||||
while(next_node(&stream, &node)) {
|
||||
get_node_name(&node, &node_name);
|
||||
|
||||
if(next_content(&stream, &content) && content.len > 1)
|
||||
{
|
||||
char *text = &content.buf[1];
|
||||
int textlen = content.len-1;
|
||||
|
||||
if(!strcasecmp(node_name.buf, "title"))
|
||||
{
|
||||
int wlen = MultiByteToWideChar(CP_ACP, 0, text, textlen, NULL, 0);
|
||||
title = heap_alloc((wlen+1)*sizeof(WCHAR));
|
||||
MultiByteToWideChar(CP_ACP, 0, text, textlen, title, wlen);
|
||||
title[wlen] = 0;
|
||||
}
|
||||
|
||||
buffer = heap_realloc(buffer, buffer_size + textlen + 1);
|
||||
memcpy(&buffer[buffer_size], text, textlen);
|
||||
buffer[buffer_size + textlen] = '\0';
|
||||
buffer_size += textlen;
|
||||
}
|
||||
|
||||
strbuf_zero(&node);
|
||||
strbuf_zero(&content);
|
||||
}
|
||||
|
||||
/* Convert the buffer to lower case for comparison against the
|
||||
* requested text (already in lower case).
|
||||
*/
|
||||
for(i=0;i<buffer_size;i++)
|
||||
buffer[i] = tolower(buffer[i]);
|
||||
|
||||
/* Search the decoded buffer for the requested text */
|
||||
if(strstr(buffer, needle))
|
||||
found = TRUE;
|
||||
|
||||
strbuf_free(&node);
|
||||
strbuf_free(&content);
|
||||
strbuf_free(&node_name);
|
||||
|
||||
cleanup:
|
||||
heap_free(buffer);
|
||||
if(temp_stream)
|
||||
IStream_Release(temp_stream);
|
||||
if(!found)
|
||||
{
|
||||
heap_free(title);
|
||||
return NULL;
|
||||
}
|
||||
return title;
|
||||
}
|
||||
|
||||
/* Search all children of a CHM storage object for the requested text and
|
||||
* return the last found search item.
|
||||
*/
|
||||
static SearchItem *SearchCHM_Storage(SearchItem *item, IStorage *pStorage,
|
||||
const char *needle)
|
||||
{
|
||||
const WCHAR szHTMext[] = {'.','h','t','m',0};
|
||||
IEnumSTATSTG *elem = NULL;
|
||||
WCHAR *filename = NULL;
|
||||
STATSTG entries;
|
||||
HRESULT hres;
|
||||
ULONG retr;
|
||||
|
||||
hres = IStorage_EnumElements(pStorage, 0, NULL, 0, &elem);
|
||||
if(hres != S_OK)
|
||||
{
|
||||
FIXME("Could not enumerate '/' storage elements: %08x\n", hres);
|
||||
return NULL;
|
||||
}
|
||||
while (IEnumSTATSTG_Next(elem, 1, &entries, &retr) == NOERROR)
|
||||
{
|
||||
switch(entries.type) {
|
||||
case STGTY_STORAGE:
|
||||
item = SearchCHM_Folder(item, pStorage, entries.pwcsName, needle);
|
||||
break;
|
||||
case STGTY_STREAM:
|
||||
filename = entries.pwcsName;
|
||||
while(strchrW(filename, '/'))
|
||||
filename = strchrW(filename, '/')+1;
|
||||
if(strstrW(filename, szHTMext))
|
||||
{
|
||||
WCHAR *title = SearchCHM_File(pStorage, filename, needle);
|
||||
|
||||
if(title)
|
||||
{
|
||||
item->next = alloc_search_item(title, entries.pwcsName);
|
||||
item = item->next;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
FIXME("Unhandled IStorage stream element.\n");
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
/* Open a CHM storage object (folder) by name and find all items with
|
||||
* the requested text. The last found item is returned.
|
||||
*/
|
||||
static SearchItem *SearchCHM_Folder(SearchItem *item, IStorage *pStorage,
|
||||
const WCHAR *folder, const char *needle)
|
||||
{
|
||||
IStorage *temp_storage = NULL;
|
||||
HRESULT hres;
|
||||
|
||||
hres = IStorage_OpenStorage(pStorage, folder, NULL, STGM_READ, NULL, 0, &temp_storage);
|
||||
if(FAILED(hres))
|
||||
{
|
||||
FIXME("Could not open '%s' storage object: %08x\n", debugstr_w(folder), hres);
|
||||
return NULL;
|
||||
}
|
||||
item = SearchCHM_Storage(item, temp_storage, needle);
|
||||
|
||||
IStorage_Release(temp_storage);
|
||||
return item;
|
||||
}
|
||||
|
||||
/* Search the entire CHM file for the requested text and add all of
|
||||
* the found items to a ListView for the user to choose the item
|
||||
* they want.
|
||||
*/
|
||||
void InitSearch(HHInfo *info, const char *needle)
|
||||
{
|
||||
CHMInfo *chm = info->pCHMInfo;
|
||||
SearchItem *root_item = alloc_search_item(NULL, NULL);
|
||||
|
||||
SearchCHM_Storage(root_item, chm->pStorage, needle);
|
||||
fill_search_tree(info->search.hwndList, root_item->next);
|
||||
if(info->search.root)
|
||||
ReleaseSearch(info);
|
||||
info->search.root = root_item;
|
||||
}
|
||||
|
||||
/* Free all of the found Search items. */
|
||||
void ReleaseSearch(HHInfo *info)
|
||||
{
|
||||
SearchItem *item = info->search.root;
|
||||
|
||||
info->search.root = NULL;
|
||||
while(item) {
|
||||
heap_free(item->filename);
|
||||
item = item->next;
|
||||
}
|
||||
}
|
179
reactos/dll/win32/hhctrl.ocx/stream.c
Normal file
179
reactos/dll/win32/hhctrl.ocx/stream.c
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* Copyright 2007 Jacek Caban for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "hhctrl.h"
|
||||
#include "stream.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp);
|
||||
|
||||
void strbuf_init(strbuf_t *buf)
|
||||
{
|
||||
buf->size = 8;
|
||||
buf->len = 0;
|
||||
buf->buf = heap_alloc(buf->size);
|
||||
}
|
||||
|
||||
void strbuf_zero(strbuf_t *buf)
|
||||
{
|
||||
buf->len = 0;
|
||||
}
|
||||
|
||||
void strbuf_free(strbuf_t *buf)
|
||||
{
|
||||
heap_free(buf->buf);
|
||||
}
|
||||
|
||||
void strbuf_append(strbuf_t *buf, const char *data, int len)
|
||||
{
|
||||
if(buf->len+len > buf->size) {
|
||||
buf->size = buf->len+len;
|
||||
buf->buf = heap_realloc(buf->buf, buf->size);
|
||||
}
|
||||
|
||||
memcpy(buf->buf+buf->len, data, len);
|
||||
buf->len += len;
|
||||
}
|
||||
|
||||
void stream_init(stream_t *stream, IStream *str)
|
||||
{
|
||||
memset(stream, 0, sizeof(stream_t));
|
||||
stream->str = str;
|
||||
}
|
||||
|
||||
BOOL stream_chr(stream_t *stream, strbuf_t *buf, char c)
|
||||
{
|
||||
BOOL b = TRUE;
|
||||
ULONG i;
|
||||
|
||||
while(b) {
|
||||
for(i=stream->p; i<stream->size; i++) {
|
||||
if(stream->buf[i] == c) {
|
||||
b = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(buf && i > stream->p)
|
||||
strbuf_append(buf, stream->buf+stream->p, i-stream->p);
|
||||
stream->p = i;
|
||||
|
||||
if(stream->p == stream->size) {
|
||||
stream->p = 0;
|
||||
IStream_Read(stream->str, stream->buf, sizeof(stream->buf), &stream->size);
|
||||
if(!stream->size)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return stream->size != 0;
|
||||
}
|
||||
|
||||
void get_node_name(strbuf_t *node, strbuf_t *name)
|
||||
{
|
||||
const char *ptr = node->buf+1;
|
||||
|
||||
strbuf_zero(name);
|
||||
|
||||
while(*ptr != '>' && !isspace(*ptr))
|
||||
ptr++;
|
||||
|
||||
strbuf_append(name, node->buf+1, ptr-node->buf-1);
|
||||
strbuf_append(name, "", 1);
|
||||
}
|
||||
|
||||
/* Return the stream content up to the next HTML tag.
|
||||
*
|
||||
* Note: the first returned character is the end of the last tag (>).
|
||||
*/
|
||||
BOOL next_content(stream_t *stream, strbuf_t *buf)
|
||||
{
|
||||
if(!stream_chr(stream, buf, '<'))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL next_node(stream_t *stream, strbuf_t *buf)
|
||||
{
|
||||
if(!stream_chr(stream, NULL, '<'))
|
||||
return FALSE;
|
||||
|
||||
if(!stream_chr(stream, buf, '>'))
|
||||
return FALSE;
|
||||
|
||||
strbuf_append(buf, ">", 2);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the value of a named HTML attribute.
|
||||
*
|
||||
* Note: Attribute names are case insensitive, so it is necessary to
|
||||
* put both the node text and the attribute name in the same case
|
||||
* before attempting a string search.
|
||||
*/
|
||||
const char *get_attr(const char *node, const char *name, int *len)
|
||||
{
|
||||
const char *ptr, *ptr2;
|
||||
int name_len, node_len;
|
||||
char name_buf[32];
|
||||
char *node_buf;
|
||||
int i;
|
||||
|
||||
/* Create a lower case copy of the node */
|
||||
node_len = strlen(node)+1;
|
||||
node_buf = heap_alloc(node_len*sizeof(char));
|
||||
if(!node_buf)
|
||||
return NULL;
|
||||
memcpy(node_buf, node, node_len);
|
||||
for(i=0;i<node_len;i++)
|
||||
node_buf[i] = tolower(node_buf[i]);
|
||||
/* Create a lower case copy of the attribute name (search string) */
|
||||
name_len = strlen(name);
|
||||
memcpy(name_buf, name, name_len);
|
||||
for(i=0;i<name_len;i++)
|
||||
name_buf[i] = tolower(name_buf[i]);
|
||||
name_buf[name_len++] = '=';
|
||||
name_buf[name_len++] = '\"';
|
||||
name_buf[name_len] = 0;
|
||||
|
||||
ptr = strstr(node_buf, name_buf);
|
||||
if(!ptr) {
|
||||
WARN("name not found\n");
|
||||
heap_free(node_buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ptr += name_len;
|
||||
ptr2 = strchr(ptr, '\"');
|
||||
if(!ptr2)
|
||||
{
|
||||
heap_free(node_buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*len = ptr2-ptr;
|
||||
/* Return the pointer offset within the original string */
|
||||
ptr = node+(ptr-node_buf);
|
||||
|
||||
heap_free(node_buf);
|
||||
return ptr;
|
||||
}
|
48
reactos/dll/win32/hhctrl.ocx/stream.h
Normal file
48
reactos/dll/win32/hhctrl.ocx/stream.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2007 Jacek Caban for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef HHCTRL_STREAM_H
|
||||
#define HHCTRL_STREAM_H
|
||||
|
||||
#define BLOCK_SIZE 0x1000
|
||||
|
||||
typedef struct {
|
||||
char *buf;
|
||||
int size;
|
||||
int len;
|
||||
} strbuf_t;
|
||||
|
||||
typedef struct {
|
||||
IStream *str;
|
||||
char buf[BLOCK_SIZE];
|
||||
ULONG size;
|
||||
ULONG p;
|
||||
} stream_t;
|
||||
|
||||
void strbuf_init(strbuf_t *buf);
|
||||
void strbuf_zero(strbuf_t *buf);
|
||||
void strbuf_free(strbuf_t *buf);
|
||||
void strbuf_append(strbuf_t *buf, const char *data, int len);
|
||||
void stream_init(stream_t *stream, IStream *str);
|
||||
BOOL stream_chr(stream_t *stream, strbuf_t *buf, char c);
|
||||
void get_node_name(strbuf_t *node, strbuf_t *name);
|
||||
BOOL next_content(stream_t *stream, strbuf_t *buf);
|
||||
BOOL next_node(stream_t *stream, strbuf_t *buf);
|
||||
const char *get_attr(const char *node, const char *name, int *len);
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue