diff --git a/reactos/subsys/system/ibrowser/Makefile b/reactos/subsys/system/ibrowser/Makefile new file mode 100644 index 00000000000..36881540edb --- /dev/null +++ b/reactos/subsys/system/ibrowser/Makefile @@ -0,0 +1,47 @@ +# +# ROS Internet Web Browser +# +# Makefile +# + +PATH_TO_TOP := ../../.. + +TARGET_TYPE := program + +TARGET_APPTYPE := windows + +TARGET_NAME := ibrowser + +TARGET_INSTALLDIR := . + +TARGET_CFLAGS := \ + -D__USE_W32API -DWIN32 -D_ROS_ \ + -D_WIN32_IE=0x0600 -D_WIN32_WINNT=0x0501 -DWINVER=0x0500 \ + -DUNICODE -fexceptions -Wall + +TARGET_CPPFLAGS := $(TARGET_CFLAGS) + +TARGET_RCFLAGS := -D__USE_W32API -DWIN32 -D_ROS_ -D__WINDRES__ + +TARGET_SDKLIBS := gdi32.a comctl32.a ole32.a oleaut32.a shell32.a expat.a + +TARGET_GCCLIBS := stdc++ uuid + +TARGET_OBJECTS := \ + ibrowser.o \ + mainframe.o \ + webchild.o \ + favorites.o \ + utility/utility.o \ + utility/window.o \ + utility/xmlstorage.o + +TARGET_CPPAPP := yes + +TARGET_PCH := precomp.h + +DEP_OBJECTS := $(TARGET_OBJECTS) + +include $(PATH_TO_TOP)/rules.mak +include $(TOOLS_PATH)/helper.mk +include $(TOOLS_PATH)/depend.mk diff --git a/reactos/subsys/system/ibrowser/Makefile.MinGW b/reactos/subsys/system/ibrowser/Makefile.MinGW new file mode 100644 index 00000000000..b968c1c4938 --- /dev/null +++ b/reactos/subsys/system/ibrowser/Makefile.MinGW @@ -0,0 +1,67 @@ +# +# ROS Internet Web Browser +# +# Makefile.MinGW +# + +CC = gcc +CXX = g++ +LINK = g++ + +CFLAGS = -DWIN32 -D_WIN32_IE=0x0600 -D_WIN32_WINNT=0x0501 -DWINVER=0x0500 -fexceptions -Wall -I. +RCFLAGS = -DWIN32 -D__WINDRES__ +LFLAGS = -Wl,--subsystem,windows + +ifdef DEBUG +CFLAGS += -D_DEBUG -g +RCFLAGS += -D_DEBUG +LFLAGS += -g +else +CFLAGS += -DNDEBUG -Os +RCFLAGS += -DNDEBUG +LFLAGS += -s +endif + +ifndef UNICODE +UNICODE = 1 +endif + +ifeq ($(UNICODE),1) +CFLAGS += -DUNICODE +# LFLAGS+= -Wl,--entry,_wWinMain@16 +RCFLAGS += -DUNICODE +endif + +CXXFLAGS = $(CFLAGS) + +EXEC_SUFFIX = .exe +RES_SUFFIX = .coff + +VPATH = utility + +PROGRAM = ibrowser + +TARGET = $(PROGRAM)$(EXEC_SUFFIX) + +OBJECTS = \ + utility.o \ + window.o \ + ibrowser.o \ + webchild.o \ + mainframe.o \ + favorites.o \ + xmlstorage.o + +LIBS = gdi32 comctl32 shell32 ole32 uuid oleaut32 + +all: $(TARGET) + +$(TARGET): $(OBJECTS) $(PROGRAM)$(RES_SUFFIX) libexpat.dll + $(LINK) $(LFLAGS) -o $@ $^ $(addprefix -l,$(LIBS)) $(addprefix -l,$(DELAYIMPORTS)) + +ibrowser$(RES_SUFFIX): $(PROGRAM)_intres.rc res/*.bmp res/*.ico + windres $(RCFLAGS) -o $@ $(PROGRAM)_intres.rc + +clean: + rm -f $(TARGET) $(OBJECTS) $(PROGRAM)$(RES_SUFFIX) \ + desktop/*.o dialogs/*.o shell/*.o taskbar/*.o utility/*.o diff --git a/reactos/subsys/system/ibrowser/Makefile.PCH b/reactos/subsys/system/ibrowser/Makefile.PCH new file mode 100644 index 00000000000..71fc8575fa3 --- /dev/null +++ b/reactos/subsys/system/ibrowser/Makefile.PCH @@ -0,0 +1,72 @@ +# +# ROS Internet Web Browser +# +# Makefile.PCH +# +# MinGW Makefile with precompiled header support +# + +CC = gcc +CXX = g++ +LINK = g++ + +CFLAGS = -DWIN32 -D_WIN32_IE=0x0600 -D_WIN32_WINNT=0x0501 -DWINVER=0x0500 -fexceptions -Wall -I. +RCFLAGS = -DWIN32 -D__WINDRES__ +LFLAGS = -Wl,--subsystem,windows + +ifdef DEBUG +CFLAGS += -D_DEBUG -g +RCFLAGS += -D_DEBUG +LFLAGS += -g +else +CFLAGS += -DNDEBUG -Os -march=pentium4 +RCFLAGS += -DNDEBUG +LFLAGS += -s +endif + +ifndef UNICODE +UNICODE = 1 +endif + +ifeq ($(UNICODE),1) +CFLAGS += -DUNICODE +# LFLAGS+= -Wl,--entry,_wWinMain@16 +RCFLAGS += -DUNICODE +endif + +CXXFLAGS = $(CFLAGS) + +EXEC_SUFFIX = .exe +RES_SUFFIX = .coff + +VPATH = utility + +PROGRAM = ibrowser + +TARGET = $(PROGRAM)$(EXEC_SUFFIX) + +OBJECTS = \ + utility.o \ + window.o \ + ibrowser.o \ + webchild.o \ + mainframe.o \ + favorites.o \ + xmlstorage.o + +LIBS = gdi32 comctl32 shell32 ole32 oleaut32 uuid + +all: precomp.h.gch $(TARGET) + +precomp.h.gch: *.h utility/*.h + $(CXX) $(CFLAGS) precomp.h + +$(TARGET): $(OBJECTS) $(PROGRAM)$(RES_SUFFIX) libexpat.dll + $(LINK) $(LFLAGS) -o $@ $^ $(addprefix -l,$(LIBS)) $(addprefix -l,$(DELAYIMPORTS)) + +ibrowser$(RES_SUFFIX): $(PROGRAM)_intres.rc res/*.bmp res/*.ico + windres $(RCFLAGS) -o $@ $(PROGRAM)_intres.rc + +clean: + rm -f $(TARGET) $(OBJECTS) $(PROGRAM)$(RES_SUFFIX) precomp.h.gch \ + utility/*.o diff --git a/reactos/subsys/system/ibrowser/expat.license b/reactos/subsys/system/ibrowser/expat.license new file mode 100644 index 00000000000..5c5d524a1f8 --- /dev/null +++ b/reactos/subsys/system/ibrowser/expat.license @@ -0,0 +1,22 @@ +Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + and Clark Cooper +Copyright (c) 2001, 2002, 2003 Expat maintainers. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/reactos/subsys/system/ibrowser/favorites.cpp b/reactos/subsys/system/ibrowser/favorites.cpp new file mode 100644 index 00000000000..0da5cc365e2 --- /dev/null +++ b/reactos/subsys/system/ibrowser/favorites.cpp @@ -0,0 +1,494 @@ +/* + * Copyright 2004 Martin Fuchs + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + + // + // Explorer and Desktop clone + // + // favorites.cpp + // + // Martin Fuchs, 04.04.2004 + // + + +#include "precomp.h" + + +String DecodeURLString(const char* s) +{ + TCHAR buffer[BUFFER_LEN]; + LPTSTR o = buffer; + + for(const char* p=s; *p; ++p) + if (*p == '%') { + if (!strncmp(p+1, "20", 2)) { + *o++ = ' '; + p += 2; + } else + *o++ = *p; + } else + *o++ = *p; + + return String(buffer, o-buffer); +} + + + /// read .URL file +bool Bookmark::read_url(LPCTSTR path) +{ + char line[BUFFER_LEN]; + + tifstream in(path); + + while(in.good()) { + in.getline(line, BUFFER_LEN); + + const char* p = line; + while(isspace(*p)) + ++p; + + const char* keyword = p; + const char* eq = strchr(p, '='); + + if (eq) { + const char* cont = eq + 1; + while(isspace(*cont)) + ++cont; + + if (!strnicmp(keyword, "URL", 3)) + _url = DecodeURLString(cont); + else if (!strnicmp(keyword, "IconFile", 8)) + _icon_path = DecodeURLString(cont); + } + } + + return true; +} + + /// convert XBEL bookmark node +bool Bookmark::read(const_XMLPos& pos) +{ + _url = pos.get("href").c_str(); + + if (pos.go_down("title")) { + _name = pos->get_content(); + pos.back(); + } + + if (pos.go_down("desc")) { + _description = pos->get_content(); + pos.back(); + } + + if (pos.go_down("info")) { + const_XMLChildrenFilter metadata(pos, "metadata"); + + for(const_XMLChildrenFilter::const_iterator it=metadata.begin(); it!=metadata.end(); ++it) { + const XMLNode& node = **it; + const_XMLPos sub_pos(&node); + + if (node.get("owner") == "ros-explorer") { + if (sub_pos.go_down("icon")) { + _icon_path = sub_pos.get("path").c_str(); + _icon_idx = XS_toi(sub_pos.get("index")); + + sub_pos.back(); // + } + } + } + + pos.back(); // + pos.back(); // + } + + return !_url.empty(); // _url is mandatory. +} + + /// write XBEL bookmark node +void Bookmark::write(XMLPos& pos) const +{ + pos.create("bookmark"); + + pos["href"] = _url.c_str(); + + if (!_name.empty()) { + pos.create("title"); + pos->set_content(_name); + pos.back(); + } + + if (!_description.empty()) { + pos.create("desc"); + pos->set_content(_description); + pos.back(); + } + + if (!_icon_path.empty()) { + pos.create("info"); + pos.create("metadata"); + pos["owner"] = "ros-explorer"; + pos.create("icon"); + pos["path"] = _icon_path.c_str(); + pos["index"].printf(XS_TEXT("%d"), _icon_idx); + pos.back(); // + pos.back(); // + pos.back(); // + } + + pos.back(); +} + + + /// read bookmark folder from XBEL formated XML tree +void BookmarkFolder::read(const_XMLPos& pos) +{ + if (pos.go_down("title")) { + _name = pos->get_content(); + pos.back(); + } + + if (pos.go_down("desc")) { + _description = pos->get_content(); + pos.back(); + } + + _bookmarks.read(pos); +} + + /// write bookmark folder content from XBEL formated XML tree +void BookmarkFolder::write(XMLPos& pos) const +{ + pos.create("folder"); + + if (!_name.empty()) { + pos.create("title"); + pos->set_content(_name); + pos.back(); + } + + if (!_description.empty()) { + pos.create("desc"); + pos->set_content(_description); + pos.back(); + } + + _bookmarks.write(pos); +} + + +BookmarkNode::BookmarkNode() + : _type(BMNT_NONE) +{ + _pbookmark = NULL; +} + +BookmarkNode::BookmarkNode(const Bookmark& bm) + : _type(BMNT_BOOKMARK) +{ + _pbookmark = new Bookmark(bm); +} + +BookmarkNode::BookmarkNode(const BookmarkFolder& bmf) + : _type(BMNT_FOLDER) +{ + _pfolder = new BookmarkFolder(bmf); +} + +BookmarkNode::BookmarkNode(const BookmarkNode& other) + : _type(other._type) +{ + if (other._type == BMNT_BOOKMARK) + _pbookmark = new Bookmark(*other._pbookmark); + else if (other._type == BMNT_FOLDER) + _pfolder = new BookmarkFolder(*other._pfolder); + else + _pbookmark = NULL; +} + +BookmarkNode::~BookmarkNode() +{ + if (_type == BMNT_BOOKMARK) + delete _pbookmark; + else if (_type == BMNT_FOLDER) + delete _pfolder; +} + +BookmarkNode& BookmarkNode::operator=(const Bookmark& bm) +{ + clear(); + + _pbookmark = new Bookmark(bm); + + return *this; +} + +BookmarkNode& BookmarkNode::operator=(const BookmarkFolder& bmf) +{ + clear(); + + _pfolder = new BookmarkFolder(bmf); + + return *this; +} + +BookmarkNode& BookmarkNode::operator=(const BookmarkNode& other) +{ + clear(); + + _type = other._type; + + if (other._type == BMNT_BOOKMARK) + _pbookmark = new Bookmark(*other._pbookmark); + else if (other._type == BMNT_FOLDER) + _pfolder = new BookmarkFolder(*other._pfolder); + + return *this; +} + +void BookmarkNode::clear() +{ + if (_type == BMNT_BOOKMARK) { + delete _pbookmark; + _pbookmark = NULL; + } + else if (_type == BMNT_FOLDER) { + delete _pfolder; + _pfolder = NULL; + } + + _type = BMNT_NONE; +} + + + /// read bookmark list from XBEL formated XML tree +void BookmarkList::read(const_XMLPos& pos) +{ + const XMLNode::Children& children = pos->get_children(); + + for(XMLNode::Children::const_iterator it=children.begin(); it!=children.end(); ++it) { + const XMLNode& node = **it; + const_XMLPos sub_pos(&node); + + if (node == "folder") { + BookmarkFolder folder; + + folder.read(sub_pos); + + push_back(folder); + } else if (node == "bookmark") { + Bookmark bookmark; + + if (bookmark.read(sub_pos)) + push_back(bookmark); + } + } +} + + /// write bookmark list into XBEL formated XML tree +void BookmarkList::write(XMLPos& pos) const +{ + for(const_iterator it=begin(); it!=end(); ++it) { + const BookmarkNode& node = *it; + + if (node._type == BookmarkNode::BMNT_FOLDER) { + const BookmarkFolder& folder = *node._pfolder; + + folder.write(pos); + + pos.back(); + } else if (node._type == BookmarkNode::BMNT_BOOKMARK) { + const Bookmark& bookmark = *node._pbookmark; + + if (!bookmark._url.empty()) + bookmark.write(pos); + } + } +} + + + /// fill treeview control with bookmark tree content +void BookmarkList::fill_tree(HWND hwnd, HTREEITEM parent, HIMAGELIST himagelist, HDC hdc_wnd) const +{ + TV_INSERTSTRUCT tvi; + + tvi.hParent = parent; + tvi.hInsertAfter = TVI_LAST; + + TV_ITEM& tv = tvi.item; + tv.mask = TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM; + + for(const_iterator it=begin(); it!=end(); ++it) { + const BookmarkNode& node = *it; + + tv.lParam = (LPARAM)&node; + + if (node._type == BookmarkNode::BMNT_FOLDER) { + const BookmarkFolder& folder = *node._pfolder; + + tv.pszText = (LPTSTR)folder._name.c_str(); + tv.iImage = 3; // folder + tv.iSelectedImage = 4; // open folder + HTREEITEM hitem = TreeView_InsertItem(hwnd, &tvi); + + folder._bookmarks.fill_tree(hwnd, hitem, himagelist, hdc_wnd); + } else if (node._type == BookmarkNode::BMNT_BOOKMARK) { + const Bookmark& bookmark = *node._pbookmark; + + tv.pszText = (LPTSTR)bookmark._name.c_str(); + tv.iImage = 1; // bookmark + tv.iSelectedImage = 2; // selected bookmark + + if (!bookmark._icon_path.empty()) { + const Icon& icon = g_icon_cache.extract(bookmark._icon_path, bookmark._icon_idx); + + if ((ICON_ID)icon != ICID_NONE) + tv.iImage = tv.iSelectedImage = icon.add_to_imagelist(himagelist, hdc_wnd); + } + + TreeView_InsertItem(hwnd, &tvi); + } + } +} + + +/*@@ + + /// import Internet Explorer bookmarks from Favorites folder into bookmark list +void BookmarkList::import_IE_favorites(ShellDirectory& dir, HWND hwnd) +{ + TCHAR path[MAX_PATH], ext[_MAX_EXT]; + + dir.smart_scan(SORT_NAME, SCAN_FILESYSTEM); + + for(Entry*entry=dir._down; entry; entry=entry->_next) { + if (entry->_shell_attribs & SFGAO_HIDDEN) // ignore files like "desktop.ini" + continue; + + String name; + + if (entry->_etype == ET_SHELL) + name = dir._folder.get_name(static_cast(entry)->_pidl); + else + name = entry->_display_name; + + if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + BookmarkFolder new_folder; + + new_folder._name = DecodeXMLString(name); + + if (entry->_etype == ET_SHELL) { + ShellDirectory new_dir(dir._folder, static_cast(entry)->_pidl, hwnd); + new_folder._bookmarks.import_IE_favorites(new_dir, hwnd); + } else { + entry->get_path(path); + ShellDirectory new_dir(GetDesktopFolder(), path, hwnd); + new_folder._bookmarks.import_IE_favorites(new_dir, hwnd); + } + + push_back(new_folder); + } else { + Bookmark bookmark; + + bookmark._name = DecodeXMLString(name); + + entry->get_path(path); + _tsplitpath(path, NULL, NULL, NULL, ext); + + if (!_tcsicmp(ext, TEXT(".url"))) { + bookmark.read_url(path); + push_back(bookmark); + } else { + ///@todo read shell links + //assert(0); + } + } + } +} + +*/ + + + /// read XBEL bookmark file +bool Favorites::read(LPCTSTR path) +{ + XMLDoc xbel; + + if (!xbel.read(path)) + if (xbel._last_error == XML_ERROR_NO_ELEMENTS) + return false; + else + MessageBox(0/*@@g_Globals._hwndDesktop*/, String(xbel._last_error_msg.c_str()), + TEXT("ROS Explorer - reading bookmark file"), MB_OK); + + const_XMLPos pos(&xbel); + + if (!pos.go_down("xbel")) + return false; + + super::read(pos); + + pos.back(); + + return true; +} + + /// write XBEL bookmark file +void Favorites::write(LPCTSTR path) const +{ + XMLDoc xbel; + + XMLPos pos(&xbel); + pos.create("xbel"); + super::write(pos); + pos.back(); + + xbel.write(path, XMLNode::FORMAT_SMART, XMLHeader("1.0", "UTF-8", "")); +} + + +/*@@ + + /// import Internet Explorer bookmarks from Favorites folder +bool Favorites::import_IE_favorites(HWND hwnd) +{ + WaitCursor wait; + + StartMenuShellDirs dirs; + + try { + dirs.push_back(ShellDirectory(GetDesktopFolder(), SpecialFolderPath(CSIDL_COMMON_FAVORITES, hwnd), hwnd)); + dirs.push_back(ShellDirectory(GetDesktopFolder(), SpecialFolderPath(CSIDL_FAVORITES, hwnd), hwnd)); + } catch(COMException&) { + } + + for(StartMenuShellDirs::iterator it=dirs.begin(); it!=dirs.end(); ++it) { + StartMenuDirectory& smd = *it; + ShellDirectory& dir = smd._dir; + + try { + super::import_IE_favorites(dir, hwnd); + } catch(COMException&) { + } + } + + return true; +} + +*/ diff --git a/reactos/subsys/system/ibrowser/favorites.h b/reactos/subsys/system/ibrowser/favorites.h new file mode 100644 index 00000000000..4d139ee0d1d --- /dev/null +++ b/reactos/subsys/system/ibrowser/favorites.h @@ -0,0 +1,104 @@ +/* + * Copyright 2004 Martin Fuchs + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + + // + // Explorer and Desktop clone + // + // favorites.h + // + // Martin Fuchs, 04.04.2004 + // + + +extern String DecodeURLString(const char* s); + + +struct Bookmark +{ + Bookmark() : _icon_idx(0) {} + + String _name; + String _description; + String _url; + String _icon_path; + int _icon_idx; + + bool read_url(LPCTSTR path); + bool read(const_XMLPos& pos); + void write(XMLPos& pos) const; +}; + +struct BookmarkFolder; + +struct BookmarkNode +{ + BookmarkNode(); + BookmarkNode(const Bookmark& bm); + BookmarkNode(const BookmarkFolder& bmf); + BookmarkNode(const BookmarkNode& other); + + ~BookmarkNode(); + + BookmarkNode& operator=(const Bookmark& bm); + BookmarkNode& operator=(const BookmarkFolder& bmf); + BookmarkNode& operator=(const BookmarkNode& other); + + void clear(); + + enum BOOKMARKNODE_TYPE { + BMNT_NONE, BMNT_BOOKMARK, BMNT_FOLDER + }; + + BOOKMARKNODE_TYPE _type; + + union { + Bookmark* _pbookmark; + BookmarkFolder* _pfolder; + }; +}; + +struct BookmarkList : public list +{ + void import_IE_favorites(struct ShellDirectory& dir, HWND hwnd); + + void read(const_XMLPos& pos); + void write(XMLPos& pos) const; + + void fill_tree(HWND hwnd, HTREEITEM parent, HIMAGELIST, HDC hdc_wnd) const; +}; + +struct BookmarkFolder +{ + String _name; + String _description; + BookmarkList _bookmarks; + + void read(const_XMLPos& pos); + void write(XMLPos& pos) const; +}; + +struct Favorites : public BookmarkList +{ + typedef BookmarkList super; + + bool read(LPCTSTR path); + void write(LPCTSTR path) const; + + bool import_IE_favorites(HWND hwnd); +}; diff --git a/reactos/subsys/system/ibrowser/ibrowser.cpp b/reactos/subsys/system/ibrowser/ibrowser.cpp new file mode 100644 index 00000000000..7165a4e8946 --- /dev/null +++ b/reactos/subsys/system/ibrowser/ibrowser.cpp @@ -0,0 +1,517 @@ +/* + * Copyright 2005 Martin Fuchs + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + + // + // ROS Internet Web Browser + // + // ibrowser.cpp + // + // Martin Fuchs, 24.01.2005 + // + + +#include "precomp.h" + +#include "ibrowser_intres.h" + +#include // for setlocale() + +#ifndef __WINE__ +#include // for dup2() +#include // for _O_RDONLY +#endif + + + // globals + +HINSTANCE g_hInstance; +IconCache g_icon_cache; +ATOM g_hframeClass; + + +/*@@ +void ExplorerGlobals::read_persistent() +{ + // read configuration file + _cfg_dir.printf(TEXT("%s\\ReactOS"), (LPCTSTR)SpecialFolderFSPath(CSIDL_APPDATA,0)); + _cfg_path.printf(TEXT("%s\\ros-ibrowser-cfg.xml"), _cfg_dir.c_str()); + + if (!_cfg.read(_cfg_path)) { + if (_cfg._last_error != XML_ERROR_NO_ELEMENTS) + MessageBox(g_Globals._hwndDesktop, String(_cfg._last_error_msg.c_str()), + TEXT("ROS Explorer - reading user settings"), MB_OK); + + _cfg.read(TEXT("ibrowser-cfg-template.xml")); + } + + // read bookmarks + _favorites_path.printf(TEXT("%s\\ros-ibrowser-bookmarks.xml"), _cfg_dir.c_str()); + + if (!_favorites.read(_favorites_path)) { + _favorites.import_IE_favorites(0); + _favorites.write(_favorites_path); + } +} + +void ExplorerGlobals::write_persistent() +{ + // write configuration file + RecursiveCreateDirectory(_cfg_dir); + + _cfg.write(_cfg_path); + _favorites.write(_favorites_path); +} + + +XMLPos ExplorerGlobals::get_cfg() +{ + XMLPos cfg_pos(&_cfg); + + cfg_pos.smart_create("ibrowser-cfg"); + + return cfg_pos; +} + +XMLPos ExplorerGlobals::get_cfg(const char* path) +{ + XMLPos cfg_pos(&_cfg); + + cfg_pos.smart_create("ibrowser-cfg"); + cfg_pos.create_relative(path); + + return cfg_pos; +} +*/ + + +Icon::Icon() + : _id(ICID_UNKNOWN), + _itype(IT_STATIC), + _hicon(0) +{ +} + +Icon::Icon(ICON_ID id, UINT nid) + : _id(id), + _itype(IT_STATIC), + _hicon(SmallIcon(nid)) +{ +} + +Icon::Icon(ICON_TYPE itype, int id, HICON hIcon) + : _id((ICON_ID)id), + _itype(itype), + _hicon(hIcon) +{ +} + +Icon::Icon(ICON_TYPE itype, int id, int sys_idx) + : _id((ICON_ID)id), + _itype(itype), + _sys_idx(sys_idx) +{ +} + +void Icon::draw(HDC hdc, int x, int y, int cx, int cy, COLORREF bk_color, HBRUSH bk_brush) const +{ + if (_itype == IT_SYSCACHE) + ImageList_DrawEx(g_icon_cache.get_sys_imagelist(), _sys_idx, hdc, x, y, cx, cy, bk_color, CLR_DEFAULT, ILD_NORMAL); + else + DrawIconEx(hdc, x, y, _hicon, cx, cy, 0, bk_brush, DI_NORMAL); +} + +HBITMAP Icon::create_bitmap(COLORREF bk_color, HBRUSH hbrBkgnd, HDC hdc_wnd) const +{ + if (_itype == IT_SYSCACHE) { + HIMAGELIST himl = g_icon_cache.get_sys_imagelist(); + + int cx, cy; + ImageList_GetIconSize(himl, &cx, &cy); + + HBITMAP hbmp = CreateCompatibleBitmap(hdc_wnd, cx, cy); + HDC hdc = CreateCompatibleDC(hdc_wnd); + HBITMAP hbmp_old = SelectBitmap(hdc, hbmp); + ImageList_DrawEx(himl, _sys_idx, hdc, 0, 0, cx, cy, bk_color, CLR_DEFAULT, ILD_NORMAL); + SelectBitmap(hdc, hbmp_old); + DeleteDC(hdc); + + return hbmp; + } else + return create_bitmap_from_icon(_hicon, hbrBkgnd, hdc_wnd); +} + + +int Icon::add_to_imagelist(HIMAGELIST himl, HDC hdc_wnd, COLORREF bk_color, HBRUSH bk_brush) const +{ + int ret; + + if (_itype == IT_SYSCACHE) { + HIMAGELIST himl = g_icon_cache.get_sys_imagelist(); + + int cx, cy; + ImageList_GetIconSize(himl, &cx, &cy); + + HBITMAP hbmp = CreateCompatibleBitmap(hdc_wnd, cx, cy); + HDC hdc = CreateCompatibleDC(hdc_wnd); + HBITMAP hbmp_old = SelectBitmap(hdc, hbmp); + ImageList_DrawEx(himl, _sys_idx, hdc, 0, 0, cx, cy, bk_color, CLR_DEFAULT, ILD_NORMAL); + SelectBitmap(hdc, hbmp_old); + DeleteDC(hdc); + + ret = ImageList_Add(himl, hbmp, 0); + + DeleteObject(hbmp); + } else + ret = ImageList_AddAlphaIcon(himl, _hicon, bk_brush, hdc_wnd); + + return ret; +} + +HBITMAP create_bitmap_from_icon(HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd) +{ + int cx = GetSystemMetrics(SM_CXSMICON); + int cy = GetSystemMetrics(SM_CYSMICON); + HBITMAP hbmp = CreateCompatibleBitmap(hdc_wnd, cx, cy); + + MemCanvas canvas; + BitmapSelection sel(canvas, hbmp); + + RECT rect = {0, 0, cx, cy}; + FillRect(canvas, &rect, hbrush_bkgnd); + + DrawIconEx(canvas, 0, 0, hIcon, cx, cy, 0, hbrush_bkgnd, DI_NORMAL); + + return hbmp; +} + +int ImageList_AddAlphaIcon(HIMAGELIST himl, HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd) +{ + HBITMAP hbmp = create_bitmap_from_icon(hIcon, hbrush_bkgnd, hdc_wnd); + + int ret = ImageList_Add(himl, hbmp, 0); + + DeleteObject(hbmp); + + return ret; +} + + +int IconCache::s_next_id = ICID_DYNAMIC; + + +void IconCache::init() +{ + _icons[ICID_NONE] = Icon(IT_STATIC, ICID_NONE, (HICON)0); + + _icons[ICID_IBROWSER] = Icon(ICID_IBROWSER, IDI_IBROWSER); + _icons[ICID_BOOKMARK] = Icon(ICID_BOOKMARK, IDI_DOT_TRANS); +} + + +const Icon& IconCache::extract(const String& path) +{ + PathMap::iterator found = _pathMap.find(path); + + if (found != _pathMap.end()) + return _icons[found->second]; + + SHFILEINFO sfi; + +#if 1 // use system image list + HIMAGELIST himlSys = (HIMAGELIST) SHGetFileInfo(path, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX|SHGFI_SMALLICON); + + if (himlSys) { + _himlSys = himlSys; + + const Icon& icon = add(sfi.iIcon/*, IT_SYSCACHE*/); +#else + if (SHGetFileInfo(path, 0, &sfi, sizeof(sfi), SHGFI_ICON|SHGFI_SMALLICON)) { + const Icon& icon = add(sfi.hIcon, IT_CACHED); +#endif + + ///@todo limit cache size + _pathMap[path] = icon; + + return icon; + } else + return _icons[ICID_NONE]; +} + +const Icon& IconCache::extract(LPCTSTR path, int idx) +{ + CachePair key(path, idx); + +#ifndef __WINE__ ///@todo _tcslwr() for Wine + _tcslwr((LPTSTR)key.first.c_str()); +#endif + + PathIdxMap::iterator found = _pathIdxMap.find(key); + + if (found != _pathIdxMap.end()) + return _icons[found->second]; + + HICON hIcon; + + if ((int)ExtractIconEx(path, idx, NULL, &hIcon, 1) > 0) { + const Icon& icon = add(hIcon, IT_CACHED); + + _pathIdxMap[key] = icon; + + return icon; + } else { + + ///@todo retreive "http://.../favicon.ico" format icons + + return _icons[ICID_NONE]; + } +} + + +const Icon& IconCache::add(HICON hIcon, ICON_TYPE type) +{ + int id = ++s_next_id; + + return _icons[id] = Icon(type, id, hIcon); +} + +const Icon& IconCache::add(int sys_idx/*, ICON_TYPE type=IT_SYSCACHE*/) +{ + int id = ++s_next_id; + + return _icons[id] = SysCacheIcon(id, sys_idx); +} + +const Icon& IconCache::get_icon(int id) +{ + return _icons[id]; +} + +void IconCache::free_icon(int icon_id) +{ + IconMap::iterator found = _icons.find(icon_id); + + if (found != _icons.end()) { + Icon& icon = found->second; + + if (icon.destroy()) + _icons.erase(found); + } +} + + +ResString::ResString(UINT nid) +{ + TCHAR buffer[BUFFER_LEN]; + + int len = LoadString(g_hInstance, nid, buffer, sizeof(buffer)/sizeof(TCHAR)); + + super::assign(buffer, len); +} + + +ResIcon::ResIcon(UINT nid) +{ + _hicon = LoadIcon(g_hInstance, MAKEINTRESOURCE(nid)); +} + +SmallIcon::SmallIcon(UINT nid) +{ + _hicon = (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(nid), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED); +} + +ResIconEx::ResIconEx(UINT nid, int w, int h) +{ + _hicon = (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(nid), IMAGE_ICON, w, h, LR_SHARED); +} + + +void SetWindowIcon(HWND hwnd, UINT nid) +{ + HICON hIcon = ResIcon(nid); + Window_SetIcon(hwnd, ICON_BIG, hIcon); + + HICON hIconSmall = SmallIcon(nid); + Window_SetIcon(hwnd, ICON_SMALL, hIconSmall); +} + + +ResBitmap::ResBitmap(UINT nid) +{ + _hBmp = LoadBitmap(g_hInstance, MAKEINTRESOURCE(nid)); +} + + +void ibrowser_show_frame(int cmdshow, LPTSTR lpCmdLine) +{ + MainFrameBase::Create(lpCmdLine, cmdshow); +} + + +PopupMenu::PopupMenu(UINT nid) +{ + HMENU hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(nid)); + _hmenu = GetSubMenu(hMenu, 0); +} + + + /// "About Explorer" Dialog +struct ExplorerAboutDlg : public + CtlColorParent< + OwnerDrawParent + > +{ + typedef CtlColorParent< + OwnerDrawParent + > super; + + ExplorerAboutDlg(HWND hwnd) + : super(hwnd) + { + SetWindowIcon(hwnd, IDI_REACTOS); + + new FlatButton(hwnd, IDOK); + + _hfont = CreateFont(20, 0, 0, 0, FW_BOLD, TRUE, 0, 0, 0, 0, 0, 0, 0, TEXT("Sans Serif")); + new ColorStatic(hwnd, IDC_ROS_IBROWSER, RGB(32,32,128), 0, _hfont); + + new HyperlinkCtrl(hwnd, IDC_WWW); + + FmtString ver_txt(ResString(IDS_IBROWSER_VERSION_STR), (LPCTSTR)ResString(IDS_VERSION_STR)); + SetWindowText(GetDlgItem(hwnd, IDC_VERSION_TXT), ver_txt); + + /*@@ + HWND hwnd_winver = GetDlgItem(hwnd, IDC_WIN_VERSION); + SetWindowText(hwnd_winver, get_windows_version_str()); + SetWindowFont(hwnd_winver, GetStockFont(DEFAULT_GUI_FONT), FALSE); + */ + + CenterWindow(hwnd); + } + + ~ExplorerAboutDlg() + { + DeleteObject(_hfont); + } + +protected: + HFONT _hfont; +}; + +void ibrowser_about(HWND hwndParent) +{ + Dialog::DoModal(IDD_ABOUT_IBROWSER, WINDOW_CREATOR(ExplorerAboutDlg), hwndParent); +} + + +static void InitInstance(HINSTANCE hInstance) +{ + CONTEXT("InitInstance"); + + // register frame window class + g_hframeClass = IconWindowClass(CLASSNAME_FRAME,IDI_IBROWSER); + + // register child window class + WindowClass(CLASSNAME_CHILDWND, CS_CLASSDC|CS_VREDRAW).Register(); +} + + +int ibrowser_main(HINSTANCE hInstance, LPTSTR lpCmdLine, int cmdshow) +{ + CONTEXT("ibrowser_main"); + + // initialize Common Controls library + CommonControlInit usingCmnCtrl; + + try { + InitInstance(hInstance); + } catch(COMException& e) { + HandleException(e, GetDesktopWindow()); + return -1; + } + + if (cmdshow != SW_HIDE) { +/* // don't maximize if being called from the ROS desktop + if (cmdshow == SW_SHOWNORMAL) + ///@todo read window placement from registry + cmdshow = SW_MAXIMIZE; +*/ + + ibrowser_show_frame(cmdshow, lpCmdLine); + } + + return Window::MessageLoop(); +} + + + // MinGW does not provide a Unicode startup routine, so we have to implement an own. +#if defined(__MINGW32__) && defined(UNICODE) + +#define _tWinMain wWinMain +int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int); + +int main(int argc, char* argv[]) +{ + CONTEXT("main"); + + STARTUPINFO startupinfo; + int nShowCmd = SW_SHOWNORMAL; + + GetStartupInfo(&startupinfo); + + if (startupinfo.dwFlags & STARTF_USESHOWWINDOW) + nShowCmd = startupinfo.wShowWindow; + + LPWSTR cmdline = GetCommandLineW(); + + while(*cmdline && !_istspace(*cmdline)) + ++cmdline; + + return wWinMain(GetModuleHandle(NULL), 0, cmdline, nShowCmd); +} + +#endif // __MINGW && UNICODE + + +int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd) +{ + CONTEXT("WinMain()"); + + g_hInstance = hInstance; + + // initialize COM and OLE before creating the desktop window + OleInit usingCOM; + + // init common controls library + CommonControlInit usingCmnCtrl; + +//@@ g_Globals.read_persistent(); + + /**TODO fix command line handling */ + if (*lpCmdLine=='"' && lpCmdLine[_tcslen(lpCmdLine)-1]=='"') { + ++lpCmdLine; + lpCmdLine[_tcslen(lpCmdLine)-1] = '\0'; + } + + int ret = ibrowser_main(hInstance, lpCmdLine, nShowCmd); + + // write configuration file +//@@ g_Globals.write_persistent(); + + return ret; +} diff --git a/reactos/subsys/system/ibrowser/ibrowser.dsp b/reactos/subsys/system/ibrowser/ibrowser.dsp new file mode 100644 index 00000000000..02291f30a2a --- /dev/null +++ b/reactos/subsys/system/ibrowser/ibrowser.dsp @@ -0,0 +1,305 @@ +# Microsoft Developer Studio Project File - Name="ibrowser" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=IBROWSER - WIN32 DEBUG +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ibrowser.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ibrowser.mak" CFG="IBROWSER - WIN32 DEBUG" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ibrowser - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "ibrowser - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "ibrowser - Win32 Debug Release" (based on "Win32 (x86) Console Application") +!MESSAGE "ibrowser - Win32 Unicode Release" (based on "Win32 (x86) Console Application") +!MESSAGE "ibrowser - Win32 Unicode Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ibrowser - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GR /GX /O1 /D "NDEBUG" /D "WIN32" /D _WIN32_IE=0x0600 /D _WIN32_WINNT=0x0501 /Yu"precomp.h" /FD /c +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 gdi32.lib comctl32.lib shell32.lib ole32.lib /nologo /subsystem:windows /machine:I386 /libpath:"Release" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "ibrowser - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D _WIN32_IE=0x0600 /D _WIN32_WINNT=0x0501 /FR /Yu"precomp.h" /FD /GZ /c +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib gdi32.lib comctl32.lib shell32.lib ole32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept /libpath:"Debug" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "ibrowser - Win32 Debug Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "DRelease" +# PROP BASE Intermediate_Dir "DRelease" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "DRelease" +# PROP Intermediate_Dir "DRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_ROS_" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GR /GX /Zi /O2 /D "NDEBUG" /D "WIN32" /D _WIN32_IE=0x0600 /D _WIN32_WINNT=0x0501 /FR /Yu"precomp.h" /FD /c +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 user32.lib gdi32.lib advapi32.lib shell32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 gdi32.lib comctl32.lib shell32.lib ole32.lib /nologo /subsystem:windows /debug /machine:I386 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "ibrowser - Win32 Unicode Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "URelease" +# PROP BASE Intermediate_Dir "URelease" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "URelease" +# PROP Intermediate_Dir "URelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "UNICODE" /D "_ROS_" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GR /GX /O2 /D "NDEBUG" /D "UNICODE" /D "WIN32" /D _WIN32_IE=0x0600 /D _WIN32_WINNT=0x0501 /Yu"precomp.h" /FD /c +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 user32.lib gdi32.lib advapi32.lib shell32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 gdi32.lib comctl32.lib shell32.lib ole32.lib /nologo /subsystem:windows /machine:I386 /libpath:"Release" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "ibrowser - Win32 Unicode Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "UDebug" +# PROP BASE Intermediate_Dir "UDebug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "UDebug" +# PROP Intermediate_Dir "UDebug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "UNICODE" /D "_ROS_" /FR /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /D "_DEBUG" /D "UNICODE" /D "WIN32" /D _WIN32_IE=0x0600 /D _WIN32_WINNT=0x0501 /FR /Yu"precomp.h" /FD /GZ /c +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 user32.lib gdi32.lib advapi32.lib shell32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 gdi32.lib comctl32.lib shell32.lib ole32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept /libpath:"Debug" +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "ibrowser - Win32 Release" +# Name "ibrowser - Win32 Debug" +# Name "ibrowser - Win32 Debug Release" +# Name "ibrowser - Win32 Unicode Release" +# Name "ibrowser - Win32 Unicode Debug" +# Begin Group "utility" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\utility\comutil.h +# End Source File +# Begin Source File + +SOURCE=.\utility\expat.h +# End Source File +# Begin Source File + +SOURCE=.\utility\utility.cpp +# End Source File +# Begin Source File + +SOURCE=.\utility\utility.h +# End Source File +# Begin Source File + +SOURCE=.\utility\window.cpp +# End Source File +# Begin Source File + +SOURCE=.\utility\window.h +# End Source File +# Begin Source File + +SOURCE=.\utility\xmlstorage.cpp +# End Source File +# Begin Source File + +SOURCE=.\utility\xmlstorage.h +# End Source File +# End Group +# Begin Group "resources" + +# PROP Default_Filter "bmp,ico" +# Begin Source File + +SOURCE=.\res\dot.ico +# End Source File +# Begin Source File + +SOURCE=.\res\dot_red.ico +# End Source File +# Begin Source File + +SOURCE=.\res\dot_trans.ico +# End Source File +# Begin Source File + +SOURCE=.\res\favorites.ico +# End Source File +# Begin Source File + +SOURCE=.\res\ibrowser.ico +# End Source File +# Begin Source File + +SOURCE=.\ibrowser_intres.h +# End Source File +# Begin Source File + +SOURCE=.\ibrowser_intres.rc +# End Source File +# Begin Source File + +SOURCE=.\res\iexplore.ico +# End Source File +# Begin Source File + +SOURCE=.\res\network.ico +# End Source File +# Begin Source File + +SOURCE=.\res\reactos.ico +# End Source File +# Begin Source File + +SOURCE=.\res\toolbar.bmp +# End Source File +# End Group +# Begin Group "main" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\favorites.cpp +# End Source File +# Begin Source File + +SOURCE=.\favorites.h +# End Source File +# Begin Source File + +SOURCE=.\ibrowser.cpp +# End Source File +# Begin Source File + +SOURCE=.\ibrowser.h +# End Source File +# Begin Source File + +SOURCE=.\mainframe.cpp +# End Source File +# Begin Source File + +SOURCE=.\mainframe.h +# End Source File +# Begin Source File + +SOURCE=.\precomp.cpp +# ADD CPP /Yc"precomp.h" +# End Source File +# Begin Source File + +SOURCE=.\precomp.h +# End Source File +# Begin Source File + +SOURCE=.\webchild.cpp +# End Source File +# Begin Source File + +SOURCE=.\webchild.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\readme.txt +# End Source File +# End Target +# End Project diff --git a/reactos/subsys/system/ibrowser/ibrowser.dsw b/reactos/subsys/system/ibrowser/ibrowser.dsw new file mode 100644 index 00000000000..eb8d2593f88 --- /dev/null +++ b/reactos/subsys/system/ibrowser/ibrowser.dsw @@ -0,0 +1,41 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "ibrowser"=.\ibrowser.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "make_ibrowser"=.\make_ibrowser.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/reactos/subsys/system/ibrowser/ibrowser.h b/reactos/subsys/system/ibrowser/ibrowser.h new file mode 100644 index 00000000000..39265f27dbd --- /dev/null +++ b/reactos/subsys/system/ibrowser/ibrowser.h @@ -0,0 +1,216 @@ +/* + * Copyright 2005 Martin Fuchs + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + + // + // ROS Internet Web Browser + // + // ibrowser.h + // + // Martin Fuchs, 25.01.2005 + // + + +#include "utility/window.h" + + +#define IDW_STATUSBAR 0x100 +#define IDW_TOOLBAR 0x101 +#define IDW_EXTRABAR 0x102 +#define IDW_ADDRESSBAR 0x104 +#define IDW_SIDEBAR 0x106 +#define IDW_FIRST_CHILD 0xC000 /*0x200*/ + + +#define PM_GET_FILEWND_PTR (WM_APP+0x05) +#define PM_GET_SHELLBROWSER_PTR (WM_APP+0x06) + +#define PM_GET_CONTROLWINDOW (WM_APP+0x16) + +#define PM_RESIZE_CHILDREN (WM_APP+0x17) +#define PM_GET_WIDTH (WM_APP+0x18) + +#define PM_REFRESH (WM_APP+0x1B) +#define PM_REFRESH_CONFIG (WM_APP+0x1C) + + +#define CLASSNAME_FRAME TEXT("IBrowserFrameWClass") + +#define CLASSNAME_CHILDWND TEXT("IBrowserChildWClass") + + +#include "mainframe.h" + + + /// convenient loading of string resources +struct ResString : public String +{ + ResString(UINT nid); +}; + + /// convenient loading of standard (32x32) icon resources +struct ResIcon +{ + ResIcon(UINT nid); + + operator HICON() const {return _hicon;} + +protected: + HICON _hicon; +}; + + /// convenient loading of small (16x16) icon resources +struct SmallIcon +{ + SmallIcon(UINT nid); + + operator HICON() const {return _hicon;} + +protected: + HICON _hicon; +}; + + /// convenient loading of icon resources with specified sizes +struct ResIconEx +{ + ResIconEx(UINT nid, int w, int h); + + operator HICON() const {return _hicon;} + +protected: + HICON _hicon; +}; + + /// set big and small icons out of the resources for a window +extern void SetWindowIcon(HWND hwnd, UINT nid); + + /// convenient loading of bitmap resources +struct ResBitmap +{ + ResBitmap(UINT nid); + ~ResBitmap() {DeleteObject(_hBmp);} + + operator HBITMAP() const {return _hBmp;} + +protected: + HBITMAP _hBmp; +}; + + +enum ICON_TYPE { + IT_STATIC, + IT_CACHED, + IT_DYNAMIC, + IT_SYSCACHE +}; + +enum ICON_ID { + ICID_UNKNOWN, + ICID_NONE, + + ICID_IBROWSER, + ICID_BOOKMARK, + + ICID_DYNAMIC +}; + +struct Icon { + Icon(); + Icon(ICON_ID id, UINT nid); + Icon(ICON_TYPE itype, int id, HICON hIcon); + Icon(ICON_TYPE itype, int id, int sys_idx); + + operator ICON_ID() const {return _id;} + + void draw(HDC hdc, int x, int y, int cx, int cy, COLORREF bk_color, HBRUSH bk_brush) const; + HBITMAP create_bitmap(COLORREF bk_color, HBRUSH hbrBkgnd, HDC hdc_wnd) const; + int add_to_imagelist(HIMAGELIST himl, HDC hdc_wnd, COLORREF bk_color=GetSysColor(COLOR_WINDOW), HBRUSH bk_brush=GetSysColorBrush(COLOR_WINDOW)) const; + + int get_sysiml_idx() const {return _itype==IT_SYSCACHE? _sys_idx: -1;} + + bool destroy() {if (_itype == IT_DYNAMIC) {DestroyIcon(_hicon); return true;} else return false;} + +protected: + ICON_ID _id; + ICON_TYPE _itype; + HICON _hicon; + int _sys_idx; +}; + +struct SysCacheIcon : public Icon { + SysCacheIcon(int id, int sys_idx) + : Icon(IT_SYSCACHE, id, sys_idx) {} +}; + +struct IconCache { + IconCache() : _himlSys(0) {} + + void init(); + + const Icon& extract(const String& path); + const Icon& extract(LPCTSTR path, int idx); + const Icon& extract(IExtractIcon* pExtract, LPCTSTR path, int idx); + + const Icon& add(HICON hIcon, ICON_TYPE type=IT_DYNAMIC); + const Icon& add(int sys_idx/*, ICON_TYPE type=IT_SYSCACHE*/); + + const Icon& get_icon(int icon_id); + HIMAGELIST get_sys_imagelist() const {return _himlSys;} + + void free_icon(int icon_id); + +protected: + static int s_next_id; + + typedef map IconMap; + IconMap _icons; + + typedef map PathMap; + PathMap _pathMap; + + typedef pair CachePair; + typedef map PathIdxMap; + PathIdxMap _pathIdxMap; + + HIMAGELIST _himlSys; +}; + + + /// create a bitmap from an icon +extern HBITMAP create_bitmap_from_icon(HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd); + + /// add icon with alpha channel to imagelist using the specified background color +extern int ImageList_AddAlphaIcon(HIMAGELIST himl, HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd); + + +#include "utility/xmlstorage.h" + +using namespace XMLStorage; + +#include "favorites.h" + + + // globals +extern HINSTANCE g_hInstance; +extern IconCache g_icon_cache; +extern ATOM g_hframeClass; + + + // display explorer "About" dialog +extern void ibrowser_about(HWND hwndParent); + diff --git a/reactos/subsys/system/ibrowser/ibrowser.rc b/reactos/subsys/system/ibrowser/ibrowser.rc new file mode 100644 index 00000000000..6868a248ca4 --- /dev/null +++ b/reactos/subsys/system/ibrowser/ibrowser.rc @@ -0,0 +1,24 @@ +/* $Id: ibrowser.rc 12752 2005-01-03 11:25:40Z mf $ */ + +#include + +#include "ibrowser_intres.rc" + +#define REACTOS_STR_FILE_DESCRIPTION "ROS Internet Web Browser\0" +#define REACTOS_STR_INTERNAL_NAME "ibrowser\0" +#define REACTOS_STR_ORIGINAL_FILENAME "ibrowser.exe\0" +#include + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#define IDS_VERSION_STR 5000 +#define IDS_IBROWSER_VERSION_STR 5001 + +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL + +STRINGTABLE DISCARDABLE +BEGIN + IDS_VERSION_STR REACTOS_STR_PRODUCT_VERSION + IDS_IBROWSER_VERSION_STR "ReactOS %s Web Browser" +END + diff --git a/reactos/subsys/system/ibrowser/ibrowser_intres.h b/reactos/subsys/system/ibrowser/ibrowser_intres.h new file mode 100644 index 00000000000..ec6e1882c44 --- /dev/null +++ b/reactos/subsys/system/ibrowser/ibrowser_intres.h @@ -0,0 +1,51 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by ibrowser_intres.rc +// +#define IDS_TITLE 1 +#define IDS_EMPTY 13 +#define IDS_ABOUT_IBROWSER 27 +#define IDI_REACTOS 100 +#define IDB_TOOLBAR 103 +#define IDA_IBROWSER 104 +#define IDM_SDIFRAME 113 +#define IDD_ABOUT_IBROWSER 135 +#define IDI_FAVORITES 140 +#define IDI_DOT 163 +#define IDI_DOT_TRANS 164 +#define IDI_DOT_RED 165 +#define IDI_IBROWSER 169 +#define ID_VIEW_STATUSBAR 503 +#define ID_VIEW_TOOL_BAR 508 +#define ID_VIEW_SIDE_BAR 510 +#define IDC_ROS_IBROWSER 1000 +#define IDC_WWW 1012 +#define IDC_VERSION_TXT 1029 +#define IDC_WIN_VERSION 1030 +#define ID_REFRESH 1704 +#define IDS_VERSION_STR 5000 +#define IDS_IBROWSER_VERSION_STR 5001 +#define ID_IBROWSER_FAQ 10002 +#define ID_VIEW_FULLSCREEN 0x8004 +#define ID_ABOUT_WINDOWS 40002 +#define ID_ABOUT_IBROWSER 40003 +#define ID_GO_BACK 40005 +#define ID_GO_FORWARD 40006 +#define ID_GO_HOME 40007 +#define ID_GO_SEARCH 40008 +#define ID_GO_UP 40009 +#define ID_STOP 40010 +#define ID_FILE_EXIT 0xE141 +#define ID_HELP 0xE146 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 170 +#define _APS_NEXT_COMMAND_VALUE 40024 +#define _APS_NEXT_CONTROL_VALUE 1033 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/reactos/subsys/system/ibrowser/ibrowser_intres.rc b/reactos/subsys/system/ibrowser/ibrowser_intres.rc new file mode 100644 index 00000000000..60a97e0c94e --- /dev/null +++ b/reactos/subsys/system/ibrowser/ibrowser_intres.rc @@ -0,0 +1,398 @@ +//Microsoft Developer Studio generated resource script. +// +#include "ibrowser_intres.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Romanian resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ROM) +#ifdef _WIN32 +LANGUAGE LANG_ROMANIAN, SUBLANG_DEFAULT +#pragma code_page(1250) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDM_SDIFRAME MENU PRELOAD DISCARDABLE +BEGIN + POPUP "&Fiºier" + BEGIN + MENUITEM "&Ieºire", ID_FILE_EXIT + END + POPUP "&Prezentare" + BEGIN + MENUITEM "&Bara cu instrumente", ID_VIEW_TOOL_BAR + MENUITEM "&Side Bar", ID_VIEW_SIDE_BAR, GRAYED + MENUITEM "&Bara de stare", ID_VIEW_STATUSBAR + MENUITEM SEPARATOR + MENUITEM "&Resetare\tF5", ID_REFRESH + MENUITEM "F&ull Screen\tCtrl+Shift+S", ID_VIEW_FULLSCREEN + END + POPUP "&Ajutor" + BEGIN + MENUITEM "Explorer &FAQ...", ID_IBROWSER_FAQ + MENUITEM "&Despre Explorer...", ID_ABOUT_IBROWSER + MENUITEM "Despre &OS...", ID_ABOUT_WINDOWS + END +END + +#endif // Romanian resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_TOOLBAR BITMAP DISCARDABLE "res/toolbar.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDA_IBROWSER ACCELERATORS DISCARDABLE +BEGIN + "X", ID_FILE_EXIT, VIRTKEY, ALT, NOINVERT + "S", ID_VIEW_FULLSCREEN, VIRTKEY, SHIFT, CONTROL, + NOINVERT +END + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// German (Germany) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) +#ifdef _WIN32 +LANGUAGE LANG_GERMAN, SUBLANG_GERMAN +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDM_SDIFRAME MENU PRELOAD DISCARDABLE +BEGIN + POPUP "&Datei" + BEGIN + MENUITEM "&Beenden", ID_FILE_EXIT + END + POPUP "&Ansicht" + BEGIN + MENUITEM "&Toolbar", ID_VIEW_TOOL_BAR + MENUITEM "S&ide Bar", ID_VIEW_SIDE_BAR, GRAYED + MENUITEM "&Status Bar", ID_VIEW_STATUSBAR + MENUITEM SEPARATOR + MENUITEM "&Aktualisieren\tF5", ID_REFRESH + MENUITEM "&Vollbild\tCtrl+Shift+S", ID_VIEW_FULLSCREEN + END + POPUP "&Hilfe" + BEGIN + MENUITEM "Explorer &FAQ...", ID_IBROWSER_FAQ + MENUITEM "&About Explorer...", ID_ABOUT_IBROWSER + MENUITEM "About &OS...", ID_ABOUT_WINDOWS + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUT_IBROWSER DIALOG DISCARDABLE 0, 0, 199, 106 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About ReactOS Web Browser" +FONT 10, "MS Sans Serif" +BEGIN + LTEXT "ReactOS Web Browser",IDC_ROS_IBROWSER,91,13,104,11 + LTEXT "V 0.9",IDC_VERSION_TXT,91,27,104,8 + LTEXT "(c) 2005 Martin Fuchs",IDC_STATIC,91,42,104,8 + LTEXT "",IDC_WIN_VERSION,91,58,98,22 + LTEXT "http://www.sky.franken.de/explorer/",IDC_WWW,17,84,129, + 8 + CONTROL "&OK",IDOK,"Button",BS_OWNERDRAW | BS_FLAT | WS_GROUP, + 154,90,38,12 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_ABOUT_IBROWSER, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 192 + TOPMARGIN, 7 + BOTTOMMARGIN, 102 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "ibrowser_intres.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include \r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "#ifndef _ROS_\r\n" + "LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL\r\n" + "STRINGTABLE DISCARDABLE \r\n" + "BEGIN\r\n" + "IDS_VERSION_STR """"\r\n" + "#ifdef UNICODE\r\n" + "IDS_IBROWSER_VERSION_STR ""ROS Explorer%0s""\r\n" + "#else\r\n" + "IDS_IBROWSER_VERSION_STR ""ROS Explorer Ansi%0s""\r\n" + "#endif\r\n" + "END\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_REACTOS ICON DISCARDABLE "res/reactos.ico" +IDI_FAVORITES ICON DISCARDABLE "res/favorites.ico" +IDI_DOT ICON DISCARDABLE "res/dot.ico" +IDI_DOT_TRANS ICON DISCARDABLE "res/dot_trans.ico" +IDI_DOT_RED ICON DISCARDABLE "res/dot_red.ico" +IDI_IBROWSER ICON DISCARDABLE "res\\ibrowser.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDS_TITLE "Reactos Internet Web Browser" + IDS_EMPTY "(Empty)" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_ABOUT_IBROWSER "&Über..." +END + +#endif // German (Germany) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDM_SDIFRAME MENU PRELOAD DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "E&xit", ID_FILE_EXIT + END + POPUP "&View" + BEGIN + MENUITEM "&Toolbar", ID_VIEW_TOOL_BAR + MENUITEM "S&ide Bar", ID_VIEW_SIDE_BAR, GRAYED + MENUITEM "&Status Bar", ID_VIEW_STATUSBAR + MENUITEM SEPARATOR + MENUITEM "&Refresh\tF5", ID_REFRESH + MENUITEM "F&ull Screen\tCtrl+Shift+S", ID_VIEW_FULLSCREEN + END + POPUP "&Help" + BEGIN + MENUITEM "Explorer &FAQ...", ID_IBROWSER_FAQ + MENUITEM "&About Explorer...", ID_ABOUT_IBROWSER + MENUITEM "About &OS...", ID_ABOUT_WINDOWS + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDS_TITLE "Reactos Internet Web Browser" + IDS_EMPTY "(Empty)" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_ABOUT_IBROWSER "&About..." +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Spanish (Castilian) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESP) +#ifdef _WIN32 +LANGUAGE LANG_SPANISH, SUBLANG_SPANISH +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDM_SDIFRAME MENU PRELOAD DISCARDABLE +BEGIN + POPUP "&Archivo" + BEGIN + MENUITEM "S&alir", ID_FILE_EXIT + END + POPUP "&Ver" + BEGIN + MENUITEM "&Barra de Herramientas", ID_VIEW_TOOL_BAR + MENUITEM "Barra &Lateral", ID_VIEW_SIDE_BAR, GRAYED + MENUITEM "Barra de &Estado", ID_VIEW_STATUSBAR + MENUITEM SEPARATOR + MENUITEM "&Actualizar\tF5", ID_REFRESH + MENUITEM "P&antalla Completa\tCtrl+Shift+S", ID_VIEW_FULLSCREEN + END + POPUP "&Ayuda" + BEGIN + MENUITEM "Explorer &FAQ...", ID_IBROWSER_FAQ + MENUITEM "&Acerca de Explorer...", ID_ABOUT_IBROWSER + MENUITEM "Acerca de &OS...", ID_ABOUT_WINDOWS + END +END + +#endif // Spanish (Castilian) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// French (France) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA) +#ifdef _WIN32 +LANGUAGE LANG_FRENCH, SUBLANG_FRENCH +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDM_SDIFRAME MENU PRELOAD DISCARDABLE +BEGIN + POPUP "&Fichier" + BEGIN + MENUITEM "&Fermer", ID_FILE_EXIT + END + POPUP "&Affichage" + BEGIN + MENUITEM "Barre d'&outils", ID_VIEW_TOOL_BAR + MENUITEM "&Side Bar", ID_VIEW_SIDE_BAR, GRAYED + MENUITEM "Barre d'&état", ID_VIEW_STATUSBAR + MENUITEM SEPARATOR + MENUITEM "&Refresh\tF5", ID_REFRESH + MENUITEM "F&ull Screen\tCtrl+Shift+S", ID_VIEW_FULLSCREEN + END + POPUP "A&ide" + BEGIN + MENUITEM "&FAQ Explorateur...", ID_IBROWSER_FAQ + MENUITEM "A propos de l'&explorateur...", ID_ABOUT_WINDOWS + MENUITEM "A propos de l'&OS...", ID_ABOUT_IBROWSER + END +END + +#endif // French (France) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#ifndef _ROS_ +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +STRINGTABLE DISCARDABLE +BEGIN +IDS_VERSION_STR "" +#ifdef UNICODE +IDS_IBROWSER_VERSION_STR "ROS Explorer%0s" +#else +IDS_IBROWSER_VERSION_STR "ROS Explorer Ansi%0s" +#endif +END +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/reactos/subsys/system/ibrowser/mainframe.cpp b/reactos/subsys/system/ibrowser/mainframe.cpp new file mode 100644 index 00000000000..ba34da97ec7 --- /dev/null +++ b/reactos/subsys/system/ibrowser/mainframe.cpp @@ -0,0 +1,796 @@ +/* + * Copyright 2005 Martin Fuchs + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + + // + // ROS Internet Web Browser + // + // mainframe.cpp + // + // Martin Fuchs, 25.01.2005 + // + + +#include "precomp.h" + +/* We can't include webchild.h here - otherwise MinGW produces errors like: "multiple definition of `QACONTAINERFLAGS'" +#include "webchild.h" +*/ +extern HWND create_webchildwindow(const WebChildWndInfo& info); + +#include "ibrowser_intres.h" + + +HWND MainFrameBase::Create(LPCTSTR url, UINT cmdshow) +{ + HWND hMainFrame; + + hMainFrame = MainFrame::Create(); + //@@hMainFrame = MainFrame::Create(url); + + if (hMainFrame) { + String sPath; + + if (url) { + sPath = url; // copy url to avoid accessing freed memory + url = sPath; + } + + ShowWindow(hMainFrame, cmdshow); + UpdateWindow(hMainFrame); + + // Open the first child window after initializing the application + PostMessage(hMainFrame, PM_OPEN_WINDOW, 0, (LPARAM)url); + } + + return hMainFrame; +} + + +MainFrameBase::MainFrameBase(HWND hwnd) + : super(hwnd), + _himl(ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_MASK|ILC_COLOR24, 2, 0)) +{ + _hMenuFrame = GetMenu(hwnd); + _hMenuWindow = GetSubMenu(_hMenuFrame, GetMenuItemCount(_hMenuFrame)-3); + + _menu_info._hMenuView = GetSubMenu(_hMenuFrame, 1); + + _hAccel = LoadAccelerators(g_hInstance, MAKEINTRESOURCE(IDA_IBROWSER)); + + + TBBUTTON toolbarBtns[] = { +#ifdef _NO_REBAR + {0, 0, 0, BTNS_SEP, {0, 0}, 0, 0}, +#endif + {7, ID_GO_BACK, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0}, + {8, ID_GO_FORWARD, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0}, + {9, ID_GO_UP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0}, + {10, ID_GO_HOME, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0}, + {11, ID_GO_SEARCH, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0}, + {12, ID_REFRESH, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0}, + {13, ID_STOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0} + }; + + _htoolbar = CreateToolbarEx(hwnd, +#ifndef _NO_REBAR + CCS_NOPARENTALIGN|CCS_NORESIZE| +#endif + WS_CHILD|WS_VISIBLE, IDW_TOOLBAR, 2, g_hInstance, IDB_TOOLBAR, + toolbarBtns, sizeof(toolbarBtns)/sizeof(TBBUTTON), + 16, 15, 16, 15, sizeof(TBBUTTON)); + + CheckMenuItem(_menu_info._hMenuView, ID_VIEW_TOOL_BAR, MF_BYCOMMAND|MF_CHECKED); + + + // address bar + WindowCanvas canvas(hwnd); + RECT rect = {0, 0, 0, 0}; + DrawText(canvas, TEXT("My"), -1, &rect, DT_SINGLELINE|DT_NOPREFIX|DT_CALCRECT); + HFONT hfont = GetStockFont(DEFAULT_GUI_FONT); + + _haddressedit = CreateWindow(TEXT("EDIT"), NULL, WS_CHILD|WS_VISIBLE, 0, 0, 0, rect.bottom, + hwnd, (HMENU)IDW_ADDRESSBAR, g_hInstance, 0); + SetWindowFont(_haddressedit, hfont, FALSE); + new EditController(_haddressedit); + + /* CreateStatusWindow does not accept WS_BORDER + _hstatusbar = CreateWindowEx(WS_EX_NOPARENTNOTIFY, STATUSCLASSNAME, 0, + WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_BORDER|CCS_NODIVIDER, 0,0,0,0, + hwnd, (HMENU)IDW_STATUSBAR, g_hInstance, 0);*/ + + _hstatusbar = CreateStatusWindow(WS_CHILD|WS_VISIBLE, 0, hwnd, IDW_STATUSBAR); + CheckMenuItem(_menu_info._hMenuView, ID_VIEW_STATUSBAR, MF_BYCOMMAND|MF_CHECKED); + + _hsidebar = CreateWindowEx(WS_EX_STATICEDGE, WC_TREEVIEW, TEXT("Sidebar"), + WS_CHILD|WS_TABSTOP|WS_BORDER|/*WS_VISIBLE|*/WS_CHILD|TVS_HASLINES|TVS_HASBUTTONS|TVS_SHOWSELALWAYS|TVS_INFOTIP, + -1, -1, 200, 0, _hwnd, (HMENU)IDW_SIDEBAR, g_hInstance, 0); + + TreeView_SetImageList(_hsidebar, _himl, TVSIL_NORMAL); + + CheckMenuItem(_menu_info._hMenuView, ID_VIEW_SIDE_BAR, MF_BYCOMMAND|MF_UNCHECKED/*MF_CHECKED*/); + + + // create rebar window to manage toolbar and drivebar +#ifndef _NO_REBAR + _hwndrebar = CreateWindowEx(WS_EX_TOOLWINDOW, REBARCLASSNAME, NULL, + WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN| + RBS_VARHEIGHT|RBS_AUTOSIZE|RBS_DBLCLKTOGGLE| + CCS_NODIVIDER|CCS_NOPARENTALIGN, + 0, 0, 0, 0, _hwnd, 0, g_hInstance, 0); + + int btn_hgt = HIWORD(SendMessage(_htoolbar, TB_GETBUTTONSIZE, 0, 0)); + + REBARBANDINFO rbBand; + + rbBand.cbSize = sizeof(REBARBANDINFO); + rbBand.fMask = RBBIM_TEXT|RBBIM_STYLE|RBBIM_CHILD|RBBIM_CHILDSIZE|RBBIM_SIZE; +#ifndef RBBS_HIDETITLE // missing in MinGW headers as of 25.02.2004 +#define RBBS_HIDETITLE 0x400 +#endif + rbBand.fStyle = RBBS_CHILDEDGE|RBBS_GRIPPERALWAYS|RBBS_HIDETITLE; + + rbBand.cxMinChild = 0; + rbBand.cyMinChild = 0; + rbBand.cyChild = 0; + rbBand.cyMaxChild = 0; + rbBand.cyIntegral = btn_hgt; + + rbBand.lpText = NULL;//TEXT("Toolbar"); + rbBand.hwndChild = _htoolbar; + rbBand.cxMinChild = 0; + rbBand.cyMinChild = btn_hgt + 4; + rbBand.cx = 284; + SendMessage(_hwndrebar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand); +#endif +} + + +MainFrameBase::~MainFrameBase() +{ + ImageList_Destroy(_himl); + +//@@if (g_Globals._hMainWnd == _hwnd) + PostQuitMessage(0); +} + + +LRESULT MainFrameBase::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) +{ + LRESULT res; + + if (ProcessMessage(nmsg, wparam, lparam, &res)) + return res; + else + return super::WndProc(nmsg, wparam, lparam); +} + +bool MainFrameBase::ProcessMessage(UINT nmsg, WPARAM wparam, LPARAM lparam, LRESULT* pres) +{ + switch(nmsg) { + case PM_TRANSLATE_MSG: + *pres = TranslateMsg((MSG*)lparam); + return true; + + case WM_SHOWWINDOW: + if (wparam) // trigger child resizing after window creation - now we can succesfully call IsWindowVisible() + resize_frame_client(); + return false; // goto def; + + case WM_CLOSE: + DestroyWindow(_hwnd); +//@@ g_Globals._hMainWnd = 0; + break; + + case WM_DESTROY: + break; + + case WM_SIZE: + resize_frame(LOWORD(lparam), HIWORD(lparam)); + break; // do not pass message to DefFrameProc + + case WM_GETMINMAXINFO: { + LPMINMAXINFO lpmmi = (LPMINMAXINFO)lparam; + + lpmmi->ptMaxTrackSize.x <<= 1;/*2*GetSystemMetrics(SM_CXSCREEN) / SM_CXVIRTUALSCREEN */ + lpmmi->ptMaxTrackSize.y <<= 1;/*2*GetSystemMetrics(SM_CYSCREEN) / SM_CYVIRTUALSCREEN */ + break;} + + case PM_FRM_CALC_CLIENT: + frame_get_clientspace((PRECT)lparam); + *pres = TRUE; + return true; + + case PM_FRM_GET_MENUINFO: + *pres = (LPARAM)&_menu_info; + return true; + + case PM_GET_CONTROLWINDOW: + if (wparam == FCW_STATUS) { + *pres = (LRESULT)(HWND)_hstatusbar; + return true; + } + break; + + case PM_SETSTATUSTEXT: + SendMessage(_hstatusbar, SB_SETTEXT, 0, lparam); + break; + + case PM_URL_CHANGED: + SetWindowText(_haddressedit, (LPCTSTR)lparam); + break; + + default: + return false; + } + + *pres = 0; + return true; +} + +BOOL MainFrameBase::TranslateMsg(MSG* pmsg) +{ + if (TranslateAccelerator(_hwnd, _hAccel, pmsg)) + return TRUE; + + return FALSE; +} + + +int MainFrameBase::Command(int id, int code) +{ + CONTEXT("MainFrameBase::Command()"); + + switch(id) { + case ID_FILE_EXIT: + SendMessage(_hwnd, WM_CLOSE, 0, 0); + break; + + case ID_VIEW_TOOL_BAR: + toggle_child(_hwnd, id, _htoolbar, 0); + break; + + case ID_VIEW_STATUSBAR: + toggle_child(_hwnd, id, _hstatusbar); + break; + + case ID_VIEW_SIDE_BAR: + // lazy initialization + if (!TreeView_GetCount(_hsidebar)) + FillBookmarks(); + + toggle_child(_hwnd, id, _hsidebar); + break; + + case ID_HELP: + WinHelp(_hwnd, TEXT("ibrowser")/*file ibrowser.hlp*/, HELP_INDEX, 0); + break; + + case ID_VIEW_FULLSCREEN: + CheckMenuItem(_menu_info._hMenuView, id, toggle_fullscreen()?MF_CHECKED:0); + break; + + case ID_ABOUT_WINDOWS: + ShellAbout(_hwnd, ResString(IDS_TITLE), NULL, 0); + break; + + case ID_ABOUT_IBROWSER: + ibrowser_about(_hwnd); + break; + + case ID_IBROWSER_FAQ: + launch_file(_hwnd, TEXT("http://www.sky.franken.de/explorer/"), SW_SHOW); + break; + + case IDW_ADDRESSBAR: + if (code == 1) { + TCHAR url[BUFFER_LEN]; + + if (GetWindowText(_haddressedit, url, BUFFER_LEN)) + go_to(url, false); + } + break; + + default: + return 1; // no command handlers in Window::Command() + } + + return 0; +} + + +int MainFrameBase::Notify(int id, NMHDR* pnmh) +{ + switch(pnmh->code) { + // resize children windows when the rebar size changes + case RBN_AUTOSIZE: + resize_frame_client(); + break; + + case TVN_GETINFOTIP: { + NMTVGETINFOTIP* pnmgit = (NMTVGETINFOTIP*)pnmh; + + if (pnmgit->lParam) { + const BookmarkNode& node = *(BookmarkNode*)pnmgit->lParam; + + if (node._type == BookmarkNode::BMNT_FOLDER) { + // display tooltips for bookmark folders + if (!node._pfolder->_description.empty()) + lstrcpyn(pnmgit->pszText, node._pfolder->_description.c_str(), pnmgit->cchTextMax); + } else if (node._type == BookmarkNode::BMNT_BOOKMARK) { + // display tooltips for bookmark folders + String txt = node._pbookmark->_description; + + if (!node._pbookmark->_url.empty()) { + if (!txt.empty()) + txt += TEXT(" - "); + + txt += node._pbookmark->_url; + } + + lstrcpyn(pnmgit->pszText, txt.c_str(), pnmgit->cchTextMax); + } + } + break;} + + case NM_DBLCLK: { + HTREEITEM hitem = TreeView_GetSelection(_hsidebar); + LPARAM lparam = TreeView_GetItemData(_hsidebar, hitem); + + if (lparam) { + const BookmarkNode& node = *(BookmarkNode*)lparam; + + if (node._type == BookmarkNode::BMNT_BOOKMARK) { + bool new_window = GetAsyncKeyState(VK_SHIFT)<0; + + go_to(node._pbookmark->_url, new_window); + } + } + break;} + } + + return 0; +} + + +void MainFrameBase::resize_frame(int cx, int cy) +{ + if (cy <= 0) + return; // avoid resizing children when receiving RBN_AUTOSIZE while getting minimized + + RECT rect = {0, 0, cx, cy}; + + if (_hwndrebar) { + int height = ClientRect(_hwndrebar).bottom; + MoveWindow(_hwndrebar, rect.left, rect.top, rect.right-rect.left, height, TRUE); + rect.top += height; + } else { + if (IsWindowVisible(_htoolbar)) { + SendMessage(_htoolbar, WM_SIZE, 0, 0); + WindowRect rt(_htoolbar); + rect.top = rt.bottom; + // rect.bottom -= rt.bottom; + } + } + + if (IsWindowVisible(_hstatusbar)) { + int parts[] = {300, 500}; + + SendMessage(_hstatusbar, WM_SIZE, 0, 0); + SendMessage(_hstatusbar, SB_SETPARTS, 2, (LPARAM)&parts); + ClientRect rt(_hstatusbar); + rect.bottom -= rt.bottom; + } + + if (IsWindowVisible(_haddressedit)) { + ClientRect rt(_haddressedit); + rect.bottom -= rt.bottom; + + SetWindowPos(_haddressedit, 0, 0, rect.bottom, rect.right-rect.left, rt.bottom, SWP_NOACTIVATE|SWP_NOZORDER); + } + + if (IsWindowVisible(_hsidebar)) { + WindowRect rt(_hsidebar); + rect.left += rt.right-rt.left; + + SetWindowPos(_hsidebar, 0, -1, rect.top-1, rt.right-rt.left, rect.bottom-rect.top+1, SWP_NOACTIVATE|SWP_NOZORDER); + } +} + +void MainFrameBase::resize_frame_client() +{ + ClientRect rect(_hwnd); + + resize_frame(rect.right, rect.bottom); +} + +void MainFrameBase::frame_get_clientspace(PRECT prect) +{ + if (!IsIconic(_hwnd)) + GetClientRect(_hwnd, prect); + else { + WINDOWPLACEMENT wp; + + GetWindowPlacement(_hwnd, &wp); + + prect->left = prect->top = 0; + prect->right = wp.rcNormalPosition.right-wp.rcNormalPosition.left- + 2*(GetSystemMetrics(SM_CXSIZEFRAME)+GetSystemMetrics(SM_CXEDGE)); + prect->bottom = wp.rcNormalPosition.bottom-wp.rcNormalPosition.top- + 2*(GetSystemMetrics(SM_CYSIZEFRAME)+GetSystemMetrics(SM_CYEDGE))- + GetSystemMetrics(SM_CYCAPTION)-GetSystemMetrics(SM_CYMENUSIZE); + } + + if (IsWindowVisible(_htoolbar)) { + ClientRect rt(_htoolbar); + prect->top += rt.bottom+2; + } + + if (IsWindowVisible(_hstatusbar)) { + ClientRect rt(_hstatusbar); + prect->bottom -= rt.bottom; + } +} + +BOOL MainFrameBase::toggle_fullscreen() +{ + RECT rt; + + if ((_fullscreen._mode=!_fullscreen._mode)) { + GetWindowRect(_hwnd, &_fullscreen._orgPos); + _fullscreen._wasZoomed = IsZoomed(_hwnd); + + Frame_CalcFrameClient(_hwnd, &rt); + ClientToScreen(_hwnd, (LPPOINT)&rt.left); + ClientToScreen(_hwnd, (LPPOINT)&rt.right); + + rt.left = _fullscreen._orgPos.left-rt.left; + rt.top = _fullscreen._orgPos.top-rt.top; + rt.right = GetSystemMetrics(SM_CXSCREEN)+_fullscreen._orgPos.right-rt.right; + rt.bottom = GetSystemMetrics(SM_CYSCREEN)+_fullscreen._orgPos.bottom-rt.bottom; + + MoveWindow(_hwnd, rt.left, rt.top, rt.right-rt.left, rt.bottom-rt.top, TRUE); + } else { + MoveWindow(_hwnd, _fullscreen._orgPos.left, _fullscreen._orgPos.top, + _fullscreen._orgPos.right-_fullscreen._orgPos.left, + _fullscreen._orgPos.bottom-_fullscreen._orgPos.top, TRUE); + + if (_fullscreen._wasZoomed) + ShowWindow(_hwnd, WS_MAXIMIZE); + } + + return _fullscreen._mode; +} + +void MainFrameBase::fullscreen_move() +{ + RECT rt, pos; + GetWindowRect(_hwnd, &pos); + + Frame_CalcFrameClient(_hwnd, &rt); + ClientToScreen(_hwnd, (LPPOINT)&rt.left); + ClientToScreen(_hwnd, (LPPOINT)&rt.right); + + rt.left = pos.left-rt.left; + rt.top = pos.top-rt.top; + rt.right = GetSystemMetrics(SM_CXSCREEN)+pos.right-rt.right; + rt.bottom = GetSystemMetrics(SM_CYSCREEN)+pos.bottom-rt.bottom; + + MoveWindow(_hwnd, rt.left, rt.top, rt.right-rt.left, rt.bottom-rt.top, TRUE); +} + + +void MainFrameBase::toggle_child(HWND hwnd, UINT cmd, HWND hchild, int band_idx) +{ + BOOL vis = IsWindowVisible(hchild); + + CheckMenuItem(_menu_info._hMenuView, cmd, vis?MF_BYCOMMAND:MF_BYCOMMAND|MF_CHECKED); + + if (band_idx != -1) + SendMessage(_hwndrebar, RB_SHOWBAND, band_idx, !vis); + else + ShowWindow(hchild, vis? SW_HIDE: SW_SHOW); + + if (_fullscreen._mode) + fullscreen_move(); + + resize_frame_client(); +} + +void MainFrameBase::FillBookmarks() +{ +/*@@ + HiddenWindow hide(_hsidebar); + WindowCanvas canvas(_hwnd); + + TreeView_DeleteAllItems(_hsidebar); + + g_icon_cache.get_icon(ICID_FAVORITES).add_to_imagelist(_himl, canvas); + g_icon_cache.get_icon(ICID_BOOKMARK).add_to_imagelist(_himl, canvas); + ImageList_AddAlphaIcon(_himl, SmallIcon(IDI_DOT), GetStockBrush(WHITE_BRUSH), canvas); + g_icon_cache.get_icon(ICID_FOLDER).add_to_imagelist(_himl, canvas); + g_icon_cache.get_icon(ICID_FOLDER).add_to_imagelist(_himl, canvas); + + TV_INSERTSTRUCT tvi; + + tvi.hParent = TVI_ROOT; + tvi.hInsertAfter = TVI_LAST; + tvi.item.mask = TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE; + ResString sFavorites(IDS_FAVORITES); + tvi.item.pszText = (LPTSTR)sFavorites.c_str(); + tvi.item.iSelectedImage = tvi.item.iImage = 0; + + HTREEITEM hitem_bookmarks = TreeView_InsertItem(_hsidebar, &tvi); + + g_Globals._favorites.fill_tree(_hsidebar, hitem_bookmarks, _himl, canvas); + + TreeView_Expand(_hsidebar, hitem_bookmarks, TVE_EXPAND); +*/ +} + + +MainFrame::MainFrame(HWND hwnd) + : super(hwnd) +{ + _split_pos = DEFAULT_SPLIT_POS; + _last_split = DEFAULT_SPLIT_POS; +} + +HWND MainFrame::Create() +{ + HMENU hMenuFrame = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDM_SDIFRAME)); + + return Window::Create(WINDOW_CREATOR(MainFrame), 0, + (LPCTSTR)(int)g_hframeClass, ResString(IDS_TITLE), WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + 0/*hwndDesktop*/, hMenuFrame); +} + +/*@@ +HWND MainFrame::Create(LPCTSTR url) +{ + HWND hFrame = Create(); + if (!hFrame) + return 0; + + ShowWindow(hFrame, SW_SHOW); + + MainFrame* pFrame = GET_WINDOW(MainFrame, hFrame); + + if (pFrame) + pFrame->set_url(url); + + return hFrame; +} +*/ + +LRESULT MainFrame::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) +{ + switch(nmsg) { + case WM_SIZE: + resize_frame(LOWORD(lparam), HIWORD(lparam)); + break; + + case WM_PAINT: { + PaintCanvas canvas(_hwnd); + + if (_left_hwnd && _right_hwnd) { + ClientRect rt(_hwnd); + rt.left = _split_pos-SPLIT_WIDTH/2; + rt.right = _split_pos+SPLIT_WIDTH/2+1; + + if (_right_hwnd) { + WindowRect right_rect(_right_hwnd); + ScreenToClient(_hwnd, &right_rect); + rt.top = right_rect.top; + rt.bottom = right_rect.bottom; + } + + HBRUSH lastBrush = SelectBrush(canvas, GetStockBrush(COLOR_SPLITBAR)); + Rectangle(canvas, rt.left, rt.top-1, rt.right, rt.bottom+1); + SelectObject(canvas, lastBrush); + } + break;} + + case WM_SETCURSOR: + if (LOWORD(lparam) == HTCLIENT) { + POINT pt; + GetCursorPos(&pt); + ScreenToClient(_hwnd, &pt); + + if (pt.x>=_split_pos-SPLIT_WIDTH/2 && pt.x<_split_pos+SPLIT_WIDTH/2+1) { + SetCursor(LoadCursor(0, IDC_SIZEWE)); + return TRUE; + } + } + goto def; + + case WM_LBUTTONDOWN: { + int x = GET_X_LPARAM(lparam); + + ClientRect rt(_hwnd); + + if (x>=_split_pos-SPLIT_WIDTH/2 && x<_split_pos+SPLIT_WIDTH/2+1) { + _last_split = _split_pos; + SetCapture(_hwnd); + } + + break;} + + case WM_LBUTTONUP: + if (GetCapture() == _hwnd) + ReleaseCapture(); + break; + + case WM_KEYDOWN: + if (wparam == VK_ESCAPE) + if (GetCapture() == _hwnd) { + _split_pos = _last_split; + resize_children(); + _last_split = -1; + ReleaseCapture(); + SetCursor(LoadCursor(0, IDC_ARROW)); + } + break; + + case WM_MOUSEMOVE: + if (GetCapture() == _hwnd) { + int x = LOWORD(lparam); + + ClientRect rt(_hwnd); + + if (x>=0 && x +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) External Target" 0x0106 + +CFG=make_ibrowser - Win32 bjam +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "make_ibrowser.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "make_ibrowser.mak" CFG="make_ibrowser - Win32 bjam" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "make_ibrowser - Win32 Release" (based on "Win32 (x86) External Target") +!MESSAGE "make_ibrowser - Win32 Debug" (based on "Win32 (x86) External Target") +!MESSAGE "make_ibrowser - Win32 Unicode Debug" (based on "Win32 (x86) External Target") +!MESSAGE "make_ibrowser - Win32 Unicode Release" (based on "Win32 (x86) External Target") +!MESSAGE "make_ibrowser - Win32 bjam" (based on "Win32 (x86) External Target") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" + +!IF "$(CFG)" == "make_ibrowser - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Cmd_Line "NMAKE /f make_ibrowser.mak" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "make_ibrowser.exe" +# PROP BASE Bsc_Name "make_ibrowser.bsc" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Cmd_Line "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" make -f Makefile.PCH UNICODE=0" +# PROP Rebuild_Opt "clean all" +# PROP Target_File "ibrowser.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "make_ibrowser - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Cmd_Line "NMAKE /f make_ibrowser.mak" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "make_ibrowser.exe" +# PROP BASE Bsc_Name "make_ibrowser.bsc" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Cmd_Line "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" make -f Makefile.PCH UNICODE=0 DEBUG=1" +# PROP Rebuild_Opt "clean all" +# PROP Target_File "ibrowser.exe" +# PROP Bsc_Name "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" make -f Makefile.MinGW UNICODE=0 DEBUG=1" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "make_ibrowser - Win32 Unicode Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "UDebug" +# PROP BASE Intermediate_Dir "UDebug" +# PROP BASE Cmd_Line "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" make -f Makefile.MinGW UNICODE=1 DEBUG=1" +# PROP BASE Rebuild_Opt "clean all" +# PROP BASE Target_File "ibrowser.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "UDebug" +# PROP Intermediate_Dir "UDebug" +# PROP Cmd_Line "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" make -f Makefile.MinGW UNICODE=1 DEBUG=1" +# PROP Rebuild_Opt "clean all" +# PROP Target_File "ibrowser.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "make_ibrowser - Win32 Unicode Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "URelease" +# PROP BASE Intermediate_Dir "URelease" +# PROP BASE Cmd_Line "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" make -f Makefile.MinGW UNICODE=1" +# PROP BASE Rebuild_Opt "clean all" +# PROP BASE Target_File "ibrowser.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "URelease" +# PROP Intermediate_Dir "URelease" +# PROP Cmd_Line "msdevfilt -gcc make -f Makefile.PCH UNICODE=1" +# PROP Rebuild_Opt "clean all" +# PROP Target_File "ibrowser.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "make_ibrowser - Win32 bjam" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Cmd_Line "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" make -f Makefile.MinGW DEBUG=1" +# PROP BASE Rebuild_Opt "clean all" +# PROP BASE Target_File "ibrowser.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Cmd_Line "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" bjam" +# PROP Rebuild_Opt "clean&bjam release" +# PROP Target_File "ibrowser.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ENDIF + +# Begin Target + +# Name "make_ibrowser - Win32 Release" +# Name "make_ibrowser - Win32 Debug" +# Name "make_ibrowser - Win32 Unicode Debug" +# Name "make_ibrowser - Win32 Unicode Release" +# Name "make_ibrowser - Win32 bjam" + +!IF "$(CFG)" == "make_ibrowser - Win32 Release" + +!ELSEIF "$(CFG)" == "make_ibrowser - Win32 Debug" + +!ELSEIF "$(CFG)" == "make_ibrowser - Win32 Unicode Debug" + +!ELSEIF "$(CFG)" == "make_ibrowser - Win32 Unicode Release" + +!ELSEIF "$(CFG)" == "make_ibrowser - Win32 bjam" + +!ENDIF + +# Begin Source File + +SOURCE=.\Jamfile +# End Source File +# Begin Source File + +SOURCE=.\Makefile +# End Source File +# Begin Source File + +SOURCE=.\Makefile.MinGW +# End Source File +# Begin Source File + +SOURCE=.\Makefile.PCH +# End Source File +# End Target +# End Project diff --git a/reactos/subsys/system/ibrowser/precomp.cpp b/reactos/subsys/system/ibrowser/precomp.cpp new file mode 100644 index 00000000000..c786813cbda --- /dev/null +++ b/reactos/subsys/system/ibrowser/precomp.cpp @@ -0,0 +1,28 @@ +/* + * Copyright 2005 Martin Fuchs + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + + // + // ROS Internet Web Browser - precompiled header support + // + // precomp.h + // + // Martin Fuchs, 25.01.2005 + // + +#include "precomp.h" diff --git a/reactos/subsys/system/ibrowser/precomp.h b/reactos/subsys/system/ibrowser/precomp.h new file mode 100644 index 00000000000..c0d382d9681 --- /dev/null +++ b/reactos/subsys/system/ibrowser/precomp.h @@ -0,0 +1,32 @@ +/* + * Copyright 2005 Martin Fuchs + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + + // + // ROS Internet Web Browser - precompiled header support + // + // precomp.h + // + // Martin Fuchs, 25.01.2005 + // + +#include "utility/utility.h" +#include "utility/comutil.h" + +#include "ibrowser.h" + diff --git a/reactos/subsys/system/ibrowser/readme.txt b/reactos/subsys/system/ibrowser/readme.txt new file mode 100644 index 00000000000..234c112c97e --- /dev/null +++ b/reactos/subsys/system/ibrowser/readme.txt @@ -0,0 +1,9 @@ + +IBrowser is a Web Browser User Interface similar derived from ROS Explorer. +It encapsulates the Mozilla or MS Web Browser Control. + + +For more information about ReactOS Explorer please look at the FAQ web page: + +http://www.sky.franken.de/explorer/ + diff --git a/reactos/subsys/system/ibrowser/res/dot.ico b/reactos/subsys/system/ibrowser/res/dot.ico new file mode 100644 index 00000000000..9ddbb8a41c7 Binary files /dev/null and b/reactos/subsys/system/ibrowser/res/dot.ico differ diff --git a/reactos/subsys/system/ibrowser/res/dot_red.ico b/reactos/subsys/system/ibrowser/res/dot_red.ico new file mode 100644 index 00000000000..4d176eef1d5 Binary files /dev/null and b/reactos/subsys/system/ibrowser/res/dot_red.ico differ diff --git a/reactos/subsys/system/ibrowser/res/dot_trans.ico b/reactos/subsys/system/ibrowser/res/dot_trans.ico new file mode 100644 index 00000000000..d5ede5a3800 Binary files /dev/null and b/reactos/subsys/system/ibrowser/res/dot_trans.ico differ diff --git a/reactos/subsys/system/ibrowser/res/favorites.ico b/reactos/subsys/system/ibrowser/res/favorites.ico new file mode 100644 index 00000000000..558748e9ed0 Binary files /dev/null and b/reactos/subsys/system/ibrowser/res/favorites.ico differ diff --git a/reactos/subsys/system/ibrowser/res/ibrowser.ico b/reactos/subsys/system/ibrowser/res/ibrowser.ico new file mode 100644 index 00000000000..700ca0da4b1 Binary files /dev/null and b/reactos/subsys/system/ibrowser/res/ibrowser.ico differ diff --git a/reactos/subsys/system/ibrowser/res/network.ico b/reactos/subsys/system/ibrowser/res/network.ico new file mode 100644 index 00000000000..5bcf5ec7cbf Binary files /dev/null and b/reactos/subsys/system/ibrowser/res/network.ico differ diff --git a/reactos/subsys/system/ibrowser/res/reactos.ico b/reactos/subsys/system/ibrowser/res/reactos.ico new file mode 100644 index 00000000000..492e388a939 Binary files /dev/null and b/reactos/subsys/system/ibrowser/res/reactos.ico differ diff --git a/reactos/subsys/system/ibrowser/res/toolbar.bmp b/reactos/subsys/system/ibrowser/res/toolbar.bmp new file mode 100644 index 00000000000..7e88726f33b Binary files /dev/null and b/reactos/subsys/system/ibrowser/res/toolbar.bmp differ diff --git a/reactos/subsys/system/ibrowser/utility/comutil.h b/reactos/subsys/system/ibrowser/utility/comutil.h new file mode 100644 index 00000000000..d73b7b42327 --- /dev/null +++ b/reactos/subsys/system/ibrowser/utility/comutil.h @@ -0,0 +1,321 @@ +/* + * Copyright 2005 Martin Fuchs + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + + // + // ROS Internet Web Browser + // + // comutil.h + // + // C++ wrapper classes for COM interfaces + // + // Martin Fuchs, 25.01.2005 + // + + + // windows shell headers +#include +#include + +/*@@ +#if _MSC_VER>=1300 // VS.Net +#include +using namespace _com_util; +#endif +*/ + +#ifndef _INC_COMUTIL // is comutil.h of MS headers not available? +#ifndef _NO_COMUTIL +#define _NO_COMUTIL +#endif +#endif + + + // Exception Handling + +#ifndef _NO_COMUTIL + +#define COMExceptionBase _com_error + +#else + + /// COM ExceptionBase class as replacement for _com_error +struct COMExceptionBase +{ + COMExceptionBase(HRESULT hr) + : _hr(hr) + { + } + + HRESULT Error() const + { + return _hr; + } + + LPCTSTR ErrorMessage() const + { + if (_msg.empty()) { + LPTSTR pBuf; + + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, + 0, _hr, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (LPTSTR)&pBuf, 0, NULL)) { + _msg = pBuf; + LocalFree(pBuf); + } else { + TCHAR buffer[128]; + _stprintf(buffer, TEXT("unknown Exception: 0x%08lX"), _hr); + _msg = buffer; + } + } + + return _msg; + } + +protected: + HRESULT _hr; + mutable String _msg; +}; + +#endif + + + /// Exception with context information + +struct COMException : public COMExceptionBase +{ + typedef COMExceptionBase super; + + COMException(HRESULT hr) + : super(hr), + _context(CURRENT_CONTEXT), + _file(NULL), _line(0) + { + LOG(toString()); + LOG(CURRENT_CONTEXT.getStackTrace()); + } + + COMException(HRESULT hr, const char* file, int line) + : super(hr), + _context(CURRENT_CONTEXT), + _file(file), _line(line) + { + LOG(toString()); + LOG(CURRENT_CONTEXT.getStackTrace()); + } + + COMException(HRESULT hr, const String& obj) + : super(hr), + _context(CURRENT_CONTEXT), + _file(NULL), _line(0) + { + LOG(toString()); + LOG(CURRENT_CONTEXT.getStackTrace()); + } + + COMException(HRESULT hr, const String& obj, const char* file, int line) + : super(hr), + _context(CURRENT_CONTEXT), + _file(file), _line(line) + { + LOG(toString()); + LOG(CURRENT_CONTEXT.getStackTrace()); + } + + String toString() const; + + Context _context; + + const char* _file; + int _line; +}; + +#define THROW_EXCEPTION(hr) throw COMException(hr, __FILE__, __LINE__) +#define CHECKERROR(hr) ((void)(FAILED(hr)? THROW_EXCEPTION(hr): 0)) + + +#ifdef _NO_COMUTIL + +inline void CheckError(HRESULT hr) +{ + if (FAILED(hr)) + throw COMException(hr); +} + +#endif + + + /// COM Initialisation + +struct ComInit +{ + ComInit() + { + CHECKERROR(CoInitialize(0)); + } + +#if (_WIN32_WINNT>=0x0400) || defined(_WIN32_DCOM) + ComInit(DWORD flag) + { + CHECKERROR(CoInitializeEx(0, flag)); + } +#endif + + ~ComInit() + { + CoUninitialize(); + } +}; + + + /// OLE initialisation for drag drop support + +struct OleInit +{ + OleInit() + { + CHECKERROR(OleInitialize(0)); + } + + ~OleInit() + { + OleUninitialize(); + } +}; + + + /// Exception Handler for COM exceptions + +extern void HandleException(COMException& e, HWND hwnd); + + + /// wrapper class for COM interface pointers + +template struct SIfacePtr +{ + SIfacePtr() + : _p(0) + { + } + + SIfacePtr(T* p) + : _p(p) + { + if (p) + p->AddRef(); + } + + SIfacePtr(IUnknown* unknown, REFIID riid) + { + CHECKERROR(unknown->QueryInterface(riid, (LPVOID*)&_p)); + } + + ~SIfacePtr() + { + Free(); + } + + T* operator->() + { + return _p; + } + + const T* operator->() const + { + return _p; + } + +/* not GCC compatible + operator const T*() const + { + return _p; + } */ + + operator T*() + { + return _p; + } + + T** operator&() + { + return &_p; + } + + bool empty() const //NOTE: GCC seems not to work correctly when defining operator bool() AND operator T*() at one time + { + return !_p; + } + + SIfacePtr& operator=(T* p) + { + Free(); + + if (p) { + p->AddRef(); + _p = p; + } + + return *this; + } + + void operator=(SIfacePtr const& o) + { + T* h = _p; + + if (o._p) + o._p->AddRef(); + + _p = o._p; + + if (h) + h->Release(); + } + + HRESULT CreateInstance(REFIID clsid, REFIID riid) + { + return CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, riid, (LPVOID*)&_p); + } + + template HRESULT QueryInterface(REFIID riid, I* p) + { + return _p->QueryInterface(riid, (LPVOID*)p); + } + + T* get() + { + return _p; + } + + void Free() + { + T* h = _p; + _p = NULL; + + if (h) + h->Release(); + } + +protected: + SIfacePtr(const SIfacePtr& o) + : _p(o._p) + { + if (_p) + _p->AddRef(); + } + + T* _p; +}; diff --git a/reactos/subsys/system/ibrowser/utility/expat.h b/reactos/subsys/system/ibrowser/utility/expat.h new file mode 100644 index 00000000000..b34f94ea8dd --- /dev/null +++ b/reactos/subsys/system/ibrowser/utility/expat.h @@ -0,0 +1,1081 @@ +/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#ifndef XmlParse_INCLUDED +#define XmlParse_INCLUDED 1 + +#ifdef __VMS +/* 0 1 2 3 0 1 2 3 + 1234567890123456789012345678901 1234567890123456789012345678901 */ +#define XML_SetProcessingInstructionHandler XML_SetProcessingInstrHandler +#define XML_SetUnparsedEntityDeclHandler XML_SetUnparsedEntDeclHandler +#define XML_SetStartNamespaceDeclHandler XML_SetStartNamespcDeclHandler +#define XML_SetExternalEntityRefHandlerArg XML_SetExternalEntRefHandlerArg +#endif + +#include + +#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__) +#define XML_USE_MSC_EXTENSIONS 1 +#endif + +/* Expat tries very hard to make the API boundary very specifically + defined. There are two macros defined to control this boundary; + each of these can be defined before including this header to + achieve some different behavior, but doing so it not recommended or + tested frequently. + + XMLCALL - The calling convention to use for all calls across the + "library boundary." This will default to cdecl, and + try really hard to tell the compiler that's what we + want. + + XMLIMPORT - Whatever magic is needed to note that a function is + to be imported from a dynamically loaded library + (.dll, .so, or .sl, depending on your platform). + + The XMLCALL macro was added in Expat 1.95.7. The only one which is + expected to be directly useful in client code is XMLCALL. + + Note that on at least some Unix versions, the Expat library must be + compiled with the cdecl calling convention as the default since + system headers may assume the cdecl convention. +*/ +#ifndef XMLCALL +#if defined(XML_USE_MSC_EXTENSIONS) +#define XMLCALL __cdecl +#elif defined(__GNUC__) && defined(__i386) +//MF#define XMLCALL __attribute__((cdecl)) +#define XMLCALL//MF +#else +/* For any platform which uses this definition and supports more than + one calling convention, we need to extend this definition to + declare the convention used on that platform, if it's possible to + do so. + + If this is the case for your platform, please file a bug report + with information on how to identify your platform via the C + pre-processor and how to specify the same calling convention as the + platform's malloc() implementation. +*/ +#define XMLCALL +#endif +#endif /* not defined XMLCALL */ + + +#if !defined(XML_STATIC) && !defined(XMLIMPORT) +#ifndef XML_BUILDING_EXPAT +/* using Expat from an application */ + +#ifdef XML_USE_MSC_EXTENSIONS +#define XMLIMPORT __declspec(dllimport) +#endif + +#endif +#endif /* not defined XML_STATIC */ + +/* If we didn't define it above, define it away: */ +#ifndef XMLIMPORT +#define XMLIMPORT +#endif + + +#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef XML_UNICODE_WCHAR_T +#define XML_UNICODE +#endif + +struct XML_ParserStruct; +typedef struct XML_ParserStruct *XML_Parser; + +#ifdef XML_UNICODE /* Information is UTF-16 encoded. */ +#ifdef XML_UNICODE_WCHAR_T +typedef wchar_t XML_Char; +typedef wchar_t XML_LChar; +#else +typedef unsigned short XML_Char; +typedef char XML_LChar; +#endif /* XML_UNICODE_WCHAR_T */ +#else /* Information is UTF-8 encoded. */ +typedef char XML_Char; +typedef char XML_LChar; +#endif /* XML_UNICODE */ + +/* Should this be defined using stdbool.h when C99 is available? */ +typedef unsigned char XML_Bool; +#define XML_TRUE ((XML_Bool) 1) +#define XML_FALSE ((XML_Bool) 0) + +/* The XML_Status enum gives the possible return values for several + API functions. The preprocessor #defines are included so this + stanza can be added to code that still needs to support older + versions of Expat 1.95.x: + + #ifndef XML_STATUS_OK + #define XML_STATUS_OK 1 + #define XML_STATUS_ERROR 0 + #endif + + Otherwise, the #define hackery is quite ugly and would have been + dropped. +*/ +enum XML_Status { + XML_STATUS_ERROR = 0, +#define XML_STATUS_ERROR XML_STATUS_ERROR + XML_STATUS_OK = 1, +#define XML_STATUS_OK XML_STATUS_OK + XML_STATUS_SUSPENDED = 2, +#define XML_STATUS_SUSPENDED XML_STATUS_SUSPENDED +}; + +enum XML_Error { + XML_ERROR_NONE, + XML_ERROR_NO_MEMORY, + XML_ERROR_SYNTAX, + XML_ERROR_NO_ELEMENTS, + XML_ERROR_INVALID_TOKEN, + XML_ERROR_UNCLOSED_TOKEN, + XML_ERROR_PARTIAL_CHAR, + XML_ERROR_TAG_MISMATCH, + XML_ERROR_DUPLICATE_ATTRIBUTE, + XML_ERROR_JUNK_AFTER_DOC_ELEMENT, + XML_ERROR_PARAM_ENTITY_REF, + XML_ERROR_UNDEFINED_ENTITY, + XML_ERROR_RECURSIVE_ENTITY_REF, + XML_ERROR_ASYNC_ENTITY, + XML_ERROR_BAD_CHAR_REF, + XML_ERROR_BINARY_ENTITY_REF, + XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, + XML_ERROR_MISPLACED_XML_PI, + XML_ERROR_UNKNOWN_ENCODING, + XML_ERROR_INCORRECT_ENCODING, + XML_ERROR_UNCLOSED_CDATA_SECTION, + XML_ERROR_EXTERNAL_ENTITY_HANDLING, + XML_ERROR_NOT_STANDALONE, + XML_ERROR_UNEXPECTED_STATE, + XML_ERROR_ENTITY_DECLARED_IN_PE, + XML_ERROR_FEATURE_REQUIRES_XML_DTD, + XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING, + XML_ERROR_UNBOUND_PREFIX, + XML_ERROR_SUSPENDED, + XML_ERROR_NOT_SUSPENDED, + XML_ERROR_ABORTED, + XML_ERROR_FINISHED, + XML_ERROR_SUSPEND_PE +}; + +enum XML_Content_Type { + XML_CTYPE_EMPTY = 1, + XML_CTYPE_ANY, + XML_CTYPE_MIXED, + XML_CTYPE_NAME, + XML_CTYPE_CHOICE, + XML_CTYPE_SEQ +}; + +enum XML_Content_Quant { + XML_CQUANT_NONE, + XML_CQUANT_OPT, + XML_CQUANT_REP, + XML_CQUANT_PLUS +}; + +/* If type == XML_CTYPE_EMPTY or XML_CTYPE_ANY, then quant will be + XML_CQUANT_NONE, and the other fields will be zero or NULL. + If type == XML_CTYPE_MIXED, then quant will be NONE or REP and + numchildren will contain number of elements that may be mixed in + and children point to an array of XML_Content cells that will be + all of XML_CTYPE_NAME type with no quantification. + + If type == XML_CTYPE_NAME, then the name points to the name, and + the numchildren field will be zero and children will be NULL. The + quant fields indicates any quantifiers placed on the name. + + CHOICE and SEQ will have name NULL, the number of children in + numchildren and children will point, recursively, to an array + of XML_Content cells. + + The EMPTY, ANY, and MIXED types will only occur at top level. +*/ + +typedef struct XML_cp XML_Content; + +struct XML_cp { + enum XML_Content_Type type; + enum XML_Content_Quant quant; + XML_Char * name; + unsigned int numchildren; + XML_Content * children; +}; + + +/* This is called for an element declaration. See above for + description of the model argument. It's the caller's responsibility + to free model when finished with it. +*/ +typedef void (XMLCALL *XML_ElementDeclHandler) (void *userData, + const XML_Char *name, + XML_Content *model); + +XMLPARSEAPI(void) +XML_SetElementDeclHandler(XML_Parser parser, + XML_ElementDeclHandler eldecl); + +/* The Attlist declaration handler is called for *each* attribute. So + a single Attlist declaration with multiple attributes declared will + generate multiple calls to this handler. The "default" parameter + may be NULL in the case of the "#IMPLIED" or "#REQUIRED" + keyword. The "isrequired" parameter will be true and the default + value will be NULL in the case of "#REQUIRED". If "isrequired" is + true and default is non-NULL, then this is a "#FIXED" default. +*/ +typedef void (XMLCALL *XML_AttlistDeclHandler) ( + void *userData, + const XML_Char *elname, + const XML_Char *attname, + const XML_Char *att_type, + const XML_Char *dflt, + int isrequired); + +XMLPARSEAPI(void) +XML_SetAttlistDeclHandler(XML_Parser parser, + XML_AttlistDeclHandler attdecl); + +/* The XML declaration handler is called for *both* XML declarations + and text declarations. The way to distinguish is that the version + parameter will be NULL for text declarations. The encoding + parameter may be NULL for XML declarations. The standalone + parameter will be -1, 0, or 1 indicating respectively that there + was no standalone parameter in the declaration, that it was given + as no, or that it was given as yes. +*/ +typedef void (XMLCALL *XML_XmlDeclHandler) (void *userData, + const XML_Char *version, + const XML_Char *encoding, + int standalone); + +XMLPARSEAPI(void) +XML_SetXmlDeclHandler(XML_Parser parser, + XML_XmlDeclHandler xmldecl); + + +typedef struct { + void *(XMLCALL *malloc_fcn)(size_t size); + void *(XMLCALL *realloc_fcn)(void *ptr, size_t size); + void (XMLCALL *free_fcn)(void *ptr); +} XML_Memory_Handling_Suite; + +/* Constructs a new parser; encoding is the encoding specified by the + external protocol or NULL if there is none specified. +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreate(const XML_Char *encoding); + +/* Constructs a new parser and namespace processor. Element type + names and attribute names that belong to a namespace will be + expanded; unprefixed attribute names are never expanded; unprefixed + element type names are expanded only if there is a default + namespace. The expanded name is the concatenation of the namespace + URI, the namespace separator character, and the local part of the + name. If the namespace separator is '\0' then the namespace URI + and the local part will be concatenated without any separator. + When a namespace is not declared, the name and prefix will be + passed through without expansion. +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator); + + +/* Constructs a new parser using the memory management suite referred to + by memsuite. If memsuite is NULL, then use the standard library memory + suite. If namespaceSeparator is non-NULL it creates a parser with + namespace processing as described above. The character pointed at + will serve as the namespace separator. + + All further memory operations used for the created parser will come from + the given suite. +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreate_MM(const XML_Char *encoding, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *namespaceSeparator); + +/* Prepare a parser object to be re-used. This is particularly + valuable when memory allocation overhead is disproportionatly high, + such as when a large number of small documnents need to be parsed. + All handlers are cleared from the parser, except for the + unknownEncodingHandler. The parser's external state is re-initialized + except for the values of ns and ns_triplets. + + Added in Expat 1.95.3. +*/ +XMLPARSEAPI(XML_Bool) +XML_ParserReset(XML_Parser parser, const XML_Char *encoding); + +/* atts is array of name/value pairs, terminated by 0; + names and values are 0 terminated. +*/ +typedef void (XMLCALL *XML_StartElementHandler) (void *userData, + const XML_Char *name, + const XML_Char **atts); + +typedef void (XMLCALL *XML_EndElementHandler) (void *userData, + const XML_Char *name); + + +/* s is not 0 terminated. */ +typedef void (XMLCALL *XML_CharacterDataHandler) (void *userData, + const XML_Char *s, + int len); + +/* target and data are 0 terminated */ +typedef void (XMLCALL *XML_ProcessingInstructionHandler) ( + void *userData, + const XML_Char *target, + const XML_Char *data); + +/* data is 0 terminated */ +typedef void (XMLCALL *XML_CommentHandler) (void *userData, + const XML_Char *data); + +typedef void (XMLCALL *XML_StartCdataSectionHandler) (void *userData); +typedef void (XMLCALL *XML_EndCdataSectionHandler) (void *userData); + +/* This is called for any characters in the XML document for which + there is no applicable handler. This includes both characters that + are part of markup which is of a kind that is not reported + (comments, markup declarations), or characters that are part of a + construct which could be reported but for which no handler has been + supplied. The characters are passed exactly as they were in the XML + document except that they will be encoded in UTF-8 or UTF-16. + Line boundaries are not normalized. Note that a byte order mark + character is not passed to the default handler. There are no + guarantees about how characters are divided between calls to the + default handler: for example, a comment might be split between + multiple calls. +*/ +typedef void (XMLCALL *XML_DefaultHandler) (void *userData, + const XML_Char *s, + int len); + +/* This is called for the start of the DOCTYPE declaration, before + any DTD or internal subset is parsed. +*/ +typedef void (XMLCALL *XML_StartDoctypeDeclHandler) ( + void *userData, + const XML_Char *doctypeName, + const XML_Char *sysid, + const XML_Char *pubid, + int has_internal_subset); + +/* This is called for the start of the DOCTYPE declaration when the + closing > is encountered, but after processing any external + subset. +*/ +typedef void (XMLCALL *XML_EndDoctypeDeclHandler)(void *userData); + +/* This is called for entity declarations. The is_parameter_entity + argument will be non-zero if the entity is a parameter entity, zero + otherwise. + + For internal entities (), value will + be non-NULL and systemId, publicID, and notationName will be NULL. + The value string is NOT nul-terminated; the length is provided in + the value_length argument. Since it is legal to have zero-length + values, do not use this argument to test for internal entities. + + For external entities, value will be NULL and systemId will be + non-NULL. The publicId argument will be NULL unless a public + identifier was provided. The notationName argument will have a + non-NULL value only for unparsed entity declarations. + + Note that is_parameter_entity can't be changed to XML_Bool, since + that would break binary compatibility. +*/ +typedef void (XMLCALL *XML_EntityDeclHandler) ( + void *userData, + const XML_Char *entityName, + int is_parameter_entity, + const XML_Char *value, + int value_length, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +XMLPARSEAPI(void) +XML_SetEntityDeclHandler(XML_Parser parser, + XML_EntityDeclHandler handler); + +/* OBSOLETE -- OBSOLETE -- OBSOLETE + This handler has been superceded by the EntityDeclHandler above. + It is provided here for backward compatibility. + + This is called for a declaration of an unparsed (NDATA) entity. + The base argument is whatever was set by XML_SetBase. The + entityName, systemId and notationName arguments will never be + NULL. The other arguments may be. +*/ +typedef void (XMLCALL *XML_UnparsedEntityDeclHandler) ( + void *userData, + const XML_Char *entityName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +/* This is called for a declaration of notation. The base argument is + whatever was set by XML_SetBase. The notationName will never be + NULL. The other arguments can be. +*/ +typedef void (XMLCALL *XML_NotationDeclHandler) ( + void *userData, + const XML_Char *notationName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* When namespace processing is enabled, these are called once for + each namespace declaration. The call to the start and end element + handlers occur between the calls to the start and end namespace + declaration handlers. For an xmlns attribute, prefix will be + NULL. For an xmlns="" attribute, uri will be NULL. +*/ +typedef void (XMLCALL *XML_StartNamespaceDeclHandler) ( + void *userData, + const XML_Char *prefix, + const XML_Char *uri); + +typedef void (XMLCALL *XML_EndNamespaceDeclHandler) ( + void *userData, + const XML_Char *prefix); + +/* This is called if the document is not standalone, that is, it has an + external subset or a reference to a parameter entity, but does not + have standalone="yes". If this handler returns XML_STATUS_ERROR, + then processing will not continue, and the parser will return a + XML_ERROR_NOT_STANDALONE error. + If parameter entity parsing is enabled, then in addition to the + conditions above this handler will only be called if the referenced + entity was actually read. +*/ +typedef int (XMLCALL *XML_NotStandaloneHandler) (void *userData); + +/* This is called for a reference to an external parsed general + entity. The referenced entity is not automatically parsed. The + application can parse it immediately or later using + XML_ExternalEntityParserCreate. + + The parser argument is the parser parsing the entity containing the + reference; it can be passed as the parser argument to + XML_ExternalEntityParserCreate. The systemId argument is the + system identifier as specified in the entity declaration; it will + not be NULL. + + The base argument is the system identifier that should be used as + the base for resolving systemId if systemId was relative; this is + set by XML_SetBase; it may be NULL. + + The publicId argument is the public identifier as specified in the + entity declaration, or NULL if none was specified; the whitespace + in the public identifier will have been normalized as required by + the XML spec. + + The context argument specifies the parsing context in the format + expected by the context argument to XML_ExternalEntityParserCreate; + context is valid only until the handler returns, so if the + referenced entity is to be parsed later, it must be copied. + context is NULL only when the entity is a parameter entity. + + The handler should return XML_STATUS_ERROR if processing should not + continue because of a fatal error in the handling of the external + entity. In this case the calling parser will return an + XML_ERROR_EXTERNAL_ENTITY_HANDLING error. + + Note that unlike other handlers the first argument is the parser, + not userData. +*/ +typedef int (XMLCALL *XML_ExternalEntityRefHandler) ( + XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* This is called in two situations: + 1) An entity reference is encountered for which no declaration + has been read *and* this is not an error. + 2) An internal entity reference is read, but not expanded, because + XML_SetDefaultHandler has been called. + Note: skipped parameter entities in declarations and skipped general + entities in attribute values cannot be reported, because + the event would be out of sync with the reporting of the + declarations or attribute values +*/ +typedef void (XMLCALL *XML_SkippedEntityHandler) ( + void *userData, + const XML_Char *entityName, + int is_parameter_entity); + +/* This structure is filled in by the XML_UnknownEncodingHandler to + provide information to the parser about encodings that are unknown + to the parser. + + The map[b] member gives information about byte sequences whose + first byte is b. + + If map[b] is c where c is >= 0, then b by itself encodes the + Unicode scalar value c. + + If map[b] is -1, then the byte sequence is malformed. + + If map[b] is -n, where n >= 2, then b is the first byte of an + n-byte sequence that encodes a single Unicode scalar value. + + The data member will be passed as the first argument to the convert + function. + + The convert function is used to convert multibyte sequences; s will + point to a n-byte sequence where map[(unsigned char)*s] == -n. The + convert function must return the Unicode scalar value represented + by this byte sequence or -1 if the byte sequence is malformed. + + The convert function may be NULL if the encoding is a single-byte + encoding, that is if map[b] >= -1 for all bytes b. + + When the parser is finished with the encoding, then if release is + not NULL, it will call release passing it the data member; once + release has been called, the convert function will not be called + again. + + Expat places certain restrictions on the encodings that are supported + using this mechanism. + + 1. Every ASCII character that can appear in a well-formed XML document, + other than the characters + + $@\^`{}~ + + must be represented by a single byte, and that byte must be the + same byte that represents that character in ASCII. + + 2. No character may require more than 4 bytes to encode. + + 3. All characters encoded must have Unicode scalar values <= + 0xFFFF, (i.e., characters that would be encoded by surrogates in + UTF-16 are not allowed). Note that this restriction doesn't + apply to the built-in support for UTF-8 and UTF-16. + + 4. No Unicode character may be encoded by more than one distinct + sequence of bytes. +*/ +typedef struct { + int map[256]; + void *data; + int (XMLCALL *convert)(void *data, const char *s); + void (XMLCALL *release)(void *data); +} XML_Encoding; + +/* This is called for an encoding that is unknown to the parser. + + The encodingHandlerData argument is that which was passed as the + second argument to XML_SetUnknownEncodingHandler. + + The name argument gives the name of the encoding as specified in + the encoding declaration. + + If the callback can provide information about the encoding, it must + fill in the XML_Encoding structure, and return XML_STATUS_OK. + Otherwise it must return XML_STATUS_ERROR. + + If info does not describe a suitable encoding, then the parser will + return an XML_UNKNOWN_ENCODING error. +*/ +typedef int (XMLCALL *XML_UnknownEncodingHandler) ( + void *encodingHandlerData, + const XML_Char *name, + XML_Encoding *info); + +XMLPARSEAPI(void) +XML_SetElementHandler(XML_Parser parser, + XML_StartElementHandler start, + XML_EndElementHandler end); + +XMLPARSEAPI(void) +XML_SetStartElementHandler(XML_Parser parser, + XML_StartElementHandler handler); + +XMLPARSEAPI(void) +XML_SetEndElementHandler(XML_Parser parser, + XML_EndElementHandler handler); + +XMLPARSEAPI(void) +XML_SetCharacterDataHandler(XML_Parser parser, + XML_CharacterDataHandler handler); + +XMLPARSEAPI(void) +XML_SetProcessingInstructionHandler(XML_Parser parser, + XML_ProcessingInstructionHandler handler); +XMLPARSEAPI(void) +XML_SetCommentHandler(XML_Parser parser, + XML_CommentHandler handler); + +XMLPARSEAPI(void) +XML_SetCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start, + XML_EndCdataSectionHandler end); + +XMLPARSEAPI(void) +XML_SetStartCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start); + +XMLPARSEAPI(void) +XML_SetEndCdataSectionHandler(XML_Parser parser, + XML_EndCdataSectionHandler end); + +/* This sets the default handler and also inhibits expansion of + internal entities. These entity references will be passed to the + default handler, or to the skipped entity handler, if one is set. +*/ +XMLPARSEAPI(void) +XML_SetDefaultHandler(XML_Parser parser, + XML_DefaultHandler handler); + +/* This sets the default handler but does not inhibit expansion of + internal entities. The entity reference will not be passed to the + default handler. +*/ +XMLPARSEAPI(void) +XML_SetDefaultHandlerExpand(XML_Parser parser, + XML_DefaultHandler handler); + +XMLPARSEAPI(void) +XML_SetDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start, + XML_EndDoctypeDeclHandler end); + +XMLPARSEAPI(void) +XML_SetStartDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start); + +XMLPARSEAPI(void) +XML_SetEndDoctypeDeclHandler(XML_Parser parser, + XML_EndDoctypeDeclHandler end); + +XMLPARSEAPI(void) +XML_SetUnparsedEntityDeclHandler(XML_Parser parser, + XML_UnparsedEntityDeclHandler handler); + +XMLPARSEAPI(void) +XML_SetNotationDeclHandler(XML_Parser parser, + XML_NotationDeclHandler handler); + +XMLPARSEAPI(void) +XML_SetNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end); + +XMLPARSEAPI(void) +XML_SetStartNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start); + +XMLPARSEAPI(void) +XML_SetEndNamespaceDeclHandler(XML_Parser parser, + XML_EndNamespaceDeclHandler end); + +XMLPARSEAPI(void) +XML_SetNotStandaloneHandler(XML_Parser parser, + XML_NotStandaloneHandler handler); + +XMLPARSEAPI(void) +XML_SetExternalEntityRefHandler(XML_Parser parser, + XML_ExternalEntityRefHandler handler); + +/* If a non-NULL value for arg is specified here, then it will be + passed as the first argument to the external entity ref handler + instead of the parser object. +*/ +XMLPARSEAPI(void) +XML_SetExternalEntityRefHandlerArg(XML_Parser parser, + void *arg); + +XMLPARSEAPI(void) +XML_SetSkippedEntityHandler(XML_Parser parser, + XML_SkippedEntityHandler handler); + +XMLPARSEAPI(void) +XML_SetUnknownEncodingHandler(XML_Parser parser, + XML_UnknownEncodingHandler handler, + void *encodingHandlerData); + +/* This can be called within a handler for a start element, end + element, processing instruction or character data. It causes the + corresponding markup to be passed to the default handler. +*/ +XMLPARSEAPI(void) +XML_DefaultCurrent(XML_Parser parser); + +/* If do_nst is non-zero, and namespace processing is in effect, and + a name has a prefix (i.e. an explicit namespace qualifier) then + that name is returned as a triplet in a single string separated by + the separator character specified when the parser was created: URI + + sep + local_name + sep + prefix. + + If do_nst is zero, then namespace information is returned in the + default manner (URI + sep + local_name) whether or not the name + has a prefix. + + Note: Calling XML_SetReturnNSTriplet after XML_Parse or + XML_ParseBuffer has no effect. +*/ + +XMLPARSEAPI(void) +XML_SetReturnNSTriplet(XML_Parser parser, int do_nst); + +/* This value is passed as the userData argument to callbacks. */ +XMLPARSEAPI(void) +XML_SetUserData(XML_Parser parser, void *userData); + +/* Returns the last value set by XML_SetUserData or NULL. */ +#define XML_GetUserData(parser) (*(void **)(parser)) + +/* This is equivalent to supplying an encoding argument to + XML_ParserCreate. On success XML_SetEncoding returns non-zero, + zero otherwise. + Note: Calling XML_SetEncoding after XML_Parse or XML_ParseBuffer + has no effect and returns XML_STATUS_ERROR. +*/ +XMLPARSEAPI(enum XML_Status) +XML_SetEncoding(XML_Parser parser, const XML_Char *encoding); + +/* If this function is called, then the parser will be passed as the + first argument to callbacks instead of userData. The userData will + still be accessible using XML_GetUserData. +*/ +XMLPARSEAPI(void) +XML_UseParserAsHandlerArg(XML_Parser parser); + +/* If useDTD == XML_TRUE is passed to this function, then the parser + will assume that there is an external subset, even if none is + specified in the document. In such a case the parser will call the + externalEntityRefHandler with a value of NULL for the systemId + argument (the publicId and context arguments will be NULL as well). + Note: If this function is called, then this must be done before + the first call to XML_Parse or XML_ParseBuffer, since it will + have no effect after that. Returns + XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING. + Note: If the document does not have a DOCTYPE declaration at all, + then startDoctypeDeclHandler and endDoctypeDeclHandler will not + be called, despite an external subset being parsed. + Note: If XML_DTD is not defined when Expat is compiled, returns + XML_ERROR_FEATURE_REQUIRES_XML_DTD. +*/ +XMLPARSEAPI(enum XML_Error) +XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD); + + +/* Sets the base to be used for resolving relative URIs in system + identifiers in declarations. Resolving relative identifiers is + left to the application: this value will be passed through as the + base argument to the XML_ExternalEntityRefHandler, + XML_NotationDeclHandler and XML_UnparsedEntityDeclHandler. The base + argument will be copied. Returns XML_STATUS_ERROR if out of memory, + XML_STATUS_OK otherwise. +*/ +XMLPARSEAPI(enum XML_Status) +XML_SetBase(XML_Parser parser, const XML_Char *base); + +XMLPARSEAPI(const XML_Char *) +XML_GetBase(XML_Parser parser); + +/* Returns the number of the attribute/value pairs passed in last call + to the XML_StartElementHandler that were specified in the start-tag + rather than defaulted. Each attribute/value pair counts as 2; thus + this correspondds to an index into the atts array passed to the + XML_StartElementHandler. +*/ +XMLPARSEAPI(int) +XML_GetSpecifiedAttributeCount(XML_Parser parser); + +/* Returns the index of the ID attribute passed in the last call to + XML_StartElementHandler, or -1 if there is no ID attribute. Each + attribute/value pair counts as 2; thus this correspondds to an + index into the atts array passed to the XML_StartElementHandler. +*/ +XMLPARSEAPI(int) +XML_GetIdAttributeIndex(XML_Parser parser); + +/* Parses some input. Returns XML_STATUS_ERROR if a fatal error is + detected. The last call to XML_Parse must have isFinal true; len + may be zero for this call (or any other). + + Though the return values for these functions has always been + described as a Boolean value, the implementation, at least for the + 1.95.x series, has always returned exactly one of the XML_Status + values. +*/ +XMLPARSEAPI(enum XML_Status) +XML_Parse(XML_Parser parser, const char *s, int len, int isFinal); + +XMLPARSEAPI(void *) +XML_GetBuffer(XML_Parser parser, int len); + +XMLPARSEAPI(enum XML_Status) +XML_ParseBuffer(XML_Parser parser, int len, int isFinal); + +/* Stops parsing, causing XML_Parse() or XML_ParseBuffer() to return. + Must be called from within a call-back handler, except when aborting + (resumable = 0) an already suspended parser. Some call-backs may + still follow because they would otherwise get lost. Examples: + - endElementHandler() for empty elements when stopped in + startElementHandler(), + - endNameSpaceDeclHandler() when stopped in endElementHandler(), + and possibly others. + + Can be called from most handlers, including DTD related call-backs, + except when parsing an external parameter entity and resumable != 0. + Returns XML_STATUS_OK when successful, XML_STATUS_ERROR otherwise. + Possible error codes: + - XML_ERROR_SUSPENDED: when suspending an already suspended parser. + - XML_ERROR_FINISHED: when the parser has already finished. + - XML_ERROR_SUSPEND_PE: when suspending while parsing an external PE. + + When resumable != 0 (true) then parsing is suspended, that is, + XML_Parse() and XML_ParseBuffer() return XML_STATUS_SUSPENDED. + Otherwise, parsing is aborted, that is, XML_Parse() and XML_ParseBuffer() + return XML_STATUS_ERROR with error code XML_ERROR_ABORTED. + + *Note*: + This will be applied to the current parser instance only, that is, if + there is a parent parser then it will continue parsing when the + externalEntityRefHandler() returns. It is up to the implementation of + the externalEntityRefHandler() to call XML_StopParser() on the parent + parser (recursively), if one wants to stop parsing altogether. + + When suspended, parsing can be resumed by calling XML_ResumeParser(). +*/ +XMLPARSEAPI(enum XML_Status) +XML_StopParser(XML_Parser parser, XML_Bool resumable); + +/* Resumes parsing after it has been suspended with XML_StopParser(). + Must not be called from within a handler call-back. Returns same + status codes as XML_Parse() or XML_ParseBuffer(). + Additional error code XML_ERROR_NOT_SUSPENDED possible. + + *Note*: + This must be called on the most deeply nested child parser instance + first, and on its parent parser only after the child parser has finished, + to be applied recursively until the document entity's parser is restarted. + That is, the parent parser will not resume by itself and it is up to the + application to call XML_ResumeParser() on it at the appropriate moment. +*/ +XMLPARSEAPI(enum XML_Status) +XML_ResumeParser(XML_Parser parser); + +enum XML_Parsing { + XML_INITIALIZED, + XML_PARSING, + XML_FINISHED, + XML_SUSPENDED +}; + +typedef struct { + enum XML_Parsing parsing; + XML_Bool finalBuffer; +} XML_ParsingStatus; + +/* Returns status of parser with respect to being initialized, parsing, + finished, or suspended and processing the final buffer. + XXX XML_Parse() and XML_ParseBuffer() should return XML_ParsingStatus, + XXX with XML_FINISHED_OK or XML_FINISHED_ERROR replacing XML_FINISHED +*/ +XMLPARSEAPI(void) +XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status); + +/* Creates an XML_Parser object that can parse an external general + entity; context is a '\0'-terminated string specifying the parse + context; encoding is a '\0'-terminated string giving the name of + the externally specified encoding, or NULL if there is no + externally specified encoding. The context string consists of a + sequence of tokens separated by formfeeds (\f); a token consisting + of a name specifies that the general entity of the name is open; a + token of the form prefix=uri specifies the namespace for a + particular prefix; a token of the form =uri specifies the default + namespace. This can be called at any point after the first call to + an ExternalEntityRefHandler so longer as the parser has not yet + been freed. The new parser is completely independent and may + safely be used in a separate thread. The handlers and userData are + initialized from the parser argument. Returns NULL if out of memory. + Otherwise returns a new XML_Parser object. +*/ +XMLPARSEAPI(XML_Parser) +XML_ExternalEntityParserCreate(XML_Parser parser, + const XML_Char *context, + const XML_Char *encoding); + +enum XML_ParamEntityParsing { + XML_PARAM_ENTITY_PARSING_NEVER, + XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE, + XML_PARAM_ENTITY_PARSING_ALWAYS +}; + +/* Controls parsing of parameter entities (including the external DTD + subset). If parsing of parameter entities is enabled, then + references to external parameter entities (including the external + DTD subset) will be passed to the handler set with + XML_SetExternalEntityRefHandler. The context passed will be 0. + + Unlike external general entities, external parameter entities can + only be parsed synchronously. If the external parameter entity is + to be parsed, it must be parsed during the call to the external + entity ref handler: the complete sequence of + XML_ExternalEntityParserCreate, XML_Parse/XML_ParseBuffer and + XML_ParserFree calls must be made during this call. After + XML_ExternalEntityParserCreate has been called to create the parser + for the external parameter entity (context must be 0 for this + call), it is illegal to make any calls on the old parser until + XML_ParserFree has been called on the newly created parser. + If the library has been compiled without support for parameter + entity parsing (ie without XML_DTD being defined), then + XML_SetParamEntityParsing will return 0 if parsing of parameter + entities is requested; otherwise it will return non-zero. + Note: If XML_SetParamEntityParsing is called after XML_Parse or + XML_ParseBuffer, then it has no effect and will always return 0. +*/ +XMLPARSEAPI(int) +XML_SetParamEntityParsing(XML_Parser parser, + enum XML_ParamEntityParsing parsing); + +/* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then + XML_GetErrorCode returns information about the error. +*/ +XMLPARSEAPI(enum XML_Error) +XML_GetErrorCode(XML_Parser parser); + +/* These functions return information about the current parse + location. They may be called from any callback called to report + some parse event; in this case the location is the location of the + first of the sequence of characters that generated the event. When + called from callbacks generated by declarations in the document + prologue, the location identified isn't as neatly defined, but will + be within the relevant markup. When called outside of the callback + functions, the position indicated will be just past the last parse + event (regardless of whether there was an associated callback). + + They may also be called after returning from a call to XML_Parse + or XML_ParseBuffer. If the return value is XML_STATUS_ERROR then + the location is the location of the character at which the error + was detected; otherwise the location is the location of the last + parse event, as described above. +*/ +XMLPARSEAPI(int) XML_GetCurrentLineNumber(XML_Parser parser); +XMLPARSEAPI(int) XML_GetCurrentColumnNumber(XML_Parser parser); +XMLPARSEAPI(long) XML_GetCurrentByteIndex(XML_Parser parser); + +/* Return the number of bytes in the current event. + Returns 0 if the event is in an internal entity. +*/ +XMLPARSEAPI(int) +XML_GetCurrentByteCount(XML_Parser parser); + +/* If XML_CONTEXT_BYTES is defined, returns the input buffer, sets + the integer pointed to by offset to the offset within this buffer + of the current parse position, and sets the integer pointed to by size + to the size of this buffer (the number of input bytes). Otherwise + returns a NULL pointer. Also returns a NULL pointer if a parse isn't + active. + + NOTE: The character pointer returned should not be used outside + the handler that makes the call. +*/ +XMLPARSEAPI(const char *) +XML_GetInputContext(XML_Parser parser, + int *offset, + int *size); + +/* For backwards compatibility with previous versions. */ +#define XML_GetErrorLineNumber XML_GetCurrentLineNumber +#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber +#define XML_GetErrorByteIndex XML_GetCurrentByteIndex + +/* Frees the content model passed to the element declaration handler */ +XMLPARSEAPI(void) +XML_FreeContentModel(XML_Parser parser, XML_Content *model); + +/* Exposing the memory handling functions used in Expat */ +XMLPARSEAPI(void *) +XML_MemMalloc(XML_Parser parser, size_t size); + +XMLPARSEAPI(void *) +XML_MemRealloc(XML_Parser parser, void *ptr, size_t size); + +XMLPARSEAPI(void) +XML_MemFree(XML_Parser parser, void *ptr); + +/* Frees memory used by the parser. */ +XMLPARSEAPI(void) +XML_ParserFree(XML_Parser parser); + +/* Returns a string describing the error. */ +XMLPARSEAPI(const XML_LChar *) +XML_ErrorString(enum XML_Error code); + +/* Return a string containing the version number of this expat */ +XMLPARSEAPI(const XML_LChar *) +XML_ExpatVersion(void); + +typedef struct { + int major; + int minor; + int micro; +} XML_Expat_Version; + +/* Return an XML_Expat_Version structure containing numeric version + number information for this version of expat. +*/ +XMLPARSEAPI(XML_Expat_Version) +XML_ExpatVersionInfo(void); + +/* Added in Expat 1.95.5. */ +enum XML_FeatureEnum { + XML_FEATURE_END = 0, + XML_FEATURE_UNICODE, + XML_FEATURE_UNICODE_WCHAR_T, + XML_FEATURE_DTD, + XML_FEATURE_CONTEXT_BYTES, + XML_FEATURE_MIN_SIZE, + XML_FEATURE_SIZEOF_XML_CHAR, + XML_FEATURE_SIZEOF_XML_LCHAR + /* Additional features must be added to the end of this enum. */ +}; + +typedef struct { + enum XML_FeatureEnum feature; + const XML_LChar *name; + long int value; +} XML_Feature; + +XMLPARSEAPI(const XML_Feature *) +XML_GetFeatureList(void); + + +/* Expat follows the GNU/Linux convention of odd number minor version for + beta/development releases and even number minor version for stable + releases. Micro is bumped with each release, and set to 0 with each + change to major or minor version. +*/ +#define XML_MAJOR_VERSION 1 +#define XML_MINOR_VERSION 95 +#define XML_MICRO_VERSION 8 + +#ifdef __cplusplus +} +#endif + +#endif /* not XmlParse_INCLUDED */ diff --git a/reactos/subsys/system/ibrowser/utility/utility.cpp b/reactos/subsys/system/ibrowser/utility/utility.cpp new file mode 100644 index 00000000000..6d51acf72a8 --- /dev/null +++ b/reactos/subsys/system/ibrowser/utility/utility.cpp @@ -0,0 +1,419 @@ +/* + * Copyright 2003, 2004, 2005 Martin Fuchs + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + + // + // Explorer clone + // + // utility.cpp + // + // Martin Fuchs, 23.07.2003 + // + + +#include "precomp.h" + +//#include + +#include +#include + + +DWORD WINAPI Thread::ThreadProc(void* para) +{ + Thread* pThis = (Thread*) para; + + int ret = pThis->Run(); + + pThis->_alive = false; + + return ret; +} + + +void CenterWindow(HWND hwnd) +{ + RECT rt, prt; + GetWindowRect(hwnd, &rt); + + DWORD style; + HWND owner = 0; + + for(HWND wh=hwnd; (wh=GetWindow(wh,GW_OWNER))!=0; ) + if (((style=GetWindowStyle(wh))&WS_VISIBLE) && !(style&WS_MINIMIZE)) + {owner=wh; break;} + + if (owner) + GetWindowRect(owner, &prt); + else + SystemParametersInfo(SPI_GETWORKAREA, 0, &prt, 0); //@@ GetDesktopWindow() wäre auch hilfreich. + + SetWindowPos(hwnd, 0, (prt.left+prt.right+rt.left-rt.right)/2, + (prt.top+prt.bottom+rt.top-rt.bottom)/2, 0,0, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER); + + MoveVisible(hwnd); +} + +void MoveVisible(HWND hwnd) +{ + RECT rc; + GetWindowRect(hwnd, &rc); + int left=rc.left, top=rc.top; + + int xmax = GetSystemMetrics(SM_CXSCREEN); + int ymax = GetSystemMetrics(SM_CYSCREEN); + + if (rc.left < 0) + rc.left = 0; + else if (rc.right > xmax) + if ((rc.left-=rc.right-xmax) < 0) + rc.left = 0; + + if (rc.top < 0) + rc.top = 0; + else if (rc.bottom > ymax) + if ((rc.top-=rc.bottom-ymax) < 0) + rc.top = 0; + + if (rc.left!=left || rc.top!=top) + SetWindowPos(hwnd, 0, rc.left,rc.top, 0,0, SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE); +} + + +void display_error(HWND hwnd, DWORD error) //@@ CONTEXT mit ausgeben -> display_error(HWND hwnd, const Exception& e) +{ + PTSTR msg; + + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, + 0, error, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (PTSTR)&msg, 0, NULL)) { + LOG(FmtString(TEXT("display_error(%#x): %s"), error, msg)); + + SetLastError(0); + MessageBox(hwnd, msg, TEXT("ROS Explorer"), MB_OK); + + if (GetLastError() == ERROR_INVALID_WINDOW_HANDLE) + MessageBox(0, msg, TEXT("ROS Explorer"), MB_OK); + } else { + LOG(FmtString(TEXT("Unknown Error %#x"), error)); + + FmtString msg(TEXT("Unknown Error %#x"), error); + + SetLastError(0); + MessageBox(hwnd, msg, TEXT("ROS Explorer"), MB_OK); + + if (GetLastError() == ERROR_INVALID_WINDOW_HANDLE) + MessageBox(0, msg, TEXT("ROS Explorer"), MB_OK); + } + + LocalFree(msg); +} + + +Context Context::s_main("-NO-CONTEXT-"); +Context* Context::s_current = &Context::s_main; + +String Context::toString() const +{ + String str = _ctx; + + if (!_obj.empty()) + str.appendf(TEXT("\nObject: %s"), (LPCTSTR)_obj); + + return str; +} + +String Context::getStackTrace() const +{ + ostringstream str; + + str << "Context Trace:\n"; + + for(const Context*p=this; p && p!=&s_main; p=p->_last) { + str << "- " << p->_ctx; + + if (!p->_obj.empty()) + str << " obj=" << ANS(p->_obj); + + str << '\n'; + } + + return str.str(); +} + + +BOOL time_to_filetime(const time_t* t, FILETIME* ftime) +{ + struct tm* tm = gmtime(t); + SYSTEMTIME stime; + + if (!tm) + return FALSE; + + stime.wYear = tm->tm_year+1900; + stime.wMonth = tm->tm_mon+1; + stime.wDayOfWeek = (WORD)-1; + stime.wDay = tm->tm_mday; + stime.wHour = tm->tm_hour; + stime.wMinute = tm->tm_min; + stime.wSecond = tm->tm_sec; + stime.wMilliseconds = 0; + + return SystemTimeToFileTime(&stime, ftime); +} + + +BOOL launch_file(HWND hwnd, LPCTSTR cmd, UINT nCmdShow, LPCTSTR parameters) +{ + CONTEXT("launch_file()"); + + HINSTANCE hinst = ShellExecute(hwnd, NULL/*operation*/, cmd, parameters, NULL/*dir*/, nCmdShow); + + if ((int)hinst <= 32) { + display_error(hwnd, GetLastError()); + return FALSE; + } + + return TRUE; +} + +#ifdef UNICODE +BOOL launch_fileA(HWND hwnd, LPSTR cmd, UINT nCmdShow, LPCSTR parameters) +{ + HINSTANCE hinst = ShellExecuteA(hwnd, NULL/*operation*/, cmd, parameters, NULL/*dir*/, nCmdShow); + + if ((int)hinst <= 32) { + display_error(hwnd, GetLastError()); + return FALSE; + } + + return TRUE; +} +#endif + + +/* search for already running instance */ + +static int g_foundPrevInstance = 0; + +static BOOL CALLBACK EnumWndProc(HWND hwnd, LPARAM lparam) +{ + TCHAR cls[128]; + + GetClassName(hwnd, cls, 128); + + if (!lstrcmp(cls, (LPCTSTR)lparam)) { + g_foundPrevInstance++; + return FALSE; + } + + return TRUE; +} + +/* search for window of given class name to allow only one running instance */ +int find_window_class(LPCTSTR classname) +{ + EnumWindows(EnumWndProc, (LPARAM)classname); + + if (g_foundPrevInstance) + return 1; + + return 0; +} + + +typedef void (WINAPI*RUNDLLPROC)(HWND hwnd, HINSTANCE hinst, LPCTSTR cmdline, DWORD nCmdShow); + +BOOL RunDLL(HWND hwnd, LPCTSTR dllname, LPCSTR procname, LPCTSTR cmdline, UINT nCmdShow) +{ + HMODULE hmod = LoadLibrary(dllname); + if (!hmod) + return FALSE; + +/*TODO + + It is possible to create a Unicode version of the function. + Rundll32 first tries to find a function named EntryPointW. + If it cannot find this function, it tries EntryPointA, then EntryPoint. + To create a DLL that supports ANSI on Windows 95/98/Me and Unicode otherwise, + export two functions: EntryPointW and EntryPoint. +*/ + RUNDLLPROC proc = (RUNDLLPROC)GetProcAddress(hmod, procname); + if (!proc) { + FreeLibrary(hmod); + return FALSE; + } + + proc(hwnd, hmod, cmdline, nCmdShow); + + FreeLibrary(hmod); + + return TRUE; +} + + +BOOL launch_cpanel(HWND hwnd, LPCTSTR applet) +{ + //launch_file(_hwnd, applet, SW_SHOWNORMAL); // This would be enough, but we want the fastest solution. + //launch_file(_hwnd, TEXT("rundll32.exe /d shell32.dll,Control_RunDLL ")+applet, SW_SHOWNORMAL); + + return RunDLL(hwnd, TEXT("shell32"), "Control_RunDLL", applet, SW_SHOWNORMAL); +} + + +BOOL RecursiveCreateDirectory(LPCTSTR path_in) +{ + TCHAR path[MAX_PATH], hole_path[MAX_PATH]; + + _tcscpy(hole_path, path_in); + + int drv_len = 0; + LPCTSTR d; + + for(d=hole_path; *d && *d!='/' && *d!='\\'; ++d) { + ++drv_len; + + if (*d == ':') + break; + } + + LPTSTR dir = hole_path + drv_len; + + int l; + LPTSTR p = hole_path + (l=_tcslen(hole_path)); + + while(--p>=hole_path && (*p=='/' || *p=='\\')) + *p = '\0'; + + WIN32_FIND_DATA w32fd; + + HANDLE hFind = FindFirstFile(hole_path, &w32fd); + + if (hFind == INVALID_HANDLE_VALUE) { + _tcsncpy(path, hole_path, drv_len); + int i = drv_len; + + for(p=dir; *p=='/'||*p=='\\'; p++) + path[i++] = *p++; + + for(; i + + // Unicode support +#ifdef UNICODE +#define _UNICODE +#endif +#include + +#include // for SelectBrush(), ListBox_SetSel(), SubclassWindow(), ... +#include + +#ifndef _MSC_VER +#include +#endif +#include // for VARIANT + +#include // for alloca() +#include +#include // for _MAX_DIR, ... +#include // for sprintf() +#include + +#ifndef _MAX_PATH +#define _MAX_DRIVE 3 +#define _MAX_FNAME 256 +#define _MAX_DIR _MAX_FNAME +#define _MAX_EXT _MAX_FNAME +#define _MAX_PATH 260 +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define for if (0) {} else for + +#define COUNTOF(x) (sizeof(x)/sizeof(x[0])) + + +#define BUFFER_LEN 2048 + + +#define LOG(txt) + + +#ifndef _tcsrchr +#ifdef UNICODE +#define _tcsrchr wcsrchr +#else +#define _tcsrchr strrchr +#endif +#endif + +#ifndef _stprintf +#ifdef UNICODE +#define _stprintf wcsprintf +#else +#define _stprintf sprintf +#endif +#endif + +#define U2A(s, d, l) WideCharToMultiByte(CP_ACP, 0, s, -1, d, l, NULL, NULL) +#define U2nA(s, d, l) WideCharToMultiByte(CP_ACP, 0, s, l, d, l, NULL, NULL) +#define A2U(s, d, l) MultiByteToWideChar(CP_ACP, 0, s, -1, d, l) +#define A2nU(s, d, l) MultiByteToWideChar(CP_ACP, 0, s, l, d, l) + + +#ifdef __WINE__ +#ifdef UNICODE +extern void _wsplitpath(const WCHAR* path, WCHAR* drv, WCHAR* dir, WCHAR* name, WCHAR* ext); +#else +extern void _splitpath(const CHAR* path, CHAR* drv, CHAR* dir, CHAR* name, CHAR* ext); +#endif +#define _tcsnicmp strncasecmp +#define _tcsicoll strcasecmp +#endif + +#ifndef FILE_ATTRIBUTE_NOT_CONTENT_INDEXED +#define FILE_ATTRIBUTE_ENCRYPTED 0x00000040 +#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200 +#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400 +#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000 +#endif + + +#define SetDlgCtrlID(hwnd, id) SetWindowLong(hwnd, GWL_ID, id) +#define SetWindowStyle(hwnd, val) (DWORD)SetWindowLong(hwnd, GWL_STYLE, val) +#define SetWindowExStyle(h, val) (DWORD)SetWindowLong(hwnd, GWL_EXSTYLE, val) +#define Window_SetIcon(hwnd, type, hicon) (HICON)SendMessage(hwnd, WM_SETICON, type, (LPARAM)(hicon)) + + + // center window in respect to its parent window +extern void CenterWindow(HWND hwnd); + + // move window into visibility +extern void MoveVisible(HWND hwnd); + + // display error message +extern void display_error(HWND hwnd, DWORD error); + + // convert time_t to WIN32 FILETIME +extern BOOL time_to_filetime(const time_t* t, FILETIME* ftime); + + // search for windows of a specific classname +extern int find_window_class(LPCTSTR classname); + + // create a directory with all missing parent directories +BOOL RecursiveCreateDirectory(LPCTSTR path_in); + + // test for existing directory +BOOL exists_path(LPCTSTR path); + + +#ifdef __cplusplus +} // extern "C" +#endif + + +#ifdef __cplusplus + +#ifdef _MSC_VER +#pragma warning(disable: 4786) // disable warnings about too long debug information symbols +#endif + + // STL headers for strings and streams +#include +#include +using namespace std; + + // containers +#include +#include +#include +#include +#include + + +#if _MSC_VER>=1300 // VS.Net +#define _NO_COMUTIL //@@ +#endif + +#if defined(_MSC_VER) && !defined(_NO_COMUTIL) + + // COM utility headers +#include +using namespace _com_util; + +#endif // _MSC_VER && !_NO_COMUTIL + + + // launch a program or document file +extern BOOL launch_file(HWND hwnd, LPCTSTR cmd, UINT nCmdShow, LPCTSTR parameters=NULL); +#ifdef UNICODE +extern BOOL launch_fileA(HWND hwnd, LPSTR cmd, UINT nCmdShow, LPCSTR parameters=NULL); +#else +#define launch_fileA launch_file +#endif + + // call an DLL export like rundll32 +extern BOOL RunDLL(HWND hwnd, LPCTSTR dllname, LPCSTR procname, LPCTSTR cmdline, UINT nCmdShow); + + // launch control panel applet +extern BOOL launch_cpanel(HWND hwnd, LPCTSTR applet); + + + /// initialization of windows common controls +struct CommonControlInit +{ + CommonControlInit(DWORD flags=ICC_LISTVIEW_CLASSES|ICC_TREEVIEW_CLASSES|ICC_BAR_CLASSES|ICC_PROGRESS_CLASS|ICC_COOL_CLASSES) + { + INITCOMMONCONTROLSEX icc = {sizeof(INITCOMMONCONTROLSEX), flags}; + + InitCommonControlsEx(&icc); + } +}; + + + /// wait cursor + +struct WaitCursor ///@todo integrate with WM_SETCURSOR to enable multithreaded background tasks as program launching +{ + WaitCursor() + { + _old_cursor = SetCursor(LoadCursor(0, IDC_WAIT)); + } + + ~WaitCursor() + { + SetCursor(_old_cursor); + } + +protected: + HCURSOR _old_cursor; +}; + + + /// base of all structures storing a window handle +struct WindowHandle +{ + WindowHandle(HWND hwnd=0) + : _hwnd(hwnd) {} + + operator HWND() const {return _hwnd;} + HWND* operator&() {return &_hwnd;} + +protected: + HWND _hwnd; +}; + + + /// locally hide a window +struct HiddenWindow : public WindowHandle +{ + HiddenWindow(HWND hwnd) + : WindowHandle(IsWindowVisible(hwnd)? hwnd: 0) + { + if (_hwnd) + SetWindowPos(_hwnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW|SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER); + } + + ~HiddenWindow() + { + if (_hwnd) + SetWindowPos(_hwnd, 0, 0, 0, 0, 0, SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER); + } +}; + + + /// critical section wrapper + +struct CritSect : public CRITICAL_SECTION +{ + CritSect() + { + InitializeCriticalSection(this); + } + + ~CritSect() + { + DeleteCriticalSection(this); + } +}; + + + /// Lock protects a code section utilizing a critical section + +struct Lock +{ + Lock(CritSect& crit_sect) + : _crit_sect(crit_sect) + { + EnterCriticalSection(&crit_sect); + } + + ~Lock() + { + LeaveCriticalSection(&_crit_sect); + } + +protected: + CritSect& _crit_sect; +}; + + + /// Thread base class + +struct Thread +{ + Thread() + : _alive(false) + { + _hThread = INVALID_HANDLE_VALUE; + } + + virtual ~Thread() + { + Stop(); + + CloseHandle(_hThread); + } + + void Start() + { + if (!_alive) { + _alive = true; + _hThread = CreateThread(NULL, 0, ThreadProc, this, 0, NULL); + } + } + + void Stop() + { + if (_alive) { + { + Lock lock(_crit_sect); + _alive = false; + } + + // wait for finishing + WaitForSingleObject(_hThread, INFINITE); + } + } + + virtual int Run() = 0; + + bool is_alive() const {return _alive;} + + CritSect _crit_sect; + +protected: + static DWORD WINAPI ThreadProc(void* para); + + HANDLE _hThread; + bool _alive; +}; + + + // window utilities + + /// ClientRect retreives the client area rectangle of a window. +struct ClientRect : public RECT +{ + ClientRect(HWND hwnd) + { + GetClientRect(hwnd, this); + } + + operator LPRECT() {return this;} + + POINT& pos() {return *(LPPOINT)this;} +}; + + /// ClientRect retreives the window rectangle of a window. +struct WindowRect : public RECT +{ + WindowRect(HWND hwnd) + { + GetWindowRect(hwnd, this); + } + + operator LPRECT() {return this;} + + POINT& pos() {return *(LPPOINT)this;} +}; + + /// PointL encapsulates the POINT structure into a C++ object. +struct Point : public POINT +{ + Point(LONG x_, LONG y_) + { + x = x_; + y = y_; + } + + // constructor for being used in processing WM_MOUSEMOVE, WM_LBUTTONDOWN, ... messages + Point(LPARAM lparam) + { + x = GET_X_LPARAM(lparam); + y = GET_Y_LPARAM(lparam); + } + + operator LPPOINT() {return this;} +}; + + + /// transform coordinates in a RECT from client to screen coordiantes +inline void ClientToScreen(HWND hwnd, RECT* prect) + {::ClientToScreen(hwnd,(LPPOINT)&prect->left); ::ClientToScreen(hwnd,(LPPOINT)&prect->right);} + + /// transform coordinates in a RECT from screen to client coordiantes +inline void ScreenToClient(HWND hwnd, RECT* prect) + {::ScreenToClient(hwnd,(LPPOINT)&prect->left); ::ScreenToClient(hwnd,(LPPOINT)&prect->right);} + + + /// structure containing information about full screen display of the frame window +struct FullScreenParameters +{ + FullScreenParameters() + : _mode(FALSE) + { + } + + BOOL _mode; + RECT _orgPos; + BOOL _wasZoomed; +}; + + + // drawing utilities + + /// PaintCanvas is a encapsulation of device contexts managed by BeginPaint()/EndPaint(). +struct PaintCanvas : public PAINTSTRUCT +{ + PaintCanvas(HWND hwnd) + : _hwnd(hwnd) + { + BeginPaint(hwnd, this); + } + + ~PaintCanvas() + { + EndPaint(_hwnd, this); + } + + operator HDC() const {return hdc;} + +protected: + HWND _hwnd; +}; + + /// Canvas is a encapsulation of device contexts. +struct Canvas +{ + Canvas(HDC hdc) : _hdc(hdc) {} + + operator HDC() {return _hdc;} + +protected: + HDC _hdc; +}; + + /// WindowCanvas is a encapsulation of client area device contexts. +struct WindowCanvas : public Canvas +{ + WindowCanvas(HWND hwnd) + : Canvas(GetDC(hwnd)), _hwnd(hwnd) {} + + ~WindowCanvas() {ReleaseDC(_hwnd, _hdc);} + +protected: + HWND _hwnd; +}; + + + // double buffering classes + + /// Memory Canvas creates and destroys memory devoce contexts. +struct MemCanvas : public Canvas +{ + MemCanvas(HDC hdc=0) + : Canvas(CreateCompatibleDC(hdc)) {assert(_hdc);} + + ~MemCanvas() {DeleteDC(_hdc);} +}; + + /// SelectedBitmap is used to localy select bitmaps into device contexts. +struct SelectedBitmap +{ + SelectedBitmap(HDC hdc, HBITMAP hbmp) + : _hdc(hdc), _old_hbmp(SelectBitmap(hdc, hbmp)) {} + + ~SelectedBitmap() {DeleteObject(SelectBitmap(_hdc, _old_hbmp));} + +protected: + HDC _hdc; + HBITMAP _old_hbmp; +}; + + /// BufferCanvas manages offscreen bitmaps selected into memory device contexts. +struct BufferCanvas : public MemCanvas +{ + BufferCanvas(HDC hdc, int x, int y, int w, int h) + : MemCanvas(hdc), _hdctarg(hdc), + _x(x), _y(y), _w(w), _h(h), + _bmp(_hdc, CreateCompatibleBitmap(hdc, w, h)) {} + + BufferCanvas(HDC hdc, const RECT& rect) + : MemCanvas(hdc), _hdctarg(hdc), + _x(rect.left), _y(rect.top), _w(rect.right-rect.left), _h(rect.bottom-rect.top), + _bmp(_hdc, CreateCompatibleBitmap(hdc, _w, _h)) {} + +protected: + HDC _hdctarg; + int _x, _y, _w, _h; + SelectedBitmap _bmp; +}; + + /// BufferedCanvas enables double buffering for a device context. +struct BufferedCanvas : public BufferCanvas +{ + BufferedCanvas(HDC hdc, int x, int y, int w, int h, DWORD mode=SRCCOPY) + : BufferCanvas(hdc, x, y, w, h), _mode(mode) {} + + BufferedCanvas(HDC hdc, const RECT& rect, DWORD mode=SRCCOPY) + : BufferCanvas(hdc, rect), _mode(mode) {} + + ~BufferedCanvas() {BitBlt(_hdctarg, _x, _y, _w, _h, _hdc, 0, 0, _mode);} + + DWORD _mode; +}; + + /// BufferedPaintCanvas extends PaintCanvas for double buffering. +struct BufferedPaintCanvas : public PaintCanvas, public BufferedCanvas +{ + BufferedPaintCanvas(HWND hwnd) + : PaintCanvas(hwnd), + BufferedCanvas(PAINTSTRUCT::hdc, 0, 0, rcPaint.right, rcPaint.bottom) + { + } + + operator HDC() {return BufferedCanvas::_hdc;} +}; + + + /// TextColor locally selects a text color for drawing. +struct TextColor +{ + TextColor(HDC hdc, COLORREF color) + : _hdc(hdc), _old_color(SetTextColor(hdc, color)) {} + + ~TextColor() {SetTextColor(_hdc, _old_color);} + +protected: + HDC _hdc; + COLORREF _old_color; +}; + + /// BkMode locally sets the background mode for drawing. +struct BkMode +{ + BkMode(HDC hdc, int bkmode) + : _hdc(hdc), _old_bkmode(SetBkMode(hdc, bkmode)) {} + + ~BkMode() {SetBkMode(_hdc, _old_bkmode);} + +protected: + HDC _hdc; + COLORREF _old_bkmode; +}; + + /// FontSelection locally selects a font for drawing. +struct FontSelection +{ + FontSelection(HDC hdc, HFONT hFont) + : _hdc(hdc), _old_hFont(SelectFont(hdc, hFont)) {} + + ~FontSelection() {SelectFont(_hdc, _old_hFont);} + +protected: + HDC _hdc; + HFONT _old_hFont; +}; + + /// BitmapSelection locally selects a bitmap into a device context. +struct BitmapSelection +{ + BitmapSelection(HDC hdc, HBITMAP hBmp) + : _hdc(hdc), _old_hBmp(SelectBitmap(hdc, hBmp)) {} + + ~BitmapSelection() {SelectBitmap(_hdc, _old_hBmp);} + +protected: + HDC _hdc; + HBITMAP _old_hBmp; +}; + + /// BrushSelection locally selects a brush into a device context. +struct BrushSelection +{ + BrushSelection(HDC hdc, HBRUSH hBrush) + : _hdc(hdc), _old_hBrush(SelectBrush(hdc, hBrush)) {} + + ~BrushSelection() {SelectBrush(_hdc, _old_hBrush);} + +protected: + HDC _hdc; + HBRUSH _old_hBrush; +}; + + + /// Popup Menus +struct PopupMenu +{ + PopupMenu() + : _hmenu(CreatePopupMenu()) + { + } + + PopupMenu(UINT nid); + + operator HMENU() {return _hmenu;} + + void Append(UINT id, LPCTSTR str, UINT flags=MF_STRING) + { + AppendMenu(_hmenu, flags, id, str); + } + + int TrackPopupMenu(HWND hwnd, const POINT& pt, UINT flags=TPM_LEFTBUTTON|TPM_RIGHTBUTTON, LPTPMPARAMS tpm=NULL) { + return TrackPopupMenuEx(_hmenu, flags, pt.x, pt.y, hwnd, tpm); + } + + int PopupContextMenu(HWND hwnd, POINTS pos, UINT flags=TPM_LEFTBUTTON|TPM_RIGHTBUTTON) { + POINT pt; POINTSTOPOINT(pt, pos); + return TrackPopupMenuEx(_hmenu, flags, pt.x, pt.y, hwnd, NULL); + } + + int TrackPopupMenu(HWND hwnd, POINTS pos, UINT flags=TPM_LEFTBUTTON|TPM_RIGHTBUTTON) { + POINT pt; POINTSTOPOINT(pt, pos); + ClientToScreen(hwnd, &pt); + return TrackPopupMenuEx(_hmenu, flags, pt.x, pt.y, hwnd, NULL); + } + + int TrackPopupMenuAtCursor(HWND hwnd, UINT flags=TPM_LEFTBUTTON) { + POINT pt; GetCursorPos(&pt); + return TrackPopupMenuEx(_hmenu, flags, pt.x, pt.y, hwnd, NULL); + } + + int TrackPopupMenuAtPos(HWND hwnd, DWORD pos, UINT flags=TPM_LEFTBUTTON) { + return TrackPopupMenuEx(_hmenu, flags, GET_X_LPARAM(pos), GET_Y_LPARAM(pos), hwnd, NULL); + } + +protected: + HMENU _hmenu; +}; + + +struct Variant : public VARIANT +{ + Variant() {VariantInit(this);} + Variant(const VARIANT& var); + Variant(const VARIANT* var); + ~Variant(); + + operator long() const; + operator bool() const; + operator VARIANT_BOOL() const; + operator IDispatch*() const; +}; + + +struct BStr +{ + BStr() + { + _p = NULL; + } + + BStr(const BSTR s) + { + _p = SysAllocString(s); + } + + BStr(LPCSTR s) + { + WCHAR b[BUFFER_LEN]; + + if (s) + _p = SysAllocStringLen(b, MultiByteToWideChar(CP_ACP, 0, s, -1, b, BUFFER_LEN)-1); + else + _p = NULL; + } + + BStr(LPCWSTR s) + { + _p = SysAllocString(s); + } + + BStr(const VARIANT& var) + : _p(NULL) + { + assign(var); + } + + ~BStr() + { + SysFreeString(_p); + } + + void assign(BSTR s); + void assign(const VARIANT& var); + + operator BSTR() const + { + return _p? _p: (BSTR)L""; + } + + int length() const + { + return _p? wcslen(_p): 0; + } + +protected: + BSTR _p; +}; + + + /// string class for TCHAR strings +struct String +#ifdef UNICODE + : public wstring +#else + : public string +#endif +{ +#ifdef UNICODE + typedef wstring super; +#else + typedef string super; +#endif + + String() {} + + String(LPCTSTR s) {if (s) super::assign(s);} + String(LPCTSTR s, int l) : super(s, l) {} + + String(const super& other) : super(other) {} + String(const String& other) : super(other) {} + +#ifdef UNICODE + String(LPCSTR s) {assign(s);} + String(LPCSTR s, int l) {assign(s, l);} + String(const string& other) {assign(other.c_str());} + String& operator=(LPCSTR s) {assign(s); return *this;} + void assign(LPCSTR s) {if (s) {TCHAR b[BUFFER_LEN]; super::assign(b, MultiByteToWideChar(CP_ACP, 0, s, -1, b, BUFFER_LEN)-1);} else erase();} + void assign(LPCSTR s, int l) {if (s) {TCHAR b[BUFFER_LEN]; super::assign(b, MultiByteToWideChar(CP_ACP, 0, s, l, b, BUFFER_LEN));} else erase();} + void assign(const BStr& s) {int l = s.length(); super::assign(s, l);} +#else + String(LPCWSTR s) {assign(s);} + String(LPCWSTR s, int l) {assign(s, l);} + String(const wstring& other) {assign(other.c_str());} + String& operator=(LPCWSTR s) {assign(s); return *this;} + void assign(LPCWSTR s) {if (s) {char b[BUFFER_LEN]; super::assign(b, WideCharToMultiByte(CP_ACP, 0, s, -1, b, BUFFER_LEN, 0, 0)-1);} else erase();} + void assign(LPCWSTR s, int l) {if (s) {char b[BUFFER_LEN]; super::assign(b, WideCharToMultiByte(CP_ACP, 0, s, l, b, BUFFER_LEN, 0, 0));} else erase();} + void assign(const BStr& s) {int l = s.length(); if (l) {char b[BUFFER_LEN]; super::assign(b, WideCharToMultiByte(CP_ACP, 0, s, l, b, BUFFER_LEN, 0, 0));} else erase();} +#endif + String(const BStr& s) {assign(s);} + String& operator=(const BStr& s) {assign(s); return *this;} + + String& operator=(LPCTSTR s) {if (s) super::assign(s); else erase(); return *this;} + String& operator=(const super& s) {super::assign(s); return *this;} + void assign(LPCTSTR s) {super::assign(s);} + void assign(LPCTSTR s, int l) {super::assign(s, l);} + + operator LPCTSTR() const {return c_str();} + +#ifdef UNICODE + operator string() const {char b[BUFFER_LEN]; return string(b, WideCharToMultiByte(CP_ACP, 0, c_str(), -1, b, BUFFER_LEN, 0, 0)-1);} +#else + operator wstring() const {WCHAR b[BUFFER_LEN]; return wstring(b, MultiByteToWideChar(CP_ACP, 0, c_str(), -1, b, BUFFER_LEN)-1);} +#endif + + String& printf(LPCTSTR fmt, ...) + { + va_list l; + TCHAR b[BUFFER_LEN]; + + va_start(l, fmt); + super::assign(b, _vstprintf(b, fmt, l)); + va_end(l); + + return *this; + } + + String& vprintf(LPCTSTR fmt, va_list l) + { + TCHAR b[BUFFER_LEN]; + + super::assign(b, _vstprintf(b, fmt, l)); + + return *this; + } + + String& appendf(LPCTSTR fmt, ...) + { + va_list l; + TCHAR b[BUFFER_LEN]; + + va_start(l, fmt); + super::append(b, _vstprintf(b, fmt, l)); + va_end(l); + + return *this; + } + + String& vappendf(LPCTSTR fmt, va_list l) + { + TCHAR b[BUFFER_LEN]; + + super::append(b, _vstprintf(b, fmt, l)); + + return *this; + } +}; + +#define _STRING_DEFINED + + +struct FmtString : public String +{ + FmtString(LPCTSTR fmt, ...) + { + va_list l; + + va_start(l, fmt); + vprintf(fmt, l); + va_end(l); + } +}; + + +#ifdef UNICODE + +struct ANS +{ + ANS(LPCWSTR s) + { + int l = wcslen(s) + 1; + _str = (LPSTR) malloc(2*l); + + if (WideCharToMultiByte(CP_ACP, 0, s, -1, _str, 2*l, 0, 0) <= 0) + *_str = '\0'; + } + + ~ANS() + { + free(_str); + } + + operator LPCSTR() {return _str;} + +protected: + LPSTR _str; +}; + +#define UNC(x) ((LPCWSTR)(x)) + +#else + +#define ANS(x) ((LPCSTR)(x)) + +struct UNC +{ + UNC(LPCSTR s) + { + int l = strlen(s) + 1; + _str = (LPWSTR) malloc(2*l); + + if (MultiByteToWideChar(CP_ACP, 0, s, -1, _str, l) <= 0) + *_str = '\0'; + } + + ~UNC() + { + free(_str); + } + + operator LPCWSTR() {return _str;} + +protected: + LPWSTR _str; +}; + +#endif + + + // determine windows version string +//@@String get_windows_version_str(); + + + /// link dynamicly to functions by using GetModuleHandle() and GetProcAddress() +template struct DynamicFct +{ + DynamicFct(LPCTSTR moduleName, UINT ordinal) + { + HMODULE hModule = GetModuleHandle(moduleName); + + _fct = (FCT) GetProcAddress(hModule, (LPCSTR)ordinal); + } + + DynamicFct(LPCTSTR moduleName, LPCSTR name) + { + HMODULE hModule = GetModuleHandle(moduleName); + + _fct = (FCT) GetProcAddress(hModule, name); + } + + FCT operator*() const {return _fct;} + operator bool() const {return _fct? true: false;} + +protected: + FCT _fct; +}; + + + /// link dynamicly to functions by using LoadLibrary() and GetProcAddress() +template struct DynamicLoadLibFct +{ + DynamicLoadLibFct(LPCTSTR moduleName, UINT ordinal) + { + _hModule = LoadLibrary(moduleName); + + _fct = (FCT) GetProcAddress(_hModule, (LPCSTR)ordinal); + } + + DynamicLoadLibFct(LPCTSTR moduleName, LPCSTR name) + { + _hModule = LoadLibrary(moduleName); + + _fct = (FCT) GetProcAddress(_hModule, name); + } + + ~DynamicLoadLibFct() + { + FreeLibrary(_hModule); + } + + FCT operator*() const {return _fct;} + operator bool() const {return _fct? true: false;} + +protected: + HMODULE _hModule; + FCT _fct; +}; + + +struct Context +{ + Context(const char* ctx) + : _ctx(ctx) + { + _last = s_current; + s_current = this; + } + + Context(const char* ctx, LPCSTR obj) + : _ctx(ctx), + _obj(obj) + { + _last = s_current; + s_current = this; + } + + Context(const char* ctx, LPCWSTR obj) + : _ctx(ctx), + _obj(obj) + { + _last = s_current; + s_current = this; + } + + Context(const Context& other) + : _ctx(other._ctx), + _obj(other._obj) + { + _last = NULL; + } + + ~Context() + { + if (_last) { + s_current = _last; + _last = NULL; + } + } + + String toString() const; + String getStackTrace() const; + + const char* _ctx; + String _obj; + + static Context& current() {return *s_current;} + +protected: + Context* _last; + + static Context* s_current; ///@todo use TLS + static Context s_main; +}; + +#define CONTEXT_OBJ __ctx__._obj +#define CONTEXT(c) Context __ctx__(c) +#define CURRENT_CONTEXT Context::current() +#define OBJ_CONTEXT(c, o) Context __ctx__(c, o) + + +extern bool SplitFileSysURL(LPCTSTR url, String& dir_out, String& fname_out); + + +#endif // __cplusplus diff --git a/reactos/subsys/system/ibrowser/utility/window.cpp b/reactos/subsys/system/ibrowser/utility/window.cpp new file mode 100644 index 00000000000..c9d7085a98d --- /dev/null +++ b/reactos/subsys/system/ibrowser/utility/window.cpp @@ -0,0 +1,1206 @@ +/* + * Copyright 2003, 2004, 2005 Martin Fuchs + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + + // + // ROS Internet Web Browser + // + // window.cpp + // + // Martin Fuchs, 23.07.2003 + // + + +#include "precomp.h" + +#include "../ibrowser_intres.h" // for ID_GO_BACK, ... + + +WindowClass::WindowClass(LPCTSTR classname, UINT style_, WNDPROC wndproc) +{ + memset(this, 0, sizeof(WNDCLASSEX)); + + cbSize = sizeof(WNDCLASSEX); + style = style_; + hInstance = g_hInstance; + hCursor = LoadCursor(0, IDC_ARROW); + + lpszClassName = classname; + lpfnWndProc = wndproc; + + _atomClass = 0; +} + + +IconWindowClass::IconWindowClass(LPCTSTR classname, UINT nid, UINT style, WNDPROC wndproc) + : WindowClass(classname, style, wndproc) +{ + hIcon = ResIcon(nid); + hIconSm = SmallIcon(nid); +} + + +Window::WindowMap Window::s_wnd_map; + +Window::CREATORFUNC Window::s_window_creator = NULL; +const void* Window::s_new_info = NULL; + + +Window::StaticWindowData& Window::GetStaticWindowData() +{ + static StaticWindowData s_initialized_data; + + return s_initialized_data; +} + + +Window::Window(HWND hwnd) + : WindowHandle(hwnd) +{ + Lock lock(GetStaticWindowData()._map_crit_sect); // protect access to s_wnd_map + + s_wnd_map[_hwnd] = this; +} + +Window::~Window() +{ + Lock lock(GetStaticWindowData()._map_crit_sect); // protect access to s_wnd_map + + s_wnd_map.erase(_hwnd); +} + + +HWND Window::Create(CREATORFUNC creator, DWORD dwExStyle, + LPCTSTR lpClassName, LPCTSTR lpWindowName, + DWORD dwStyle, int x, int y, int w, int h, + HWND hwndParent, HMENU hMenu/*, LPVOID lpParam*/) +{ + Lock lock(GetStaticWindowData()._create_crit_sect); // protect access to s_window_creator and s_new_info + + s_window_creator = creator; + s_new_info = NULL; + + return CreateWindowEx(dwExStyle, lpClassName, lpWindowName, dwStyle, + x, y, w, h, + hwndParent, hMenu, g_hInstance, 0/*lpParam*/); +} + +HWND Window::Create(CREATORFUNC_INFO creator, const void* info, DWORD dwExStyle, + LPCTSTR lpClassName, LPCTSTR lpWindowName, + DWORD dwStyle, int x, int y, int w, int h, + HWND hwndParent, HMENU hMenu/*, LPVOID lpParam*/) +{ + Lock lock(GetStaticWindowData()._create_crit_sect); // protect access to s_window_creator and s_new_info + + s_window_creator = (CREATORFUNC) creator; + s_new_info = info; + + return CreateWindowEx(dwExStyle, lpClassName, lpWindowName, dwStyle, + x, y, w, h, + hwndParent, hMenu, g_hInstance, 0/*lpParam*/); +} + + + /// get window controller from window handle + +Window* Window::get_window(HWND hwnd) +{ + { + Lock lock(GetStaticWindowData()._map_crit_sect); // protect access to s_wnd_map + + WindowMap::const_iterator found = s_wnd_map.find(hwnd); + + if (found!=s_wnd_map.end()) + return found->second; + } + + return NULL; +} + + + /// create controller for a new window + +Window* Window::create_controller(HWND hwnd) +{ + if (s_window_creator) { // protect for recursion and create the window object only for the first window + Lock lock(GetStaticWindowData()._create_crit_sect); // protect access to s_window_creator and s_new_info + + const void* info = s_new_info; + s_new_info = NULL; + + CREATORFUNC window_creator = s_window_creator; + s_window_creator = NULL; + + if (info) + return CREATORFUNC_INFO(window_creator)(hwnd, info); + else + return CREATORFUNC(window_creator)(hwnd); + } + + return NULL; +} + + +LRESULT Window::Init(LPCREATESTRUCT pcs) +{ + return 0; +} + + +LRESULT CALLBACK Window::WindowWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam) +{ + Window* pThis = get_window(hwnd); + + if (!pThis) + pThis = create_controller(hwnd); + + if (pThis) { + switch(nmsg) { + case WM_COMMAND: + return pThis->Command(LOWORD(wparam), HIWORD(wparam)); + + case WM_NOTIFY: + return pThis->Notify(wparam, (NMHDR*)lparam); + + case WM_NOTIFYFORMAT: + return NFR_CURRENT; + + case WM_CREATE: + return pThis->Init((LPCREATESTRUCT)lparam); + + case WM_NCDESTROY: + delete pThis; + return 0; + + default: + return pThis->WndProc(nmsg, wparam, lparam); + } + } + else + return DefWindowProc(hwnd, nmsg, wparam, lparam); +} + +LRESULT Window::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) +{ + return DefWindowProc(_hwnd, nmsg, wparam, lparam); +} + +int Window::Command(int id, int code) +{ + return 1; // no command handler found +} + +int Window::Notify(int id, NMHDR* pnmh) +{ + return 0; +} + +void Window::CancelModes(HWND hwnd) +{ + if (hwnd) + PostMessage(hwnd, WM_CANCELMODE, 0, 0); + else + PostMessage(HWND_BROADCAST, WM_CANCELMODE, 0, 0); +} + + +SubclassedWindow::SubclassedWindow(HWND hwnd) + : super(hwnd) +{ + _orgWndProc = SubclassWindow(_hwnd, SubclassedWndProc); + + if (!_orgWndProc) + delete this; +} + +LRESULT CALLBACK SubclassedWindow::SubclassedWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam) +{ + SubclassedWindow* pThis = GET_WINDOW(SubclassedWindow, hwnd); + assert(pThis); + + if (pThis) { + switch(nmsg) { + case WM_COMMAND: + if (!pThis->Command(LOWORD(wparam), HIWORD(wparam))) + return 0; + break; + + case WM_NOTIFY: + return pThis->Notify(wparam, (NMHDR*)lparam); + + case WM_NOTIFYFORMAT: + return NFR_CURRENT; + + case WM_CREATE: + return pThis->Init((LPCREATESTRUCT)lparam); + + case WM_NCDESTROY: + delete pThis; + return 0; + + default: + return pThis->WndProc(nmsg, wparam, lparam); + } + } + + return CallWindowProc(pThis->_orgWndProc, hwnd, nmsg, wparam, lparam); +} + +LRESULT SubclassedWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) +{ + return CallWindowProc(_orgWndProc, _hwnd, nmsg, wparam, lparam); +} + +int SubclassedWindow::Command(int id, int code) +{ + return 1; // no command handler found +} + +int SubclassedWindow::Notify(int id, NMHDR* pnmh) +{ + return CallWindowProc(_orgWndProc, _hwnd, WM_NOTIFY, id, (LPARAM)pnmh); +} + + +ChildWindow::ChildWindow(HWND hwnd, HWND hwndFrame) + : super(hwnd), + _hwndFrame(hwndFrame) +{ +} + + +ChildWindow* ChildWindow::create(const ChildWndInfo& info, CREATORFUNC_INFO creator, + LPCTSTR classname, LPCTSTR title, DWORD style) +{ + HWND hwnd = Window::Create(creator, &info, 0, classname, title, style, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, info._hwndFrame); + + return GET_WINDOW(ChildWindow, hwnd); +} + + +LRESULT ChildWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) +{ + switch(nmsg) { + case PM_JUMP_TO_URL: + return go_to((LPCTSTR)lparam)? TRUE: FALSE; + + default: + return super::WndProc(nmsg, wparam, lparam); + } + + return 0; +} + + +bool ChildWindow::go_to(LPCTSTR url) +{ + const String& url_str = jump_to_int(url); + + if (!url_str.empty()) { + set_url(url_str); + + _url_history.push(url_str); + + return true; + } else + return false; +} + +void ChildWindow::set_url(LPCTSTR url) +{ + if (_url != url) { + _url = url; + + SendMessage(_hwndFrame, PM_URL_CHANGED, 0, (LPARAM)url); + } +} + + +WindowSet Window::s_pretranslate_windows; + +void Window::register_pretranslate(HWND hwnd) +{ + s_pretranslate_windows.insert(hwnd); +} + +void Window::unregister_pretranslate(HWND hwnd) +{ + s_pretranslate_windows.erase(hwnd); +} + +BOOL Window::pretranslate_msg(LPMSG pmsg) +{ + for(WindowSet::const_iterator it=Window::s_pretranslate_windows.begin(); it!=s_pretranslate_windows.end(); ++it) + if (SendMessage(*it, PM_TRANSLATE_MSG, 0, (LPARAM)pmsg)) + return TRUE; + + return FALSE; +} + + +WindowSet Window::s_dialogs; + +void Window::register_dialog(HWND hwnd) +{ + s_dialogs.insert(hwnd); +} + +void Window::unregister_dialog(HWND hwnd) +{ + s_dialogs.erase(hwnd); +} + +BOOL Window::dispatch_dialog_msg(MSG* pmsg) +{ + for(WindowSet::const_iterator it=Window::s_dialogs.begin(); it!=s_dialogs.end(); ++it) + if (IsDialogMessage(*it, pmsg)) + return TRUE; + + return FALSE; +} + + +int Window::MessageLoop() +{ + MSG msg; + + while(GetMessage(&msg, 0, 0, 0)) { + try { + if (pretranslate_msg(&msg)) + continue; + + if (dispatch_dialog_msg(&msg)) + continue; + + TranslateMessage(&msg); + + try { + DispatchMessage(&msg); + } catch(COMException& e) { + HandleException(e, 0); + } + } catch(COMException& e) { + HandleException(e, 0); + } + } + + return msg.wParam; +} + + +LRESULT Window::SendParent(UINT nmsg, WPARAM wparam, LPARAM lparam) +{ + HWND parent = GetParent(_hwnd); + + if (!parent) + return 0; + + return SendMessage(parent, nmsg, wparam, lparam); +} + +LRESULT Window::PostParent(UINT nmsg, WPARAM wparam, LPARAM lparam) +{ + HWND parent = GetParent(_hwnd); + + if (!parent) + return 0; + + return PostMessage(parent, nmsg, wparam, lparam); +} + + +PreTranslateWindow::PreTranslateWindow(HWND hwnd) + : super(hwnd) +{ + register_pretranslate(hwnd); +} + +PreTranslateWindow::~PreTranslateWindow() +{ + unregister_pretranslate(_hwnd); +} + + +Dialog::Dialog(HWND hwnd) + : super(hwnd) +{ + register_dialog(hwnd); +} + +Dialog::~Dialog() +{ + unregister_dialog(_hwnd); +} + +int Dialog::DoModal(UINT nid, CREATORFUNC creator, HWND hwndParent) +{ + Lock lock(GetStaticWindowData()._create_crit_sect); // protect access to s_window_creator and s_new_info + + s_window_creator = creator; + s_new_info = NULL; + + ///@todo call Window::pretranslate_msg() + + return DialogBoxParam(g_hInstance, MAKEINTRESOURCE(nid), hwndParent, DialogProc, 0/*lpParam*/); +} + +int Dialog::DoModal(UINT nid, CREATORFUNC_INFO creator, const void* info, HWND hwndParent) +{ + Lock lock(GetStaticWindowData()._create_crit_sect); // protect access to s_window_creator and s_new_info + + s_window_creator = (CREATORFUNC) creator; + s_new_info = NULL; + + ///@todo call Window::pretranslate_msg() + + return DialogBoxParam(g_hInstance, MAKEINTRESOURCE(nid), hwndParent, DialogProc, 0/*lpParam*/); +} + +INT_PTR CALLBACK Window::DialogProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam) +{ + Window* pThis = get_window(hwnd); + + if (pThis) { + switch(nmsg) { + case WM_COMMAND: + pThis->Command(LOWORD(wparam), HIWORD(wparam)); + return TRUE; // message has been processed + + case WM_NOTIFY: + pThis->Notify(wparam, (NMHDR*)lparam); + return TRUE; // message has been processed + + case WM_NOTIFYFORMAT: + SetWindowLong(hwnd, DWLP_MSGRESULT, NFR_CURRENT); // set return value NFR_CURRENT + return TRUE; // message has been processed + + case WM_NCDESTROY: + delete pThis; + return TRUE; // message has been processed + + default: + return pThis->WndProc(nmsg, wparam, lparam); + } + } else if (nmsg == WM_INITDIALOG) { + pThis = create_controller(hwnd); + + if (pThis) + return pThis->Init(NULL); + } + + return FALSE; // message has not been processed +} + +LRESULT Dialog::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) +{ + return FALSE; // message has not been processed +} + +int Dialog::Command(int id, int code) +{ + if (code == BN_CLICKED) { + EndDialog(_hwnd, id); + return 0; // message has been processed + } + + return 1; +} + + +ResizeManager::ResizeManager(HWND hwnd) + : _hwnd(hwnd) +{ + ClientRect clnt(hwnd); + _last_size.cx = clnt.right; + _last_size.cy = clnt.bottom; + + WindowRect rect(hwnd); + _min_wnd_size.cx = rect.right - rect.left; + _min_wnd_size.cy = rect.bottom - rect.top; +} + +void ResizeManager::HandleSize(int cx, int cy) +{ + ClientRect clnt_rect(_hwnd); + SIZE new_size = {cx, cy}; + + int dx = new_size.cx - _last_size.cx; + int dy = new_size.cy - _last_size.cy; + + if (!dx && !dy) + return; + + _last_size = new_size; + + HDWP hDWP = BeginDeferWindowPos(size()); + + for(ResizeManager::const_iterator it=begin(); it!=end(); ++it) { + const ResizeEntry& e = *it; + RECT move = {0}; + + if (e._flags & MOVE_LEFT) + move.left += dx; + + if (e._flags & MOVE_RIGHT) + move.right += dx; + + if (e._flags & MOVE_TOP) + move.top += dy; + + if (e._flags & MOVE_BOTTOM) + move.bottom += dy; + + UINT flags = 0; + + if (!move.left && !move.top) + flags = SWP_NOMOVE; + + if (move.right==move.left && move.bottom==move.top) + flags |= SWP_NOSIZE; + + if (flags != (SWP_NOMOVE|SWP_NOSIZE)) { + HWND hwnd = GetDlgItem(_hwnd, e._id); + + if (hwnd) { + WindowRect rect(hwnd); + ScreenToClient(_hwnd, rect); + + rect.left += move.left; + rect.right += move.right; + rect.top += move.top; + rect.bottom += move.bottom; + + hDWP = DeferWindowPos(hDWP, hwnd, 0, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, flags|SWP_NOACTIVATE|SWP_NOZORDER); + } + } + } + + EndDeferWindowPos(hDWP); +} + +void ResizeManager::Resize(int dx, int dy) +{ + ::SetWindowPos(_hwnd, 0, 0, 0, _min_wnd_size.cx+dx, _min_wnd_size.cy+dy, SWP_NOMOVE|SWP_NOACTIVATE); + MoveVisible(_hwnd); + + ClientRect clnt_rect(_hwnd); + HandleSize(clnt_rect.right, clnt_rect.bottom); +} + + +Button::Button(HWND parent, LPCTSTR title, int left, int top, int width, int height, + int id, DWORD flags, DWORD exStyle) + : WindowHandle(CreateWindowEx(exStyle, TEXT("BUTTON"), title, flags, left, top, width, height, + parent, (HMENU)id, g_hInstance, 0)) +{ +} + + +LRESULT OwnerdrawnButton::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) +{ + if (nmsg == PM_DISPATCH_DRAWITEM) { + DrawItem((LPDRAWITEMSTRUCT)lparam); + return TRUE; + } else + return super::WndProc(nmsg, wparam, lparam); +} + + +Static::Static(HWND parent, LPCTSTR title, int left, int top, int width, int height, + int id, DWORD flags, DWORD exStyle) + : WindowHandle(CreateWindowEx(exStyle, TEXT("STATIC"), title, flags, left, top, width, height, + parent, (HMENU)id, g_hInstance, 0)) +{ +} + + +static RECT s_MyDrawText_Rect = {0, 0, 0, 0}; + +static BOOL CALLBACK MyDrawText(HDC hdc, LPARAM data, int cnt) +{ + ::DrawText(hdc, (LPCTSTR)data, cnt, &s_MyDrawText_Rect, DT_SINGLELINE); + return TRUE; +} + +void DrawGrayText(HDC hdc, LPRECT pRect, LPCTSTR title, int dt_flags) +{ + COLORREF gray = GetSysColor(COLOR_GRAYTEXT); + + if (gray) { + TextColor lcColor(hdc, GetSysColor(COLOR_BTNHIGHLIGHT)); + RECT shadowRect = {pRect->left+1, pRect->top+1, pRect->right+1, pRect->bottom+1}; + DrawText(hdc, title, -1, &shadowRect, dt_flags); + + SetTextColor(hdc, gray); + DrawText(hdc, title, -1, pRect, dt_flags); + } else { + int old_r = pRect->right; + int old_b = pRect->bottom; + + DrawText(hdc, title, -1, pRect, dt_flags|DT_CALCRECT); + + int x = pRect->left + (old_r-pRect->right)/2; + int y = pRect->top + (old_b-pRect->bottom)/2; + int w = pRect->right-pRect->left; + int h = pRect->bottom-pRect->top; + s_MyDrawText_Rect.right = w; + s_MyDrawText_Rect.bottom = h; + + GrayString(hdc, GetSysColorBrush(COLOR_GRAYTEXT), MyDrawText, (LPARAM)title, -1, x, y, w, h); + } +} + + +/* not yet used +void ColorButton::DrawItem(LPDRAWITEMSTRUCT dis) +{ + UINT state = DFCS_BUTTONPUSH; + + if (dis->itemState & ODS_DISABLED) + state |= DFCS_INACTIVE; + + RECT textRect = {dis->rcItem.left+2, dis->rcItem.top+2, dis->rcItem.right-4, dis->rcItem.bottom-4}; + + if (dis->itemState & ODS_SELECTED) { + state |= DFCS_PUSHED; + ++textRect.left; ++textRect.top; + ++textRect.right; ++textRect.bottom; + } + + DrawFrameControl(dis->hDC, &dis->rcItem, DFC_BUTTON, state); + + TCHAR title[BUFFER_LEN]; + GetWindowText(_hwnd, title, BUFFER_LEN); + + BkMode bk_mode(dis->hDC, TRANSPARENT); + + if (dis->itemState & (ODS_DISABLED|ODS_GRAYED)) + DrawGrayText(dis, &textRect, title, DT_SINGLELINE|DT_VCENTER|DT_CENTER); + else { + TextColor lcColor(dis->hDC, _textColor); + DrawText(dis->hDC, title, -1, &textRect, DT_SINGLELINE|DT_VCENTER|DT_CENTER); + } + + if (dis->itemState & ODS_FOCUS) { + RECT rect = { + dis->rcItem.left+3, dis->rcItem.top+3, + dis->rcItem.right-dis->rcItem.left-4, dis->rcItem.bottom-dis->rcItem.top-4 + }; + if (dis->itemState & ODS_SELECTED) { + ++rect.left; ++rect.top; + ++rect.right; ++rect.bottom; + } + DrawFocusRect(dis->hDC, &rect); + } +} +*/ + + +void PictureButton::DrawItem(LPDRAWITEMSTRUCT dis) +{ + UINT state = DFCS_BUTTONPUSH; + int style = GetWindowStyle(_hwnd); + + if (dis->itemState & ODS_DISABLED) + state |= DFCS_INACTIVE; + + POINT imagePos; + RECT textRect; + int dt_flags; + + if (style & BS_BOTTOM) { + // align horizontal centered, vertical floating + imagePos.x = (dis->rcItem.left + dis->rcItem.right - _cx) / 2; + imagePos.y = dis->rcItem.top + 3; + + textRect.left = dis->rcItem.left + 2; + textRect.top = dis->rcItem.top + _cy + 4; + textRect.right = dis->rcItem.right - 4; + textRect.bottom = dis->rcItem.bottom - 4; + + dt_flags = DT_SINGLELINE|DT_CENTER|DT_VCENTER; + } else { + // horizontal floating, vertical centered + imagePos.x = dis->rcItem.left + 3; + imagePos.y = (dis->rcItem.top + dis->rcItem.bottom - _cy)/2; + + textRect.left = dis->rcItem.left + _cx + 4; + textRect.top = dis->rcItem.top + 2; + textRect.right = dis->rcItem.right - 4; + textRect.bottom = dis->rcItem.bottom - 4; + + dt_flags = DT_SINGLELINE|DT_VCENTER/*|DT_CENTER*/; + } + + if (dis->itemState & ODS_SELECTED) { + state |= DFCS_PUSHED; + ++imagePos.x; ++imagePos.y; + ++textRect.left; ++textRect.top; + ++textRect.right; ++textRect.bottom; + } + + if (_flat) { + FillRect(dis->hDC, &dis->rcItem, _hBrush); + + if (style & BS_FLAT) // Only with BS_FLAT set, there will be drawn a frame without highlight. + DrawEdge(dis->hDC, &dis->rcItem, EDGE_RAISED, BF_RECT|BF_FLAT); + } else + DrawFrameControl(dis->hDC, &dis->rcItem, DFC_BUTTON, state); + + if (_hIcon) + DrawIconEx(dis->hDC, imagePos.x, imagePos.y, _hIcon, _cx, _cy, 0, _hBrush, DI_NORMAL); + else { + MemCanvas mem_dc; + BitmapSelection sel(mem_dc, _hBmp); + BitBlt(dis->hDC, imagePos.x, imagePos.y, _cx, _cy, mem_dc, 0, 0, SRCCOPY); + } + + TCHAR title[BUFFER_LEN]; + GetWindowText(_hwnd, title, BUFFER_LEN); + + BkMode bk_mode(dis->hDC, TRANSPARENT); + + if (dis->itemState & (ODS_DISABLED|ODS_GRAYED)) + DrawGrayText(dis->hDC, &textRect, title, dt_flags); + else { + TextColor lcColor(dis->hDC, GetSysColor(COLOR_BTNTEXT)); + DrawText(dis->hDC, title, -1, &textRect, dt_flags); + } + + if (dis->itemState & ODS_FOCUS) { + RECT rect = { + dis->rcItem.left+3, dis->rcItem.top+3, + dis->rcItem.right-dis->rcItem.left-4, dis->rcItem.bottom-dis->rcItem.top-4 + }; + if (dis->itemState & ODS_SELECTED) { + ++rect.left; ++rect.top; + ++rect.right; ++rect.bottom; + } + DrawFocusRect(dis->hDC, &rect); + } +} + + +void FlatButton::DrawItem(LPDRAWITEMSTRUCT dis) +{ + UINT style = DFCS_BUTTONPUSH; + + if (dis->itemState & ODS_DISABLED) + style |= DFCS_INACTIVE; + + RECT textRect = {dis->rcItem.left+2, dis->rcItem.top+2, dis->rcItem.right-4, dis->rcItem.bottom-4}; + + if (dis->itemState & ODS_SELECTED) { + style |= DFCS_PUSHED; + ++textRect.left; ++textRect.top; + ++textRect.right; ++textRect.bottom; + } + + FillRect(dis->hDC, &dis->rcItem, GetSysColorBrush(COLOR_BTNFACE)); + + // highlight the button? + if (_active) + DrawEdge(dis->hDC, &dis->rcItem, EDGE_ETCHED, BF_RECT); + else if (GetWindowStyle(_hwnd) & BS_FLAT) // Only with BS_FLAT there will be drawn a frame to show highlighting. + DrawEdge(dis->hDC, &dis->rcItem, EDGE_RAISED, BF_RECT|BF_FLAT); + + TCHAR txt[BUFFER_LEN]; + int txt_len = GetWindowText(_hwnd, txt, BUFFER_LEN); + + if (dis->itemState & (ODS_DISABLED|ODS_GRAYED)) { + COLORREF gray = GetSysColor(COLOR_GRAYTEXT); + + if (gray) { + { + TextColor lcColor(dis->hDC, GetSysColor(COLOR_BTNHIGHLIGHT)); + RECT shadowRect = {textRect.left+1, textRect.top+1, textRect.right+1, textRect.bottom+1}; + DrawText(dis->hDC, txt, txt_len, &shadowRect, DT_SINGLELINE|DT_VCENTER|DT_CENTER); + } + + BkMode mode(dis->hDC, TRANSPARENT); + TextColor lcColor(dis->hDC, gray); + DrawText(dis->hDC, txt, txt_len, &textRect, DT_SINGLELINE|DT_VCENTER|DT_CENTER); + } else { + int old_r = textRect.right; + int old_b = textRect.bottom; + DrawText(dis->hDC, txt, txt_len, &textRect, DT_SINGLELINE|DT_VCENTER|DT_CENTER|DT_CALCRECT); + int x = textRect.left + (old_r-textRect.right)/2; + int y = textRect.top + (old_b-textRect.bottom)/2; + int w = textRect.right-textRect.left; + int h = textRect.bottom-textRect.top; + s_MyDrawText_Rect.right = w; + s_MyDrawText_Rect.bottom = h; + GrayString(dis->hDC, GetSysColorBrush(COLOR_GRAYTEXT), MyDrawText, (LPARAM)txt, txt_len, x, y, w, h); + } + } else { + TextColor lcColor(dis->hDC, _active? _activeColor: _textColor); + DrawText(dis->hDC, txt, txt_len, &textRect, DT_SINGLELINE|DT_VCENTER|DT_CENTER); + } + + if (dis->itemState & ODS_FOCUS) { + RECT rect = { + dis->rcItem.left+3, dis->rcItem.top+3, + dis->rcItem.right-dis->rcItem.left-4, dis->rcItem.bottom-dis->rcItem.top-4 + }; + if (dis->itemState & ODS_SELECTED) { + ++rect.left; ++rect.top; + ++rect.right; ++rect.bottom; + } + DrawFocusRect(dis->hDC, &rect); + } +} + +LRESULT FlatButton::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) +{ + switch(nmsg) { + case WM_MOUSEMOVE: { + bool active = false; + + if (IsWindowEnabled(_hwnd)) { + DWORD pid_foreground; + HWND hwnd_foreground = GetForegroundWindow(); //@@ may be better look for WM_ACTIVATEAPP ? + GetWindowThreadProcessId(hwnd_foreground, &pid_foreground); + + if (GetCurrentProcessId() == pid_foreground) { + POINT pt = {GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam)}; + ClientRect clntRect(_hwnd); + + // highlight the button? + if (pt.x>=clntRect.left && pt.x=clntRect.top && pt.y=clntRect.right || pt.y=clntRect.bottom) + goto cancel_press; + + goto def;} + + case WM_CANCELMODE: + cancel_press: { + TRACKMOUSEEVENT tme = {sizeof(tme), /*TME_HOVER|*/TME_LEAVE|TME_CANCEL, _hwnd/*, HOVER_DEFAULT*/}; + _TrackMouseEvent(&tme); + _active = false; + ReleaseCapture();} + // fall through + + case WM_MOUSELEAVE: + if (_active) { + _active = false; + + InvalidateRect(_hwnd, NULL, TRUE); + } + + return 0; + + default: def: + return super::WndProc(nmsg, wparam, lparam); + } +} + + +HyperlinkCtrl::HyperlinkCtrl(HWND hwnd, COLORREF colorLink, COLORREF colorVisited) + : super(hwnd), + _cmd(ResString(GetDlgCtrlID(hwnd))), + _textColor(colorLink), + _colorVisited(colorVisited), + _hfont(0), + _crsr_link(0) +{ + init(); +} + +HyperlinkCtrl::HyperlinkCtrl(HWND owner, int id, COLORREF colorLink, COLORREF colorVisited) + : super(GetDlgItem(owner, id)), + _cmd(ResString(id)), + _textColor(colorLink), + _colorVisited(colorVisited), + _hfont(0), + _crsr_link(0) +{ + init(); +} + +void HyperlinkCtrl::init() +{ + if (_cmd.empty()) { + TCHAR txt[BUFFER_LEN]; + _cmd.assign(txt, GetWindowText(_hwnd, txt, BUFFER_LEN)); + } +} + +HyperlinkCtrl::~HyperlinkCtrl() +{ + if (_hfont) + DeleteObject(_hfont); +} + +LRESULT HyperlinkCtrl::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) +{ + switch(nmsg) { + case PM_DISPATCH_CTLCOLOR: { + if (!_hfont) { + HFONT hfont = (HFONT) SendMessage(_hwnd, WM_GETFONT, 0, 0); + LOGFONT lf; GetObject(hfont, sizeof(lf), &lf); + lf.lfUnderline = TRUE; + _hfont = CreateFontIndirect(&lf); + } + + HDC hdc = (HDC) wparam; + SetTextColor(hdc, _textColor); //@@ + SelectFont(hdc, _hfont); + SetBkMode(hdc, TRANSPARENT); + return (LRESULT)GetStockObject(HOLLOW_BRUSH); + } + + case WM_SETCURSOR: + if (!_crsr_link) + _crsr_link = LoadCursor(0, IDC_HAND); + + if (_crsr_link) + SetCursor(_crsr_link); + return 0; + + case WM_NCHITTEST: + return HTCLIENT; // Aktivierung von Maus-Botschaften + + case WM_LBUTTONDOWN: + if (LaunchLink()) { + _textColor = _colorVisited; + InvalidateRect(_hwnd, NULL, FALSE); + } else + MessageBeep(0); + return 0; + + default: + return super::WndProc(nmsg, wparam, lparam); + } +} + + +ToolTip::ToolTip(HWND owner) + : super(CreateWindowEx(WS_EX_TOPMOST|WS_EX_NOPARENTNOTIFY, TOOLTIPS_CLASS, 0, + WS_POPUP|TTS_NOPREFIX|TTS_ALWAYSTIP, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, + owner, 0, g_hInstance, 0)) +{ + activate(); +} + + +ListSort::ListSort(HWND hwndListview, PFNLVCOMPARE compare_fct) + : WindowHandle(hwndListview), + _compare_fct(compare_fct) +{ + _sort_crit = 0; + _direction = false; +} + +void ListSort::toggle_sort(int idx) +{ + if (_sort_crit == idx) + _direction = !_direction; + else { + _sort_crit = idx; + _direction = false; + } +} + +void ListSort::sort() +{ + int idx = ListView_GetSelectionMark(_hwnd); + LPARAM param = ListView_GetItemData(_hwnd, idx); + + ListView_SortItems(_hwnd, _compare_fct, (LPARAM)this); + + if (idx >= 0) { + idx = ListView_FindItemPara(_hwnd, param); + ListView_EnsureVisible(_hwnd, idx, FALSE); + } +} + + +PropSheetPage::PropSheetPage(UINT nid, Window::CREATORFUNC dlg_creator) + : _dlg_creator(dlg_creator) +{ + PROPSHEETPAGE::dwSize = sizeof(PROPSHEETPAGE); + PROPSHEETPAGE::dwFlags = 0; + PROPSHEETPAGE::hInstance = g_hInstance; + PROPSHEETPAGE::pszTemplate = MAKEINTRESOURCE(nid); + PROPSHEETPAGE::pfnDlgProc = PropSheetPageDlg::DialogProc; + PROPSHEETPAGE::lParam = (LPARAM) this; +} + + +#ifndef PSM_GETRESULT // currently (as of 18.01.2004) missing in MinGW headers +#define PSM_GETRESULT (WM_USER + 135) +#define PropSheet_GetResult(hDlg) SNDMSG(hDlg, PSM_GETRESULT, 0, 0) +#endif + + +PropertySheetDialog::PropertySheetDialog(HWND owner) + : _hwnd(0) +{ + PROPSHEETHEADER::dwSize = sizeof(PROPSHEETHEADER); + PROPSHEETHEADER::dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS; + PROPSHEETHEADER::hwndParent = owner; + PROPSHEETHEADER::hInstance = g_hInstance; +} + +void PropertySheetDialog::add(PropSheetPage& psp) +{ + _pages.push_back(psp); +} + +int PropertySheetDialog::DoModal(int start_page) +{ + PROPSHEETHEADER::ppsp = (LPCPROPSHEETPAGE) &_pages[0]; + PROPSHEETHEADER::nPages = _pages.size(); + PROPSHEETHEADER::nStartPage = start_page; +/* + Window* pwnd = Window::create_property_sheet(this, WINDOW_CREATOR(PropertySheetDlg), NULL); + if (!pwnd) + return -1; + + HWND hwndPropSheet = *pwnd; +*/ + int ret = PropertySheet(this); + if (ret == -1) + return -1; + + HWND hwndPropSheet = (HWND) ret; + HWND hwndparent = GetParent(hwndPropSheet); + + if (hwndparent) + EnableWindow(hwndparent, FALSE); + + ret = 0; + MSG msg; + + while(GetMessage(&msg, 0, 0, 0)) { + try { + if (Window::pretranslate_msg(&msg)) + continue; + + if (PropSheet_IsDialogMessage(hwndPropSheet, &msg)) + continue; + + if (Window::dispatch_dialog_msg(&msg)) + continue; + + TranslateMessage(&msg); + + try { + DispatchMessage(&msg); + } catch(COMException& e) { + HandleException(e, 0); + } + + if (!PropSheet_GetCurrentPageHwnd(hwndPropSheet)) { + ret = PropSheet_GetResult(hwndPropSheet); + break; + } + } catch(COMException& e) { + HandleException(e, 0); + } + } + + if (hwndparent) + EnableWindow(hwndparent, TRUE); + + DestroyWindow(hwndPropSheet); + + return ret; +} + +HWND PropertySheetDialog::GetCurrentPage() +{ + HWND hdlg = PropSheet_GetCurrentPageHwnd(_hwnd); + return hdlg; +} + + +PropSheetPageDlg::PropSheetPageDlg(HWND hwnd) + : super(hwnd) +{ +} + +INT_PTR CALLBACK PropSheetPageDlg::DialogProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam) +{ + PropSheetPageDlg* pThis = GET_WINDOW(PropSheetPageDlg, hwnd); + + if (pThis) { + switch(nmsg) { + case WM_COMMAND: + pThis->Command(LOWORD(wparam), HIWORD(wparam)); + return TRUE; // message has been processed + + case WM_NOTIFY: + pThis->Notify(wparam, (NMHDR*)lparam); + return TRUE; // message has been processed + + case WM_NOTIFYFORMAT: + SetWindowLong(hwnd, DWLP_MSGRESULT, NFR_CURRENT); // set return value NFR_CURRENT + return TRUE; // message has been processed + + case WM_NCDESTROY: + delete pThis; + return TRUE; // message has been processed + + default: + return pThis->WndProc(nmsg, wparam, lparam); + } + } else if (nmsg == WM_INITDIALOG) { + PROPSHEETPAGE* psp = (PROPSHEETPAGE*) lparam; + PropSheetPage* ppsp = (PropSheetPage*) psp->lParam; + + if (ppsp->_dlg_creator) { + pThis = static_cast(ppsp->_dlg_creator(hwnd)); + + if (pThis) + return pThis->Init(NULL); + } + } + + return FALSE; // message has not been processed +} + +int PropSheetPageDlg::Command(int id, int code) +{ + // override call to EndDialog in Dialog::Command(); + + return FALSE; +} diff --git a/reactos/subsys/system/ibrowser/utility/window.h b/reactos/subsys/system/ibrowser/utility/window.h new file mode 100644 index 00000000000..bd568797aaf --- /dev/null +++ b/reactos/subsys/system/ibrowser/utility/window.h @@ -0,0 +1,1100 @@ +/* + * Copyright 2003, 2004, 2005 Martin Fuchs + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + + // + // ROS Internet Web Browser + // + // window.h + // + // Martin Fuchs, 23.07.2003 + // + + +typedef set WindowSet; + + + /* + Classes are declared using "struct", not "class" because the default + access mode is "public". This way we can list the member functions in a + natural order without explicitly specifying any access mode at the begin + of the definition. + First are public constructors and destructor, then public member functions. + After that we list protected member varibables and functions. If needed, + private implemenation varibales and functions are positioned at the end. + */ + + + /// information structure for creation of a child window +struct ChildWndInfo +{ + ChildWndInfo(HWND hwndFrame) + : _hwndFrame(hwndFrame) {} + + HWND _hwndFrame; +}; + + + /** + Class Window is the base class for several C++ window wrapper classes. + Window objects are allocated from the heap. They are automatically freed + when the window gets destroyed. + */ +struct Window : public WindowHandle +{ + Window(HWND hwnd); + virtual ~Window(); + + + typedef map WindowMap; + + typedef Window* (*CREATORFUNC)(HWND); + typedef Window* (*CREATORFUNC_INFO)(HWND, const void*); + + static HWND Create(CREATORFUNC creator, DWORD dwExStyle, + LPCTSTR lpClassName, LPCTSTR lpWindowName, + DWORD dwStyle, int x, int y, int w, int h, + HWND hwndParent=0, HMENU hMenu=0/*, LPVOID lpParam=0*/); + + static HWND Create(CREATORFUNC_INFO creator, const void* info, + DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName, + DWORD dwStyle, int x, int y, int w, int h, + HWND hwndParent=0, HMENU hMenu=0/*, LPVOID lpParam=0*/); + + static LRESULT CALLBACK WindowWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam); + static INT_PTR CALLBACK DialogProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam); + + static Window* get_window(HWND hwnd); +#ifndef _MSC_VER + template static CLASS* get_window(HWND hwnd) {return static_cast(get_window(hwnd));} +#define GET_WINDOW(CLASS, hwnd) Window::get_window(hwnd) +#endif + + static void register_pretranslate(HWND hwnd); + static void unregister_pretranslate(HWND hwnd); + static BOOL pretranslate_msg(LPMSG pmsg); + + static void register_dialog(HWND hwnd); + static void unregister_dialog(HWND hwnd); + static BOOL dispatch_dialog_msg(LPMSG pmsg); + + static int MessageLoop(); + + + LRESULT SendParent(UINT nmsg, WPARAM wparam=0, LPARAM lparam=0); + LRESULT PostParent(UINT nmsg, WPARAM wparam=0, LPARAM lparam=0); + + static void CancelModes(HWND hwnd=0); + + +protected: + virtual LRESULT Init(LPCREATESTRUCT pcs); // WM_CREATE processing + virtual LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam); + virtual int Command(int id, int code); // WM_COMMAND processing + virtual int Notify(int id, NMHDR* pnmh); // WM_NOTIFY processing + + static Window* create_controller(HWND hwnd); + + + static WindowMap s_wnd_map; + + static const void* s_new_info; + static CREATORFUNC s_window_creator; + + + /// structure for managing critical sections as static class information in struct Window + struct StaticWindowData { + CritSect _map_crit_sect; + CritSect _create_crit_sect; + }; + + static StaticWindowData& GetStaticWindowData(); + + + static WindowSet s_pretranslate_windows; + static WindowSet s_dialogs; +}; + +#ifdef UNICODE +#define NFR_CURRENT NFR_UNICODE +#else +#define NFR_CURRENT NFR_ANSI +#endif + + +#ifdef _MSC_VER +template struct GetWindowHelper +{ + static CLASS* get_window(HWND hwnd) { + return static_cast(Window::get_window(hwnd)); + } +}; +#define GET_WINDOW(CLASS, hwnd) GetWindowHelper::get_window(hwnd) +#endif + + + /// dynamic casting of Window pointers +template struct TypeCheck +{ + static CLASS* dyn_cast(Window* wnd) + {return dynamic_cast(wnd);} +}; + +#define WINDOW_DYNAMIC_CAST(CLASS, hwnd) \ + TypeCheck::dyn_cast(Window::get_window(hwnd)) + + + /** + SubclassedWindow is used to wrap already existing window handles + into C++ Window objects. To construct a object, use the "new" operator + to put it in the heap. It is automatically freed, when the window + gets destroyed. + */ +struct SubclassedWindow : public Window +{ + typedef Window super; + + SubclassedWindow(HWND); + +protected: + WNDPROC _orgWndProc; + + static LRESULT CALLBACK SubclassedWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam); + + virtual LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam); + virtual int Command(int id, int code); + virtual int Notify(int id, NMHDR* pnmh); +}; + + + /// template class used in macro WINDOW_CREATOR to define the creater functions for Window objects +template struct WindowCreator +{ + static WND_CLASS* window_creator(HWND hwnd) + { + return new WND_CLASS(hwnd); + } +}; + +#define WINDOW_CREATOR(WND_CLASS) \ + ((Window::CREATORFUNC) WindowCreator::window_creator) + + + /// template class used in macro WINDOW_CREATOR_INFO to the define creater functions for Window objects with additional creation information +template struct WindowCreatorInfo +{ + static WND_CLASS* window_creator(HWND hwnd, const void* info) + { + return new WND_CLASS(hwnd, *static_cast(info)); + } +}; + +#define WINDOW_CREATOR_INFO(WND_CLASS, INFO_CLASS) \ + ((Window::CREATORFUNC_INFO) WindowCreatorInfo::window_creator) + + + /** + WindowClass is a neat wrapper for RegisterClassEx(). + Just construct a WindowClass object, override the attributes you want + to change, then call Register() or simply request the ATOM value to + register the window class. You don't have to worry calling Register() + more than once. It checks if, the class has already been registered. + */ +struct WindowClass : public WNDCLASSEX +{ + WindowClass(LPCTSTR classname, UINT style=0, WNDPROC wndproc=Window::WindowWndProc); + + ATOM Register() + { + if (!_atomClass) + _atomClass = RegisterClassEx(this); + + return _atomClass; + } + + operator ATOM() {return Register();} + + // return LPCTSTR for the CreateWindowEx() parameter + operator LPCTSTR() {return (LPCTSTR)(int)Register();} + +protected: + ATOM _atomClass; +}; + + /// window class with gray background color +struct BtnWindowClass : public WindowClass +{ + BtnWindowClass(LPCTSTR classname, UINT style=0, WNDPROC wndproc=Window::WindowWndProc) + : WindowClass(classname, style, wndproc) + { + hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); + } +}; + + /// window class with specified icon from resources +struct IconWindowClass : public WindowClass +{ + IconWindowClass(LPCTSTR classname, UINT nid, UINT style=0, WNDPROC wndproc=Window::WindowWndProc); +}; + + + // private message constants +#define PM_DISPATCH_COMMAND (WM_APP+0x00) +#define PM_TRANSLATE_MSG (WM_APP+0x01) + + +#define SPLIT_WIDTH 5 +#define DEFAULT_SPLIT_POS 300 +#define COLOR_SPLITBAR LTGRAY_BRUSH + + + /// menu info structure +struct MenuInfo +{ + HMENU _hMenuView; +}; + +#define PM_FRM_GET_MENUINFO (WM_APP+0x02) + +#define Frame_GetMenuInfo(hwnd) ((MenuInfo*)SNDMSG(hwnd, PM_FRM_GET_MENUINFO, 0, 0)) + + + /** + Class ChildWindow is used with class MainFrame. + */ +struct ChildWindow : public Window +{ + typedef Window super; + + ChildWindow(HWND hwnd, HWND hwndFrame); + + static ChildWindow* create(const ChildWndInfo& info, CREATORFUNC_INFO creator, + LPCTSTR classname, LPCTSTR title=NULL, DWORD style=0); + + bool go_to(LPCTSTR url); + +protected: + LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam); + + virtual String jump_to_int(LPCTSTR url) = 0; + +protected: + MenuInfo*_menu_info; + + HWND _hwndFrame; + String _statusText; + String _url; + + stack _url_history; + + void set_url(LPCTSTR url); +}; + +#define PM_SETSTATUSTEXT (WM_APP+0x1E) + + + /** + PreTranslateWindow is used to register windows to be called by Window::pretranslate_msg(). + This way you get PM_TRANSLATE_MSG messages before the message loop dispatches messages. + You can then for example use TranslateAccelerator() to implement key shortcuts. + */ +struct PreTranslateWindow : public Window +{ + typedef Window super; + + PreTranslateWindow(HWND); + ~PreTranslateWindow(); +}; + + + /** + The class DialogWindow implements modeless dialogs, which are managed by + Window::dispatch_dialog_msg() in Window::MessageLoop(). + A DialogWindow object should be constructed by calling Window::Create() + and specifying the class using the WINDOW_CREATOR() macro. + */ +struct DialogWindow : public Window +{ + typedef Window super; + + DialogWindow(HWND hwnd) + : super(hwnd) + { + register_dialog(hwnd); + } + + ~DialogWindow() + { + unregister_dialog(_hwnd); + } +}; + + + /** + The class Dialog implements modal dialogs. + A Dialog object should be constructed by calling Dialog::DoModal() + and specifying the class using the WINDOW_CREATOR() macro. + */ +struct Dialog : public Window +{ + typedef Window super; + + Dialog(HWND); + ~Dialog(); + + static int DoModal(UINT nid, CREATORFUNC creator, HWND hwndParent=0); + static int DoModal(UINT nid, CREATORFUNC_INFO creator, const void* info, HWND hwndParent=0); + +protected: + LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam); + int Command(int id, int code); +}; + + +#define PM_FRM_CALC_CLIENT (WM_APP+0x03) +#define Frame_CalcFrameClient(hwnd, prt) ((BOOL)SNDMSG(hwnd, PM_FRM_CALC_CLIENT, 0, (LPARAM)(PRECT)prt)) + +#define PM_JUMP_TO_URL (WM_APP+0x25) +#define PM_URL_CHANGED (WM_APP+0x26) + + +struct PropSheetPage : public PROPSHEETPAGE +{ + PropSheetPage(UINT nid, Window::CREATORFUNC dlg_creator); + + void init(struct PropertySheetDialog*); + +protected: + friend struct PropSheetPageDlg; + + Window::CREATORFUNC _dlg_creator; +}; + + + /// Property Sheet dialog +struct PropertySheetDialog : public PROPSHEETHEADER +{ + PropertySheetDialog(HWND owner); + + void add(PropSheetPage& psp); + int DoModal(int start_page=0); + + HWND GetCurrentPage(); + +protected: + typedef vector Vector; + Vector _pages; + HWND _hwnd; +}; + + + /// Property Sheet Page (inner dialog) +struct PropSheetPageDlg : public Dialog +{ + typedef Dialog super; + + PropSheetPageDlg(HWND); + +protected: + friend struct PropertySheetDialog; + friend struct PropSheetPage; + + static INT_PTR CALLBACK DialogProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam); + + int Command(int id, int code); +}; + + +/* + /// Property Sheet Dialog (outer dialog) +struct PropertySheetDlg : public SubclassedWindow +{ + typedef SubclassedWindow super; + + PropertySheetDlg(HWND hwnd) : super(hwnd) {} +}; +*/ + + + // Layouting of resizable windows + + /// Flags to specify how to move and resize controls when resizing their parent window +enum RESIZE_FLAGS { + MOVE_LEFT = 0x1, + MOVE_RIGHT = 0x2, + MOVE_TOP = 0x4, + MOVE_BOTTOM = 0x8, + + MOVE_X = MOVE_LEFT | MOVE_RIGHT, + MOVE_Y = MOVE_TOP | MOVE_BOTTOM, + RESIZE_X= MOVE_RIGHT, + RESIZE_Y= MOVE_BOTTOM, + + MOVE = MOVE_X | MOVE_Y, + RESIZE = RESIZE_X | RESIZE_Y +}; + + /// structure to assign RESIZE_FLAGS to dialogs control +struct ResizeEntry +{ + ResizeEntry(UINT id, int flags) + : _id(id), _flags(flags) {} + + ResizeEntry(HWND hwnd, int flags) + : _id(GetDlgCtrlID(hwnd)), _flags(flags) {} + + UINT _id; + int _flags; +}; + + + /// Management of controls in resizable dialogs +struct ResizeManager : public std::list +{ + typedef std::list super; + + ResizeManager(HWND hwnd); + + void Add(UINT id, int flags) + {push_back(ResizeEntry(id, flags));} + + void Add(HWND hwnd, int flags) + {push_back(ResizeEntry(hwnd, flags));} + + void HandleSize(int cx, int cy); + void Resize(int dx, int dy); + + void SetMinMaxInfo(LPMINMAXINFO lpmmi) + { + lpmmi->ptMinTrackSize.x = _min_wnd_size.cx; + lpmmi->ptMinTrackSize.y = _min_wnd_size.cy; + } + + SIZE _min_wnd_size; + +protected: + HWND _hwnd; + SIZE _last_size; +}; + + + /// Controller base template class for resizable dialogs +template struct ResizeController : public BASE +{ + typedef BASE super; + + ResizeController(HWND hwnd) + : super(hwnd), + _resize_mgr(hwnd) + { + } + + LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) + { + switch(nmsg) { + case PM_FRM_CALC_CLIENT: + GetClientSpace((PRECT)lparam); + return TRUE; + + case WM_SIZE: + if (wparam != SIZE_MINIMIZED) + _resize_mgr.HandleSize(LOWORD(lparam), HIWORD(lparam)); + goto def; + + case WM_GETMINMAXINFO: + _resize_mgr.SetMinMaxInfo((LPMINMAXINFO)lparam); + goto def; + + default: def: + return super::WndProc(nmsg, wparam, lparam); + } + } + + virtual void GetClientSpace(PRECT prect) + { + if (!IsIconic(this->_hwnd)) { + GetClientRect(this->_hwnd, prect); + } else { + WINDOWPLACEMENT wp; + GetWindowPlacement(this->_hwnd, &wp); + prect->left = prect->top = 0; + prect->right = wp.rcNormalPosition.right-wp.rcNormalPosition.left- + 2*(GetSystemMetrics(SM_CXSIZEFRAME)+GetSystemMetrics(SM_CXEDGE)); + prect->bottom = wp.rcNormalPosition.bottom-wp.rcNormalPosition.top- + 2*(GetSystemMetrics(SM_CYSIZEFRAME)+GetSystemMetrics(SM_CYEDGE))- + GetSystemMetrics(SM_CYCAPTION)-GetSystemMetrics(SM_CYMENUSIZE); + } + } + +protected: + ResizeManager _resize_mgr; +}; + + + /** + This class constructs button controls. + The button will remain existent when the C++ Button object is destroyed. + There is no conjunction between C++ object and windows control life time. + */ +struct Button : public WindowHandle +{ + Button(HWND parent, LPCTSTR text, int left, int top, int width, int height, + int id, DWORD flags=WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, DWORD exStyle=0); +}; + + + /** + This class constructs static controls. + The control will remain existent when the C++ object is destroyed. + There is no conjunction between C++ object and windows control life time. + */ +struct Static : public WindowHandle +{ + Static(HWND parent, LPCTSTR text, int left, int top, int width, int height, + int id, DWORD flags=WS_VISIBLE|WS_CHILD|SS_SIMPLE, DWORD ex_flags=0); +}; + + + // control color message routing for ColorStatic and HyperlinkCtrl + +#define PM_DISPATCH_CTLCOLOR (WM_APP+0x08) + +template struct CtlColorParent : public BASE +{ + typedef BASE super; + + CtlColorParent(HWND hwnd) + : super(hwnd) {} + + LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) + { + switch(nmsg) { + case WM_CTLCOLOR: + case WM_CTLCOLORBTN: + case WM_CTLCOLORDLG: + case WM_CTLCOLORSCROLLBAR: + case WM_CTLCOLORSTATIC: { + HWND hctl = (HWND) lparam; + return SendMessage(hctl, PM_DISPATCH_CTLCOLOR, wparam, nmsg); + } + + default: + return super::WndProc(nmsg, wparam, lparam); + } + } +}; + + +#define PM_DISPATCH_DRAWITEM (WM_APP+0x09) + + /// draw message routing for ColorButton and PictureButton +template struct OwnerDrawParent : public BASE +{ + typedef BASE super; + + OwnerDrawParent(HWND hwnd) + : super(hwnd) {} + + LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) + { + switch(nmsg) { + case WM_DRAWITEM: + if (wparam) { // should there be drawn a control? + HWND hctl = GetDlgItem(this->_hwnd, wparam); + + if (hctl) + return SendMessage(hctl, PM_DISPATCH_DRAWITEM, wparam, lparam); + } /*else // or is it a menu entry? + ; */ + + return 0; + + default: + return super::WndProc(nmsg, wparam, lparam); + } + } +}; + + + /** + Subclass button controls to draw them by using PM_DISPATCH_DRAWITEM + The owning window should use the OwnerDrawParent template to route owner draw messages to the buttons. + */ +struct OwnerdrawnButton : public SubclassedWindow +{ + typedef SubclassedWindow super; + + OwnerdrawnButton(HWND hwnd) + : super(hwnd) {} + +protected: + LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam); + + virtual void DrawItem(LPDRAWITEMSTRUCT dis) = 0; +}; + +extern void DrawGrayText(HDC hdc, LPRECT pRect, LPCTSTR text, int dt_flags); + + + /** + Subclass button controls to paint colored text labels. + The owning window should use the OwnerDrawParent template to route owner draw messages to the buttons. + */ +/* not yet used +struct ColorButton : public OwnerdrawnButton +{ + typedef OwnerdrawnButton super; + + ColorButton(HWND hwnd, COLORREF textColor) + : super(hwnd), _textColor(textColor) {} + +protected: + virtual void DrawItem(LPDRAWITEMSTRUCT dis); + + COLORREF _textColor; +}; +*/ + + +struct FlatButton : public OwnerdrawnButton +{ + typedef OwnerdrawnButton super; + + FlatButton(HWND hwnd) + : super(hwnd), _active(false) {} + + FlatButton(HWND owner, int id) + : super(GetDlgItem(owner, IDOK)), _active(false) {} + +protected: + LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam); + virtual void DrawItem(LPDRAWITEMSTRUCT dis); + + COLORREF _textColor; + COLORREF _activeColor; + bool _active; +}; + + + /** + Subclass button controls to paint pictures left to the labels. + The buttons should have set the style bit BS_OWNERDRAW. + The owning window should use the OwnerDrawParent template to route owner draw messages to the buttons. + */ +struct PictureButton : public OwnerdrawnButton +{ + typedef OwnerdrawnButton super; + + PictureButton(HWND hwnd, HICON hIcon, HBRUSH hbrush=GetSysColorBrush(COLOR_BTNFACE), bool flat=false) + : super(hwnd), _hIcon(hIcon), _hBmp(0), _hBrush(hbrush), _flat(flat) + { + _cx = 16; + _cy = 16; + } + + PictureButton(HWND hparent, int id, HICON hIcon, HBRUSH hbrush=GetSysColorBrush(COLOR_BTNFACE), bool flat=false) + : super(GetDlgItem(hparent, id)), _hIcon(hIcon), _hBmp(0), _hBrush(hbrush), _flat(flat) + { + _cx = 16; + _cy = 16; + } + + PictureButton(HWND hwnd, HBITMAP hBmp, HBRUSH hbrush=GetSysColorBrush(COLOR_BTNFACE), bool flat=false) + : super(hwnd), _hIcon(0), _hBmp(hBmp), _hBrush(hbrush), _flat(flat) + { + BITMAP bmp; + GetObject(hBmp, sizeof(bmp), &bmp); + _cx = bmp.bmWidth; + _cy = bmp.bmHeight; + } + + PictureButton(HWND hparent, int id, HBITMAP hBmp, HBRUSH hbrush=GetSysColorBrush(COLOR_BTNFACE), bool flat=false) + : super(GetDlgItem(hparent, id)), _hIcon(0), _hBmp(hBmp), _hBrush(hbrush), _flat(flat) + { + BITMAP bmp; + GetObject(hBmp, sizeof(bmp), &bmp); + _cx = bmp.bmWidth; + _cy = bmp.bmHeight; + } + +protected: + virtual void DrawItem(LPDRAWITEMSTRUCT dis); + + HICON _hIcon; + HBITMAP _hBmp; + HBRUSH _hBrush; + + int _cx; + int _cy; + + bool _flat; +}; + + +struct ColorStatic : public SubclassedWindow +{ + typedef SubclassedWindow super; + + ColorStatic(HWND hwnd, COLORREF textColor=RGB(255,0,0), HBRUSH hbrush_bkgnd=0, HFONT hfont=0) + : super(hwnd), + _textColor(textColor), + _hbrush_bkgnd(hbrush_bkgnd), + _hfont(hfont) + { + } + + ColorStatic(HWND owner, int id, COLORREF textColor=RGB(255,0,0), HBRUSH hbrush_bkgnd=0, HFONT hfont=0) + : super(GetDlgItem(owner, id)), + _textColor(textColor), + _hbrush_bkgnd(hbrush_bkgnd), + _hfont(hfont) + { + } + +protected: + LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) + { + if (nmsg == PM_DISPATCH_CTLCOLOR) { + HDC hdc = (HDC) wparam; + + SetTextColor(hdc, _textColor); + + if (_hfont) + SelectFont(hdc, _hfont); + + if (_hbrush_bkgnd) + return (LRESULT)_hbrush_bkgnd; + else { + SetBkMode(hdc, TRANSPARENT); + return (LRESULT)GetStockBrush(HOLLOW_BRUSH); + } + } else + return super::WndProc(nmsg, wparam, lparam); + } + + COLORREF _textColor; + HBRUSH _hbrush_bkgnd; + HFONT _hfont; +}; + + + /// Hyperlink Controls + +struct HyperlinkCtrl : public SubclassedWindow +{ + typedef SubclassedWindow super; + + HyperlinkCtrl(HWND hwnd, COLORREF colorLink=RGB(0,0,255), COLORREF colorVisited=RGB(128,0,128)); + HyperlinkCtrl(HWND owner, int id, COLORREF colorLink=RGB(0,0,255), COLORREF colorVisited=RGB(128,0,128)); + + ~HyperlinkCtrl(); + + String _cmd; + +protected: + COLORREF _textColor; + COLORREF _colorVisited; + HFONT _hfont; + HCURSOR _crsr_link; + + LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam); + + void init(); + + bool LaunchLink() + { + if (!_cmd.empty()) { + HINSTANCE hinst = ShellExecute(GetParent(_hwnd), _T("open"), _cmd, 0, 0, SW_SHOWNORMAL); + return (int)hinst > HINSTANCE_ERROR; + } + + return true; + } +}; + + + /// encapsulation of tool tip controls +struct ToolTip : public WindowHandle +{ + typedef WindowHandle super; + + ToolTip(HWND owner); + + void activate(BOOL active=TRUE) + { + SendMessage(_hwnd, TTM_ACTIVATE, active, 0); + } + + void add(HWND hparent, HWND htool, LPCTSTR txt=LPSTR_TEXTCALLBACK, LPARAM lparam=0) + { + TOOLINFO ti = { + sizeof(TOOLINFO), TTF_SUBCLASS|TTF_IDISHWND|TTF_TRANSPARENT, hparent, (UINT)htool, + {0,0,0,0}, 0, (LPTSTR)txt, lparam + }; + +#ifdef UNICODE ///@todo Why is it neccesary to try both TTM_ADDTOOLW and TTM_ADDTOOLW ?! + if (!SendMessage(_hwnd, TTM_ADDTOOLW, 0, (LPARAM)&ti)) + SendMessage(_hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti); +#else + if (!SendMessage(_hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti)) + SendMessage(_hwnd, TTM_ADDTOOLW, 0, (LPARAM)&ti); +#endif + } + + void add(HWND hparent, UINT id, const RECT& rect, LPCTSTR txt=LPSTR_TEXTCALLBACK, LPARAM lparam=0) + { + TOOLINFO ti = { + sizeof(TOOLINFO), TTF_SUBCLASS|TTF_TRANSPARENT, hparent, id, + {rect.left,rect.top,rect.right,rect.bottom}, 0, (LPTSTR)txt, lparam + }; + +#ifdef UNICODE + if (!SendMessage(_hwnd, TTM_ADDTOOLW, 0, (LPARAM)&ti)) + SendMessage(_hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti); +#else + if (!SendMessage(_hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti)) + SendMessage(_hwnd, TTM_ADDTOOLW, 0, (LPARAM)&ti); +#endif + } + + void remove(HWND hparent, HWND htool) + { + TOOLINFO ti = { + sizeof(TOOLINFO), TTF_IDISHWND, hparent, (UINT)htool, + {0,0,0,0}, 0, 0, 0 + }; + + SendMessage(_hwnd, TTM_DELTOOL, 0, (LPARAM)&ti); + } + + void remove(HWND hparent, UINT id) + { + TOOLINFO ti = { + sizeof(TOOLINFO), 0, hparent, id, + {0,0,0,0}, 0, 0, 0 + }; + + SendMessage(_hwnd, TTM_DELTOOL, 0, (LPARAM)&ti); + } +}; + + +inline int ListView_GetItemData(HWND list_ctrl, int idx) +{ + LV_ITEM item; + + item.mask = LVIF_PARAM; + item.iItem = idx; + + if (!ListView_GetItem(list_ctrl, &item)) + return 0; + + return item.lParam; +} + +inline int ListView_FindItemPara(HWND list_ctrl, LPARAM param) +{ + LVFINDINFO fi; + + fi.flags = LVFI_PARAM; + fi.lParam = param; + + return ListView_FindItem(list_ctrl, (unsigned)-1, &fi); +} + +inline int ListView_GetFocusedItem(HWND list_ctrl) +{ + int idx = ListView_GetItemCount(list_ctrl); + + while(--idx >= 0) + if (ListView_GetItemState(list_ctrl, idx, LVIS_FOCUSED)) + break; + + return idx; +} + + + /// sorting of list controls +struct ListSort : public WindowHandle +{ + ListSort(HWND hwndListview, PFNLVCOMPARE compare_fct); + + void toggle_sort(int idx); + void sort(); + + int _sort_crit; + bool _direction; + +protected: + PFNLVCOMPARE _compare_fct; + + static int CALLBACK CompareFunc(LPARAM lparam1, LPARAM lparam2, LPARAM lparamSort); +}; + + +inline LPARAM TreeView_GetItemData(HWND hwndTreeView, HTREEITEM hItem) +{ + TVITEM tvItem; + + tvItem.mask = TVIF_PARAM; + tvItem.hItem = hItem; + + if (!TreeView_GetItem(hwndTreeView, &tvItem)) + return 0; + + return tvItem.lParam; +} + + +enum {TRAYBUTTON_LEFT=0, TRAYBUTTON_RIGHT, TRAYBUTTON_MIDDLE}; + +#define PM_TRAYICON (WM_APP+0x20) + +#define WINMSG_TASKBARCREATED TEXT("TaskbarCreated") + + +struct TrayIcon +{ + TrayIcon(HWND hparent, UINT id) + : _hparent(hparent), _id(id) {} + + ~TrayIcon() + {Remove();} + + void Add(HICON hIcon, LPCTSTR tooltip=NULL) + {Set(NIM_ADD, _id, hIcon, tooltip);} + + void Modify(HICON hIcon, LPCTSTR tooltip=NULL) + {Set(NIM_MODIFY, _id, hIcon, tooltip);} + + void Remove() + { + NOTIFYICONDATA nid = { + sizeof(NOTIFYICONDATA), // cbSize + _hparent, // hWnd + _id, // uID + }; + + Shell_NotifyIcon(NIM_DELETE, &nid); + } + +protected: + HWND _hparent; + UINT _id; + + void Set(DWORD dwMessage, UINT id, HICON hIcon, LPCTSTR tooltip=NULL) + { + NOTIFYICONDATA nid = { + sizeof(NOTIFYICONDATA), // cbSize + _hparent, // hWnd + id, // uID + NIF_MESSAGE|NIF_ICON, // uFlags + PM_TRAYICON, // uCallbackMessage + hIcon // hIcon + }; + + if (tooltip) + lstrcpyn(nid.szTip, tooltip, COUNTOF(nid.szTip)); + + if (nid.szTip[0]) + nid.uFlags |= NIF_TIP; + + Shell_NotifyIcon(dwMessage, &nid); + } +}; + + +template struct TrayIconControllerTemplate : public BASE +{ + typedef BASE super; + + TrayIconControllerTemplate(HWND hwnd) : BASE(hwnd), + WM_TASKBARCREATED(RegisterWindowMessage(WINMSG_TASKBARCREATED)) + { + } + + LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) + { + if (nmsg == PM_TRAYICON) { + switch(lparam) { + case WM_MOUSEMOVE: + TrayMouseOver(wparam); + break; + + case WM_LBUTTONDOWN: + TrayClick(wparam, TRAYBUTTON_LEFT); + break; + + case WM_LBUTTONDBLCLK: + TrayDblClick(wparam, TRAYBUTTON_LEFT); + break; + + case WM_RBUTTONDOWN: + TrayClick(wparam, TRAYBUTTON_RIGHT); + break; + + case WM_RBUTTONDBLCLK: + TrayDblClick(wparam, TRAYBUTTON_RIGHT); + break; + + case WM_MBUTTONDOWN: + TrayClick(wparam, TRAYBUTTON_MIDDLE); + break; + + case WM_MBUTTONDBLCLK: + TrayDblClick(wparam, TRAYBUTTON_MIDDLE); + break; + } + + return 0; + } else if (nmsg == WM_TASKBARCREATED) { + AddTrayIcons(); + return 0; + } else + return super::WndProc(nmsg, wparam, lparam); + } + + virtual void AddTrayIcons() = 0; + virtual void TrayMouseOver(UINT id) {} + virtual void TrayClick(UINT id, int btn) {} + virtual void TrayDblClick(UINT id, int btn) {} + +protected: + const UINT WM_TASKBARCREATED; +}; + + +struct EditController : public SubclassedWindow +{ + typedef SubclassedWindow super; + + EditController(HWND hwnd) + : super(hwnd) + { + } + +protected: + LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) + { + if (nmsg==WM_KEYDOWN && wparam==VK_RETURN) { + SendParent(WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(_hwnd),1), (LPARAM)_hwnd); + return 0; + } else + return super::WndProc(nmsg, wparam, lparam); + } +}; diff --git a/reactos/subsys/system/ibrowser/utility/xmlstorage.cpp b/reactos/subsys/system/ibrowser/utility/xmlstorage.cpp new file mode 100644 index 00000000000..51019f3ebab --- /dev/null +++ b/reactos/subsys/system/ibrowser/utility/xmlstorage.cpp @@ -0,0 +1,612 @@ + + // + // XML storage classes + // + // xmlstorage.cpp + // + // Copyright (c) 2004, Martin Fuchs + // + + +/* + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +*/ + +//#include "xmlstorage.h" +#include "precomp.h" + + + // work around GCC's wide string constant bug +#ifdef __GNUC__ +const LPCXSSTR XMLStorage::XS_TRUE = XS_TEXT("true"); +const LPCXSSTR XMLStorage::XS_FALSE = XS_TEXT("false"); +const LPCXSSTR XMLStorage::XS_NUMBERFMT = XS_TEXT("%d"); +#endif + + +namespace XMLStorage { + + +static std::string unescape(const char* s, char b='"', char e='"') +{ + const char* end = s + strlen(s); + +// if (*s == b) +// ++s; +// +// if (end>s && end[-1]==e) +// --end; + + if (*s == b) + if (end>s && end[-1]==e) + ++s, --end; + + return std::string(s, end-s); +} + +static std::string unescape(const char* s, int l, char b='"', char e='"') +{ + const char* end = s + l; + +// if (*s == b) +// ++s; +// +// if (end>s && end[-1]==e) +// --end; + + if (*s == b) + if (end>s && end[-1]==e) + ++s, --end; + + return std::string(s, end-s); +} + + + /// move XPath like to position in XML tree +bool XMLPos::go(const char* path) +{ + XMLNode* node = _cur; + + // Is this an absolute path? + if (*path == '/') { + node = _root; + ++path; + } + + node = node->find_relative(path); + + if (node) { + go_to(node); + return true; + } else + return false; +} + + /// move XPath like to position in XML tree +bool const_XMLPos::go(const char* path) +{ + const XMLNode* node = _cur; + + // Is this an absolute path? + if (*path == '/') { + node = _root; + ++path; + } + + node = node->find_relative(path); + + if (node) { + go_to(node); + return true; + } else + return false; +} + + +const XMLNode* XMLNode::find_relative(const char* path) const +{ + const XMLNode* node = this; + + // parse relative path + while(*path) { + const char* slash = strchr(path, '/'); + if (slash == path) + return NULL; + + int l = slash? slash-path: strlen(path); + std::string comp(path, l); + path += l; + + // look for [n] and [@attr_name="attr_value"] expressions in path components + const char* bracket = strchr(comp.c_str(), '['); + l = bracket? bracket-comp.c_str(): comp.length(); + std::string child_name(comp.c_str(), l); + std::string attr_name, attr_value; + + int n = 0; + if (bracket) { + std::string expr = unescape(bracket, '[', ']'); + const char* p = expr.c_str(); + + n = atoi(p); // read index number + + if (n) + n = n - 1; // convert into zero based index + + const char* at = strchr(p, '@'); + + if (at) { + p = at + 1; + const char* equal = strchr(p, '='); + + // read attribute name and value + if (equal) { + attr_name = unescape(p, equal-p); + attr_value = unescape(equal+1); + } + } + } + + if (attr_name.empty()) + // search n.th child node with specified name + node = node->find(child_name, n); + else + // search n.th child node with specified name and matching attribute value + node = node->find(child_name, attr_name, attr_value, n); + + if (!node) + return NULL; + + if (*path == '/') + ++path; + } + + return node; +} + +XMLNode* XMLNode::create_relative(const char* path) +{ + XMLNode* node = this; + + // parse relative path + while(*path) { + const char* slash = strchr(path, '/'); + if (slash == path) + return NULL; + + int l = slash? slash-path: strlen(path); + std::string comp(path, l); + path += l; + + // look for [n] and [@attr_name="attr_value"] expressions in path components + const char* bracket = strchr(comp.c_str(), '['); + l = bracket? bracket-comp.c_str(): comp.length(); + std::string child_name(comp.c_str(), l); + std::string attr_name, attr_value; + + int n = 0; + if (bracket) { + std::string expr = unescape(bracket, '[', ']'); + const char* p = expr.c_str(); + + n = atoi(p); // read index number + + if (n) + n = n - 1; // convert into zero based index + + const char* at = strchr(p, '@'); + + if (at) { + p = at + 1; + const char* equal = strchr(p, '='); + + // read attribute name and value + if (equal) { + attr_name = unescape(p, equal-p); + attr_value = unescape(equal+1); + } + } + } + + XMLNode* child; + + if (attr_name.empty()) + // search n.th child node with specified name + child = node->find(child_name, n); + else + // search n.th child node with specified name and matching attribute value + child = node->find(child_name, attr_name, attr_value, n); + + if (!child) { + child = new XMLNode(child_name); + node->add_child(child); + + if (!attr_name.empty()) + (*node)[attr_name] = attr_value; + } + + node = child; + + if (*path == '/') + ++path; + } + + return node; +} + + + /// read XML stream into XML tree below _pos +XML_Status XMLReaderBase::read() +{ + XML_Status status = XML_STATUS_OK; + + while(status == XML_STATUS_OK) { + char* buffer = (char*) XML_GetBuffer(_parser, BUFFER_LEN); + + int l = read_buffer(buffer, BUFFER_LEN); + if (l < 0) + break; + + status = XML_ParseBuffer(_parser, l, false); + } + + if (status != XML_STATUS_ERROR) + status = XML_ParseBuffer(_parser, 0, true); + + if (_pos->_children.empty()) + _pos->_trailing.append(_content); + else + _pos->_children.back()->_trailing.append(_content); + + _content.erase(); + + return status; +} + + + /// store XML version and encoding into XML reader +void XMLCALL XMLReaderBase::XML_XmlDeclHandler(void* userData, const XML_Char* version, const XML_Char* encoding, int standalone) +{ + XMLReaderBase* pReader = (XMLReaderBase*) userData; + + if (version) + pReader->_xml_version = version; + + if (encoding) + pReader->_encoding = encoding; +} + + /// notifications about XML start tag +void XMLCALL XMLReaderBase::XML_StartElementHandler(void* userData, const XML_Char* name, const XML_Char** atts) +{ + XMLReaderBase* pReader = (XMLReaderBase*) userData; + XMLPos& pos = pReader->_pos; + + // search for end of first line + const char* s = pReader->_content.c_str(); + const char* p = s; + const char* e = p + pReader->_content.length(); + + for(; p_children.empty()) { // no children in last node? + if (pReader->_last_tag == TAG_START) + pos->_content.append(s, p-s); + else if (pReader->_last_tag == TAG_END) + pos->_trailing.append(s, p-s); + // else TAG_NONE -> don't store white space in root node + } else + pos->_children.back()->_trailing.append(s, p-s); + + std::string leading; + + if (p != e) + leading.assign(p, e-p); + + XMLNode* node = new XMLNode(String_from_XML_Char(name), leading); + + pos.add_down(node); + + while(*atts) { + const XML_Char* attr_name = *atts++; + const XML_Char* attr_value = *atts++; + + (*node)[String_from_XML_Char(attr_name)] = String_from_XML_Char(attr_value); + } + + pReader->_last_tag = TAG_START; + pReader->_content.erase(); +} + + /// notifications about XML end tag +void XMLCALL XMLReaderBase::XML_EndElementHandler(void* userData, const XML_Char* name) +{ + XMLReaderBase* pReader = (XMLReaderBase*) userData; + XMLPos& pos = pReader->_pos; + + // search for end of first line + const char* s = pReader->_content.c_str(); + const char* p = s; + const char* e = p + pReader->_content.length(); + + for(; p_children.empty()) // no children in current node? + pos->_content.append(s, p-s); + else + if (pReader->_last_tag == TAG_START) + pos->_content.append(s, p-s); + else + pos->_children.back()->_trailing.append(s, p-s); + + if (p != e) + pos->_end_leading.assign(p, e-p); + + pos.back(); + + pReader->_last_tag = TAG_END; + pReader->_content.erase(); +} + + /// store content, white space and comments +void XMLCALL XMLReaderBase::XML_DefaultHandler(void* userData, const XML_Char* s, int len) +{ + XMLReaderBase* pReader = (XMLReaderBase*) userData; + + pReader->_content.append(s, len); +} + + +std::string XMLReaderBase::get_error_string() const +{ + XML_Error error = XML_GetErrorCode(_parser); + + switch(error) { + case XML_ERROR_NONE: return "XML_ERROR_NONE"; + case XML_ERROR_NO_MEMORY: return "XML_ERROR_NO_MEMORY"; + case XML_ERROR_SYNTAX: return "XML_ERROR_SYNTAX"; + case XML_ERROR_NO_ELEMENTS: return "XML_ERROR_NO_ELEMENTS"; + case XML_ERROR_INVALID_TOKEN: return "XML_ERROR_INVALID_TOKEN"; + case XML_ERROR_UNCLOSED_TOKEN: return "XML_ERROR_UNCLOSED_TOKEN"; + case XML_ERROR_PARTIAL_CHAR: return "XML_ERROR_PARTIAL_CHAR"; + case XML_ERROR_TAG_MISMATCH: return "XML_ERROR_TAG_MISMATCH"; + case XML_ERROR_DUPLICATE_ATTRIBUTE: return "XML_ERROR_DUPLICATE_ATTRIBUTE"; + case XML_ERROR_JUNK_AFTER_DOC_ELEMENT: return "XML_ERROR_JUNK_AFTER_DOC_ELEMENT"; + case XML_ERROR_PARAM_ENTITY_REF: return "XML_ERROR_PARAM_ENTITY_REF"; + case XML_ERROR_UNDEFINED_ENTITY: return "XML_ERROR_UNDEFINED_ENTITY"; + case XML_ERROR_RECURSIVE_ENTITY_REF: return "XML_ERROR_RECURSIVE_ENTITY_REF"; + case XML_ERROR_ASYNC_ENTITY: return "XML_ERROR_ASYNC_ENTITY"; + case XML_ERROR_BAD_CHAR_REF: return "XML_ERROR_BAD_CHAR_REF"; + case XML_ERROR_BINARY_ENTITY_REF: return "XML_ERROR_BINARY_ENTITY_REF"; + case XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF: return "XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF"; + case XML_ERROR_MISPLACED_XML_PI: return "XML_ERROR_MISPLACED_XML_PI"; + case XML_ERROR_UNKNOWN_ENCODING: return "XML_ERROR_UNKNOWN_ENCODING"; + case XML_ERROR_INCORRECT_ENCODING: return "XML_ERROR_INCORRECT_ENCODING"; + case XML_ERROR_UNCLOSED_CDATA_SECTION: return "XML_ERROR_UNCLOSED_CDATA_SECTION"; + case XML_ERROR_EXTERNAL_ENTITY_HANDLING: return "XML_ERROR_EXTERNAL_ENTITY_HANDLING"; + case XML_ERROR_NOT_STANDALONE: return "XML_ERROR_NOT_STANDALONE"; + case XML_ERROR_UNEXPECTED_STATE: return "XML_ERROR_UNEXPECTED_STATE"; + case XML_ERROR_ENTITY_DECLARED_IN_PE: return "XML_ERROR_ENTITY_DECLARED_IN_PE"; + case XML_ERROR_FEATURE_REQUIRES_XML_DTD: return "XML_ERROR_FEATURE_REQUIRES_XML_DTD"; + case XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING: return "XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING"; + case XML_ERROR_UNBOUND_PREFIX: return "XML_ERROR_UNBOUND_PREFIX"; + // EXPAT version >= 1.95.8 +#if XML_MAJOR_VERSION>1 || (XML_MAJOR_VERSION==1 && XML_MINOR_VERSION>95) || (XML_MAJOR_VERSION==1 && XML_MINOR_VERSION==95 && XML_MICRO_VERSION>7) + case XML_ERROR_SUSPENDED: return "XML_ERROR_SUSPENDED"; + case XML_ERROR_NOT_SUSPENDED: return "XML_ERROR_NOT_SUSPENDED"; + case XML_ERROR_ABORTED: return "XML_ERROR_ABORTED"; + case XML_ERROR_FINISHED: return "XML_ERROR_FINISHED"; + case XML_ERROR_SUSPEND_PE: return "XML_ERROR_SUSPEND_PE"; +#endif + } + + std::ostringstream out; + + out << "XML parser error #" << error; + + return out.str(); +} + + +std::string EncodeXMLString(const XS_String& str) +{ + LPCXSSTR s = str.c_str(); + LPXSSTR buffer = (LPXSSTR)alloca(5*sizeof(XS_CHAR)*XS_len(s)); // worst case. "&" + LPXSSTR o = buffer; + + for(LPCXSSTR p=s; *p; ++p) + switch(*p) { + case '&': + *o++ = '&'; *o++ = 'a'; *o++ = 'm'; *o++ = 'p'; *o++ = ';'; + break; + + case '<': + *o++ = '&'; *o++ = 'l'; *o++ = 't'; *o++ = ';'; + break; + + case '>': + *o++ = '&'; *o++ = 'g'; *o++ = 't'; *o++ = ';'; + break; + + case '"': + *o++ = '&'; *o++ = 'q'; *o++ = 'u'; *o++ = 'o'; *o++ = 't'; *o++ = ';'; + break; + + case '\'': + *o++ = '&'; *o++ = 'a'; *o++ = 'p'; *o++ = 'o'; *o++ = 's'; *o++ = ';'; + break; + + default: + *o++ = *p; + } + +#ifdef XS_STRING_UTF8 + return XS_String(buffer, o-buffer); +#else + return get_utf8(buffer, o-buffer); +#endif +} + +XS_String DecodeXMLString(const XS_String& str) +{ + LPCXSSTR s = str.c_str(); + LPXSSTR buffer = (LPXSSTR)alloca(sizeof(XS_CHAR)*XS_len(s)); + LPXSSTR o = buffer; + + for(LPCXSSTR p=s; *p; ++p) + if (*p == '&') { + if (!XS_nicmp(p+1, XS_TEXT("lt;"), 3)) { + *o++ = '<'; + p += 3; + } else if (!XS_nicmp(p+1, XS_TEXT("gt;"), 3)) { + *o++ = '>'; + p += 3; + } else if (!XS_nicmp(p+1, XS_TEXT("amp;"), 4)) { + *o++ = '&'; + p += 4; + } else if (!XS_nicmp(p+1, XS_TEXT("quot;"), 5)) { + *o++ = '"'; + p += 5; + } else if (!XS_nicmp(p+1, XS_TEXT("apos;"), 5)) { + *o++ = '\''; + p += 5; + } else + *o++ = *p; + } else + *o++ = *p; + + return XS_String(buffer, o-buffer); +} + + + /// write node with children tree to output stream using original white space +void XMLNode::write_worker(std::ostream& out, int indent) const +{ + out << _leading << '<' << EncodeXMLString(*this); + + for(AttributeMap::const_iterator it=_attributes.begin(); it!=_attributes.end(); ++it) + out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\""; + + if (!_children.empty() || !_content.empty()) { + out << '>' << _content; + + for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) + (*it)->write_worker(out, indent+1); + + out << _end_leading << "'; + } else + out << "/>"; + + out << _trailing; +} + + + /// pretty print node with children tree to output stream +void XMLNode::pretty_write_worker(std::ostream& out, int indent) const +{ + for(int i=indent; i--; ) + out << XML_INDENT_SPACE; + + out << '<' << EncodeXMLString(*this); + + for(AttributeMap::const_iterator it=_attributes.begin(); it!=_attributes.end(); ++it) + out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\""; + + if (!_children.empty() || !_content.empty()) { + out << ">\n"; + + for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) + (*it)->pretty_write_worker(out, indent+1); + + for(int i=indent; i--; ) + out << XML_INDENT_SPACE; + + out << "\n"; + } else + out << "/>\n"; +} + + + /// write node with children tree to output stream using smart formating +void XMLNode::smart_write_worker(std::ostream& out, int indent) const +{ + if (_leading.empty()) + for(int i=indent; i--; ) + out << XML_INDENT_SPACE; + else + out << _leading; + + out << '<' << EncodeXMLString(*this); + + for(AttributeMap::const_iterator it=_attributes.begin(); it!=_attributes.end(); ++it) + out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\""; + + if (_children.empty() && _content.empty()) + out << "/>"; + else { + out << '>'; + + if (_content.empty()) + out << '\n'; + else + out << _content; + + Children::const_iterator it = _children.begin(); + + if (it != _children.end()) { + for(; it!=_children.end(); ++it) + (*it)->smart_write_worker(out, indent+1); + + if (_end_leading.empty()) + for(int i=indent; i--; ) + out << XML_INDENT_SPACE; + else + out << _end_leading; + } else + out << _end_leading; + + out << "'; + } + + if (_trailing.empty()) + out << '\n'; + else + out << _trailing; +} + + +} // namespace XMLStorage diff --git a/reactos/subsys/system/ibrowser/utility/xmlstorage.h b/reactos/subsys/system/ibrowser/utility/xmlstorage.h new file mode 100644 index 00000000000..60b5fab1daf --- /dev/null +++ b/reactos/subsys/system/ibrowser/utility/xmlstorage.h @@ -0,0 +1,1722 @@ + + // + // XML storage classes + // + // xmlstorage.h + // + // Copyright (c) 2004, Martin Fuchs + // + + +/* + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _XMLSTORAGE_H + +#include "expat.h" + +#ifdef _MSC_VER +#pragma comment(lib, "libexpat.lib") +#pragma warning(disable: 4786) +#endif + + +#include // for LPCTSTR + +#ifdef UNICODE +#define _UNICODE +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include + + +#ifndef BUFFER_LEN +#define BUFFER_LEN 2048 +#endif + + +namespace XMLStorage { + + +#ifndef XS_String + +#ifdef XS_STRING_UTF8 +#define XS_CHAR char +#define XS_TEXT(x) x +#define LPXSSTR LPSTR +#define LPCXSSTR LPCSTR +#define XS_icmp stricmp +#define XS_nicmp strnicmp +#define XS_toi atoi +#define XS_len strlen +#define XS_sprintf sprintf +#define XS_vsprintf vsprintf +#else +#define XS_CHAR TCHAR +#define XS_TEXT(x) TEXT(x) +#define LPXSSTR LPTSTR +#define LPCXSSTR LPCTSTR +#define XS_icmp _tcsicmp +#define XS_nicmp _tcsnicmp +#define XS_toi _ttoi +#define XS_len _tcslen +#define XS_sprintf _stprintf +#define XS_vsprintf _vstprintf +#endif + +#if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8) + +#define XS_String String + +#else // _STRING_DEFINED, !XS_STRING_UTF8 + + /// string class for TCHAR strings + +struct XS_String +#if defined(UNICODE) && !defined(XS_STRING_UTF8) + : public std::wstring +#else + : public std::string +#endif +{ +#if defined(UNICODE) && !defined(XS_STRING_UTF8) + typedef std::wstring super; +#else + typedef std::string super; +#endif + + XS_String() {} + + XS_String(LPCXSSTR s) {if (s) super::assign(s);} + XS_String(LPCXSSTR s, int l) : super(s, l) {} + + XS_String(const super& other) : super(other) {} + XS_String(const XS_String& other) : super(other) {} + +#if defined(UNICODE) && !defined(XS_STRING_UTF8) + XS_String(LPCSTR s) {assign(s);} + XS_String(LPCSTR s, int l) {assign(s, l);} + XS_String(const std::string& other) {assign(other.c_str());} + XS_String& operator=(LPCSTR s) {assign(s); return *this;} + void assign(LPCSTR s) {if (s) {int bl=strlen(s); LPWSTR b=(LPWSTR)alloca(sizeof(WCHAR)*bl); super::assign(b, MultiByteToWideChar(CP_ACP, 0, s, bl, b, bl));} else erase();} + void assign(LPCSTR s, int l) {if (s) {int bl=l; LPWSTR b=(LPWSTR)alloca(sizeof(WCHAR)*bl); super::assign(b, MultiByteToWideChar(CP_ACP, 0, s, l, b, bl));} else erase();} +#else + XS_String(LPCWSTR s) {assign(s);} + XS_String(LPCWSTR s, int l) {assign(s, l);} + XS_String(const std::wstring& other) {assign(other.c_str());} + XS_String& operator=(LPCWSTR s) {assign(s); return *this;} +#ifdef XS_STRING_UTF8 + void assign(const XS_String& s) {assign(s.c_str());} + void assign(LPCWSTR s) {if (s) {int bl=wcslen(s); LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_UTF8, 0, s, bl, b, bl, 0, 0));} else erase();} + void assign(LPCWSTR s, int l) {int bl=l; if (s) {LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_UTF8, 0, s, l, b, bl, 0, 0));} else erase();} +#else // if !UNICODE && !XS_STRING_UTF8 + void assign(LPCWSTR s) {if (s) {int bl=wcslen(s); LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_ACP, 0, s, bl, b, bl, 0, 0));} else erase();} + void assign(LPCWSTR s, int l) {int bl=l; if (s) {LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_ACP, 0, s, l, b, bl, 0, 0));} else erase();} +#endif +#endif + + XS_String& operator=(LPCXSSTR s) {if (s) super::assign(s); else erase(); return *this;} + XS_String& operator=(const super& s) {super::assign(s); return *this;} + void assign(LPCXSSTR s) {super::assign(s);} + void assign(LPCXSSTR s, int l) {super::assign(s, l);} + + operator LPCXSSTR() const {return c_str();} + +#ifdef XS_STRING_UTF8 + operator std::wstring() const {int bl=length(); LPWSTR b=(LPWSTR)alloca(sizeof(WCHAR)*bl); return std::wstring(b, MultiByteToWideChar(CP_UTF8, 0, c_str(), bl, b, bl));} +#elif defined(UNICODE) + operator std::string() const {int bl=length(); LPSTR b=(LPSTR)alloca(bl); return std::string(b, WideCharToMultiByte(CP_ACP, 0, c_str(), bl, b, bl, 0, 0));} +#else + operator std::wstring() const {int bl=length(); LPWSTR b=(LPWSTR)alloca(sizeof(WCHAR)*bl); return std::wstring(b, MultiByteToWideChar(CP_ACP, 0, c_str(), bl, b, bl));} +#endif + + XS_String& printf(LPCXSSTR fmt, ...) + { + va_list l; + XS_CHAR b[BUFFER_LEN]; + + va_start(l, fmt); + super::assign(b, XS_vsprintf(b, fmt, l)); + va_end(l); + + return *this; + } + + XS_String& vprintf(LPCXSSTR fmt, va_list l) + { + XS_CHAR b[BUFFER_LEN]; + + super::assign(b, XS_vsprintf(b, fmt, l)); + + return *this; + } + + XS_String& appendf(LPCXSSTR fmt, ...) + { + va_list l; + XS_CHAR b[BUFFER_LEN]; + + va_start(l, fmt); + super::append(b, XS_vsprintf(b, fmt, l)); + va_end(l); + + return *this; + } + + XS_String& vappendf(LPCXSSTR fmt, va_list l) + { + XS_CHAR b[BUFFER_LEN]; + + super::append(b, XS_vsprintf(b, fmt, l)); + + return *this; + } +}; + +#endif // _STRING_DEFINED, !XS_STRING_UTF8 + +#endif // XS_String + + +#ifndef XS_STRING_UTF8 + +inline void assign_utf8(XS_String& s, const char* str) +{ + int lutf8 = strlen(str); + +#ifdef UNICODE + LPTSTR buffer = (LPTSTR)alloca(sizeof(TCHAR)*lutf8); + int l = MultiByteToWideChar(CP_UTF8, 0, str, lutf8, buffer, lutf8); +#else + LPWSTR wbuffer = (LPWSTR)alloca(sizeof(WCHAR)*lutf8); + int l = MultiByteToWideChar(CP_UTF8, 0, str, lutf8, wbuffer, lutf8); + + int bl=2*l; LPSTR buffer = (LPSTR)alloca(bl); + l = WideCharToMultiByte(CP_ACP, 0, wbuffer, l, buffer, bl, 0, 0); +#endif + + s.assign(buffer, l); +} + +inline std::string get_utf8(LPCTSTR s, int l) +{ +#ifdef UNICODE + int bl=2*l; LPSTR buffer = (LPSTR)alloca(bl); + l = WideCharToMultiByte(CP_UTF8, 0, s, l, buffer, bl, 0, 0); +#else + LPWSTR wbuffer = (LPWSTR)alloca(sizeof(WCHAR)*l); + l = MultiByteToWideChar(CP_ACP, 0, s, l, wbuffer, l); + + int bl=2*l; LPSTR buffer = (LPSTR)alloca(bl); + l = WideCharToMultiByte(CP_UTF8, 0, wbuffer, l, buffer, bl, 0, 0); +#endif + + return std::string(buffer, l); +} + +inline std::string get_utf8(const XS_String& s) +{ + return get_utf8(s.c_str(), s.length()); +} + +#endif // XS_STRING_UTF8 + +extern std::string EncodeXMLString(const XS_String& str); +extern XS_String DecodeXMLString(const XS_String& str); + + +#ifdef __GNUC__ +#include +typedef __gnu_cxx::stdio_filebuf STDIO_FILEBUF; +#else +typedef std::filebuf STDIO_FILEBUF; +#endif + + /// input file stream with ANSI/UNICODE file names +struct tifstream : public std::istream +{ + typedef std::istream super; + + tifstream(LPCTSTR path) + : super(&_buf), + _pfile(_tfopen(path, TEXT("r"))), +#ifdef __GNUC__ + _buf(_pfile, ios::in) +#else + _buf(_pfile) +#endif + { + } + + ~tifstream() + { + if (_pfile) + fclose(_pfile); + } + +protected: + FILE* _pfile; + STDIO_FILEBUF _buf; +}; + + /// output file stream with ANSI/UNICODE file names +struct tofstream : public std::ostream +{ + typedef std::ostream super; + + tofstream(LPCTSTR path) + : super(&_buf), + _pfile(_tfopen(path, TEXT("w"))), +#ifdef __GNUC__ + _buf(_pfile, ios::out) +#else + _buf(_pfile) +#endif + { + } + + ~tofstream() + { + flush(); + + if (_pfile) + fclose(_pfile); + } + +protected: + FILE* _pfile; + STDIO_FILEBUF _buf; +}; + + + // write XML files with 2 spaces indenting +#define XML_INDENT_SPACE " " + + +#ifdef XML_UNICODE // Are XML_Char strings UTF-16 encoded? + +typedef XS_String String_from_XML_Char; + +#elif defined(XS_STRING_UTF8) + +typedef XS_String String_from_XML_Char; + +#else + +struct String_from_XML_Char : public XS_String +{ + String_from_XML_Char(const XML_Char* str) + { + assign_utf8(*this, str); + } +}; + +#endif + + +#if defined(UNICODE) && !defined(XS_STRING_UTF8) + + // optimization for faster UNICODE/ASCII string comparison without temporary A/U conversion +inline bool operator==(const XS_String& s1, const char* s2) +{ + LPCWSTR p = s1; + const unsigned char* q = (const unsigned char*)s2; + + while(*p && *q) + if (*p++ != *q++) + return false; + + return *p == *q; +}; + +#endif + + + /// in memory representation of an XML node +struct XMLNode : public XS_String +{ +#if defined(UNICODE) && !defined(XS_STRING_UTF8) + // optimized read access without temporary A/U conversion when using ASCII attribute names + struct AttributeMap : public std::map + { + typedef std::map super; + + const_iterator find(const char* x) const + { + for(const_iterator it=begin(); it!=end(); ++it) + if (it->first == x) + return it; + + return end(); + } + + const_iterator find(const key_type& x) const + { + return super::find(x); + } + + iterator find(const key_type& x) + { + return super::find(x); + } + }; +#else + typedef std::map AttributeMap; +#endif + + struct Children : public std::list + { + void assign(const Children& other) + { + clear(); + + for(Children::const_iterator it=other.begin(); it!=other.end(); ++it) + push_back(new XMLNode(**it)); + } + + void clear() + { + while(!empty()) { + XMLNode* node = back(); + pop_back(); + + node->clear(); + delete node; + } + } + }; + + // access to protected class members for XMLPos and XMLReader + friend struct XMLPos; + friend struct const_XMLPos; + friend struct XMLReaderBase; + + XMLNode(const XS_String& name) + : XS_String(name) + { + } + + XMLNode(const XS_String& name, const std::string& leading) + : XS_String(name), + _leading(leading) + { + } + + XMLNode(const XMLNode& other) + : _attributes(other._attributes), + _leading(other._leading), + _content(other._content), + _end_leading(other._end_leading), + _trailing(other._trailing) + { + for(Children::const_iterator it=other._children.begin(); it!=other._children.end(); ++it) + _children.push_back(new XMLNode(**it)); + } + + ~XMLNode() + { + while(!_children.empty()) { + delete _children.back(); + _children.pop_back(); + } + } + + void clear() + { + _leading.erase(); + _content.erase(); + _end_leading.erase(); + _trailing.erase(); + + _attributes.clear(); + _children.clear(); + + XS_String::erase(); + } + + XMLNode& operator=(const XMLNode& other) + { + _children.assign(other._children); + + _attributes = other._attributes; + + _leading = other._leading; + _content = other._content; + _end_leading = other._end_leading; + _trailing = other._trailing; + + return *this; + } + + /// add a new child node + void add_child(XMLNode* child) + { + _children.push_back(child); + } + + /// write access to an attribute + void put(const XS_String& attr_name, const XS_String& value) + { + _attributes[attr_name] = value; + } + + /// C++ write access to an attribute + XS_String& operator[](const XS_String& attr_name) + { + return _attributes[attr_name]; + } + + /// read only access to an attribute + template XS_String get(const T& attr_name) const + { + AttributeMap::const_iterator found = _attributes.find(attr_name); + + if (found != _attributes.end()) + return found->second; + else + return XS_String(); + } + + /// convenient value access in children node + XS_String subvalue(const XS_String& name, const XS_String& attr_name, int n=0) const + { + const XMLNode* node = find(name, n); + + if (node) + return node->get(attr_name); + else + return XS_String(); + } + + /// convenient storage of distinct values in children node + XS_String& subvalue(const XS_String& name, const XS_String& attr_name, int n=0) + { + XMLNode* node = find(name, n); + + if (!node) { + node = new XMLNode(name); + add_child(node); + } + + return (*node)[attr_name]; + } + +#if defined(UNICODE) && !defined(XS_STRING_UTF8) + /// convenient value access in children node + XS_String subvalue(const char* name, const char* attr_name, int n=0) const + { + const XMLNode* node = find(name, n); + + if (node) + return node->get(attr_name); + else + return XS_String(); + } + + /// convenient storage of distinct values in children node + XS_String& subvalue(const char* name, const XS_String& attr_name, int n=0) + { + XMLNode* node = find(name, n); + + if (!node) { + node = new XMLNode(name); + add_child(node); + } + + return (*node)[attr_name]; + } +#endif + + const Children& get_children() const + { + return _children; + } + + Children& get_children() + { + return _children; + } + + XS_String get_content() const + { +#ifdef XS_STRING_UTF8 + const XS_String& ret = _content; +#else + XS_String ret; + assign_utf8(ret, _content.c_str()); +#endif + + return DecodeXMLString(ret.c_str()); + } + + void set_content(const XS_String& s) + { + _content.assign(EncodeXMLString(s.c_str())); + } + + enum WRITE_MODE { + FORMAT_SMART = 0, /// preserve original white space and comments if present; pretty print otherwise + FORMAT_ORIGINAL = 1, /// write XML stream preserving original white space and comments + FORMAT_PRETTY = 2 /// pretty print node to stream without preserving original white space + }; + + /// write node with children tree to output stream + std::ostream& write(std::ostream& out, WRITE_MODE mode=FORMAT_SMART, int indent=0) const + { + switch(mode) { + case FORMAT_PRETTY: + pretty_write_worker(out, indent); + break; + + case FORMAT_ORIGINAL: + write_worker(out, indent); + break; + + default: // FORMAT_SMART + smart_write_worker(out, indent); + } + + return out; + } + + XMLNode* find(const XS_String& name, int n=0) const + { + for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) + if (**it == name) + if (!n--) + return *it; + + return NULL; + } + + XMLNode* find(const XS_String& name, const XS_String& attr_name, const XS_String& attr_value, int n=0) const + { + for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) { + const XMLNode& node = **it; + + if (node==name && node.get(attr_name)==attr_value) + if (!n--) + return *it; + } + + return NULL; + } + +#if defined(UNICODE) && !defined(XS_STRING_UTF8) + XMLNode* find(const char* name, int n=0) const + { + for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) + if (**it == name) + if (!n--) + return *it; + + return NULL; + } + + template + XMLNode* find(const char* name, const T& attr_name, const U& attr_value, int n=0) const + { + for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) { + const XMLNode& node = **it; + + if (node==name && node.get(attr_name)==attr_value) + if (!n--) + return *it; + } + + return NULL; + } +#endif + + /// XPath find functions + const XMLNode* find_relative(const char* path) const; + + XMLNode* find_relative(const char* path) + {return const_cast(const_cast(this)->find_relative(path));} + + /// relative XPath create function + XMLNode* create_relative(const char* path); + +protected: + Children _children; + AttributeMap _attributes; + + std::string _leading; + std::string _content; + std::string _end_leading; + std::string _trailing; + + XMLNode* get_first_child() const + { + if (!_children.empty()) + return _children.front(); + else + return NULL; + } + + void write_worker(std::ostream& out, int indent) const; + void pretty_write_worker(std::ostream& out, int indent) const; + void smart_write_worker(std::ostream& out, int indent) const; +}; + + + /// iterator access to children nodes with name filtering +struct XMLChildrenFilter +{ + XMLChildrenFilter(XMLNode::Children& children, const XS_String& name) + : _begin(children.begin(), children.end(), name), + _end(children.end(), children.end(), name) + { + } + + XMLChildrenFilter(XMLNode* node, const XS_String& name) + : _begin(node->get_children().begin(), node->get_children().end(), name), + _end(node->get_children().end(), node->get_children().end(), name) + { + } + + struct iterator + { + typedef XMLNode::Children::iterator BaseIterator; + + iterator(BaseIterator begin, BaseIterator end, const XS_String& filter_name) + : _cur(begin), + _end(end), + _filter_name(filter_name) + { + search_next(); + } + + operator BaseIterator() + { + return _cur; + } + + const XMLNode* operator*() const + { + return *_cur; + } + + XMLNode* operator*() + { + return *_cur; + } + + iterator& operator++() + { + ++_cur; + search_next(); + + return *this; + } + + iterator operator++(int) + { + iterator ret = *this; + + ++_cur; + search_next(); + + return ret; + } + + bool operator==(const BaseIterator& other) const + { + return _cur == other; + } + + bool operator!=(const BaseIterator& other) const + { + return _cur != other; + } + + protected: + BaseIterator _cur; + BaseIterator _end; + XS_String _filter_name; + + void search_next() + { + while(_cur!=_end && **_cur!=_filter_name) + ++_cur; + } + }; + + iterator begin() + { + return _begin; + } + + iterator end() + { + return _end; + } + +protected: + iterator _begin; + iterator _end; +}; + + + /// read only iterator access to children nodes with name filtering +struct const_XMLChildrenFilter +{ + const_XMLChildrenFilter(const XMLNode::Children& children, const XS_String& name) + : _begin(children.begin(), children.end(), name), + _end(children.end(), children.end(), name) + { + } + + const_XMLChildrenFilter(const XMLNode* node, const XS_String& name) + : _begin(node->get_children().begin(), node->get_children().end(), name), + _end(node->get_children().end(), node->get_children().end(), name) + { + } + + struct const_iterator + { + typedef XMLNode::Children::const_iterator BaseIterator; + + const_iterator(BaseIterator begin, BaseIterator end, const XS_String& filter_name) + : _cur(begin), + _end(end), + _filter_name(filter_name) + { + search_next(); + } + + operator BaseIterator() + { + return _cur; + } + + const XMLNode* operator*() const + { + return *_cur; + } + + const_iterator& operator++() + { + ++_cur; + search_next(); + + return *this; + } + + const_iterator operator++(int) + { + const_iterator ret = *this; + + ++_cur; + search_next(); + + return ret; + } + + bool operator==(const BaseIterator& other) const + { + return _cur == other; + } + + bool operator!=(const BaseIterator& other) const + { + return _cur != other; + } + + protected: + BaseIterator _cur; + BaseIterator _end; + XS_String _filter_name; + + void search_next() + { + while(_cur!=_end && **_cur!=_filter_name) + ++_cur; + } + }; + + const_iterator begin() + { + return _begin; + } + + const_iterator end() + { + return _end; + } + +protected: + const_iterator _begin; + const_iterator _end; +}; + + + /// iterator for XML trees +struct XMLPos +{ + XMLPos(XMLNode* root) + : _root(root), + _cur(root) + { + } + + XMLPos(const XMLPos& other) + : _root(other._root), + _cur(other._cur) + { // don't copy _stack + } + + XMLPos(XMLNode* node, const XS_String& name) + : _root(node), + _cur(node) + { + smart_create(name); + } + + XMLPos(XMLNode* node, const XS_String& name, const XS_String& attr_name, const XS_String& attr_value) + : _root(node), + _cur(node) + { + smart_create(name, attr_name, attr_value); + } + + XMLPos(const XMLPos& other, const XS_String& name) + : _root(other._root), + _cur(other._cur) + { + smart_create(name); + } + + XMLPos(const XMLPos& other, const XS_String& name, const XS_String& attr_name, const XS_String& attr_value) + : _root(other._root), + _cur(other._cur) + { + smart_create(name, attr_name, attr_value); + } + + /// access to current node + XMLNode& cur() + { + return *_cur; + } + + const XMLNode& cur() const + { + return *_cur; + } + + /// C++ access to current node + operator const XMLNode*() const {return _cur;} + operator XMLNode*() {return _cur;} + + const XMLNode* operator->() const {return _cur;} + XMLNode* operator->() {return _cur;} + + const XMLNode& operator*() const {return *_cur;} + XMLNode& operator*() {return *_cur;} + + /// attribute access + XS_String get(const XS_String& attr_name) const + { + return _cur->get(attr_name); + } + + void put(const XS_String& attr_name, const XS_String& value) + { + _cur->put(attr_name, value); + } + + /// C++ attribute access + template XS_String get(const T& attr_name) const {return (*_cur)[attr_name];} + XS_String& operator[](const XS_String& attr_name) {return (*_cur)[attr_name];} + + /// insert children when building tree + void add_down(XMLNode* child) + { + _cur->add_child(child); + go_to(child); + } + + /// go back to previous position + bool back() + { + if (!_stack.empty()) { + _cur = _stack.top(); + _stack.pop(); + return true; + } else + return false; + } + + /// go down to first child + bool go_down() + { + XMLNode* node = _cur->get_first_child(); + + if (node) { + go_to(node); + return true; + } else + return false; + } + + /// search for child and go down + bool go_down(const XS_String& name, int n=0) + { + XMLNode* node = _cur->find(name, n); + + if (node) { + go_to(node); + return true; + } else + return false; + } + + /// move XPath like to position in XML tree + bool go(const char* path); + + /// create child nodes using XPath notation and move to the deepest child + bool create_relative(const char* path) + { + XMLNode* node = _cur->create_relative(path); + if (!node) + return false; // invalid path specified + + go_to(node); + return true; + } + + /// create node and move to it + void create(const XS_String& name) + { + add_down(new XMLNode(name)); + } + + /// create node if not already existing and move to it + void smart_create(const XS_String& name) + { + XMLNode* node = _cur->find(name); + + if (node) + go_to(node); + else + add_down(new XMLNode(name)); + } + + /// search matching child node identified by key name and an attribute value + void smart_create(const XS_String& name, const XS_String& attr_name, const XS_String& attr_value) + { + XMLNode* node = _cur->find(name, attr_name, attr_value); + + if (node) + go_to(node); + else { + node = new XMLNode(name); + add_down(node); + (*node)[attr_name] = attr_value; + } + } + +#if defined(UNICODE) && !defined(XS_STRING_UTF8) + /// search for child and go down + bool go_down(const char* name, int n=0) + { + XMLNode* node = _cur->find(name, n); + + if (node) { + go_to(node); + return true; + } else + return false; + } + + /// create node and move to it + void create(const char* name) + { + add_down(new XMLNode(name)); + } + + /// create node if not already existing and move to it + void smart_create(const char* name) + { + XMLNode* node = _cur->find(name); + + if (node) + go_to(node); + else + add_down(new XMLNode(name)); + } + + /// search matching child node identified by key name and an attribute value + template + void smart_create(const char* name, const T& attr_name, const U& attr_value) + { + XMLNode* node = _cur->find(name, attr_name, attr_value); + + if (node) + go_to(node); + else { + XMLNode* node = new XMLNode(name); + add_down(node); + (*node)[attr_name] = attr_value; + } + } +#endif + + XS_String& str() {return *_cur;} + const XS_String& str() const {return *_cur;} + +protected: + XMLNode* _root; + XMLNode* _cur; + std::stack _stack; + + /// go to specified node + void go_to(XMLNode* child) + { + _stack.push(_cur); + _cur = child; + } +}; + + + /// iterator for XML trees +struct const_XMLPos +{ + const_XMLPos(const XMLNode* root) + : _root(root), + _cur(root) + { + } + + const_XMLPos(const const_XMLPos& other) + : _root(other._root), + _cur(other._cur) + { // don't copy _stack + } + + /// access to current node + const XMLNode& cur() const + { + return *_cur; + } + + /// C++ access to current node + operator const XMLNode*() const {return _cur;} + + const XMLNode* operator->() const {return _cur;} + + const XMLNode& operator*() const {return *_cur;} + + /// attribute access + XS_String get(const XS_String& attr_name) const + { + return _cur->get(attr_name); + } + + /// C++ attribute access + template XS_String get(const T& attr_name) const {return _cur->get(attr_name);} + + /// go back to previous position + bool back() + { + if (!_stack.empty()) { + _cur = _stack.top(); + _stack.pop(); + return true; + } else + return false; + } + + /// go down to first child + bool go_down() + { + const XMLNode* node = _cur->get_first_child(); + + if (node) { + go_to(node); + return true; + } else + return false; + } + + /// search for child and go down + bool go_down(const XS_String& name, int n=0) + { + XMLNode* node = _cur->find(name, n); + + if (node) { + go_to(node); + return true; + } else + return false; + } + + /// move XPath like to position in XML tree + bool go(const char* path); + +#if defined(UNICODE) && !defined(XS_STRING_UTF8) + /// search for child and go down + bool go_down(const char* name, int n=0) + { + XMLNode* node = _cur->find(name, n); + + if (node) { + go_to(node); + return true; + } else + return false; + } +#endif + + const XS_String& str() const {return *_cur;} + +protected: + const XMLNode* _root; + const XMLNode* _cur; + std::stack _stack; + + /// go to specified node + void go_to(const XMLNode* child) + { + _stack.push(_cur); + _cur = child; + } +}; + + + // work around GCC's wide string constant bug +#ifdef __GNUC__ +extern const LPCXSSTR XS_TRUE; +extern const LPCXSSTR XS_FALSE; +extern const LPCXSSTR XS_NUMBERFMT; +#else +#define XS_TRUE XS_TEXT("true") +#define XS_FALSE XS_TEXT("false") +#define XS_NUMBERFMT XS_TEXT("%d") +#endif + + +struct XMLBool +{ + XMLBool(bool value=false) + : _value(value) + { + } + + XMLBool(LPCXSSTR value, bool def=false) + { + if (value && *value) + _value = !XS_icmp(value, XS_TRUE); + else + _value = def; + } + + XMLBool(const XMLNode* node, const XS_String& attr_name, bool def=false) + { + const XS_String& value = node->get(attr_name); + + if (!value.empty()) + _value = !XS_icmp(value.c_str(), XS_TRUE); + else + _value = def; + } + + operator bool() const + { + return _value; + } + + bool operator!() const + { + return !_value; + } + + operator LPCXSSTR() const + { + return _value? XS_TRUE: XS_FALSE; + } + +protected: + bool _value; + +private: + void operator=(const XMLBool&); // disallow assignment operations +}; + +struct XMLBoolRef +{ + XMLBoolRef(XMLNode* node, const XS_String& attr_name, bool def=false) + : _ref((*node)[attr_name]) + { + if (_ref.empty()) + assign(def); + } + + operator bool() const + { + return !XS_icmp(_ref.c_str(), XS_TRUE); + } + + bool operator!() const + { + return XS_icmp(_ref.c_str(), XS_TRUE)? true: false; + } + + XMLBoolRef& operator=(bool value) + { + assign(value); + + return *this; + } + + void assign(bool value) + { + _ref.assign(value? XS_TRUE: XS_FALSE); + } + + void toggle() + { + assign(!operator bool()); + } + +protected: + XS_String& _ref; +}; + + +struct XMLInt +{ + XMLInt(int value) + : _value(value) + { + } + + XMLInt(LPCXSSTR value, int def=0) + { + if (value && *value) + _value = XS_toi(value); + else + _value = def; + } + + XMLInt(const XMLNode* node, const XS_String& attr_name, int def=0) + { + const XS_String& value = node->get(attr_name); + + if (!value.empty()) + _value = XS_toi(value.c_str()); + else + _value = def; + } + + operator int() const + { + return _value; + } + + operator XS_String() const + { + XS_CHAR buffer[32]; + XS_sprintf(buffer, XS_NUMBERFMT, _value); + return buffer; + } + +protected: + int _value; + +private: + void operator=(const XMLInt&); // disallow assignment operations +}; + +struct XMLIntRef +{ + XMLIntRef(XMLNode* node, const XS_String& attr_name, int def=0) + : _ref((*node)[attr_name]) + { + if (_ref.empty()) + assign(def); + } + + XMLIntRef& operator=(int value) + { + assign(value); + + return *this; + } + + operator int() const + { + return XS_toi(_ref.c_str()); + } + + void assign(int value) + { + XS_CHAR buffer[32]; + XS_sprintf(buffer, XS_NUMBERFMT, value); + _ref.assign(buffer); + } + +protected: + XS_String& _ref; +}; + + +struct XMLString +{ + XMLString(const XS_String& value) + : _value(value) + { + } + + XMLString(LPCXSSTR value, LPCXSSTR def=XS_TEXT("")) + { + if (value && *value) + _value = value; + else + _value = def; + } + + XMLString(const XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_TEXT("")) + { + const XS_String& value = node->get(attr_name); + + if (!value.empty()) + _value = value; + else + _value = def; + } + + operator const XS_String&() const + { + return _value; + } + + const XS_String& c_str() const + { + return _value; + } + +protected: + XS_String _value; + +private: + void operator=(const XMLString&); // disallow assignment operations +}; + +struct XMStringRef +{ + XMStringRef(XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_TEXT("")) + : _ref((*node)[attr_name]) + { + if (_ref.empty()) + assign(def); + } + + XMStringRef(XMLNode* node, const XS_String& node_name, const XS_String& attr_name, LPCXSSTR def=XS_TEXT("")) + : _ref(node->subvalue(node_name, attr_name)) + { + if (_ref.empty()) + assign(def); + } + + XMStringRef& operator=(const XS_String& value) + { + assign(value); + + return *this; + } + + operator const XS_String&() const + { + return _ref; + } + + void assign(const XS_String& value) + { + _ref.assign(value); + } + +protected: + XS_String& _ref; +}; + + +template + inline void read_option(T& var, const_XMLPos& cfg, LPCXSSTR key) + { + const XS_String& val = cfg.get(key); + + if (!val.empty()) + var = val; + } + +template<> + inline void read_option(int& var, const_XMLPos& cfg, LPCXSSTR key) + { + const XS_String& val = cfg.get(key); + + if (!val.empty()) + var = XS_toi(val.c_str()); + } + + +#ifdef _MSC_VER +#pragma warning(disable: 4355) +#endif + + /// XML reader base class +struct XMLReaderBase +{ + XMLReaderBase(XMLNode* node) + : _pos(node), + _parser(XML_ParserCreate(NULL)) + { + XML_SetUserData(_parser, this); + XML_SetXmlDeclHandler(_parser, XML_XmlDeclHandler); + XML_SetElementHandler(_parser, XML_StartElementHandler, XML_EndElementHandler); + XML_SetDefaultHandler(_parser, XML_DefaultHandler); + + _last_tag = TAG_NONE; + } + + virtual ~XMLReaderBase() + { + XML_ParserFree(_parser); + } + + XML_Status read(); + + virtual int read_buffer(char* buffer, int len) = 0; + + std::string get_position() const + { + int line = XML_GetCurrentLineNumber(_parser); + int column = XML_GetCurrentColumnNumber(_parser); + + std::ostringstream out; + out << "(" << line << ") : [column " << column << "]"; + + return out.str(); + } + + XML_Error get_error_code() {return XML_GetErrorCode(_parser);} + std::string get_error_string() const; + +protected: + XMLPos _pos; + XML_Parser _parser; + std::string _xml_version; + std::string _encoding; + + std::string _content; + enum {TAG_NONE, TAG_START, TAG_END} _last_tag; + + static void XMLCALL XML_XmlDeclHandler(void* userData, const XML_Char* version, const XML_Char* encoding, int standalone); + static void XMLCALL XML_StartElementHandler(void* userData, const XML_Char* name, const XML_Char** atts); + static void XMLCALL XML_EndElementHandler(void* userData, const XML_Char* name); + static void XMLCALL XML_DefaultHandler(void* userData, const XML_Char* s, int len); +}; + + + /// XML file reader +struct XMLReader : public XMLReaderBase +{ + XMLReader(XMLNode* node, std::istream& in) + : XMLReaderBase(node), + _in(in) + { + } + + /// read XML stream into XML tree below _pos + int read_buffer(char* buffer, int len) + { + if (!_in.good()) + return -1; + + _in.read(buffer, len); + + return _in.gcount(); + } + +protected: + std::istream& _in; +}; + + +struct XMLHeader +{ + XMLHeader(const std::string& xml_version="1.0", const std::string& encoding="UTF-8", const std::string& doctype="") + : _version(xml_version), + _encoding(encoding), + _doctype(doctype) + { + } + + void print(std::ostream& out) const + { + out << "\n"; + + if (!_doctype.empty()) + out << _doctype << '\n'; + } + + std::string _version; + std::string _encoding; + std::string _doctype; +}; + + +struct XMLDoc : public XMLNode +{ + XMLDoc() + : XMLNode(""), + _last_error(XML_ERROR_NONE) + { + } + + XMLDoc(LPCTSTR path) + : XMLNode(""), + _last_error(XML_ERROR_NONE) + { + read(path); + } + + std::istream& read(std::istream& in) + { + XMLReader reader(this, in); + + read(reader); + + return in; + } + + bool read(LPCTSTR path) + { + tifstream in(path); + XMLReader reader(this, in); + +//#if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8) +// return read(reader, std::string(ANS(path))); +//#else + return read(reader, XS_String(path)); +//#endif + } + + bool read(XMLReaderBase& reader) + { + XML_Status status = reader.read(); + + if (status == XML_STATUS_ERROR) { + std::ostringstream out; + + out << "input stream" << reader.get_position() << " " << reader.get_error_string(); + + _last_error = reader.get_error_code(); + _last_error_msg = out.str(); + } + + return status != XML_STATUS_ERROR; + } + + bool read(XMLReaderBase& reader, const std::string& display_path) + { + XML_Status status = reader.read(); + + if (status == XML_STATUS_ERROR) { + std::ostringstream out; + + out << display_path << reader.get_position() << " " << reader.get_error_string(); + + _last_error = reader.get_error_code(); + _last_error_msg = out.str(); + } + + return status != XML_STATUS_ERROR; + } + + /// write XML stream preserving previous white space and comments + std::ostream& write(std::ostream& out, WRITE_MODE mode=FORMAT_SMART, const XMLHeader& header=XMLHeader()) const + { + header.print(out); + + if (!_children.empty()) + _children.front()->write(out); + + return out; + } + + /// write XML stream with formating + std::ostream& write_formating(std::ostream& out) const + { + return write(out, FORMAT_PRETTY); + } + + void write(LPCTSTR path, WRITE_MODE mode=FORMAT_SMART, const XMLHeader& header=XMLHeader()) const + { + tofstream out(path); + + write(out, mode, header); + } + + void write_formating(LPCTSTR path) const + { + tofstream out(path); + + write_formating(out); + } + + XML_Error _last_error; + std::string _last_error_msg; +}; + + +struct XMLMessage : public XMLDoc +{ + XMLMessage(const char* name) + : _pos(this) + { + _pos.create(name); + } + + XMLPos _pos; +}; + + +} // namespace XMLStorage + +#define _XMLSTORAGE_H +#endif // _XMLSTORAGE_H diff --git a/reactos/subsys/system/ibrowser/webchild.cpp b/reactos/subsys/system/ibrowser/webchild.cpp new file mode 100644 index 00000000000..78cc3c0f72a --- /dev/null +++ b/reactos/subsys/system/ibrowser/webchild.cpp @@ -0,0 +1,309 @@ +/* + * Copyright 2004, 2005 Martin Fuchs + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + + // + // ROS Internet Web Browser + // + // webchild.cpp + // + // Martin Fuchs, 25.01.2005 + // + + +#include "precomp.h" + +#include "ibrowser_intres.h" + +#include "webchild.h" + + +#ifdef _MSC_VER + +#if _MSC_VER>=1300 // vtMissing for VS.Net +#include +#pragma comment(lib, "comsupp") +#endif + +#else + +#ifdef __MINGW32__ // MinGW is lacking vtMissing (as of 07.02.2004) +static Variant vtMissing; +#endif + +#endif + +//#include + + +Variant::Variant(const VARIANT& var) +{ + VariantInit(this); + CheckError(VariantCopy(this, const_cast(&var))); +} + +Variant::Variant(const VARIANT* var) +{ + VariantInit(this); + CheckError(VariantCopy(this, const_cast(var))); +} + +Variant::~Variant() +{ + VariantClear(this); +} + + +Variant::operator long() const +{ + Variant v; + CheckError(VariantChangeType(&v, (VARIANT*)this, 0, VT_I4)); + return V_I4(&v); +} + +Variant::operator bool() const +{ + Variant v; + CheckError(VariantChangeType(&v, (VARIANT*)this, 0, VT_BOOL)); + return V_BOOL(&v)? true: false; +} + +Variant::operator IDispatch*() const +{ + Variant v; + CheckError(VariantChangeType(&v, (VARIANT*)this, 0, VT_DISPATCH)); + return V_DISPATCH(&v); +} + +Variant::operator VARIANT_BOOL() const +{ + Variant v; + CheckError(VariantChangeType(&v, (VARIANT*)this, 0, VT_BOOL)); + return V_BOOL(&v); +} + + +void BStr::assign(BSTR s) +{ + if (!SysReAllocString(&_p, s)) + THROW_EXCEPTION(E_OUTOFMEMORY); +} + +void BStr::assign(const VARIANT& var) +{ + if (V_VT(&var) == VT_BSTR) + assign(V_BSTR(&var)); + else { + Variant v; + CheckError(VariantChangeType(&v, const_cast(&var), 0, VT_BSTR)); + assign(V_BSTR(&v)); + } +} + + +BrowserNavigator::BrowserNavigator() + : _browser_initialized(false) +{ +} + +void BrowserNavigator::attach(IWebBrowser* browser) +{ + _browser = browser; +} + +void BrowserNavigator::goto_url(LPCTSTR url) +{ + if (_browser_initialized) + _browser->Navigate(BStr(url), NULL, NULL, NULL, NULL); + else { + _new_url = url; + + _browser->Navigate(L"about:blank", NULL, NULL, NULL, NULL); + } +} + +void BrowserNavigator::set_html_page(const String& html_txt) +{ + _new_html_txt = html_txt; + + goto_url(TEXT("about:blank")); +} + +void T2nA_binary(LPCTSTR s, LPSTR d, int len) +{ + while(len-- > 0) + *d++ = (unsigned char)*s++; +} + +void BrowserNavigator::navigated(LPCTSTR url) +{ + _browser_initialized = true; + + bool nav = false; + + if (!_new_url.empty()) { + if (!_tcscmp(url,TEXT("about:blank")) && _new_url!=TEXT("about:blank")) { + _browser->Navigate(BStr(_new_url), NULL, NULL, NULL, NULL); + ++nav; + } + + _new_url.erase(); + } + + if (!nav && !_new_html_txt.empty()) { ///@todo move this into DocumentComplete() ? + int len = _new_html_txt.length(); + HGLOBAL hHtmlText = GlobalAlloc(GPTR, len); + + if (!hHtmlText) { + T2nA_binary(_new_html_txt, (char*)hHtmlText, len); + _new_html_txt.erase(); + + SIfacePtr pStream; + HRESULT hr = CreateStreamOnHGlobal(hHtmlText, TRUE, &pStream); + + if (SUCCEEDED(hr)) { + SIfacePtr pHtmlDoc; + CheckError(_browser->get_Document(&pHtmlDoc)); + + SIfacePtr pPersistStreamInit; + pHtmlDoc.QueryInterface(IID_IPersistStreamInit, &pPersistStreamInit); + + CheckError(pPersistStreamInit->InitNew()); + CheckError(pPersistStreamInit->Load(pStream)); + } else + GlobalFree(hHtmlText); + } + } +} + + +HWND create_webchildwindow(const WebChildWndInfo& info) +{ + WebChildWindow* pWnd = WebChildWindow::create(info); + + if (!pWnd) + return 0; + + return *pWnd; +} + +static const CLSID CLSID_MozillaBrowser = + {0x1339B54C, 0x3453, 0x11D2, {0x93, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + + +WebChildWindow::WebChildWindow(HWND hwnd, const WebChildWndInfo& info) + : super(hwnd, info._hwndFrame), + web_super(_navigator) +{ + // first try to create a web control with MS IE's CLASSID + HRESULT hr = create_control(hwnd, CLSID_WebBrowser, IID_IWebBrowser2); + + // If this failed, try to use Mozilla's web control + if (FAILED(hr)) + hr = create_control(hwnd, CLSID_MozillaBrowser, IID_IWebBrowser2); + + if (SUCCEEDED(hr)) { + _navigator.attach(_control); + + _connector = auto_ptr(new EventConnector(_control, DIID_DWebBrowserEvents2, this)); + + _control->Navigate(BStr(info._url), &vtMissing, &vtMissing, &vtMissing, &vtMissing); + //browser->Navigate2(&Variant(info._url), &vtMissing, &vtMissing, &vtMissing, &vtMissing); + } +} + +LRESULT WebChildWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) +{ + try { + switch(nmsg) { + case WM_ERASEBKGND: + if (!_control) { + HDC hdc = (HDC)wparam; + ClientRect rect(_hwnd); + + HBRUSH hbrush = CreateSolidBrush(RGB(200,200,235)); + BkMode mode(hdc, TRANSPARENT); + TextColor color(hdc, RGB(200,40,40)); + FillRect(hdc, &rect, hbrush); + DrawText(hdc, TEXT("Sorry - no web browser control could be loaded."), -1, &rect, DT_CENTER|DT_VCENTER|DT_SINGLELINE); + DeleteObject(hbrush); + } + + return TRUE; + + + case PM_DISPATCH_COMMAND: { + if (_control) { + HRESULT hr = E_FAIL; + + switch(LOWORD(wparam)) { + case ID_GO_BACK: + hr = _control->GoBack(); + break; + + case ID_GO_FORWARD: + hr = _control->GoForward(); + break; + + case ID_GO_UP: + ///@todo + break; + + case ID_GO_HOME: + hr = _control->GoHome(); + break; + + case ID_GO_SEARCH: + hr = _control->GoSearch(); + break; + + case ID_REFRESH: + hr = _control->Refresh(); + break; + + case ID_STOP: + hr = _control->Stop(); + break; + + default: + return super::WndProc(nmsg, wparam, lparam); + } + + if (FAILED(hr) && hr!=E_FAIL) + THROW_EXCEPTION(hr); + } + + return TRUE;} + + default: + return super::WndProc(nmsg, wparam, lparam); + } + } catch(COMException& e) { + HandleException(e, _hwnd); + } + + return 0; +} + + +String WebChildWindow::jump_to_int(LPCTSTR url) +{ + _navigator.goto_url(url); + + return url; +} diff --git a/reactos/subsys/system/ibrowser/webchild.h b/reactos/subsys/system/ibrowser/webchild.h new file mode 100644 index 00000000000..3ffc2a36316 --- /dev/null +++ b/reactos/subsys/system/ibrowser/webchild.h @@ -0,0 +1,1079 @@ +/* + * Copyright 2004, 2005 Martin Fuchs + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + + // + // ROS Internet Web Browser + // + // webchild.h + // + // Martin Fuchs, 25.01.2005 + // + + +#ifndef _MSC_VER +#include // for IConnectionPointContainer +#include // for DWebBrowserEvents2 IDs +#endif + +#ifndef DISPID_BEFORENAVIGATE // missing in MinGW (as of 07.02.2004) +#define DISPID_BEFORENAVIGATE 100 +#define DISPID_NAVIGATECOMPLETE 101 +#define DISPID_STATUSTEXTCHANGE 102 +#define DISPID_QUIT 103 +#define DISPID_DOWNLOADCOMPLETE 104 +#define DISPID_COMMANDSTATECHANGE 105 +#define DISPID_DOWNLOADBEGIN 106 +#define DISPID_NEWWINDOW 107 +#define DISPID_PROGRESSCHANGE 108 +#define DISPID_WINDOWMOVE 109 +#define DISPID_WINDOWRESIZE 110 +#define DISPID_WINDOWACTIVATE 111 +#define DISPID_PROPERTYCHANGE 112 +#define DISPID_TITLECHANGE 113 +#define DISPID_TITLEICONCHANGE 114 +#define DISPID_FRAMEBEFORENAVIGATE 200 +#define DISPID_FRAMENAVIGATECOMPLETE 201 +#define DISPID_FRAMENEWWINDOW 204 + +#define DISPID_NAVIGATECOMPLETE2 252 +#define DISPID_ONQUIT 253 +#define DISPID_ONVISIBLE 254 +#define DISPID_ONTOOLBAR 255 +#define DISPID_ONMENUBAR 256 +#define DISPID_ONSTATUSBAR 257 +#define DISPID_ONFULLSCREEN 258 +#define DISPID_DOCUMENTCOMPLETE 259 +#define DISPID_ONTHEATERMODE 260 +#define DISPID_ONADDRESSBAR 261 +#define DISPID_WINDOWSETRESIZABLE 262 +#define DISPID_WINDOWCLOSING 263 +#define DISPID_WINDOWSETLEFT 264 +#define DISPID_WINDOWSETTOP 265 +#define DISPID_WINDOWSETWIDTH 266 +#define DISPID_WINDOWSETHEIGHT 267 +#define DISPID_CLIENTTOHOSTWINDOW 268 +#define DISPID_SETSECURELOCKICON 269 +#define DISPID_FILEDOWNLOAD 270 +#define DISPID_NAVIGATEERROR 271 +#define DISPID_PRIVACYIMPACTEDSTATECHANGE 272 +#endif + +#ifndef V_INT // missing in MinGW (as of 07.02.2004) +#define V_INT(x) V_UNION(x, intVal) +#endif + +#ifdef _MSC_VER +#define NOVTABLE __declspec(novtable) +#else +#define NOVTABLE +#endif +#define ANSUNC + +#ifdef _MSC_VER +#pragma warning(disable: 4355) // use of 'this' for initialization of _connector +#endif + + +struct NOVTABLE ComSrvObject // NOVTABLE erlaubt, da protected Destruktor +{ +protected: + ComSrvObject() : _ref(1) {} + virtual ~ComSrvObject() {} + + ULONG _ref; +}; + +struct SimpleComObject : public ComSrvObject +{ + ULONG IncRef() {return ++_ref;} + ULONG DecRef() {ULONG ref=--_ref; if (!ref) {_ref++; delete this;} return ref;} +}; + + + // server object interfaces + +template struct IComSrvQI : public BASE +{ + IComSrvQI(REFIID uuid_base) + : _uuid_base(uuid_base) + { + } + + STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppv) {*ppv=0; + if (IsEqualIID(riid, _uuid_base) || + IsEqualIID(riid, IID_IUnknown)) {*ppv=static_cast(this); this->AddRef(); return S_OK;} + return E_NOINTERFACE;} + +protected: + IComSrvQI() {} + + REFIID _uuid_base; +}; + +template<> struct IComSrvQI : public IUnknown +{ + STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppv) {*ppv=0; + if (IsEqualIID(riid, IID_IUnknown)) {*ppv=this; AddRef(); return S_OK;} + return E_NOINTERFACE;} + +protected: + IComSrvQI() {} +}; + + +template + class IComSrvBase : public IComSrvQI +{ + typedef IComSrvQI super; + +protected: + IComSrvBase(REFIID uuid_base) + : super(uuid_base) + { + } + +public: + STDMETHODIMP_(ULONG) AddRef() {return static_cast(this)->IncRef();} + STDMETHODIMP_(ULONG) Release() {return static_cast(this)->DecRef();} +}; + + +template struct ConnectionPoint : public SIfacePtr +{ + ConnectionPoint(IConnectionPointContainer* pCPC, REFIID riid) + { + CheckError(pCPC->FindConnectionPoint(riid, &this->_p)); + } +}; + +struct EventConnection +{ + EventConnection(IConnectionPoint* connectionpoint, IUnknown* sink) + { + CheckError(connectionpoint->Advise(sink, &_cookie)); + _connectionpoint = connectionpoint; + } + + template EventConnection(T& connectionpoint, IUnknown* sink) + { + CheckError(connectionpoint->Advise(sink, &_cookie)); + _connectionpoint = connectionpoint; + } + +/* template EventConnection(SIfacePtr& connectionpoint, IUnknown* sink) + { + CheckError(connectionpoint->Advise(sink, &_cookie)); + _connectionpoint = connectionpoint.GetPtr(); + } */ + +/* template EventConnection(T& connectionpoint, IUnknown* sink) + { + CheckError(connectionpoint->Advise(sink, &_cookie)); + _connectionpoint = connectionpoint; + } */ + + ~EventConnection() + { + if (_connectionpoint) + _connectionpoint->Unadvise(_cookie); + } + +protected: + SIfacePtr _connectionpoint; + DWORD _cookie; +}; + +struct EventConnector : public EventConnection +{ + EventConnector(IUnknown* unknown, REFIID riid, IUnknown* sink) + : EventConnection(ConnectionPoint( + SIfacePtr(unknown, IID_IConnectionPointContainer), riid), sink) + { + } +}; + + +struct OleInPlaceClient : public SimpleComObject, + public IOleClientSite, + public IOleInPlaceSite +{ +protected: + HWND _hwnd; + +public: + OleInPlaceClient(HWND hwnd=0) + : _hwnd(hwnd) + { + } + + void attach(HWND hwnd) + { + _hwnd = hwnd; + } + + HRESULT attach_control(IOleObject* ole_obj, LONG iVerb=OLEIVERB_INPLACEACTIVATE, HWND hwndParent=0, LPCRECT pRect=NULL) + { + HRESULT hr = ole_obj->SetClientSite(this); + if (FAILED(hr)) + return hr; + +// hr = ole_obj->SetHostNames(app, doc)); + + hr = ole_obj->DoVerb(iVerb, NULL, this, 0, 0/*hwnd*/, NULL/*&rcPos*/); + + return hr; + } + + HRESULT detach(IOleObject* ole_obj, DWORD dwSaveOption=OLECLOSE_SAVEIFDIRTY) + { + HRESULT hr = ole_obj->Close(dwSaveOption); + + _hwnd = 0; + + return hr; + } + + STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppv) + { + if (IsEqualIID(riid, IID_IOleClientSite)) + {*ppv=static_cast(this); IncRef(); return S_OK;} + + if (IsEqualIID(riid, IID_IOleInPlaceSite)) + {*ppv=static_cast(this); IncRef(); return S_OK;} + + if (IsEqualIID(riid, IID_IUnknown)) + {*ppv=static_cast(this); IncRef(); return S_OK;} + + return E_NOINTERFACE; + } + + STDMETHODIMP_(ULONG) AddRef() {return IncRef();} + STDMETHODIMP_(ULONG) Release() {return DecRef();} + + + // IOleWindow: + + virtual /* [input_sync] */ HRESULT STDMETHODCALLTYPE GetWindow(/* [out] */ HWND __RPC_FAR *phwnd) + { + *phwnd = _hwnd; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(/* [in] */ BOOL fEnterMode) + { + return E_NOTIMPL; + } + + + // IOleClientSite: + + virtual HRESULT STDMETHODCALLTYPE SaveObject() + { + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker __RPC_FAR *__RPC_FAR *ppmk) + { + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE GetContainer(IOleContainer __RPC_FAR *__RPC_FAR *ppContainer) + { + ppContainer = 0; + return E_NOINTERFACE; + } + + virtual HRESULT STDMETHODCALLTYPE ShowObject() + { + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE OnShowWindow(BOOL fShow) + { + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE RequestNewObjectLayout() + { + return S_OK; + } + + + // IOleInPlaceSite: + + virtual HRESULT STDMETHODCALLTYPE CanInPlaceActivate() + { + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE OnInPlaceActivate() + { + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE OnUIActivate() + { + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE GetWindowContext( + /* [out] */ IOleInPlaceFrame __RPC_FAR *__RPC_FAR *ppFrame, + /* [out] */ IOleInPlaceUIWindow __RPC_FAR *__RPC_FAR *ppDoc, + /* [out] */ LPRECT lprcPosRect, + /* [out] */ LPRECT lprcClipRect, + /* [out][in] */ LPOLEINPLACEFRAMEINFO lpFrameInfo) + { + ClientRect rect(_hwnd); + + ppFrame = 0; + ppDoc = 0; + *lprcPosRect = rect; + *lprcClipRect = rect; + + assert(lpFrameInfo->cb>=sizeof(OLEINPLACEFRAMEINFO)); + lpFrameInfo->fMDIApp = FALSE; + lpFrameInfo->hwndFrame = 0; + lpFrameInfo->haccel = 0; + lpFrameInfo->cAccelEntries = 0; + + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE Scroll(/* [in] */ SIZE scrollExtant) + { + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE OnUIDeactivate(/* [in] */ BOOL fUndoable) + { + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE OnInPlaceDeactivate() + { + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE DiscardUndoState() + { + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE DeactivateAndUndo() + { + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE OnPosRectChange(/* [in] */ LPCRECT lprcPosRect) + { + return S_OK; + } +}; + + + // window with in place activates Active-X Control + +template struct IPCtrlWindow : public BASE +{ + typedef BASE super; + + IPCtrlWindow(HWND hwnd) + : super(hwnd) + { + } + + template IPCtrlWindow(HWND hwnd, T& info) + : super(hwnd, info) + { + } + + HRESULT create_control(HWND hwnd, REFIID clsid, REFIID riid) + { + // Erzeugen einer Instanz des Controls + HRESULT hr = _control.CreateInstance(clsid, riid); + if (FAILED(hr)) + return hr; + + _client_side.attach(hwnd); + + hr = _client_side.attach_control(SIfacePtr(_control, IID_IOleObject)/*, OLEIVERB_INPLACEACTIVATE, + hwnd, &Rect(10, 10, 500, 500)*/); + if (FAILED(hr)) + return hr; + + // try to get a IOleInPlaceObject interface for window resizing + return _control.QueryInterface(IID_IOleInPlaceObject, &_in_place_object); // _in_place_object = _control + } + +protected: + LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) + { + if (nmsg == WM_SIZE) { + if (_in_place_object) { + RECT rect = {0, 0, LOWORD(lparam), HIWORD(lparam)}; + + _in_place_object->SetObjectRects(&rect, &rect); + } + } else if (nmsg == WM_CLOSE) { + _in_place_object = NULL; + + if (_control) { + _client_side.detach(SIfacePtr(_control, IID_IOleObject), OLECLOSE_NOSAVE); + _control = NULL; + } + } + + return super::WndProc(nmsg, wparam, lparam); + } + + ComInit _usingCOM; + SMARTPTR _control; + OleInPlaceClient _client_side; + SIfacePtr _in_place_object; +}; + + + +#include "exdispid.h" + + +struct DWebBrowserEvents2IF +{ + virtual void StatusTextChange(const BStr& text) + {} + + virtual void ProgressChange(long progress, long progressMax) + {} + + virtual void WindowMove() + {} + + virtual void WindowResize() + {} + + virtual void WindowActivate() + {} + + virtual void PropertyChange(const BStr& property) + {} + + virtual void DownloadComplete() + {} + + virtual void CommandStateChange(long command, bool enable) + {} + + virtual void DownloadBegin() + {} + + virtual void NewWindow2(IDispatch** ppDisp, VARIANT_BOOL& cancel) + {} + + virtual void TitleChange(const BStr& text) + {} + + virtual void TitleIconChange(const BStr& text) + {} + + virtual void FrameBeforeNavigate(const BStr& url, long flags, const BStr& targetFrameName, VARIANT* postData, const BStr& headers, VARIANT_BOOL& cancel) + {} + + virtual void FrameNavigateComplete(const BStr& url) + {} + + virtual void FrameNewWindow(const BStr&url, long flags, const BStr& targetFrameName, VARIANT* postData, const BStr& headers, VARIANT_BOOL& processed) + {} + + virtual void BeforeNavigate2(IDispatch* pDisp, const Variant& url, const Variant& flags, + const Variant& targetFrameName, const Variant& postData, + const Variant& headers, VARIANT_BOOL& cancel) + {} + + virtual void NavigateComplete2(IDispatch* pDisp, const Variant& url) + {} + + virtual void OnQuit() + {} + + virtual void OnVisible(bool Visible) + {} + + virtual void OnToolbar(bool Visible) + {} + + virtual void OnMenubar(bool Visible) + {} + + virtual void OnStatusbar(bool Visible) + {} + + virtual void OnFullscreen(bool Visible) + {} + + virtual void DocumentComplete() + {} + + virtual void OnTheatermode(bool Visible) + {} + + virtual void OnAddressbar(bool Visible) + {} + + virtual void WindowSetResizable(bool Visible) + {} + + virtual void WindowClosing(VARIANT_BOOL IsChildWindow, VARIANT_BOOL& cancel) + {} + + virtual void WindowSetLeft(long Left) + {} + + virtual void WindowSetTop(long Top) + {} + + virtual void WindowSetWidth(long Width) + {} + + virtual void WindowSetHeight(long Height) + {} + + virtual void ClientToHostWindow(long& CX, long& CY) + {} + + virtual void SetSecureLockIcon(long SecureLockIcon) + {} + + virtual void FileDownload(Variant& cancel) + {} + + virtual void NavigateError(IDispatch* pDisp, const Variant& url, const Variant& Frame, const Variant& StatusCode, VARIANT_BOOL& cancel) + {} + + virtual void PrivacyImpactedStateChange(bool bImpacted) + {} +}; + + + // The web browser control has to be initialized completely before being able, + // to display a page, that does not access internet. +struct ANSUNC BrowserNavigator +{ + BrowserNavigator(); + + void attach(IWebBrowser* browser); + void goto_url(LPCTSTR url); + void set_html_page(const String& html_txt); + void navigated(LPCTSTR url); + + IWebBrowser* get_browser() {return _browser.get();} + +protected: + SIfacePtr _browser; + String _new_url; + String _new_html_txt; + bool _browser_initialized; +}; + + + // MinGW defines a wrong FixedDWebBrowserEvents2 interface with virtual functions for DISPID calls, so we use our own, corrected version: +interface FixedDWebBrowserEvents2 : public IDispatch +{ +}; + +struct ANSUNC DWebBrowserEvents2Impl : public SimpleComObject, + public IComSrvBase, + public DWebBrowserEvents2IF +{ + typedef IComSrvBase super; + + + DWebBrowserEvents2IF* _callback; + + + DWebBrowserEvents2Impl(BrowserNavigator& navigator) + : super(DIID_DWebBrowserEvents2), + _navigator(navigator) + { + _callback = this; + } + + +/* // IUnknown + STDMETHOD(QueryInterface)(REFIID riid, LPVOID* ppv) + { + *ppv = NULL; + + if (SUCCEEDED(super::QueryInterface(riid, ppv))) + return S_OK; + + return E_NOINTERFACE; + } */ + + + // IDispatch + STDMETHOD(GetTypeInfoCount)(UINT* pctinfo) + {return E_NOTIMPL;} + + STDMETHOD(GetTypeInfo)(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) + {return E_NOTIMPL;} + + STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) + {return E_NOTIMPL;} + + STDMETHOD(Invoke)(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, + DISPPARAMS __RPC_FAR *pDispParams, VARIANT __RPC_FAR *pVarResult, EXCEPINFO __RPC_FAR *pExcepInfo, UINT __RPC_FAR *puArgErr) + { + switch(dispIdMember) { + case DISPID_STATUSTEXTCHANGE: + _callback->StatusTextChange((BStr)Variant(pDispParams->rgvarg[0])); + break; + + case DISPID_COMMANDSTATECHANGE: + _callback->CommandStateChange(Variant(pDispParams->rgvarg[1]), Variant(pDispParams->rgvarg[0])); + break; + + case DISPID_DOWNLOADBEGIN: + _callback->DownloadBegin(); + break; + + case DISPID_PROGRESSCHANGE: // sent when download progress is updated + _callback->ProgressChange(Variant(pDispParams->rgvarg[1]), Variant(pDispParams->rgvarg[0])); + break; + + case DISPID_WINDOWMOVE: // sent when main window has been moved + _callback->WindowMove(); + break; + + case DISPID_WINDOWRESIZE: // sent when main window has been sized + _callback->WindowResize(); + break; + + case DISPID_WINDOWACTIVATE: // sent when main window has been activated + _callback->WindowActivate(); + break; + + case DISPID_PROPERTYCHANGE: // sent when the PutProperty method is called + _callback->PropertyChange((BStr)Variant(pDispParams->rgvarg[0])); + break; + + case DISPID_TITLECHANGE: // sent when the document title changes + _callback->TitleChange((BStr)Variant(pDispParams->rgvarg[0])); + break; + + case DISPID_TITLEICONCHANGE: // sent when the top level window icon may have changed. + _callback->TitleIconChange((BStr)Variant(pDispParams->rgvarg[0])); + break; + + + // anything below here is not present in DWebBrowserEvents, only in DWebBrowserEvents2: -> + + case DISPID_FRAMEBEFORENAVIGATE: + if (pDispParams->cArgs != 6) + return E_INVALIDARG; + if (V_VT(&pDispParams->rgvarg[0]) != (VT_BOOL|VT_BYREF)) + return E_INVALIDARG; + _callback->FrameBeforeNavigate( + (BStr)Variant(&pDispParams->rgvarg[5]), Variant(&pDispParams->rgvarg[4]), + (BStr)Variant(&pDispParams->rgvarg[3]), &pDispParams->rgvarg[2], + (BStr)Variant(&pDispParams->rgvarg[1]), *V_BOOLREF(&pDispParams->rgvarg[0])); + break; + + case DISPID_FRAMENAVIGATECOMPLETE: + if (pDispParams->cArgs != 1) + return E_INVALIDARG; + _callback->FrameNavigateComplete((BStr)Variant(pDispParams->rgvarg[0])); + break; + + case DISPID_FRAMENEWWINDOW: + if (pDispParams->cArgs != 6) + return E_INVALIDARG; + if (V_VT(&pDispParams->rgvarg[0]) != (VT_BOOL|VT_BYREF)) + return E_INVALIDARG; + _callback->FrameNewWindow((BStr)Variant(&pDispParams->rgvarg[5]), Variant(&pDispParams->rgvarg[4]), + (BStr)Variant(&pDispParams->rgvarg[3]), &pDispParams->rgvarg[2], + (BStr)Variant(&pDispParams->rgvarg[1]), *V_BOOLREF(&pDispParams->rgvarg[0])); + break; + + case DISPID_BEFORENAVIGATE2: // hyperlink clicked on + if (pDispParams->cArgs != 7) + return E_INVALIDARG; + if (V_VT(&pDispParams->rgvarg[0]) != (VT_BOOL|VT_BYREF)) + return E_INVALIDARG; + _callback->BeforeNavigate2(Variant(pDispParams->rgvarg[6]), + pDispParams->rgvarg[5], &pDispParams->rgvarg[4], + pDispParams->rgvarg[3], &pDispParams->rgvarg[2], + pDispParams->rgvarg[1], *V_BOOLREF(&pDispParams->rgvarg[0])); + break; + + case DISPID_NEWWINDOW2: // sent when a new window should be created + if (pDispParams->cArgs != 2) + return E_INVALIDARG; + if (V_VT(&pDispParams->rgvarg[0]) != (VT_BOOL|VT_BYREF)) + return E_INVALIDARG; + if (V_VT(&pDispParams->rgvarg[1]) != (VT_DISPATCH|VT_BYREF)) + return E_INVALIDARG; + _callback->NewWindow2(V_DISPATCHREF(&pDispParams->rgvarg[1]), *V_BOOLREF(&pDispParams->rgvarg[0])); + break; + + case DISPID_NAVIGATECOMPLETE2:// UIActivate new document + if (pDispParams->cArgs != 2) + return E_INVALIDARG; + + // notify the navigator + NavigateComplete2(Variant(pDispParams->rgvarg[1]), Variant(pDispParams->rgvarg[0])); + + _callback->NavigateComplete2(Variant(pDispParams->rgvarg[1]), Variant(pDispParams->rgvarg[0])); + break; + + case DISPID_ONQUIT: + _callback->OnQuit(); + break; + + case DISPID_ONVISIBLE: // sent when the window goes visible/hidden + if (pDispParams->cArgs != 1) + return E_INVALIDARG; + _callback->OnVisible(Variant(pDispParams->rgvarg[0])); + break; + + case DISPID_ONTOOLBAR: // sent when the toolbar should be shown/hidden + if (pDispParams->cArgs != 1) + return E_INVALIDARG; + _callback->OnToolbar(Variant(pDispParams->rgvarg[0])); + break; + + case DISPID_ONMENUBAR: // sent when the menubar should be shown/hidden + if (pDispParams->cArgs != 1) + return E_INVALIDARG; + _callback->OnMenubar(Variant(pDispParams->rgvarg[0])); + break; + + case DISPID_ONSTATUSBAR: // sent when the statusbar should be shown/hidden + if (pDispParams->cArgs != 1) + return E_INVALIDARG; + _callback->OnStatusbar(Variant(pDispParams->rgvarg[0])); + break; + + case DISPID_ONFULLSCREEN: // sent when kiosk mode should be on/off + if (pDispParams->cArgs != 1) + return E_INVALIDARG; + _callback->OnFullscreen(Variant(pDispParams->rgvarg[0])); + break; + + case DISPID_DOCUMENTCOMPLETE:// new document goes ReadyState_Complete + _callback->DocumentComplete(); + break; + + case DISPID_DOWNLOADCOMPLETE: + _callback->DownloadComplete(); + break; + + case DISPID_ONTHEATERMODE: // sent when theater mode should be on/off + if (pDispParams->cArgs != 1) + return E_INVALIDARG; + _callback->OnTheatermode(Variant(pDispParams->rgvarg[0])); + break; + + case DISPID_ONADDRESSBAR: // sent when the address bar should be shown/hidden + if (pDispParams->cArgs != 1) + return E_INVALIDARG; + _callback->OnAddressbar(Variant(pDispParams->rgvarg[0])); + break; + + case DISPID_WINDOWSETRESIZABLE:// sent to set the style of the host window frame + if (pDispParams->cArgs != 1) + return E_INVALIDARG; + _callback->WindowSetResizable(Variant(pDispParams->rgvarg[0])); + break; + + case DISPID_WINDOWCLOSING: // sent before script window.close closes the window + if (pDispParams->cArgs != 2) + return E_INVALIDARG; + if (V_VT(&pDispParams->rgvarg[0]) != (VT_BOOL|VT_BYREF)) + return E_INVALIDARG; + _callback->WindowClosing(Variant(pDispParams->rgvarg[1]), *V_BOOLREF(&pDispParams->rgvarg[0])); + break; + + case DISPID_WINDOWSETLEFT: // sent when the put_left method is called on the WebOC + if (pDispParams->cArgs != 1) + return E_INVALIDARG; + _callback->WindowSetLeft(Variant(pDispParams->rgvarg[0])); + break; + + case DISPID_WINDOWSETTOP: // sent when the put_top method is called on the WebOC + if (pDispParams->cArgs != 1) + return E_INVALIDARG; + _callback->WindowSetTop(Variant(pDispParams->rgvarg[0])); + break; + + case DISPID_WINDOWSETWIDTH: // sent when the put_width method is called on the WebOC + if (pDispParams->cArgs != 1) + return E_INVALIDARG; + _callback->WindowSetWidth(Variant(pDispParams->rgvarg[0])); + break; + + case DISPID_WINDOWSETHEIGHT: // sent when the put_height method is called on the WebOC + if (pDispParams->cArgs != 1) + return E_INVALIDARG; + _callback->WindowSetHeight(Variant(pDispParams->rgvarg[0])); + break; + + case DISPID_CLIENTTOHOSTWINDOW:// sent during window.open to request conversion of dimensions + if (pDispParams->cArgs != 2) + return E_INVALIDARG; + if (V_VT(&pDispParams->rgvarg[0]) != (VT_I4|VT_BYREF)) + return E_INVALIDARG; + if (V_VT(&pDispParams->rgvarg[1]) != (VT_I4|VT_BYREF)) + return E_INVALIDARG; + _callback->ClientToHostWindow(*V_I4REF(&pDispParams->rgvarg[1]), *V_I4REF(&pDispParams->rgvarg[0])); + break; + + case DISPID_SETSECURELOCKICON:// sent to suggest the appropriate security icon to show + if (pDispParams->cArgs != 1) + return E_INVALIDARG; + _callback->SetSecureLockIcon(Variant(pDispParams->rgvarg[0])); + break; + + case DISPID_FILEDOWNLOAD: { // Fired to indicate the File Download dialog is opening + if (pDispParams->cArgs != 1) //@@ every time 2 ?! + return E_INVALIDARG; + Variant var(pDispParams->rgvarg[0]); + _callback->FileDownload(var);} + break; + + case DISPID_NAVIGATEERROR: // Fired to indicate the a binding error has occured + if (pDispParams->cArgs != 5) + return E_INVALIDARG; + if (V_VT(&pDispParams->rgvarg[0]) != (VT_BOOL|VT_BYREF)) + return E_INVALIDARG; + _callback->NavigateError(Variant(pDispParams->rgvarg[4]), Variant(pDispParams->rgvarg[3]), + Variant(pDispParams->rgvarg[2]), Variant(pDispParams->rgvarg[1]), + *V_BOOLREF(&pDispParams->rgvarg[0])); + break; + + case DISPID_PRIVACYIMPACTEDSTATECHANGE:// Fired when the user's browsing experience is impacted + if (pDispParams->cArgs != 1) + return E_INVALIDARG; + _callback->PrivacyImpactedStateChange(Variant(pDispParams->rgvarg[0])); + break; + + default: + return NOERROR; + } + + return S_OK; + } + +protected: + BrowserNavigator& _navigator; + + void NavigateComplete2(IDispatch* pDisp, const Variant& url) + { + String adr = (BStr)url; + + _navigator.navigated(adr); + } +}; + + + /// encapsulation of the Web control +struct WebChildWindow : public IPCtrlWindow >, + public DWebBrowserEvents2Impl +{ + typedef IPCtrlWindow > super; + typedef DWebBrowserEvents2Impl web_super; + + WebChildWindow(HWND hwnd, const WebChildWndInfo& info); + + static WebChildWindow* create(const WebChildWndInfo& info) + { + ChildWindow* child = ChildWindow::create(info, + WINDOW_CREATOR_INFO(WebChildWindow,WebChildWndInfo), CLASSNAME_CHILDWND, NULL, WS_CHILD|WS_VISIBLE); + + return static_cast(child); + } + + + // DWebBrowserEvents2Impl overides -> + + void BeforeNavigate2(IDispatch* pDisp, const Variant& url, const Variant& flags, + const Variant& targetFrameName, const Variant& postData, + const Variant& headers, VARIANT_BOOL& cancel) + { + //String adr = (BStr)url; + } + + void NavigateComplete2(IDispatch* pDisp, const Variant& url) + { + web_super::NavigateComplete2(pDisp, url); + + set_url(String(BStr(url))); + } + + void StatusTextChange(const BStr& text) + { + _statusText = text; + SendMessage(_hwndFrame, PM_SETSTATUSTEXT, 0, (LPARAM)_statusText.c_str()); + } + + void ProgressChange(long Progress, long ProgressMax) + { + } + + void WindowMove() + { + } + + void WindowResize() + { + } + + void WindowActivate() + { + } + + void PropertyChange(const BStr& Property) + { + Variant value; + _control->GetProperty(Property, &value); + } + + void CommandStateChange(long command/*CSC_NAVIGATEFORWARD, CSC_NAVIGATEBACK*/, bool enable) + { + } + + void DownloadBegin() + { + } + + void NewWindow2(IDispatch** ppDisp, VARIANT_BOOL& cancel) + { + //*ppDisp = ; + //cancel = TRUE; + } + + void TitleChange(const BStr& text) + { + SetWindowText(_hwnd, String(text)); + } + + void TitleIconChange(const BStr& text) + { + } + + void FrameBeforeNavigate(const BStr& url, long flags, const BStr& targetFrameName, VARIANT* postData, const BStr& headers, VARIANT_BOOL& cancel) + { + } + + void FrameNavigateComplete(const BStr& url) + { + } + + void FrameNewWindow(const BStr& url, long flags, const BStr& targetFrameName, VARIANT* postData, const BStr& headers, VARIANT_BOOL& processed) + { + } + + void OnQuit() + { + } + + void OnVisible(bool Visible) + { + } + + void OnToolbar(bool Visible) + { + } + + void OnMenubar(bool Visible) + { + } + + void OnStatusbar(bool Visible) + { + } + + void OnFullscreen(bool Visible) + { + } + + void DocumentComplete() + { + } + + void OnTheatermode(bool Visible) + { + } + + void OnAddressbar(bool Visible) + { + } + + void WindowSetResizable(bool Visible) + { + } + + void WindowClosing(VARIANT_BOOL IsChildWindow, VARIANT_BOOL& cancel) + { + } + + void WindowSetLeft(long Left) + { + } + + void WindowSetTop(long Top) + { + } + + void WindowSetWidth(long Width) + { + } + + void WindowSetHeight(long Height) + { + } + + void ClientToHostWindow(long& CX, long& CY) + { + } + + void SetSecureLockIcon(long SecureLockIcon) + { + } + + void FileDownload(Variant& cancel) + { + } + + void NavigateError(IDispatch* pDisp, const Variant& url, const Variant& Frame, const Variant& StatusCode, VARIANT_BOOL& cancel) + { + } + + void PrivacyImpactedStateChange(bool bImpacted) + { + } + + +protected: + BrowserNavigator _navigator; + auto_ptr _connector; + + LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam); + + virtual String jump_to_int(LPCTSTR url); +};