├── .gitignore ├── .gitmodules ├── demos ├── CMakeLists.txt ├── simple │ ├── CMakeLists.txt │ └── simple.cpp ├── resource │ ├── CMakeLists.txt │ └── resource.cpp ├── simple-headless │ ├── CMakeLists.txt │ └── simple-headless.cpp ├── cefsimple │ ├── README.md │ ├── simple_handler_win.cc │ ├── CMakeLists.txt │ ├── simple_app.h │ ├── LICENSE.txt │ ├── simple_handler_linux.cc │ ├── cefsimple_linux.cc │ ├── simple_handler.h │ ├── cefsimple_win.cc │ ├── simple_app.cc │ └── simple_handler.cc └── file-manager │ ├── CMakeLists.txt │ ├── FileManager.hpp │ ├── FileManager.cpp │ ├── file-manager-main.cpp │ └── win_dirent.h ├── index.html ├── html ├── hello-demos.html └── file-manager.html ├── common ├── CMakeLists.txt └── common │ ├── Resources.hpp │ ├── Resources.cpp │ ├── PlatformUtil.hpp │ └── PlatformUtil.cpp ├── README.md ├── CMakeLists.txt ├── LICENSE.txt └── cmake └── src_group.cmake /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | 3 | # IDEs and editors 4 | .vscode/ 5 | 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "cef-cmake"] 2 | path = cef-cmake 3 | url = https://github.com/iboB/cef-cmake.git 4 | -------------------------------------------------------------------------------- /demos/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(simple) 2 | add_subdirectory(cefsimple) 3 | add_subdirectory(simple-headless) 4 | add_subdirectory(resource) 5 | add_subdirectory(file-manager) 6 | -------------------------------------------------------------------------------- /demos/simple/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(simple 2 | simple.cpp 3 | ${CEF_CMAKE_EXECUTABLE_RESOURCES} 4 | ) 5 | 6 | target_link_libraries(simple 7 | cefdll_wrapper 8 | ) 9 | -------------------------------------------------------------------------------- /demos/resource/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(resource 2 | resource.cpp 3 | ${CEF_CMAKE_EXECUTABLE_RESOURCES} 4 | ) 5 | 6 | target_link_libraries(resource 7 | demos-common 8 | ) 9 | -------------------------------------------------------------------------------- /demos/simple-headless/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(simple-headless 2 | simple-headless.cpp 3 | ${CEF_CMAKE_EXECUTABLE_RESOURCES} 4 | ) 5 | 6 | target_link_libraries(simple-headless 7 | cefdll_wrapper 8 | ) 9 | -------------------------------------------------------------------------------- /demos/cefsimple/README.md: -------------------------------------------------------------------------------- 1 | # cefsimple 2 | 3 | A copy of the cefsimple test from the CEF project. Here to make sure everything is backwards compatible. 4 | 5 | Note that it has a different license than the rest. This demo in under the BSD 3-Clause License, while the rest are under MIT. 6 | 7 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CEF Demos 5 | 6 | 7 |

CEF Demos

8 |

This page serves as a holder for demo html files for CEF-Demos.

9 | 10 | 11 | -------------------------------------------------------------------------------- /html/hello-demos.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hello CEF Demos 5 | 6 | 7 |

Hello CEF Demos

8 |

This is a simple html file

9 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /demos/file-manager/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(file-manager 2 | file-manager-main.cpp 3 | FileManager.cpp 4 | FileManager.hpp 5 | ${CEF_CMAKE_EXECUTABLE_RESOURCES} 6 | ) 7 | 8 | target_link_libraries(file-manager 9 | demos-common 10 | ) 11 | 12 | if(MSVC) 13 | target_compile_definitions(file-manager PRIVATE 14 | -D_CRT_SECURE_NO_WARNINGS 15 | ) 16 | endif() 17 | -------------------------------------------------------------------------------- /common/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(srcs) 2 | src_group(resource srcs 3 | common/Resources.hpp 4 | common/Resources.cpp 5 | ) 6 | 7 | src_group(platform srcs 8 | common/PlatformUtil.hpp 9 | common/PlatformUtil.cpp 10 | ) 11 | 12 | add_library(demos-common STATIC 13 | ${srcs} 14 | ) 15 | 16 | target_include_directories(demos-common PUBLIC .) 17 | 18 | target_link_libraries(demos-common PUBLIC 19 | cefdll_wrapper 20 | ) 21 | -------------------------------------------------------------------------------- /demos/cefsimple/simple_handler_win.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights 2 | // reserved. Use of this source code is governed by a BSD-style license that 3 | // can be found in the LICENSE file. 4 | 5 | #include "tests/cefsimple/simple_handler.h" 6 | 7 | #include 8 | #include 9 | 10 | #include "include/cef_browser.h" 11 | 12 | void SimpleHandler::PlatformTitleChange(CefRefPtr browser, 13 | const CefString& title) { 14 | CefWindowHandle hwnd = browser->GetHost()->GetWindowHandle(); 15 | SetWindowText(hwnd, std::wstring(title).c_str()); 16 | } 17 | -------------------------------------------------------------------------------- /common/common/Resources.hpp: -------------------------------------------------------------------------------- 1 | // CEF-Demos 2 | // Copyright (c) 2019 Borislav Stanimirov 3 | // 4 | // Distributed under the MIT Software License 5 | // See accompanying file LICENSE.txt or copy at 6 | // http://opensource.org/licenses/MIT 7 | // 8 | #pragma once 9 | 10 | #include 11 | #include 12 | 13 | 14 | namespace cefdemos 15 | { 16 | 17 | class Resources 18 | { 19 | public: 20 | // setup a resource manager to associate uris below `uri` to point to files below the directory `dir` 21 | static void setupResourceManagerDirectoryProvider(CefRefPtr resource_manager, std::string uri, std::string dir); 22 | }; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /common/common/Resources.cpp: -------------------------------------------------------------------------------- 1 | // CEF-Demos 2 | // Copyright (c) 2019 Borislav Stanimirov 3 | // 4 | // Distributed under the MIT Software License 5 | // See accompanying file LICENSE.txt or copy at 6 | // http://opensource.org/licenses/MIT 7 | // 8 | #include "Resources.hpp" 9 | 10 | namespace cefdemos 11 | { 12 | 13 | void Resources::setupResourceManagerDirectoryProvider(CefRefPtr resource_manager, std::string uri, std::string dir) 14 | { 15 | if (!CefCurrentlyOn(TID_IO)) { 16 | // Execute on the browser IO thread. 17 | CefPostTask(TID_IO, base::Bind(&Resources::setupResourceManagerDirectoryProvider, resource_manager, uri, dir)); 18 | return; 19 | } 20 | 21 | resource_manager->AddDirectoryProvider(uri, dir, 1, dir); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /demos/file-manager/FileManager.hpp: -------------------------------------------------------------------------------- 1 | // CEF-Demos 2 | // Copyright (c) 2019 Borislav Stanimirov 3 | // 4 | // Distributed under the MIT Software License 5 | // See accompanying file LICENSE.txt or copy at 6 | // http://opensource.org/licenses/MIT 7 | // 8 | // GUI-agnostic file manager code 9 | #pragma once 10 | 11 | #include 12 | #include 13 | 14 | namespace fileman 15 | { 16 | 17 | class FileManager 18 | { 19 | public: 20 | FileManager(); 21 | ~FileManager(); 22 | 23 | struct DirectoryContents 24 | { 25 | std::vector files; 26 | std::vector dirs; 27 | }; 28 | 29 | // path will be interpreted as relative to inner path 30 | DirectoryContents getDirectoryContents(const char* path); 31 | 32 | private: 33 | std::string m_path; 34 | }; 35 | 36 | } -------------------------------------------------------------------------------- /common/common/PlatformUtil.hpp: -------------------------------------------------------------------------------- 1 | // CEF-Demos 2 | // Copyright (c) 2019 Borislav Stanimirov 3 | // 4 | // Distributed under the MIT Software License 5 | // See accompanying file LICENSE.txt or copy at 6 | // http://opensource.org/licenses/MIT 7 | // 8 | #pragma once 9 | 10 | #include 11 | 12 | namespace cefdemos 13 | { 14 | 15 | class PlatformUtil 16 | { 17 | public: 18 | // get the full path to the current executable 19 | static std::string getCurrentExecutablePath(); 20 | 21 | // starts looking from the current directory upwards until it discovers a valid subdirectory described by assetDir 22 | // for example 23 | // getAssetPath("/home/someuser/projects/xxx/build/bin", "assets"); will return /home/someuser/projects/xxx/assests if this directory exists 24 | static std::string getAssetPath(std::string baseDir, const std::string& assetDir); 25 | 26 | }; 27 | 28 | } 29 | -------------------------------------------------------------------------------- /demos/cefsimple/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(srcs) 2 | 3 | src_group(sources srcs 4 | simple_app.cc 5 | simple_app.h 6 | simple_handler.cc 7 | simple_handler.h 8 | ) 9 | 10 | if(CEFDEMOS_OS_LINUX) 11 | src_group(sources srcs 12 | cefsimple_linux.cc 13 | simple_handler_linux.cc 14 | ) 15 | elseif(CEFDEMOS_OS_MACOSX) 16 | src_group(sources srcs 17 | cefsimple_mac.mm 18 | simple_handler_mac.mm 19 | ) 20 | elseif(CEFDEMOS_OS_WINDOWS) 21 | src_group(sources srcs 22 | cefsimple_win.cc 23 | simple_handler_win.cc 24 | ) 25 | endif() 26 | 27 | add_executable(cefsimple 28 | ${srcs} 29 | ${CEF_CMAKE_EXECUTABLE_RESOURCES} 30 | ) 31 | 32 | if(CEFDEMOS_OS_WINDOWS) 33 | set_target_properties(cefsimple PROPERTIES WIN32_EXECUTABLE 1) 34 | endif() 35 | 36 | target_link_libraries(cefsimple 37 | cefdll_wrapper 38 | ) 39 | 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CEF Demos 2 | 3 | Small CEF Demos 4 | 5 | *More docs to come* 6 | 7 | ## Demos 8 | 9 | The simple demos have no external dependencies other than CEF and the cef.dll wrapper. 10 | 11 | * **cefsimple** - A copy of the cefsimple test from the CEF project. Here to make sure everything is backwards compatible. 12 | * **simple** - A bare-bones minimal example which launches a browser. 13 | * **simple-headless** - A minimal headless browser example 14 | 15 | The other demos depend on the `demos-common` library defined [here](common). 16 | 17 | * **resource** - Uses a resource manager to load files from the `html` subdirectory 18 | * **file-manager** - A file manager demo with HTML GUI 19 | 20 | ## License and copyright 21 | 22 | This software is distributed under the MIT Software License. 23 | 24 | See accompanying file LICENSE.txt or copy [here](https://opensource.org/licenses/MIT). 25 | 26 | Copyright © 2019 [Borislav Stanimirov](http://github.com/iboB) 27 | -------------------------------------------------------------------------------- /demos/cefsimple/simple_app.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights 2 | // reserved. Use of this source code is governed by a BSD-style license that 3 | // can be found in the LICENSE file. 4 | 5 | #ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_ 6 | #define CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_ 7 | 8 | #include "include/cef_app.h" 9 | 10 | // Implement application-level callbacks for the browser process. 11 | class SimpleApp : public CefApp, public CefBrowserProcessHandler { 12 | public: 13 | SimpleApp(); 14 | 15 | // CefApp methods: 16 | virtual CefRefPtr GetBrowserProcessHandler() 17 | OVERRIDE { 18 | return this; 19 | } 20 | 21 | // CefBrowserProcessHandler methods: 22 | virtual void OnContextInitialized() OVERRIDE; 23 | 24 | private: 25 | // Include the default reference counting implementation. 26 | IMPLEMENT_REFCOUNTING(SimpleApp); 27 | }; 28 | 29 | #endif // CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_ 30 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 4 | 5 | project(cef-demos) 6 | 7 | set(CMAKE_CXX_STANDARD 17) 8 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 9 | 10 | set(CMAKE_MODULE_PATH 11 | ${CMAKE_MODULE_PATH} 12 | ${CMAKE_CURRENT_SOURCE_DIR}/cmake 13 | ${CMAKE_CURRENT_SOURCE_DIR}/cef-cmake/cmake 14 | ) 15 | 16 | if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") 17 | set(CEFDEMOS_OS_MACOSX 1) 18 | set(CEFDEMOS_OS_POSIX 1) 19 | elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") 20 | set(CEFDEMOS_OS_LINUX 1) 21 | set(CEFDEMOS_OS_POSIX 1) 22 | elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") 23 | set(CEFDEMOS_OS_WINDOWS 1) 24 | else() 25 | message(FATAL_ERROR "CEF-Demos: Unsupported target platform") 26 | endif() 27 | 28 | include(src_group) 29 | 30 | # configure 31 | set(CEF_USE_SANDBOX OFF CACHE BOOL "Force turning off of sandbox") 32 | include(cef_cmake) 33 | add_subdirectory(cef-cmake) 34 | 35 | add_subdirectory(common) 36 | 37 | add_subdirectory(demos) 38 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Borislav Stanimirov 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /cmake/src_group.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2015 Borislav Stanimirov 2 | # 3 | # Distributed under the MIT Software License 4 | # See accompanying file LICENSE.txt or copy at 5 | # http://opensource.org/licenses/MIT 6 | # 7 | # src_group 8 | # 9 | # Defines a group of source files, while also appending them to a list 10 | # (to be used with add_executable or add_library) 11 | # Args: 12 | # GROUP_NAME - name of the group. Subroups are separated by "~" 13 | # SRC_LIST - list of sources to append to 14 | # ... the other arguments are a list of files 15 | # 16 | # Example Usage 17 | # set(mySources) 18 | # src_group("Group~Subgroup" mySources file1 file2 ... fileN) 19 | # add_executable(myexe mySources) 20 | # 21 | macro(src_group GROUP_NAME SRC_LIST) 22 | # In order to work CMake's source_group macro requiers backslashes between 23 | # groups and subgroups. However this leads to escape hell. That's why we 24 | # use tildes and then replace them with backslashes at the very end 25 | set(DEMANGLED_GROUP) 26 | string(REPLACE "~" "\\\\" DEMANGLED_GROUP ${GROUP_NAME}) 27 | 28 | source_group(${DEMANGLED_GROUP} FILES ${ARGN}) 29 | 30 | foreach(filename ${ARGN}) 31 | list(APPEND ${SRC_LIST} ${filename}) 32 | endforeach() 33 | endmacro(src_group) 34 | -------------------------------------------------------------------------------- /demos/cefsimple/LICENSE.txt: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2008-2014 Marshall A. Greenblatt. Portions Copyright (c) 2 | // 2006-2009 Google Inc. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the name Chromium Embedded 15 | // Framework nor the names of its contributors may be used to endorse 16 | // or promote products derived from this software without specific prior 17 | // written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /demos/file-manager/FileManager.cpp: -------------------------------------------------------------------------------- 1 | // CEF-Demos 2 | // Copyright (c) 2019 Borislav Stanimirov 3 | // 4 | // Distributed under the MIT Software License 5 | // See accompanying file LICENSE.txt or copy at 6 | // http://opensource.org/licenses/MIT 7 | // 8 | #include "FileManager.hpp" 9 | 10 | #if defined(_WIN32) 11 | # include 12 | # include "win_dirent.h" 13 | #else 14 | # include 15 | #endif 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | namespace fileman 22 | { 23 | 24 | namespace 25 | { 26 | void normalizePath(std::string& path) 27 | { 28 | for (auto& c : path) 29 | if (c == '\\') 30 | c = '/'; 31 | } 32 | } 33 | 34 | FileManager::FileManager() 35 | { 36 | #if defined(_WIN32) 37 | m_path = getenv("homedrive"); 38 | m_path += getenv("homepath"); 39 | normalizePath(m_path); 40 | #else 41 | m_path = getenv("HOME"); 42 | #endif 43 | } 44 | 45 | FileManager::~FileManager() = default; 46 | 47 | FileManager::DirectoryContents FileManager::getDirectoryContents(const char* path) 48 | { 49 | DirectoryContents ret; 50 | 51 | auto dir = m_path + path; 52 | auto dp = opendir(dir.c_str()); 53 | 54 | dirent* entry; 55 | while ((entry = readdir(dp)) != nullptr) 56 | { 57 | if (strcmp(".", entry->d_name) == 0 || strcmp("..", entry->d_name) == 0) continue; // don't care for this 58 | auto fullPath = dir + "/" + entry->d_name; 59 | struct stat info; 60 | if (stat(fullPath.c_str(), &info) == 0 && (info.st_mode & S_IFDIR)) 61 | { 62 | ret.dirs.emplace_back(entry->d_name); 63 | } 64 | else 65 | { 66 | ret.files.emplace_back(entry->d_name); 67 | } 68 | } 69 | 70 | closedir(dp); 71 | 72 | return ret; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /demos/cefsimple/simple_handler_linux.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights 2 | // reserved. Use of this source code is governed by a BSD-style license that 3 | // can be found in the LICENSE file. 4 | 5 | #include "tests/cefsimple/simple_handler.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "include/base/cef_logging.h" 12 | #include "include/cef_browser.h" 13 | 14 | void SimpleHandler::PlatformTitleChange(CefRefPtr browser, 15 | const CefString& title) { 16 | std::string titleStr(title); 17 | 18 | // Retrieve the X11 display shared with Chromium. 19 | ::Display* display = cef_get_xdisplay(); 20 | DCHECK(display); 21 | 22 | // Retrieve the X11 window handle for the browser. 23 | ::Window window = browser->GetHost()->GetWindowHandle(); 24 | DCHECK(window != kNullWindowHandle); 25 | 26 | // Retrieve the atoms required by the below XChangeProperty call. 27 | const char* kAtoms[] = {"_NET_WM_NAME", "UTF8_STRING"}; 28 | Atom atoms[2]; 29 | int result = 30 | XInternAtoms(display, const_cast(kAtoms), 2, false, atoms); 31 | if (!result) 32 | NOTREACHED(); 33 | 34 | // Set the window title. 35 | XChangeProperty(display, window, atoms[0], atoms[1], 8, PropModeReplace, 36 | reinterpret_cast(titleStr.c_str()), 37 | titleStr.size()); 38 | 39 | // TODO(erg): This is technically wrong. So XStoreName and friends expect 40 | // this in Host Portable Character Encoding instead of UTF-8, which I believe 41 | // is Compound Text. This shouldn't matter 90% of the time since this is the 42 | // fallback to the UTF8 property above. 43 | XStoreName(display, browser->GetHost()->GetWindowHandle(), titleStr.c_str()); 44 | } 45 | -------------------------------------------------------------------------------- /demos/simple/simple.cpp: -------------------------------------------------------------------------------- 1 | // CEF-Demos 2 | // Copyright (c) 2019 Borislav Stanimirov 3 | // 4 | // Distributed under the MIT Software License 5 | // See accompanying file LICENSE.txt or copy at 6 | // http://opensource.org/licenses/MIT 7 | // 8 | // Bare-bones minimal demo. Creates a simple Chromium browser. 9 | #include 10 | #include 11 | 12 | // this is only needed so we have a way to break the message loop 13 | class MinimalClient : public CefClient, public CefLifeSpanHandler 14 | { 15 | public: 16 | MinimalClient() = default; 17 | 18 | CefRefPtr GetLifeSpanHandler() override { return this; } 19 | void OnBeforeClose(CefRefPtr browser) override 20 | { 21 | CefQuitMessageLoop(); 22 | } 23 | 24 | IMPLEMENT_REFCOUNTING(MinimalClient); 25 | DISALLOW_COPY_AND_ASSIGN(MinimalClient); 26 | }; 27 | 28 | 29 | int main(int argc, char* argv[]) 30 | { 31 | #if defined(_WIN32) 32 | CefEnableHighDPISupport(); 33 | CefMainArgs args(GetModuleHandle(NULL)); 34 | #else 35 | CefMainArgs args(argc, argv); 36 | #endif 37 | 38 | void* windowsSandboxInfo = NULL; 39 | 40 | #if defined(CEF_USE_SANDBOX) && defined(_WIN32) 41 | // Manage the life span of the sandbox information object. This is necessary 42 | // for sandbox support on Windows. See cef_sandbox_win.h for complete details. 43 | CefScopedSandboxInfo scopedSandbox; 44 | windowsSandboxInfo = scopedSandbox.sandbox_info(); 45 | #endif 46 | 47 | int result = CefExecuteProcess(args, nullptr, windowsSandboxInfo); 48 | if (result >= 0) 49 | { 50 | // child process completed 51 | return result; 52 | } 53 | 54 | CefSettings settings; 55 | #if !defined(CEF_USE_SANDBOX) 56 | settings.no_sandbox = true; 57 | #endif 58 | 59 | CefInitialize(args, settings, nullptr, windowsSandboxInfo); 60 | 61 | 62 | CefWindowInfo windowInfo; 63 | 64 | #if defined(_WIN32) 65 | // On Windows we need to specify certain flags that will be passed to CreateWindowEx(). 66 | windowInfo.SetAsPopup(NULL, "simple"); 67 | #endif 68 | CefBrowserSettings browserSettings; 69 | CefBrowserHost::CreateBrowser(windowInfo, new MinimalClient, "https://ibob.github.io/cef-demos/html/hello-demos.html", browserSettings, nullptr); 70 | 71 | CefRunMessageLoop(); 72 | 73 | CefShutdown(); 74 | 75 | return 0; 76 | } 77 | -------------------------------------------------------------------------------- /common/common/PlatformUtil.cpp: -------------------------------------------------------------------------------- 1 | // CEF-Demos 2 | // Copyright (c) 2019 Borislav Stanimirov 3 | // 4 | // Distributed under the MIT Software License 5 | // See accompanying file LICENSE.txt or copy at 6 | // http://opensource.org/licenses/MIT 7 | // 8 | #include "PlatformUtil.hpp" 9 | 10 | #if defined(_WIN32) 11 | # include 12 | #else 13 | # include 14 | # include 15 | #endif 16 | 17 | #include 18 | #include 19 | 20 | namespace cefdemos 21 | { 22 | 23 | #if defined(_WIN32) 24 | namespace 25 | { 26 | // local function used to identify the current module on Windows 27 | void getAddr() {} 28 | } 29 | #endif 30 | 31 | std::string PlatformUtil::getCurrentExecutablePath() 32 | { 33 | std::string modulePath; 34 | #if defined(_WIN32) 35 | HMODULE engine; 36 | GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | 37 | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, 38 | (LPCSTR)getAddr, 39 | &engine); 40 | 41 | char path[_MAX_PATH + _MAX_FNAME + 1]; 42 | GetModuleFileNameA(engine, path, _MAX_PATH + _MAX_FNAME); 43 | 44 | // normalize path 45 | char* p = path; 46 | while (*p) 47 | { 48 | if (*p == '\\') 49 | { 50 | *p = '/'; 51 | } 52 | ++p; 53 | } 54 | 55 | modulePath = path; 56 | 57 | #else 58 | // retrieve the executable path and hope for the best 59 | char buff[2048]; 60 | size_t len = readlink("/proc/self/exe", buff, sizeof(buff) - 1); 61 | if (len > 0) 62 | { 63 | buff[len] = 0; 64 | modulePath = buff; 65 | } 66 | 67 | #endif 68 | 69 | return modulePath; 70 | } 71 | 72 | std::string PlatformUtil::getAssetPath(std::string baseDir, const std::string& assetDir) 73 | { 74 | while (true) 75 | { 76 | auto slash = baseDir.rfind('/'); 77 | if (slash == std::string::npos) 78 | { 79 | baseDir = assetDir; 80 | break; 81 | } 82 | 83 | baseDir.erase(slash + 1); 84 | 85 | baseDir += assetDir; 86 | 87 | struct stat info; 88 | if (stat(baseDir.c_str(), &info) == 0 && (info.st_mode & S_IFDIR)) 89 | { 90 | break; 91 | } 92 | 93 | baseDir.erase(slash); 94 | } 95 | 96 | return baseDir; 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /demos/cefsimple/cefsimple_linux.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights 2 | // reserved. Use of this source code is governed by a BSD-style license that 3 | // can be found in the LICENSE file. 4 | 5 | #include "tests/cefsimple/simple_app.h" 6 | 7 | #include 8 | 9 | #include "include/base/cef_logging.h" 10 | 11 | namespace { 12 | 13 | int XErrorHandlerImpl(Display* display, XErrorEvent* event) { 14 | LOG(WARNING) << "X error received: " 15 | << "type " << event->type << ", " 16 | << "serial " << event->serial << ", " 17 | << "error_code " << static_cast(event->error_code) << ", " 18 | << "request_code " << static_cast(event->request_code) 19 | << ", " 20 | << "minor_code " << static_cast(event->minor_code); 21 | return 0; 22 | } 23 | 24 | int XIOErrorHandlerImpl(Display* display) { 25 | return 0; 26 | } 27 | 28 | } // namespace 29 | 30 | // Entry point function for all processes. 31 | int main(int argc, char* argv[]) { 32 | // Provide CEF with command-line arguments. 33 | CefMainArgs main_args(argc, argv); 34 | 35 | // CEF applications have multiple sub-processes (render, plugin, GPU, etc) 36 | // that share the same executable. This function checks the command-line and, 37 | // if this is a sub-process, executes the appropriate logic. 38 | int exit_code = CefExecuteProcess(main_args, NULL, NULL); 39 | if (exit_code >= 0) { 40 | // The sub-process has completed so return here. 41 | return exit_code; 42 | } 43 | 44 | // Install xlib error handlers so that the application won't be terminated 45 | // on non-fatal errors. 46 | XSetErrorHandler(XErrorHandlerImpl); 47 | XSetIOErrorHandler(XIOErrorHandlerImpl); 48 | 49 | // Specify CEF global settings here. 50 | CefSettings settings; 51 | 52 | // When generating projects with CMake the CEF_USE_SANDBOX value will be defined 53 | // automatically. Pass -DUSE_SANDBOX=OFF to the CMake command-line to disable 54 | // use of the sandbox. 55 | #if !defined(CEF_USE_SANDBOX) 56 | settings.no_sandbox = true; 57 | #endif 58 | 59 | // SimpleApp implements application-level callbacks for the browser process. 60 | // It will create the first browser instance in OnContextInitialized() after 61 | // CEF has initialized. 62 | CefRefPtr app(new SimpleApp); 63 | 64 | // Initialize CEF for the browser process. 65 | CefInitialize(main_args, settings, app.get(), NULL); 66 | 67 | // Run the CEF message loop. This will block until CefQuitMessageLoop() is 68 | // called. 69 | CefRunMessageLoop(); 70 | 71 | // Shut down CEF. 72 | CefShutdown(); 73 | 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /demos/cefsimple/simple_handler.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights 2 | // reserved. Use of this source code is governed by a BSD-style license that 3 | // can be found in the LICENSE file. 4 | 5 | #ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_ 6 | #define CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_ 7 | 8 | #include "include/cef_client.h" 9 | 10 | #include 11 | 12 | class SimpleHandler : public CefClient, 13 | public CefDisplayHandler, 14 | public CefLifeSpanHandler, 15 | public CefLoadHandler { 16 | public: 17 | explicit SimpleHandler(bool use_views); 18 | ~SimpleHandler(); 19 | 20 | // Provide access to the single global instance of this object. 21 | static SimpleHandler* GetInstance(); 22 | 23 | // CefClient methods: 24 | virtual CefRefPtr GetDisplayHandler() OVERRIDE { 25 | return this; 26 | } 27 | virtual CefRefPtr GetLifeSpanHandler() OVERRIDE { 28 | return this; 29 | } 30 | virtual CefRefPtr GetLoadHandler() OVERRIDE { return this; } 31 | 32 | // CefDisplayHandler methods: 33 | virtual void OnTitleChange(CefRefPtr browser, 34 | const CefString& title) OVERRIDE; 35 | 36 | // CefLifeSpanHandler methods: 37 | virtual void OnAfterCreated(CefRefPtr browser) OVERRIDE; 38 | virtual bool DoClose(CefRefPtr browser) OVERRIDE; 39 | virtual void OnBeforeClose(CefRefPtr browser) OVERRIDE; 40 | 41 | // CefLoadHandler methods: 42 | virtual void OnLoadError(CefRefPtr browser, 43 | CefRefPtr frame, 44 | ErrorCode errorCode, 45 | const CefString& errorText, 46 | const CefString& failedUrl) OVERRIDE; 47 | 48 | // Request that all existing browser windows close. 49 | void CloseAllBrowsers(bool force_close); 50 | 51 | bool IsClosing() const { return is_closing_; } 52 | 53 | private: 54 | // Platform-specific implementation. 55 | void PlatformTitleChange(CefRefPtr browser, 56 | const CefString& title); 57 | 58 | // True if the application is using the Views framework. 59 | const bool use_views_; 60 | 61 | // List of existing browser windows. Only accessed on the CEF UI thread. 62 | typedef std::list> BrowserList; 63 | BrowserList browser_list_; 64 | 65 | bool is_closing_; 66 | 67 | // Include the default reference counting implementation. 68 | IMPLEMENT_REFCOUNTING(SimpleHandler); 69 | }; 70 | 71 | #endif // CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_ 72 | -------------------------------------------------------------------------------- /demos/cefsimple/cefsimple_win.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights 2 | // reserved. Use of this source code is governed by a BSD-style license that 3 | // can be found in the LICENSE file. 4 | 5 | #include 6 | 7 | #include "include/cef_sandbox_win.h" 8 | #include "tests/cefsimple/simple_app.h" 9 | 10 | // When generating projects with CMake the CEF_USE_SANDBOX value will be defined 11 | // automatically if using the required compiler version. Pass -DUSE_SANDBOX=OFF 12 | // to the CMake command-line to disable use of the sandbox. 13 | // Uncomment this line to manually enable sandbox support. 14 | // #define CEF_USE_SANDBOX 1 15 | 16 | #if defined(CEF_USE_SANDBOX) 17 | // The cef_sandbox.lib static library may not link successfully with all VS 18 | // versions. 19 | #pragma comment(lib, "cef_sandbox.lib") 20 | #endif 21 | 22 | // Entry point function for all processes. 23 | int APIENTRY wWinMain(HINSTANCE hInstance, 24 | HINSTANCE hPrevInstance, 25 | LPTSTR lpCmdLine, 26 | int nCmdShow) { 27 | UNREFERENCED_PARAMETER(hPrevInstance); 28 | UNREFERENCED_PARAMETER(lpCmdLine); 29 | 30 | // Enable High-DPI support on Windows 7 or newer. 31 | CefEnableHighDPISupport(); 32 | 33 | void* sandbox_info = NULL; 34 | 35 | #if defined(CEF_USE_SANDBOX) 36 | // Manage the life span of the sandbox information object. This is necessary 37 | // for sandbox support on Windows. See cef_sandbox_win.h for complete details. 38 | CefScopedSandboxInfo scoped_sandbox; 39 | sandbox_info = scoped_sandbox.sandbox_info(); 40 | #endif 41 | 42 | // Provide CEF with command-line arguments. 43 | CefMainArgs main_args(hInstance); 44 | 45 | // CEF applications have multiple sub-processes (render, plugin, GPU, etc) 46 | // that share the same executable. This function checks the command-line and, 47 | // if this is a sub-process, executes the appropriate logic. 48 | int exit_code = CefExecuteProcess(main_args, NULL, sandbox_info); 49 | if (exit_code >= 0) { 50 | // The sub-process has completed so return here. 51 | return exit_code; 52 | } 53 | 54 | // Specify CEF global settings here. 55 | CefSettings settings; 56 | 57 | #if !defined(CEF_USE_SANDBOX) 58 | settings.no_sandbox = true; 59 | #endif 60 | 61 | // SimpleApp implements application-level callbacks for the browser process. 62 | // It will create the first browser instance in OnContextInitialized() after 63 | // CEF has initialized. 64 | CefRefPtr app(new SimpleApp); 65 | 66 | // Initialize CEF. 67 | CefInitialize(main_args, settings, app.get(), sandbox_info); 68 | 69 | // Run the CEF message loop. This will block until CefQuitMessageLoop() is 70 | // called. 71 | CefRunMessageLoop(); 72 | 73 | // Shut down CEF. 74 | CefShutdown(); 75 | 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /html/file-manager.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | File Manager :: CEF Demos 6 | 7 | 42 | 43 | 44 | 45 | 46 |
Path:
47 |
48 | 49 | 50 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /demos/resource/resource.cpp: -------------------------------------------------------------------------------- 1 | // CEF-Demos 2 | // Copyright (c) 2019 Borislav Stanimirov 3 | // 4 | // Distributed under the MIT Software License 5 | // See accompanying file LICENSE.txt or copy at 6 | // http://opensource.org/licenses/MIT 7 | // 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #define URI_ROOT "https://cefdemos" 17 | const char* URL = URI_ROOT "/hello-demos.html"; 18 | 19 | class ResourceClient : public CefClient, public CefLifeSpanHandler, public CefRequestHandler 20 | { 21 | public: 22 | ResourceClient() 23 | : m_resourceManager(new CefResourceManager) 24 | { 25 | auto exePath = cefdemos::PlatformUtil::getCurrentExecutablePath(); 26 | auto assetPath = cefdemos::PlatformUtil::getAssetPath(exePath, "html"); 27 | cefdemos::Resources::setupResourceManagerDirectoryProvider(m_resourceManager, URI_ROOT, assetPath); 28 | } 29 | 30 | CefRefPtr GetLifeSpanHandler() override { return this; } 31 | virtual CefRefPtr GetRequestHandler() override { return this; } 32 | 33 | void OnBeforeClose(CefRefPtr browser) override 34 | { 35 | CefQuitMessageLoop(); 36 | } 37 | 38 | virtual cef_return_value_t OnBeforeResourceLoad( 39 | CefRefPtr browser, 40 | CefRefPtr frame, 41 | CefRefPtr request, 42 | CefRefPtr callback) override 43 | { 44 | return m_resourceManager->OnBeforeResourceLoad(browser, frame, request, callback); 45 | } 46 | 47 | virtual CefRefPtr GetResourceHandler( 48 | CefRefPtr browser, 49 | CefRefPtr frame, 50 | CefRefPtr request) override 51 | { 52 | return m_resourceManager->GetResourceHandler(browser, frame, request); 53 | } 54 | 55 | private: 56 | CefRefPtr m_resourceManager; 57 | 58 | IMPLEMENT_REFCOUNTING(ResourceClient); 59 | DISALLOW_COPY_AND_ASSIGN(ResourceClient); 60 | }; 61 | 62 | int main(int argc, char* argv[]) 63 | { 64 | #if defined(_WIN32) 65 | CefEnableHighDPISupport(); 66 | CefMainArgs args(GetModuleHandle(NULL)); 67 | #else 68 | CefMainArgs args(argc, argv); 69 | #endif 70 | 71 | void* windowsSandboxInfo = NULL; 72 | 73 | #if defined(CEF_USE_SANDBOX) && defined(_WIN32) 74 | // Manage the life span of the sandbox information object. This is necessary 75 | // for sandbox support on Windows. See cef_sandbox_win.h for complete details. 76 | CefScopedSandboxInfo scopedSandbox; 77 | windowsSandboxInfo = scopedSandbox.sandbox_info(); 78 | #endif 79 | 80 | int result = CefExecuteProcess(args, nullptr, windowsSandboxInfo); 81 | if (result >= 0) 82 | { 83 | // child process completed 84 | return result; 85 | } 86 | 87 | CefSettings settings; 88 | #if !defined(CEF_USE_SANDBOX) 89 | settings.no_sandbox = true; 90 | #endif 91 | 92 | CefInitialize(args, settings, nullptr, windowsSandboxInfo); 93 | 94 | CefWindowInfo windowInfo; 95 | 96 | #if defined(_WIN32) 97 | // On Windows we need to specify certain flags that will be passed to CreateWindowEx(). 98 | windowInfo.SetAsPopup(NULL, "Resource"); 99 | #endif 100 | CefBrowserSettings browserSettings; 101 | CefBrowserHost::CreateBrowser(windowInfo, new ResourceClient, URL, browserSettings, nullptr); 102 | 103 | CefRunMessageLoop(); 104 | 105 | CefShutdown(); 106 | 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /demos/cefsimple/simple_app.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights 2 | // reserved. Use of this source code is governed by a BSD-style license that 3 | // can be found in the LICENSE file. 4 | 5 | #include "tests/cefsimple/simple_app.h" 6 | 7 | #include 8 | 9 | #include "include/cef_browser.h" 10 | #include "include/cef_command_line.h" 11 | #include "include/views/cef_browser_view.h" 12 | #include "include/views/cef_window.h" 13 | #include "include/wrapper/cef_helpers.h" 14 | #include "tests/cefsimple/simple_handler.h" 15 | 16 | namespace { 17 | 18 | // When using the Views framework this object provides the delegate 19 | // implementation for the CefWindow that hosts the Views-based browser. 20 | class SimpleWindowDelegate : public CefWindowDelegate { 21 | public: 22 | explicit SimpleWindowDelegate(CefRefPtr browser_view) 23 | : browser_view_(browser_view) {} 24 | 25 | void OnWindowCreated(CefRefPtr window) OVERRIDE { 26 | // Add the browser view and show the window. 27 | window->AddChildView(browser_view_); 28 | window->Show(); 29 | 30 | // Give keyboard focus to the browser view. 31 | browser_view_->RequestFocus(); 32 | } 33 | 34 | void OnWindowDestroyed(CefRefPtr window) OVERRIDE { 35 | browser_view_ = NULL; 36 | } 37 | 38 | bool CanClose(CefRefPtr window) OVERRIDE { 39 | // Allow the window to close if the browser says it's OK. 40 | CefRefPtr browser = browser_view_->GetBrowser(); 41 | if (browser) 42 | return browser->GetHost()->TryCloseBrowser(); 43 | return true; 44 | } 45 | 46 | private: 47 | CefRefPtr browser_view_; 48 | 49 | IMPLEMENT_REFCOUNTING(SimpleWindowDelegate); 50 | DISALLOW_COPY_AND_ASSIGN(SimpleWindowDelegate); 51 | }; 52 | 53 | } // namespace 54 | 55 | SimpleApp::SimpleApp() {} 56 | 57 | void SimpleApp::OnContextInitialized() { 58 | CEF_REQUIRE_UI_THREAD(); 59 | 60 | CefRefPtr command_line = 61 | CefCommandLine::GetGlobalCommandLine(); 62 | 63 | #if defined(OS_WIN) || defined(OS_LINUX) 64 | // Create the browser using the Views framework if "--use-views" is specified 65 | // via the command-line. Otherwise, create the browser using the native 66 | // platform framework. The Views framework is currently only supported on 67 | // Windows and Linux. 68 | const bool use_views = command_line->HasSwitch("use-views"); 69 | #else 70 | const bool use_views = false; 71 | #endif 72 | 73 | // SimpleHandler implements browser-level callbacks. 74 | CefRefPtr handler(new SimpleHandler(use_views)); 75 | 76 | // Specify CEF browser settings here. 77 | CefBrowserSettings browser_settings; 78 | 79 | std::string url; 80 | 81 | // Check if a "--url=" value was provided via the command-line. If so, use 82 | // that instead of the default URL. 83 | url = command_line->GetSwitchValue("url"); 84 | if (url.empty()) 85 | url = "http://www.google.com"; 86 | 87 | if (use_views) { 88 | // Create the BrowserView. 89 | CefRefPtr browser_view = CefBrowserView::CreateBrowserView( 90 | handler, url, browser_settings, NULL, NULL); 91 | 92 | // Create the Window. It will show itself after creation. 93 | CefWindow::CreateTopLevelWindow(new SimpleWindowDelegate(browser_view)); 94 | } else { 95 | // Information used when creating the native window. 96 | CefWindowInfo window_info; 97 | 98 | #if defined(OS_WIN) 99 | // On Windows we need to specify certain flags that will be passed to 100 | // CreateWindowEx(). 101 | window_info.SetAsPopup(NULL, "cefsimple"); 102 | #endif 103 | 104 | // Create the first browser window. 105 | CefBrowserHost::CreateBrowser(window_info, handler, url, browser_settings, 106 | NULL); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /demos/cefsimple/simple_handler.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights 2 | // reserved. Use of this source code is governed by a BSD-style license that 3 | // can be found in the LICENSE file. 4 | 5 | #include "tests/cefsimple/simple_handler.h" 6 | 7 | #include 8 | #include 9 | 10 | #include "include/base/cef_bind.h" 11 | #include "include/cef_app.h" 12 | #include "include/views/cef_browser_view.h" 13 | #include "include/views/cef_window.h" 14 | #include "include/wrapper/cef_closure_task.h" 15 | #include "include/wrapper/cef_helpers.h" 16 | 17 | namespace { 18 | 19 | SimpleHandler* g_instance = NULL; 20 | 21 | } // namespace 22 | 23 | SimpleHandler::SimpleHandler(bool use_views) 24 | : use_views_(use_views), is_closing_(false) { 25 | DCHECK(!g_instance); 26 | g_instance = this; 27 | } 28 | 29 | SimpleHandler::~SimpleHandler() { 30 | g_instance = NULL; 31 | } 32 | 33 | // static 34 | SimpleHandler* SimpleHandler::GetInstance() { 35 | return g_instance; 36 | } 37 | 38 | void SimpleHandler::OnTitleChange(CefRefPtr browser, 39 | const CefString& title) { 40 | CEF_REQUIRE_UI_THREAD(); 41 | 42 | if (use_views_) { 43 | // Set the title of the window using the Views framework. 44 | CefRefPtr browser_view = 45 | CefBrowserView::GetForBrowser(browser); 46 | if (browser_view) { 47 | CefRefPtr window = browser_view->GetWindow(); 48 | if (window) 49 | window->SetTitle(title); 50 | } 51 | } else { 52 | // Set the title of the window using platform APIs. 53 | PlatformTitleChange(browser, title); 54 | } 55 | } 56 | 57 | void SimpleHandler::OnAfterCreated(CefRefPtr browser) { 58 | CEF_REQUIRE_UI_THREAD(); 59 | 60 | // Add to the list of existing browsers. 61 | browser_list_.push_back(browser); 62 | } 63 | 64 | bool SimpleHandler::DoClose(CefRefPtr browser) { 65 | CEF_REQUIRE_UI_THREAD(); 66 | 67 | // Closing the main window requires special handling. See the DoClose() 68 | // documentation in the CEF header for a detailed destription of this 69 | // process. 70 | if (browser_list_.size() == 1) { 71 | // Set a flag to indicate that the window close should be allowed. 72 | is_closing_ = true; 73 | } 74 | 75 | // Allow the close. For windowed browsers this will result in the OS close 76 | // event being sent. 77 | return false; 78 | } 79 | 80 | void SimpleHandler::OnBeforeClose(CefRefPtr browser) { 81 | CEF_REQUIRE_UI_THREAD(); 82 | 83 | // Remove from the list of existing browsers. 84 | BrowserList::iterator bit = browser_list_.begin(); 85 | for (; bit != browser_list_.end(); ++bit) { 86 | if ((*bit)->IsSame(browser)) { 87 | browser_list_.erase(bit); 88 | break; 89 | } 90 | } 91 | 92 | if (browser_list_.empty()) { 93 | // All browser windows have closed. Quit the application message loop. 94 | CefQuitMessageLoop(); 95 | } 96 | } 97 | 98 | void SimpleHandler::OnLoadError(CefRefPtr browser, 99 | CefRefPtr frame, 100 | ErrorCode errorCode, 101 | const CefString& errorText, 102 | const CefString& failedUrl) { 103 | CEF_REQUIRE_UI_THREAD(); 104 | 105 | // Don't display an error for downloaded files. 106 | if (errorCode == ERR_ABORTED) 107 | return; 108 | 109 | // Display a load error message. 110 | std::stringstream ss; 111 | ss << "" 112 | "

Failed to load URL " 113 | << std::string(failedUrl) << " with error " << std::string(errorText) 114 | << " (" << errorCode << ").

"; 115 | frame->LoadString(ss.str(), failedUrl); 116 | } 117 | 118 | void SimpleHandler::CloseAllBrowsers(bool force_close) { 119 | if (!CefCurrentlyOn(TID_UI)) { 120 | // Execute on the UI thread. 121 | CefPostTask(TID_UI, base::Bind(&SimpleHandler::CloseAllBrowsers, this, 122 | force_close)); 123 | return; 124 | } 125 | 126 | if (browser_list_.empty()) 127 | return; 128 | 129 | BrowserList::const_iterator it = browser_list_.begin(); 130 | for (; it != browser_list_.end(); ++it) 131 | (*it)->GetHost()->CloseBrowser(force_close); 132 | } 133 | -------------------------------------------------------------------------------- /demos/file-manager/file-manager-main.cpp: -------------------------------------------------------------------------------- 1 | // CEF-Demos 2 | // Copyright (c) 2019 Borislav Stanimirov 3 | // 4 | // Distributed under the MIT Software License 5 | // See accompanying file LICENSE.txt or copy at 6 | // http://opensource.org/licenses/MIT 7 | // 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include "FileManager.hpp" 16 | 17 | #include 18 | #include 19 | 20 | #define URI_ROOT "https://cefdemos" 21 | const char* URL = URI_ROOT "/file-manager.html"; 22 | 23 | class MessageHandler : public CefMessageRouterBrowserSide::Handler 24 | { 25 | public: 26 | MessageHandler(fileman::FileManager& f) 27 | : m_fileManager(f) 28 | {} 29 | 30 | bool OnQuery(CefRefPtr browser, 31 | CefRefPtr frame, 32 | int64 query_id, 33 | const CefString& request, 34 | bool persistent, 35 | CefRefPtr callback) override 36 | { 37 | std::string r = request; 38 | auto f = r.find(':'); 39 | if (f == std::string::npos) return false; 40 | auto rtype = r.substr(0, f); 41 | if (rtype != "contents") return false; 42 | auto rarg = r.substr(f+1); 43 | auto contents = m_fileManager.getDirectoryContents(rarg.c_str()); 44 | 45 | std::ostringstream json; 46 | json << R"json({"dirs":[)json"; 47 | for(size_t i=0; iSuccess(json.str()); 61 | return true; 62 | } 63 | 64 | private: 65 | fileman::FileManager& m_fileManager; 66 | }; 67 | 68 | class FileManagerClient : public CefClient, public CefLifeSpanHandler, public CefRequestHandler 69 | { 70 | public: 71 | FileManagerClient() 72 | : m_resourceManager(new CefResourceManager) 73 | , m_fileManager(new fileman::FileManager) 74 | { 75 | auto exePath = cefdemos::PlatformUtil::getCurrentExecutablePath(); 76 | auto assetPath = cefdemos::PlatformUtil::getAssetPath(exePath, "html"); 77 | cefdemos::Resources::setupResourceManagerDirectoryProvider(m_resourceManager, URI_ROOT, assetPath); 78 | } 79 | 80 | virtual CefRefPtr GetLifeSpanHandler() override { return this; } 81 | virtual CefRefPtr GetRequestHandler() override { return this; } 82 | 83 | virtual bool OnProcessMessageReceived(CefRefPtr browser, 84 | CefProcessId source_process, 85 | CefRefPtr message) override 86 | { 87 | return m_messageRouter->OnProcessMessageReceived(browser, source_process, message); 88 | } 89 | 90 | ///////////////////////////////////// 91 | // lifespan handler 92 | virtual void OnAfterCreated(CefRefPtr browser) override 93 | { 94 | CefMessageRouterConfig mrconfig; 95 | m_messageRouter = CefMessageRouterBrowserSide::Create(mrconfig); 96 | m_messageHandler.reset(new MessageHandler(*m_fileManager)); 97 | m_messageRouter->AddHandler(m_messageHandler.get(), false); 98 | } 99 | 100 | void OnBeforeClose(CefRefPtr browser) override 101 | { 102 | m_messageRouter->RemoveHandler(m_messageHandler.get()); 103 | m_messageHandler.reset(); 104 | m_messageRouter = nullptr; 105 | 106 | CefQuitMessageLoop(); 107 | } 108 | 109 | 110 | ///////////////////////////////////// 111 | // request handler 112 | 113 | virtual bool OnBeforeBrowse(CefRefPtr browser, 114 | CefRefPtr frame, 115 | CefRefPtr request, 116 | bool user_gesture, 117 | bool is_redirect) override 118 | { 119 | m_messageRouter->OnBeforeBrowse(browser, frame); 120 | return false; 121 | } 122 | 123 | virtual void OnRenderProcessTerminated(CefRefPtr browser, TerminationStatus status) override 124 | { 125 | m_messageRouter->OnRenderProcessTerminated(browser); 126 | } 127 | 128 | virtual cef_return_value_t OnBeforeResourceLoad( 129 | CefRefPtr browser, 130 | CefRefPtr frame, 131 | CefRefPtr request, 132 | CefRefPtr callback) override 133 | { 134 | return m_resourceManager->OnBeforeResourceLoad(browser, frame, request, callback); 135 | } 136 | 137 | virtual CefRefPtr GetResourceHandler( 138 | CefRefPtr browser, 139 | CefRefPtr frame, 140 | CefRefPtr request) override 141 | { 142 | return m_resourceManager->GetResourceHandler(browser, frame, request); 143 | } 144 | 145 | private: 146 | std::unique_ptr m_fileManager; 147 | 148 | CefRefPtr m_resourceManager; 149 | 150 | CefRefPtr m_messageRouter; 151 | scoped_ptr m_messageHandler; 152 | 153 | IMPLEMENT_REFCOUNTING(FileManagerClient); 154 | DISALLOW_COPY_AND_ASSIGN(FileManagerClient); 155 | }; 156 | 157 | //////////////////////////////////////// 158 | // renderer process handling 159 | class RendererApp : public CefApp, public CefRenderProcessHandler 160 | { 161 | public: 162 | RendererApp() = default; 163 | 164 | CefRefPtr GetRenderProcessHandler() override { 165 | return this; 166 | } 167 | 168 | void OnWebKitInitialized() override 169 | { 170 | CefMessageRouterConfig config; 171 | m_messageRouter = CefMessageRouterRendererSide::Create(config); 172 | } 173 | 174 | virtual void OnContextCreated(CefRefPtr browser, 175 | CefRefPtr frame, CefRefPtr context) override 176 | { 177 | m_messageRouter->OnContextCreated(browser, frame, context); 178 | } 179 | 180 | virtual void OnContextReleased(CefRefPtr browser, 181 | CefRefPtr frame, CefRefPtr context) override 182 | { 183 | m_messageRouter->OnContextReleased(browser, frame, context); 184 | } 185 | 186 | virtual bool OnProcessMessageReceived(CefRefPtr browser, 187 | CefProcessId source_process, CefRefPtr message) override 188 | { 189 | return m_messageRouter->OnProcessMessageReceived(browser, source_process, message); 190 | } 191 | 192 | private: 193 | CefRefPtr m_messageRouter; 194 | 195 | IMPLEMENT_REFCOUNTING(RendererApp); 196 | DISALLOW_COPY_AND_ASSIGN(RendererApp); 197 | }; 198 | //////////////////////////////////////// 199 | 200 | int main(int argc, char* argv[]) 201 | { 202 | CefRefPtr commandLine = CefCommandLine::CreateCommandLine(); 203 | #if defined(_WIN32) 204 | CefEnableHighDPISupport(); 205 | CefMainArgs args(GetModuleHandle(NULL)); 206 | commandLine->InitFromString(GetCommandLineW()); 207 | #else 208 | CefMainArgs args(argc, argv); 209 | commandLine->InitFromArgv(argc, argv); 210 | #endif 211 | 212 | void* windowsSandboxInfo = NULL; 213 | 214 | #if defined(CEF_USE_SANDBOX) && defined(_WIN32) 215 | // Manage the life span of the sandbox information object. This is necessary 216 | // for sandbox support on Windows. See cef_sandbox_win.h for complete details. 217 | CefScopedSandboxInfo scopedSandbox; 218 | windowsSandboxInfo = scopedSandbox.sandbox_info(); 219 | #endif 220 | 221 | CefRefPtr app = nullptr; 222 | std::string appType = commandLine->GetSwitchValue("type"); 223 | if (appType == "renderer" || appType == "zygote") { 224 | app = new RendererApp; 225 | } 226 | int result = CefExecuteProcess(args, app, windowsSandboxInfo); 227 | if (result >= 0) 228 | { 229 | // child process completed 230 | return result; 231 | } 232 | 233 | CefSettings settings; 234 | #if !defined(CEF_USE_SANDBOX) 235 | settings.no_sandbox = true; 236 | #endif 237 | 238 | CefInitialize(args, settings, nullptr, windowsSandboxInfo); 239 | 240 | CefWindowInfo windowInfo; 241 | 242 | #if defined(_WIN32) 243 | // On Windows we need to specify certain flags that will be passed to CreateWindowEx(). 244 | windowInfo.SetAsPopup(NULL, "Resource"); 245 | #endif 246 | CefBrowserSettings browserSettings; 247 | CefBrowserHost::CreateBrowser(windowInfo, new FileManagerClient, URL, browserSettings, nullptr); 248 | 249 | CefRunMessageLoop(); 250 | 251 | CefShutdown(); 252 | 253 | return 0; 254 | } -------------------------------------------------------------------------------- /demos/simple-headless/simple-headless.cpp: -------------------------------------------------------------------------------- 1 | // CEF-Demos 2 | // Copyright (c) 2019 Borislav Stanimirov 3 | // 4 | // Distributed under the MIT Software License 5 | // See accompanying file LICENSE.txt or copy at 6 | // http://opensource.org/licenses/MIT 7 | // 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include // so we can sleep in the main loop 14 | #include 15 | 16 | const char* HTML = R"demohtml( 17 | 18 | 19 | 26 | 27 | )demohtml"; 28 | 29 | const char* URL = "https://cef-demos/headless"; 30 | 31 | std::atomic_bool HTML_LoadingDone; 32 | 33 | class MessageHandler : public CefMessageRouterBrowserSide::Handler 34 | { 35 | public: 36 | MessageHandler() = default; 37 | 38 | bool OnQuery(CefRefPtr browser, 39 | CefRefPtr frame, 40 | int64 query_id, 41 | const CefString& request, 42 | bool persistent, 43 | CefRefPtr callback) override 44 | { 45 | if (request == "done") { 46 | HTML_LoadingDone = true; 47 | return true; 48 | } 49 | return false; 50 | } 51 | }; 52 | 53 | void SetupResourceManagerOnIOThread(CefRefPtr resourceManager) 54 | { 55 | if (!CefCurrentlyOn(TID_IO)) 56 | { 57 | CefPostTask(TID_IO, base::Bind(SetupResourceManagerOnIOThread, resourceManager)); 58 | return; 59 | } 60 | 61 | resourceManager->AddContentProvider(URL, HTML, "text/html", 10, std::string()); 62 | } 63 | 64 | class HeadlessClient : public CefClient, public CefLifeSpanHandler, public CefRequestHandler, public CefRenderHandler 65 | { 66 | public: 67 | HeadlessClient() 68 | : m_resourceManager(new CefResourceManager) 69 | { 70 | SetupResourceManagerOnIOThread(m_resourceManager); 71 | } 72 | 73 | virtual CefRefPtr GetLifeSpanHandler() override { return this; } 74 | virtual CefRefPtr GetRequestHandler() override { return this; } 75 | virtual CefRefPtr GetRenderHandler() override { return this; } 76 | 77 | virtual bool OnProcessMessageReceived(CefRefPtr browser, 78 | CefProcessId source_process, 79 | CefRefPtr message) override 80 | { 81 | return m_messageRouter->OnProcessMessageReceived(browser, source_process, message); 82 | } 83 | 84 | ///////////////////////////////////// 85 | // lifespan handler 86 | virtual void OnAfterCreated(CefRefPtr browser) override 87 | { 88 | CefMessageRouterConfig mrconfig; 89 | m_messageRouter = CefMessageRouterBrowserSide::Create(mrconfig); 90 | m_messageHandler.reset(new MessageHandler); 91 | m_messageRouter->AddHandler(m_messageHandler.get(), false); 92 | } 93 | 94 | void OnBeforeClose(CefRefPtr browser) override 95 | { 96 | m_messageRouter->RemoveHandler(m_messageHandler.get()); 97 | m_messageHandler.reset(); 98 | m_messageRouter = nullptr; 99 | } 100 | 101 | 102 | ///////////////////////////////////// 103 | // request handler 104 | 105 | virtual bool OnBeforeBrowse(CefRefPtr browser, 106 | CefRefPtr frame, 107 | CefRefPtr request, 108 | bool user_gesture, 109 | bool is_redirect) override 110 | { 111 | m_messageRouter->OnBeforeBrowse(browser, frame); 112 | return false; 113 | } 114 | 115 | virtual void OnRenderProcessTerminated(CefRefPtr browser, TerminationStatus status) override 116 | { 117 | m_messageRouter->OnRenderProcessTerminated(browser); 118 | } 119 | 120 | virtual cef_return_value_t OnBeforeResourceLoad( 121 | CefRefPtr browser, 122 | CefRefPtr frame, 123 | CefRefPtr request, 124 | CefRefPtr callback) override 125 | { 126 | return m_resourceManager->OnBeforeResourceLoad(browser, frame, request, callback); 127 | } 128 | 129 | virtual CefRefPtr GetResourceHandler( 130 | CefRefPtr browser, 131 | CefRefPtr frame, 132 | CefRefPtr request) override 133 | { 134 | return m_resourceManager->GetResourceHandler(browser, frame, request); 135 | } 136 | 137 | ///////////////////////////////////// 138 | // render handler 139 | virtual void GetViewRect(CefRefPtr browser, CefRect &rect) override 140 | { 141 | rect = CefRect(0, 0, 200, 200); // some random rect 142 | } 143 | 144 | virtual void OnPaint(CefRefPtr browser, 145 | PaintElementType type, 146 | const RectList& dirtyRects, 147 | const void* buffer, 148 | int width, 149 | int height) override 150 | {} // noop. nothing to do 151 | 152 | 153 | private: 154 | CefRefPtr m_resourceManager; 155 | 156 | CefRefPtr m_messageRouter; 157 | scoped_ptr m_messageHandler; 158 | 159 | IMPLEMENT_REFCOUNTING(HeadlessClient); 160 | DISALLOW_COPY_AND_ASSIGN(HeadlessClient); 161 | }; 162 | 163 | //////////////////////////////////////// 164 | // renderer process handling 165 | class RendererApp : public CefApp, public CefRenderProcessHandler 166 | { 167 | public: 168 | RendererApp() = default; 169 | 170 | CefRefPtr GetRenderProcessHandler() override { 171 | return this; 172 | } 173 | 174 | void OnWebKitInitialized() override 175 | { 176 | puts("WEBKIG!!!"); 177 | CefMessageRouterConfig config; 178 | m_messageRouter = CefMessageRouterRendererSide::Create(config); 179 | } 180 | 181 | virtual void OnContextCreated(CefRefPtr browser, 182 | CefRefPtr frame, CefRefPtr context) override 183 | { 184 | m_messageRouter->OnContextCreated(browser, frame, context); 185 | } 186 | 187 | virtual void OnContextReleased(CefRefPtr browser, 188 | CefRefPtr frame, CefRefPtr context) override 189 | { 190 | m_messageRouter->OnContextReleased(browser, frame, context); 191 | } 192 | 193 | virtual bool OnProcessMessageReceived(CefRefPtr browser, 194 | CefProcessId source_process, CefRefPtr message) override 195 | { 196 | return m_messageRouter->OnProcessMessageReceived(browser, source_process, message); 197 | } 198 | 199 | private: 200 | CefRefPtr m_messageRouter; 201 | 202 | IMPLEMENT_REFCOUNTING(RendererApp); 203 | DISALLOW_COPY_AND_ASSIGN(RendererApp); 204 | }; 205 | //////////////////////////////////////// 206 | 207 | int main(int argc, char* argv[]) 208 | { 209 | CefRefPtr commandLine = CefCommandLine::CreateCommandLine(); 210 | #if defined(_WIN32) 211 | CefEnableHighDPISupport(); 212 | CefMainArgs args(GetModuleHandle(NULL)); 213 | commandLine->InitFromString(GetCommandLineW()); 214 | #else 215 | CefMainArgs args(argc, argv); 216 | commandLine->InitFromArgv(argc, argv); 217 | #endif 218 | 219 | void* windowsSandboxInfo = NULL; 220 | 221 | #if defined(CEF_USE_SANDBOX) && defined(_WIN32) 222 | // Manage the life span of the sandbox information object. This is necessary 223 | // for sandbox support on Windows. See cef_sandbox_win.h for complete details. 224 | CefScopedSandboxInfo scopedSandbox; 225 | windowsSandboxInfo = scopedSandbox.sandbox_info(); 226 | #endif 227 | 228 | CefRefPtr app = nullptr; 229 | std::string appType = commandLine->GetSwitchValue("type"); 230 | if (appType == "renderer" || appType == "zygote") { 231 | app = new RendererApp; 232 | } 233 | int result = CefExecuteProcess(args, app, windowsSandboxInfo); 234 | if (result >= 0) 235 | { 236 | // child process completed 237 | return result; 238 | } 239 | 240 | CefSettings settings; 241 | settings.windowless_rendering_enabled = 1; 242 | #if !defined(CEF_USE_SANDBOX) 243 | settings.no_sandbox = true; 244 | #endif 245 | 246 | CefInitialize(args, settings, nullptr, windowsSandboxInfo); 247 | 248 | CefWindowInfo windowInfo; 249 | windowInfo.SetAsWindowless(0); 250 | 251 | CefBrowserSettings browserSettings; 252 | auto browser = CefBrowserHost::CreateBrowserSync(windowInfo, new HeadlessClient, URL, browserSettings, nullptr); 253 | 254 | // main loop 255 | while (!HTML_LoadingDone) 256 | { 257 | CefDoMessageLoopWork(); 258 | std::this_thread::sleep_for(std::chrono::milliseconds(15)); 259 | } 260 | 261 | browser = nullptr; 262 | CefShutdown(); 263 | 264 | return 0; 265 | } -------------------------------------------------------------------------------- /demos/file-manager/win_dirent.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dirent interface for Microsoft Visual Studio 3 | * 4 | * Copyright (C) 1998-2019 Toni Ronkko 5 | * This file is part of dirent. Dirent may be freely distributed 6 | * under the MIT license. For all details and documentation, see 7 | * https://github.com/tronkko/dirent 8 | */ 9 | #ifndef DIRENT_H 10 | #define DIRENT_H 11 | 12 | /* Hide warnings about unreferenced local functions */ 13 | #if defined(__clang__) 14 | # pragma clang diagnostic ignored "-Wunused-function" 15 | #elif defined(_MSC_VER) 16 | # pragma warning(disable:4505) 17 | #elif defined(__GNUC__) 18 | # pragma GCC diagnostic ignored "-Wunused-function" 19 | #endif 20 | 21 | /* 22 | * Include windows.h without Windows Sockets 1.1 to prevent conflicts with 23 | * Windows Sockets 2.0. 24 | */ 25 | #ifndef WIN32_LEAN_AND_MEAN 26 | # define WIN32_LEAN_AND_MEAN 27 | #endif 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | /* Indicates that d_type field is available in dirent structure */ 41 | #define _DIRENT_HAVE_D_TYPE 42 | 43 | /* Indicates that d_namlen field is available in dirent structure */ 44 | #define _DIRENT_HAVE_D_NAMLEN 45 | 46 | /* Entries missing from MSVC 6.0 */ 47 | #if !defined(FILE_ATTRIBUTE_DEVICE) 48 | # define FILE_ATTRIBUTE_DEVICE 0x40 49 | #endif 50 | 51 | /* File type and permission flags for stat(), general mask */ 52 | #if !defined(S_IFMT) 53 | # define S_IFMT _S_IFMT 54 | #endif 55 | 56 | /* Directory bit */ 57 | #if !defined(S_IFDIR) 58 | # define S_IFDIR _S_IFDIR 59 | #endif 60 | 61 | /* Character device bit */ 62 | #if !defined(S_IFCHR) 63 | # define S_IFCHR _S_IFCHR 64 | #endif 65 | 66 | /* Pipe bit */ 67 | #if !defined(S_IFFIFO) 68 | # define S_IFFIFO _S_IFFIFO 69 | #endif 70 | 71 | /* Regular file bit */ 72 | #if !defined(S_IFREG) 73 | # define S_IFREG _S_IFREG 74 | #endif 75 | 76 | /* Read permission */ 77 | #if !defined(S_IREAD) 78 | # define S_IREAD _S_IREAD 79 | #endif 80 | 81 | /* Write permission */ 82 | #if !defined(S_IWRITE) 83 | # define S_IWRITE _S_IWRITE 84 | #endif 85 | 86 | /* Execute permission */ 87 | #if !defined(S_IEXEC) 88 | # define S_IEXEC _S_IEXEC 89 | #endif 90 | 91 | /* Pipe */ 92 | #if !defined(S_IFIFO) 93 | # define S_IFIFO _S_IFIFO 94 | #endif 95 | 96 | /* Block device */ 97 | #if !defined(S_IFBLK) 98 | # define S_IFBLK 0 99 | #endif 100 | 101 | /* Link */ 102 | #if !defined(S_IFLNK) 103 | # define S_IFLNK 0 104 | #endif 105 | 106 | /* Socket */ 107 | #if !defined(S_IFSOCK) 108 | # define S_IFSOCK 0 109 | #endif 110 | 111 | /* Read user permission */ 112 | #if !defined(S_IRUSR) 113 | # define S_IRUSR S_IREAD 114 | #endif 115 | 116 | /* Write user permission */ 117 | #if !defined(S_IWUSR) 118 | # define S_IWUSR S_IWRITE 119 | #endif 120 | 121 | /* Execute user permission */ 122 | #if !defined(S_IXUSR) 123 | # define S_IXUSR 0 124 | #endif 125 | 126 | /* Read group permission */ 127 | #if !defined(S_IRGRP) 128 | # define S_IRGRP 0 129 | #endif 130 | 131 | /* Write group permission */ 132 | #if !defined(S_IWGRP) 133 | # define S_IWGRP 0 134 | #endif 135 | 136 | /* Execute group permission */ 137 | #if !defined(S_IXGRP) 138 | # define S_IXGRP 0 139 | #endif 140 | 141 | /* Read others permission */ 142 | #if !defined(S_IROTH) 143 | # define S_IROTH 0 144 | #endif 145 | 146 | /* Write others permission */ 147 | #if !defined(S_IWOTH) 148 | # define S_IWOTH 0 149 | #endif 150 | 151 | /* Execute others permission */ 152 | #if !defined(S_IXOTH) 153 | # define S_IXOTH 0 154 | #endif 155 | 156 | /* Maximum length of file name */ 157 | #if !defined(PATH_MAX) 158 | # define PATH_MAX MAX_PATH 159 | #endif 160 | #if !defined(FILENAME_MAX) 161 | # define FILENAME_MAX MAX_PATH 162 | #endif 163 | #if !defined(NAME_MAX) 164 | # define NAME_MAX FILENAME_MAX 165 | #endif 166 | 167 | /* File type flags for d_type */ 168 | #define DT_UNKNOWN 0 169 | #define DT_REG S_IFREG 170 | #define DT_DIR S_IFDIR 171 | #define DT_FIFO S_IFIFO 172 | #define DT_SOCK S_IFSOCK 173 | #define DT_CHR S_IFCHR 174 | #define DT_BLK S_IFBLK 175 | #define DT_LNK S_IFLNK 176 | 177 | /* Macros for converting between st_mode and d_type */ 178 | #define IFTODT(mode) ((mode) & S_IFMT) 179 | #define DTTOIF(type) (type) 180 | 181 | /* 182 | * File type macros. Note that block devices, sockets and links cannot be 183 | * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are 184 | * only defined for compatibility. These macros should always return false 185 | * on Windows. 186 | */ 187 | #if !defined(S_ISFIFO) 188 | # define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) 189 | #endif 190 | #if !defined(S_ISDIR) 191 | # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) 192 | #endif 193 | #if !defined(S_ISREG) 194 | # define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) 195 | #endif 196 | #if !defined(S_ISLNK) 197 | # define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) 198 | #endif 199 | #if !defined(S_ISSOCK) 200 | # define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) 201 | #endif 202 | #if !defined(S_ISCHR) 203 | # define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) 204 | #endif 205 | #if !defined(S_ISBLK) 206 | # define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) 207 | #endif 208 | 209 | /* Return the exact length of the file name without zero terminator */ 210 | #define _D_EXACT_NAMLEN(p) ((p)->d_namlen) 211 | 212 | /* Return the maximum size of a file name */ 213 | #define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1) 214 | 215 | 216 | #ifdef __cplusplus 217 | extern "C" { 218 | #endif 219 | 220 | 221 | /* Wide-character version */ 222 | struct _wdirent { 223 | /* Always zero */ 224 | long d_ino; 225 | 226 | /* File position within stream */ 227 | long d_off; 228 | 229 | /* Structure size */ 230 | unsigned short d_reclen; 231 | 232 | /* Length of name without \0 */ 233 | size_t d_namlen; 234 | 235 | /* File type */ 236 | int d_type; 237 | 238 | /* File name */ 239 | wchar_t d_name[PATH_MAX + 1]; 240 | }; 241 | typedef struct _wdirent _wdirent; 242 | 243 | struct _WDIR { 244 | /* Current directory entry */ 245 | struct _wdirent ent; 246 | 247 | /* Private file data */ 248 | WIN32_FIND_DATAW data; 249 | 250 | /* True if data is valid */ 251 | int cached; 252 | 253 | /* Win32 search handle */ 254 | HANDLE handle; 255 | 256 | /* Initial directory name */ 257 | wchar_t *patt; 258 | }; 259 | typedef struct _WDIR _WDIR; 260 | 261 | /* Multi-byte character version */ 262 | struct dirent { 263 | /* Always zero */ 264 | long d_ino; 265 | 266 | /* File position within stream */ 267 | long d_off; 268 | 269 | /* Structure size */ 270 | unsigned short d_reclen; 271 | 272 | /* Length of name without \0 */ 273 | size_t d_namlen; 274 | 275 | /* File type */ 276 | int d_type; 277 | 278 | /* File name */ 279 | char d_name[PATH_MAX + 1]; 280 | }; 281 | typedef struct dirent dirent; 282 | 283 | struct DIR { 284 | struct dirent ent; 285 | struct _WDIR *wdirp; 286 | }; 287 | typedef struct DIR DIR; 288 | 289 | 290 | /* Dirent functions */ 291 | static DIR *opendir(const char *dirname); 292 | static _WDIR *_wopendir(const wchar_t *dirname); 293 | 294 | static struct dirent *readdir(DIR *dirp); 295 | static struct _wdirent *_wreaddir(_WDIR *dirp); 296 | 297 | static int readdir_r( 298 | DIR *dirp, struct dirent *entry, struct dirent **result); 299 | static int _wreaddir_r( 300 | _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result); 301 | 302 | static int closedir(DIR *dirp); 303 | static int _wclosedir(_WDIR *dirp); 304 | 305 | static void rewinddir(DIR* dirp); 306 | static void _wrewinddir(_WDIR* dirp); 307 | 308 | static int scandir(const char *dirname, struct dirent ***namelist, 309 | int(*filter)(const struct dirent*), 310 | int(*compare)(const struct dirent**, const struct dirent**)); 311 | 312 | static int alphasort(const struct dirent **a, const struct dirent **b); 313 | 314 | static int versionsort(const struct dirent **a, const struct dirent **b); 315 | 316 | 317 | /* For compatibility with Symbian */ 318 | #define wdirent _wdirent 319 | #define WDIR _WDIR 320 | #define wopendir _wopendir 321 | #define wreaddir _wreaddir 322 | #define wclosedir _wclosedir 323 | #define wrewinddir _wrewinddir 324 | 325 | 326 | /* Internal utility functions */ 327 | static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp); 328 | static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp); 329 | 330 | static int dirent_mbstowcs_s( 331 | size_t *pReturnValue, 332 | wchar_t *wcstr, 333 | size_t sizeInWords, 334 | const char *mbstr, 335 | size_t count); 336 | 337 | static int dirent_wcstombs_s( 338 | size_t *pReturnValue, 339 | char *mbstr, 340 | size_t sizeInBytes, 341 | const wchar_t *wcstr, 342 | size_t count); 343 | 344 | static void dirent_set_errno(int error); 345 | 346 | 347 | /* 348 | * Open directory stream DIRNAME for read and return a pointer to the 349 | * internal working area that is used to retrieve individual directory 350 | * entries. 351 | */ 352 | static _WDIR* 353 | _wopendir( 354 | const wchar_t *dirname) 355 | { 356 | _WDIR *dirp; 357 | DWORD n; 358 | wchar_t *p; 359 | 360 | /* Must have directory name */ 361 | if (dirname == NULL || dirname[0] == '\0') { 362 | dirent_set_errno(ENOENT); 363 | return NULL; 364 | } 365 | 366 | /* Allocate new _WDIR structure */ 367 | dirp = (_WDIR*)malloc(sizeof(struct _WDIR)); 368 | if (!dirp) { 369 | return NULL; 370 | } 371 | 372 | /* Reset _WDIR structure */ 373 | dirp->handle = INVALID_HANDLE_VALUE; 374 | dirp->patt = NULL; 375 | dirp->cached = 0; 376 | 377 | /* 378 | * Compute the length of full path plus zero terminator 379 | * 380 | * Note that on WinRT there's no way to convert relative paths 381 | * into absolute paths, so just assume it is an absolute path. 382 | */ 383 | #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 384 | /* Desktop */ 385 | n = GetFullPathNameW(dirname, 0, NULL, NULL); 386 | #else 387 | /* WinRT */ 388 | n = wcslen(dirname); 389 | #endif 390 | 391 | /* Allocate room for absolute directory name and search pattern */ 392 | dirp->patt = (wchar_t*)malloc(sizeof(wchar_t) * n + 16); 393 | if (dirp->patt == NULL) { 394 | goto exit_closedir; 395 | } 396 | 397 | /* 398 | * Convert relative directory name to an absolute one. This 399 | * allows rewinddir() to function correctly even when current 400 | * working directory is changed between opendir() and rewinddir(). 401 | * 402 | * Note that on WinRT there's no way to convert relative paths 403 | * into absolute paths, so just assume it is an absolute path. 404 | */ 405 | #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 406 | /* Desktop */ 407 | n = GetFullPathNameW(dirname, n, dirp->patt, NULL); 408 | if (n <= 0) { 409 | goto exit_closedir; 410 | } 411 | #else 412 | /* WinRT */ 413 | wcsncpy_s(dirp->patt, n + 1, dirname, n); 414 | #endif 415 | 416 | /* Append search pattern \* to the directory name */ 417 | p = dirp->patt + n; 418 | switch (p[-1]) { 419 | case '\\': 420 | case '/': 421 | case ':': 422 | /* Directory ends in path separator, e.g. c:\temp\ */ 423 | /*NOP*/; 424 | break; 425 | 426 | default: 427 | /* Directory name doesn't end in path separator */ 428 | *p++ = '\\'; 429 | } 430 | *p++ = '*'; 431 | *p = '\0'; 432 | 433 | /* Open directory stream and retrieve the first entry */ 434 | if (!dirent_first(dirp)) { 435 | goto exit_closedir; 436 | } 437 | 438 | /* Success */ 439 | return dirp; 440 | 441 | /* Failure */ 442 | exit_closedir: 443 | _wclosedir(dirp); 444 | return NULL; 445 | } 446 | 447 | /* 448 | * Read next directory entry. 449 | * 450 | * Returns pointer to static directory entry which may be overwritten by 451 | * subsequent calls to _wreaddir(). 452 | */ 453 | static struct _wdirent* 454 | _wreaddir( 455 | _WDIR *dirp) 456 | { 457 | struct _wdirent *entry; 458 | 459 | /* 460 | * Read directory entry to buffer. We can safely ignore the return value 461 | * as entry will be set to NULL in case of error. 462 | */ 463 | (void)_wreaddir_r(dirp, &dirp->ent, &entry); 464 | 465 | /* Return pointer to statically allocated directory entry */ 466 | return entry; 467 | } 468 | 469 | /* 470 | * Read next directory entry. 471 | * 472 | * Returns zero on success. If end of directory stream is reached, then sets 473 | * result to NULL and returns zero. 474 | */ 475 | static int 476 | _wreaddir_r( 477 | _WDIR *dirp, 478 | struct _wdirent *entry, 479 | struct _wdirent **result) 480 | { 481 | WIN32_FIND_DATAW *datap; 482 | 483 | /* Read next directory entry */ 484 | datap = dirent_next(dirp); 485 | if (datap) { 486 | size_t n; 487 | DWORD attr; 488 | 489 | /* 490 | * Copy file name as wide-character string. If the file name is too 491 | * long to fit in to the destination buffer, then truncate file name 492 | * to PATH_MAX characters and zero-terminate the buffer. 493 | */ 494 | n = 0; 495 | while (n < PATH_MAX && datap->cFileName[n] != 0) { 496 | entry->d_name[n] = datap->cFileName[n]; 497 | n++; 498 | } 499 | entry->d_name[n] = 0; 500 | 501 | /* Length of file name excluding zero terminator */ 502 | entry->d_namlen = n; 503 | 504 | /* File type */ 505 | attr = datap->dwFileAttributes; 506 | if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { 507 | entry->d_type = DT_CHR; 508 | } 509 | else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { 510 | entry->d_type = DT_DIR; 511 | } 512 | else { 513 | entry->d_type = DT_REG; 514 | } 515 | 516 | /* Reset dummy fields */ 517 | entry->d_ino = 0; 518 | entry->d_off = 0; 519 | entry->d_reclen = sizeof(struct _wdirent); 520 | 521 | /* Set result address */ 522 | *result = entry; 523 | 524 | } 525 | else { 526 | 527 | /* Return NULL to indicate end of directory */ 528 | *result = NULL; 529 | 530 | } 531 | 532 | return /*OK*/0; 533 | } 534 | 535 | /* 536 | * Close directory stream opened by opendir() function. This invalidates the 537 | * DIR structure as well as any directory entry read previously by 538 | * _wreaddir(). 539 | */ 540 | static int 541 | _wclosedir( 542 | _WDIR *dirp) 543 | { 544 | int ok; 545 | if (dirp) { 546 | 547 | /* Release search handle */ 548 | if (dirp->handle != INVALID_HANDLE_VALUE) { 549 | FindClose(dirp->handle); 550 | } 551 | 552 | /* Release search pattern */ 553 | free(dirp->patt); 554 | 555 | /* Release directory structure */ 556 | free(dirp); 557 | ok = /*success*/0; 558 | 559 | } 560 | else { 561 | 562 | /* Invalid directory stream */ 563 | dirent_set_errno(EBADF); 564 | ok = /*failure*/-1; 565 | 566 | } 567 | return ok; 568 | } 569 | 570 | /* 571 | * Rewind directory stream such that _wreaddir() returns the very first 572 | * file name again. 573 | */ 574 | static void 575 | _wrewinddir( 576 | _WDIR* dirp) 577 | { 578 | if (dirp) { 579 | /* Release existing search handle */ 580 | if (dirp->handle != INVALID_HANDLE_VALUE) { 581 | FindClose(dirp->handle); 582 | } 583 | 584 | /* Open new search handle */ 585 | dirent_first(dirp); 586 | } 587 | } 588 | 589 | /* Get first directory entry (internal) */ 590 | static WIN32_FIND_DATAW* 591 | dirent_first( 592 | _WDIR *dirp) 593 | { 594 | WIN32_FIND_DATAW *datap; 595 | DWORD error; 596 | 597 | /* Open directory and retrieve the first entry */ 598 | dirp->handle = FindFirstFileExW( 599 | dirp->patt, FindExInfoStandard, &dirp->data, 600 | FindExSearchNameMatch, NULL, 0); 601 | if (dirp->handle != INVALID_HANDLE_VALUE) { 602 | 603 | /* a directory entry is now waiting in memory */ 604 | datap = &dirp->data; 605 | dirp->cached = 1; 606 | 607 | } 608 | else { 609 | 610 | /* Failed to open directory: no directory entry in memory */ 611 | dirp->cached = 0; 612 | datap = NULL; 613 | 614 | /* Set error code */ 615 | error = GetLastError(); 616 | switch (error) { 617 | case ERROR_ACCESS_DENIED: 618 | /* No read access to directory */ 619 | dirent_set_errno(EACCES); 620 | break; 621 | 622 | case ERROR_DIRECTORY: 623 | /* Directory name is invalid */ 624 | dirent_set_errno(ENOTDIR); 625 | break; 626 | 627 | case ERROR_PATH_NOT_FOUND: 628 | default: 629 | /* Cannot find the file */ 630 | dirent_set_errno(ENOENT); 631 | } 632 | 633 | } 634 | return datap; 635 | } 636 | 637 | /* 638 | * Get next directory entry (internal). 639 | * 640 | * Returns 641 | */ 642 | static WIN32_FIND_DATAW* 643 | dirent_next( 644 | _WDIR *dirp) 645 | { 646 | WIN32_FIND_DATAW *p; 647 | 648 | /* Get next directory entry */ 649 | if (dirp->cached != 0) { 650 | 651 | /* A valid directory entry already in memory */ 652 | p = &dirp->data; 653 | dirp->cached = 0; 654 | 655 | } 656 | else if (dirp->handle != INVALID_HANDLE_VALUE) { 657 | 658 | /* Get the next directory entry from stream */ 659 | if (FindNextFileW(dirp->handle, &dirp->data) != FALSE) { 660 | /* Got a file */ 661 | p = &dirp->data; 662 | } 663 | else { 664 | /* The very last entry has been processed or an error occurred */ 665 | FindClose(dirp->handle); 666 | dirp->handle = INVALID_HANDLE_VALUE; 667 | p = NULL; 668 | } 669 | 670 | } 671 | else { 672 | 673 | /* End of directory stream reached */ 674 | p = NULL; 675 | 676 | } 677 | 678 | return p; 679 | } 680 | 681 | /* 682 | * Open directory stream using plain old C-string. 683 | */ 684 | static DIR* 685 | opendir( 686 | const char *dirname) 687 | { 688 | struct DIR *dirp; 689 | 690 | /* Must have directory name */ 691 | if (dirname == NULL || dirname[0] == '\0') { 692 | dirent_set_errno(ENOENT); 693 | return NULL; 694 | } 695 | 696 | /* Allocate memory for DIR structure */ 697 | dirp = (DIR*)malloc(sizeof(struct DIR)); 698 | if (!dirp) { 699 | return NULL; 700 | } 701 | { 702 | int error; 703 | wchar_t wname[PATH_MAX + 1]; 704 | size_t n; 705 | 706 | /* Convert directory name to wide-character string */ 707 | error = dirent_mbstowcs_s( 708 | &n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1); 709 | if (error) { 710 | /* 711 | * Cannot convert file name to wide-character string. This 712 | * occurs if the string contains invalid multi-byte sequences or 713 | * the output buffer is too small to contain the resulting 714 | * string. 715 | */ 716 | goto exit_free; 717 | } 718 | 719 | 720 | /* Open directory stream using wide-character name */ 721 | dirp->wdirp = _wopendir(wname); 722 | if (!dirp->wdirp) { 723 | goto exit_free; 724 | } 725 | 726 | } 727 | 728 | /* Success */ 729 | return dirp; 730 | 731 | /* Failure */ 732 | exit_free: 733 | free(dirp); 734 | return NULL; 735 | } 736 | 737 | /* 738 | * Read next directory entry. 739 | */ 740 | static struct dirent* 741 | readdir( 742 | DIR *dirp) 743 | { 744 | struct dirent *entry; 745 | 746 | /* 747 | * Read directory entry to buffer. We can safely ignore the return value 748 | * as entry will be set to NULL in case of error. 749 | */ 750 | (void)readdir_r(dirp, &dirp->ent, &entry); 751 | 752 | /* Return pointer to statically allocated directory entry */ 753 | return entry; 754 | } 755 | 756 | /* 757 | * Read next directory entry into called-allocated buffer. 758 | * 759 | * Returns zero on success. If the end of directory stream is reached, then 760 | * sets result to NULL and returns zero. 761 | */ 762 | static int 763 | readdir_r( 764 | DIR *dirp, 765 | struct dirent *entry, 766 | struct dirent **result) 767 | { 768 | WIN32_FIND_DATAW *datap; 769 | 770 | /* Read next directory entry */ 771 | datap = dirent_next(dirp->wdirp); 772 | if (datap) { 773 | size_t n; 774 | int error; 775 | 776 | /* Attempt to convert file name to multi-byte string */ 777 | error = dirent_wcstombs_s( 778 | &n, entry->d_name, PATH_MAX + 1, datap->cFileName, PATH_MAX + 1); 779 | 780 | /* 781 | * If the file name cannot be represented by a multi-byte string, 782 | * then attempt to use old 8+3 file name. This allows traditional 783 | * Unix-code to access some file names despite of unicode 784 | * characters, although file names may seem unfamiliar to the user. 785 | * 786 | * Be ware that the code below cannot come up with a short file 787 | * name unless the file system provides one. At least 788 | * VirtualBox shared folders fail to do this. 789 | */ 790 | if (error && datap->cAlternateFileName[0] != '\0') { 791 | error = dirent_wcstombs_s( 792 | &n, entry->d_name, PATH_MAX + 1, 793 | datap->cAlternateFileName, PATH_MAX + 1); 794 | } 795 | 796 | if (!error) { 797 | DWORD attr; 798 | 799 | /* Length of file name excluding zero terminator */ 800 | entry->d_namlen = n - 1; 801 | 802 | /* File attributes */ 803 | attr = datap->dwFileAttributes; 804 | if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { 805 | entry->d_type = DT_CHR; 806 | } 807 | else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { 808 | entry->d_type = DT_DIR; 809 | } 810 | else { 811 | entry->d_type = DT_REG; 812 | } 813 | 814 | /* Reset dummy fields */ 815 | entry->d_ino = 0; 816 | entry->d_off = 0; 817 | entry->d_reclen = sizeof(struct dirent); 818 | 819 | } 820 | else { 821 | 822 | /* 823 | * Cannot convert file name to multi-byte string so construct 824 | * an erroneous directory entry and return that. Note that 825 | * we cannot return NULL as that would stop the processing 826 | * of directory entries completely. 827 | */ 828 | entry->d_name[0] = '?'; 829 | entry->d_name[1] = '\0'; 830 | entry->d_namlen = 1; 831 | entry->d_type = DT_UNKNOWN; 832 | entry->d_ino = 0; 833 | entry->d_off = -1; 834 | entry->d_reclen = 0; 835 | 836 | } 837 | 838 | /* Return pointer to directory entry */ 839 | *result = entry; 840 | 841 | } 842 | else { 843 | 844 | /* No more directory entries */ 845 | *result = NULL; 846 | 847 | } 848 | 849 | return /*OK*/0; 850 | } 851 | 852 | /* 853 | * Close directory stream. 854 | */ 855 | static int 856 | closedir( 857 | DIR *dirp) 858 | { 859 | int ok; 860 | if (dirp) { 861 | 862 | /* Close wide-character directory stream */ 863 | ok = _wclosedir(dirp->wdirp); 864 | dirp->wdirp = NULL; 865 | 866 | /* Release multi-byte character version */ 867 | free(dirp); 868 | 869 | } 870 | else { 871 | 872 | /* Invalid directory stream */ 873 | dirent_set_errno(EBADF); 874 | ok = /*failure*/-1; 875 | 876 | } 877 | return ok; 878 | } 879 | 880 | /* 881 | * Rewind directory stream to beginning. 882 | */ 883 | static void 884 | rewinddir( 885 | DIR* dirp) 886 | { 887 | /* Rewind wide-character string directory stream */ 888 | _wrewinddir(dirp->wdirp); 889 | } 890 | 891 | /* 892 | * Scan directory for entries. 893 | */ 894 | static int 895 | scandir( 896 | const char *dirname, 897 | struct dirent ***namelist, 898 | int(*filter)(const struct dirent*), 899 | int(*compare)(const struct dirent**, const struct dirent**)) 900 | { 901 | struct dirent **files = NULL; 902 | size_t size = 0; 903 | size_t allocated = 0; 904 | const size_t init_size = 1; 905 | DIR *dir = NULL; 906 | struct dirent *entry; 907 | struct dirent *tmp = NULL; 908 | size_t i; 909 | int result = 0; 910 | 911 | /* Open directory stream */ 912 | dir = opendir(dirname); 913 | if (dir) { 914 | 915 | /* Read directory entries to memory */ 916 | while (1) { 917 | 918 | /* Enlarge pointer table to make room for another pointer */ 919 | if (size >= allocated) { 920 | void *p; 921 | size_t num_entries; 922 | 923 | /* Compute number of entries in the enlarged pointer table */ 924 | if (size < init_size) { 925 | /* Allocate initial pointer table */ 926 | num_entries = init_size; 927 | } 928 | else { 929 | /* Double the size */ 930 | num_entries = size * 2; 931 | } 932 | 933 | /* Allocate first pointer table or enlarge existing table */ 934 | p = realloc(files, sizeof(void*) * num_entries); 935 | if (p != NULL) { 936 | /* Got the memory */ 937 | files = (dirent**)p; 938 | allocated = num_entries; 939 | } 940 | else { 941 | /* Out of memory */ 942 | result = -1; 943 | break; 944 | } 945 | 946 | } 947 | 948 | /* Allocate room for temporary directory entry */ 949 | if (tmp == NULL) { 950 | tmp = (struct dirent*) malloc(sizeof(struct dirent)); 951 | if (tmp == NULL) { 952 | /* Cannot allocate temporary directory entry */ 953 | result = -1; 954 | break; 955 | } 956 | } 957 | 958 | /* Read directory entry to temporary area */ 959 | if (readdir_r(dir, tmp, &entry) == /*OK*/0) { 960 | 961 | /* Did we get an entry? */ 962 | if (entry != NULL) { 963 | int pass; 964 | 965 | /* Determine whether to include the entry in result */ 966 | if (filter) { 967 | /* Let the filter function decide */ 968 | pass = filter(tmp); 969 | } 970 | else { 971 | /* No filter function, include everything */ 972 | pass = 1; 973 | } 974 | 975 | if (pass) { 976 | /* Store the temporary entry to pointer table */ 977 | files[size++] = tmp; 978 | tmp = NULL; 979 | 980 | /* Keep up with the number of files */ 981 | result++; 982 | } 983 | 984 | } 985 | else { 986 | 987 | /* 988 | * End of directory stream reached => sort entries and 989 | * exit. 990 | */ 991 | qsort(files, size, sizeof(void*), 992 | (int(*) (const void*, const void*)) compare); 993 | break; 994 | 995 | } 996 | 997 | } 998 | else { 999 | /* Error reading directory entry */ 1000 | result = /*Error*/ -1; 1001 | break; 1002 | } 1003 | 1004 | } 1005 | 1006 | } 1007 | else { 1008 | /* Cannot open directory */ 1009 | result = /*Error*/ -1; 1010 | } 1011 | 1012 | /* Release temporary directory entry */ 1013 | free(tmp); 1014 | 1015 | /* Release allocated memory on error */ 1016 | if (result < 0) { 1017 | for (i = 0; i < size; i++) { 1018 | free(files[i]); 1019 | } 1020 | free(files); 1021 | files = NULL; 1022 | } 1023 | 1024 | /* Close directory stream */ 1025 | if (dir) { 1026 | closedir(dir); 1027 | } 1028 | 1029 | /* Pass pointer table to caller */ 1030 | if (namelist) { 1031 | *namelist = files; 1032 | } 1033 | return result; 1034 | } 1035 | 1036 | /* Alphabetical sorting */ 1037 | static int 1038 | alphasort( 1039 | const struct dirent **a, const struct dirent **b) 1040 | { 1041 | return strcoll((*a)->d_name, (*b)->d_name); 1042 | } 1043 | 1044 | /* Sort versions */ 1045 | static int 1046 | versionsort( 1047 | const struct dirent **a, const struct dirent **b) 1048 | { 1049 | /* FIXME: implement strverscmp and use that */ 1050 | return alphasort(a, b); 1051 | } 1052 | 1053 | /* Convert multi-byte string to wide character string */ 1054 | static int 1055 | dirent_mbstowcs_s( 1056 | size_t *pReturnValue, 1057 | wchar_t *wcstr, 1058 | size_t sizeInWords, 1059 | const char *mbstr, 1060 | size_t count) 1061 | { 1062 | int error; 1063 | 1064 | #if defined(_MSC_VER) && _MSC_VER >= 1400 1065 | 1066 | /* Microsoft Visual Studio 2005 or later */ 1067 | error = mbstowcs_s(pReturnValue, wcstr, sizeInWords, mbstr, count); 1068 | 1069 | #else 1070 | 1071 | /* Older Visual Studio or non-Microsoft compiler */ 1072 | size_t n; 1073 | 1074 | /* Convert to wide-character string (or count characters) */ 1075 | n = mbstowcs(wcstr, mbstr, sizeInWords); 1076 | if (!wcstr || n < count) { 1077 | 1078 | /* Zero-terminate output buffer */ 1079 | if (wcstr && sizeInWords) { 1080 | if (n >= sizeInWords) { 1081 | n = sizeInWords - 1; 1082 | } 1083 | wcstr[n] = 0; 1084 | } 1085 | 1086 | /* Length of resulting multi-byte string WITH zero terminator */ 1087 | if (pReturnValue) { 1088 | *pReturnValue = n + 1; 1089 | } 1090 | 1091 | /* Success */ 1092 | error = 0; 1093 | 1094 | } 1095 | else { 1096 | 1097 | /* Could not convert string */ 1098 | error = 1; 1099 | 1100 | } 1101 | 1102 | #endif 1103 | return error; 1104 | } 1105 | 1106 | /* Convert wide-character string to multi-byte string */ 1107 | static int 1108 | dirent_wcstombs_s( 1109 | size_t *pReturnValue, 1110 | char *mbstr, 1111 | size_t sizeInBytes, /* max size of mbstr */ 1112 | const wchar_t *wcstr, 1113 | size_t count) 1114 | { 1115 | int error; 1116 | 1117 | #if defined(_MSC_VER) && _MSC_VER >= 1400 1118 | 1119 | /* Microsoft Visual Studio 2005 or later */ 1120 | error = wcstombs_s(pReturnValue, mbstr, sizeInBytes, wcstr, count); 1121 | 1122 | #else 1123 | 1124 | /* Older Visual Studio or non-Microsoft compiler */ 1125 | size_t n; 1126 | 1127 | /* Convert to multi-byte string (or count the number of bytes needed) */ 1128 | n = wcstombs(mbstr, wcstr, sizeInBytes); 1129 | if (!mbstr || n < count) { 1130 | 1131 | /* Zero-terminate output buffer */ 1132 | if (mbstr && sizeInBytes) { 1133 | if (n >= sizeInBytes) { 1134 | n = sizeInBytes - 1; 1135 | } 1136 | mbstr[n] = '\0'; 1137 | } 1138 | 1139 | /* Length of resulting multi-bytes string WITH zero-terminator */ 1140 | if (pReturnValue) { 1141 | *pReturnValue = n + 1; 1142 | } 1143 | 1144 | /* Success */ 1145 | error = 0; 1146 | 1147 | } 1148 | else { 1149 | 1150 | /* Cannot convert string */ 1151 | error = 1; 1152 | 1153 | } 1154 | 1155 | #endif 1156 | return error; 1157 | } 1158 | 1159 | /* Set errno variable */ 1160 | static void 1161 | dirent_set_errno( 1162 | int error) 1163 | { 1164 | #if defined(_MSC_VER) && _MSC_VER >= 1400 1165 | 1166 | /* Microsoft Visual Studio 2005 and later */ 1167 | _set_errno(error); 1168 | 1169 | #else 1170 | 1171 | /* Non-Microsoft compiler or older Microsoft compiler */ 1172 | errno = error; 1173 | 1174 | #endif 1175 | } 1176 | 1177 | 1178 | #ifdef __cplusplus 1179 | } 1180 | #endif 1181 | #endif /*DIRENT_H*/ 1182 | --------------------------------------------------------------------------------