Jelajahi Sumber

Added initial work on a wxWidgets-based test app.

Ryan C. Gordon 19 tahun lalu
induk
melakukan
40ab6d277f
3 mengubah file dengan 508 tambahan dan 2 penghapusan
  1. 1 0
      CHANGELOG.txt
  2. 21 2
      CMakeLists.txt
  3. 486 0
      test/wxtest_physfs.cpp

+ 1 - 0
CHANGELOG.txt

@@ -2,6 +2,7 @@
  * CHANGELOG.
  * CHANGELOG.
  */
  */
 
 
+04022007 - Added wxWidgets-based test program (incomplete).
 04012007 - Added PHYSFS_isInit() and PHYSFS_symbolicLinksPermitted() functions.
 04012007 - Added PHYSFS_isInit() and PHYSFS_symbolicLinksPermitted() functions.
 03312007 - Added a quick'n'dirty unpack utility to the extras directory. Moved
 03312007 - Added a quick'n'dirty unpack utility to the extras directory. Moved
            DIR archiver to start of the list, so we don't have to have every
            DIR archiver to start of the list, so we don't have to have every

+ 21 - 2
CMakeLists.txt

@@ -297,7 +297,7 @@ IF(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC)
     SET_TARGET_PROPERTIES(physfs-static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
     SET_TARGET_PROPERTIES(physfs-static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
 ENDIF(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC)
 ENDIF(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC)
 
 
-OPTION(PHYSFS_BUILD_TEST "Build test program." TRUE)
+OPTION(PHYSFS_BUILD_TEST "Build stdio test program." TRUE)
 MARK_AS_ADVANCED(PHYSFS_BUILD_TEST)
 MARK_AS_ADVANCED(PHYSFS_BUILD_TEST)
 IF(PHYSFS_BUILD_TEST)
 IF(PHYSFS_BUILD_TEST)
     CHECK_INCLUDE_FILE(readline/readline.h HAVE_READLINE_H)
     CHECK_INCLUDE_FILE(readline/readline.h HAVE_READLINE_H)
@@ -317,6 +317,24 @@ IF(PHYSFS_BUILD_TEST)
     SET(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";test_physfs")
     SET(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";test_physfs")
 ENDIF(PHYSFS_BUILD_TEST)
 ENDIF(PHYSFS_BUILD_TEST)
 
 
+OPTION(PHYSFS_BUILD_WX_TEST "Build wxWidgets test program." TRUE)
+MARK_AS_ADVANCED(PHYSFS_BUILD_WX_TEST)
+IF(PHYSFS_BUILD_WX_TEST)
+    SET(wxWidgets_USE_LIBS base core adv)
+    SET(wxWidgets_INCLUDE_DIRS_NO_SYSTEM 1)
+    FIND_PACKAGE(wxWidgets)
+    IF(wxWidgets_FOUND)
+        INCLUDE(${wxWidgets_USE_FILE})
+        ADD_EXECUTABLE(wxtest_physfs test/wxtest_physfs.cpp)
+        SET_SOURCE_FILES_PROPERTIES(test/wxtest_physfs.cpp COMPILE_FLAGS ${wxWidgets_CXX_FLAGS})
+        TARGET_LINK_LIBRARIES(wxtest_physfs ${PHYSFS_LIB_TARGET} ${wxWidgets_LIBRARIES} ${OTHER_LDFLAGS})
+        SET(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";wxtest_physfs")
+    ELSE(wxWidgets_FOUND)
+        MESSAGE(STATUS "wxWidgets not found. Disabling wx test app.")
+        SET(PHYSFS_BUILD_WX_TEST FALSE)
+    ENDIF(wxWidgets_FOUND)
+ENDIF(PHYSFS_BUILD_WX_TEST)
+
 INSTALL(TARGETS ${PHYSFS_INSTALL_TARGETS}
 INSTALL(TARGETS ${PHYSFS_INSTALL_TARGETS}
         RUNTIME DESTINATION bin
         RUNTIME DESTINATION bin
         LIBRARY DESTINATION lib
         LIBRARY DESTINATION lib
@@ -352,7 +370,8 @@ MESSAGE_BOOL_OPTION("Thread safety" PHYSFS_HAVE_THREAD_SUPPORT)
 MESSAGE_BOOL_OPTION("Build own zlib" PHYSFS_INTERNAL_ZLIB)
 MESSAGE_BOOL_OPTION("Build own zlib" PHYSFS_INTERNAL_ZLIB)
 MESSAGE_BOOL_OPTION("Build static library" PHYSFS_BUILD_STATIC)
 MESSAGE_BOOL_OPTION("Build static library" PHYSFS_BUILD_STATIC)
 MESSAGE_BOOL_OPTION("Build shared library" PHYSFS_BUILD_SHARED)
 MESSAGE_BOOL_OPTION("Build shared library" PHYSFS_BUILD_SHARED)
-MESSAGE_BOOL_OPTION("Build test program" PHYSFS_BUILD_TEST)
+MESSAGE_BOOL_OPTION("Build wxWidgets test program" PHYSFS_BUILD_WX_TEST)
+MESSAGE_BOOL_OPTION("Build stdio test program" PHYSFS_BUILD_TEST)
 IF(PHYSFS_BUILD_TEST)
 IF(PHYSFS_BUILD_TEST)
     MESSAGE_BOOL_OPTION("  Use readline in test program" HAVE_SYSTEM_READLINE)
     MESSAGE_BOOL_OPTION("  Use readline in test program" HAVE_SYSTEM_READLINE)
 ENDIF(PHYSFS_BUILD_TEST)
 ENDIF(PHYSFS_BUILD_TEST)

+ 486 - 0
test/wxtest_physfs.cpp

@@ -0,0 +1,486 @@
+/**
+ * Test program for PhysicsFS, using wxWidgets. May only work on Unix.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#if ( (defined(__MACH__)) && (defined(__APPLE__)) )
+#define PLATFORM_MACOSX 1
+#include <Carbon/Carbon.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include <wx/wx.h>
+#include <wx/treectrl.h>
+
+#include "physfs.h"
+
+#define TEST_VER_MAJOR  1
+#define TEST_VER_MINOR  1
+#define TEST_VER_PATCH  1
+
+//static PHYSFS_uint32 do_buffer_size = 0;
+
+enum WxTestPhysfsMenuCommands
+{
+    // start with standard menu items, since using the wxIDs will map them
+    //  to sane things in the platform's UI (gnome icons in GTK+, moves the
+    //  about and quit items to the Apple menu on Mac OS X, etc).
+    MENUCMD_About = wxID_ABOUT,
+    MENUCMD_Quit = wxID_EXIT,
+
+    // non-standard menu items go here.
+    MENUCMD_Init = wxID_HIGHEST,
+    MENUCMD_Deinit,
+    MENUCMD_AddArchive,
+    MENUCMD_Mount,
+    MENUCMD_Remove,
+    MENUCMD_GetCDs,
+    MENUCMD_SetWriteDir,
+    MENUCMD_PermitSymLinks,
+    MENUCMD_SetSaneConfig,
+    MENUCMD_MkDir,
+    MENUCMD_Delete,
+    MENUCMD_Cat,
+    MENUCMD_SetBuffer,
+    MENUCMD_StressBuffer,
+    MENUCMD_Append,
+    MENUCMD_Write,
+    MENUCMD_GetLastError,
+
+/*
+    { "getdirsep",      cmd_getdirsep,      0, NULL                         },
+    { "getsearchpath",  cmd_getsearchpath,  0, NULL                         },
+    { "getbasedir",     cmd_getbasedir,     0, NULL                         },
+    { "getuserdir",     cmd_getuserdir,     0, NULL                         },
+    { "getwritedir",    cmd_getwritedir,    0, NULL                         },
+    { "getrealdir",     cmd_getrealdir,     1, "<fileToFind>"               },
+    { "exists",         cmd_exists,         1, "<fileToCheck>"              },
+    { "isdir",          cmd_isdir,          1, "<fileToCheck>"              },
+    { "issymlink",      cmd_issymlink,      1, "<fileToCheck>"              },
+    { "filelength",     cmd_filelength,     1, "<fileToCheck>"              },
+    { "getlastmodtime", cmd_getlastmodtime, 1, "<fileToExamine>"            },
+*/
+};
+
+
+class WxTestPhysfsFrame : public wxFrame
+{
+public:
+    WxTestPhysfsFrame(const wxChar *argv0);
+
+    void rebuildTree();
+
+    void onMenuInit(wxCommandEvent &evt);
+    void onMenuDeinit(wxCommandEvent &evt);
+    void onMenuAddArchive(wxCommandEvent &evt);
+    void onMenuGetCDs(wxCommandEvent &evt);
+    void onMenuPermitSymLinks(wxCommandEvent &evt);
+
+private:
+    wxTreeCtrl *fileTree;
+    wxTreeItemId stateItem;
+    wxTreeItemId fsItem;
+
+    int err(int success);
+    void fillFileSystemTree(const char *path, const wxTreeItemId &item);
+    void doInit(const char *argv0);
+    void doDeinit();
+
+    DECLARE_EVENT_TABLE()
+};
+
+BEGIN_EVENT_TABLE(WxTestPhysfsFrame, wxFrame)
+    EVT_MENU(MENUCMD_Init, WxTestPhysfsFrame::onMenuInit)
+    EVT_MENU(MENUCMD_Deinit, WxTestPhysfsFrame::onMenuDeinit)
+    EVT_MENU(MENUCMD_AddArchive, WxTestPhysfsFrame::onMenuAddArchive)
+    EVT_MENU(MENUCMD_GetCDs, WxTestPhysfsFrame::onMenuGetCDs)
+    EVT_MENU(MENUCMD_PermitSymLinks, WxTestPhysfsFrame::onMenuPermitSymLinks)
+END_EVENT_TABLE()
+
+
+
+// This is the the Application itself.
+class WxTestPhysfsApp : public wxApp
+{
+public:
+    WxTestPhysfsApp() : mainWindow(NULL) { /* no-op. */ }
+    virtual bool OnInit();
+
+private:
+    WxTestPhysfsFrame *mainWindow;
+};
+
+DECLARE_APP(WxTestPhysfsApp)
+
+
+static inline char *newstr(const char *str)
+{
+    char *retval = NULL;
+    if (str != NULL)
+    {
+        retval = new char[strlen(str) + 1];
+        strcpy(retval, str);
+    } // if
+    return retval;
+} // newstr
+
+static char *newutf8(const wxString &wxstr)
+{
+    #if wxUSE_UNICODE
+    size_t len = wxstr.Len() + 1;
+    char *utf8text = new char[len * 6];
+    wxConvUTF8.WC2MB(utf8text, wxstr, len);
+    return utf8text;
+    #else
+    return newstr(wxstr);
+    #endif
+} // newutf8
+
+
+WxTestPhysfsFrame::WxTestPhysfsFrame(const wxChar *argv0)
+    : wxFrame(NULL, -1, wxT("WxTestPhysfs"))
+{
+    this->CreateStatusBar();
+
+    wxMenuBar *menuBar = new wxMenuBar;
+
+    wxMenu *stuffMenu = new wxMenu;
+    stuffMenu->Append(MENUCMD_Init, wxT("&Init"));
+    stuffMenu->Append(MENUCMD_Deinit, wxT("&Deinit"));
+    stuffMenu->Append(MENUCMD_AddArchive, wxT("&Add Archive"));
+    stuffMenu->Append(MENUCMD_Mount, wxT("&Mount Archive"));
+    stuffMenu->Append(MENUCMD_Remove, wxT("&Remove Archive"));
+    stuffMenu->Append(MENUCMD_GetCDs, wxT("&Get CD-ROM drives"));
+    stuffMenu->Append(MENUCMD_SetWriteDir, wxT("&Set Write Dir"));
+    stuffMenu->Append(MENUCMD_SetSaneConfig, wxT("Set Sane &Config"));
+    stuffMenu->Append(MENUCMD_MkDir, wxT("M&kDir"));
+    stuffMenu->Append(MENUCMD_Delete, wxT("D&elete"));
+    stuffMenu->Append(MENUCMD_Cat, wxT("&Cat"));
+    stuffMenu->Append(MENUCMD_SetBuffer, wxT("Set &Buffer"));
+    stuffMenu->Append(MENUCMD_StressBuffer, wxT("Stress &Test Buffer"));
+    stuffMenu->Append(MENUCMD_Append, wxT("&Append"));
+    stuffMenu->Append(MENUCMD_Write, wxT("&Write"));
+    stuffMenu->Append(MENUCMD_Write, wxT("&Update getLastError"));
+    stuffMenu->AppendCheckItem(MENUCMD_PermitSymLinks, wxT("&Permit symlinks"));
+    menuBar->Append(stuffMenu, wxT("&Stuff"));
+
+    //wxMenu *helpMenu = new wxMenu;
+    //helpMenu->Append(MENUCMD_About, wxT("&About\tF1"));
+    //menuBar->Append(helpMenu, wxT("&Help"));
+
+    this->SetMenuBar(menuBar);
+
+    this->fileTree = new wxTreeCtrl(this, -1);
+
+    // The sizer just makes sure that fileTree owns whole client area.
+    wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL);
+    sizer->Add(this->fileTree, 1, wxALL | wxEXPAND | wxALIGN_CENTRE);
+    sizer->SetItemMinSize(this->fileTree, 1, 1);
+    this->SetSizer(sizer);
+
+    char *utf8argv0 = newutf8(wxString(argv0));
+    this->doInit(utf8argv0);
+    delete[] utf8argv0;
+} // WxTestPhysfsFrame::WxTestPhysfsFrame
+
+
+int WxTestPhysfsFrame::err(int success)
+{
+    if (success)
+        this->SetStatusText(wxT(""));
+    else
+        this->SetStatusText(wxString(PHYSFS_getLastError(), wxConvUTF8));
+    return success;
+} // WxTestPhysfsFrame::err
+
+
+void WxTestPhysfsFrame::fillFileSystemTree(const char *path,
+                                           const wxTreeItemId &item)
+{
+    char **rc = PHYSFS_enumerateFiles(path);
+    char **i;
+    wxTreeItemId id;
+
+    if (rc == NULL)
+    {
+        const wxString quote(wxT("'"));
+        wxString str(wxT("Enumeration error: "));
+        str << quote << wxString(PHYSFS_getLastError(), wxConvUTF8) << quote;
+        id = this->fileTree->AppendItem(item, str);
+        this->fileTree->SetItemTextColour(id, wxColour(255, 0, 0));
+    } // if
+    else
+    {
+        for (i = rc; *i != NULL; i++)
+        {
+            id = this->fileTree->AppendItem(item, wxString(*i, wxConvUTF8));
+            const int len = strlen(path) + strlen(*i) + 2;
+            char *fname = new char[len];
+            const char *origdir = path;
+            if (strcmp(origdir, "/") == 0)
+                origdir = "";
+            snprintf(fname, len, "%s/%s", origdir, *i);
+
+            if (PHYSFS_isDirectory(fname))
+            {
+                this->fileTree->SetItemTextColour(id, wxColour(0, 0, 255));
+                this->fillFileSystemTree(fname, id);
+            } // if
+
+            else if (PHYSFS_isSymbolicLink(fname))
+            {
+                this->fileTree->SetItemTextColour(id, wxColour(0, 255, 0));
+            } // else if
+
+            else  // ...file.
+            {
+            } // else
+
+            delete[] fname;
+        } // for
+
+        PHYSFS_freeList(rc);
+    } // else
+} // fillFileSystemTree
+
+
+void WxTestPhysfsFrame::rebuildTree()
+{
+    const wxString dot(wxT("."));
+    const wxString quote(wxT("'"));
+    wxTreeItemId item;
+    wxString str;
+    const char *cstr = NULL;
+    const bool wasInit = PHYSFS_isInit() ? true : false;
+
+    this->fileTree->DeleteAllItems();
+    wxTreeItemId root = this->fileTree->AddRoot(wxT("PhysicsFS"));
+    this->stateItem = this->fileTree->AppendItem(root, wxT("Library state"));
+
+    str = wxT("Initialized: ");
+    str << ((wasInit) ? wxT("true") : wxT("false"));
+    this->fileTree->AppendItem(this->stateItem, str);
+
+    this->fileTree->Expand(this->stateItem);
+    this->fileTree->Expand(root);
+
+    // Fill in version information...
+
+    PHYSFS_Version ver;
+    item = this->stateItem;
+    str = wxT("wxtest_physfs version: ");
+    str << TEST_VER_MAJOR << dot << TEST_VER_MINOR << dot << TEST_VER_PATCH;
+    this->fileTree->AppendItem(item, str);
+    PHYSFS_VERSION(&ver);
+    str = wxT("Compiled against PhysicsFS version: ");
+    str << (int) ver.major << dot << (int) ver.minor << dot << ver.patch;
+    this->fileTree->AppendItem(item, str);
+    PHYSFS_getLinkedVersion(&ver);
+    str = wxT("Linked against PhysicsFS version: ");
+    str << (int) ver.major << dot << (int) ver.minor << dot << ver.patch;
+    this->fileTree->AppendItem(item, str);
+
+    if (!wasInit)
+        return;   // nothing else to do before initialization...
+
+    str = wxT("Symbolic links permitted: ");
+    str << ((PHYSFS_symbolicLinksPermitted()) ? wxT("true") : wxT("false"));
+    this->fileTree->AppendItem(this->stateItem, str);
+
+    str = wxT("Native directory separator: ");
+    str << quote << wxString(PHYSFS_getDirSeparator(), wxConvUTF8) << quote;
+    this->fileTree->AppendItem(this->stateItem, str);
+
+    // Fill in supported archives...
+
+    item = this->fileTree->AppendItem(this->stateItem, wxT("Archivers"));
+    const PHYSFS_ArchiveInfo **arcs = PHYSFS_supportedArchiveTypes();
+    if (*arcs == NULL)
+        this->fileTree->AppendItem(item, wxT("(none)"));
+    else
+    {
+        const PHYSFS_ArchiveInfo **i;
+        for (i = arcs; *i != NULL; i++)
+        {
+            const wxString ext((*i)->extension, wxConvUTF8);
+            const wxString desc((*i)->description, wxConvUTF8);
+            const wxString auth((*i)->author, wxConvUTF8);
+            const wxString url((*i)->url, wxConvUTF8);
+            wxTreeItemId arcitem = this->fileTree->AppendItem(item, ext);
+            this->fileTree->AppendItem(arcitem, desc);
+            this->fileTree->AppendItem(arcitem, auth);
+            this->fileTree->AppendItem(arcitem, url);
+        } // for
+    } // else
+
+
+    // Fill in the standard paths...
+
+    item = this->fileTree->AppendItem(this->stateItem, wxT("Paths"));
+    str = wxT("Base directory: ");
+    str << quote << wxString(PHYSFS_getBaseDir(), wxConvUTF8) << quote;
+    this->fileTree->AppendItem(item, str);
+    str = wxT("User directory: ");
+    str << quote << wxString(PHYSFS_getUserDir(), wxConvUTF8) << quote;
+    this->fileTree->AppendItem(item, str);
+    str = wxT("Write directory: ");
+    if ((cstr = PHYSFS_getWriteDir()) == NULL)
+        str << wxT("(NULL)");
+    else
+        str << quote << wxString(cstr ? cstr : "(NULL)", wxConvUTF8) << quote;
+    this->fileTree->AppendItem(item, str);
+    //str = wxT("Preference directory: ");
+    //str << wxString(PHYSFS_getUserDir(), wxConvUTF8);
+    //this->fileTree->AppendItem(item, str);
+
+    // Fill in the CD-ROMs...
+
+    item = this->fileTree->AppendItem(this->stateItem, wxT("CD-ROMs"));
+    char **cds = PHYSFS_getCdRomDirs();
+    if (cds == NULL)
+    {
+        str = wxT("Error: ");
+        str << quote << wxString(PHYSFS_getLastError(), wxConvUTF8) << quote;
+        wxTreeItemId id = this->fileTree->AppendItem(item, str);
+        this->fileTree->SetItemTextColour(id, wxColour(255, 0, 0));
+    } // if
+    else
+    {
+        if (*cds == NULL)
+            this->fileTree->AppendItem(item, wxT("(none)"));
+        else
+        {
+            char **i;
+            for (i = cds; *i != NULL; i++)
+                this->fileTree->AppendItem(item, wxString(*i, wxConvUTF8));
+        } // else
+        PHYSFS_freeList(cds);
+    } // else
+
+    // Fill in search path...
+
+    item = this->fileTree->AppendItem(this->stateItem, wxT("Search path"));
+    char **sp = PHYSFS_getSearchPath();
+    if (sp == NULL)
+    {
+        str = wxT("Error: ");
+        str << quote << wxString(PHYSFS_getLastError(), wxConvUTF8) << quote;
+        wxTreeItemId id = this->fileTree->AppendItem(item, str);
+        this->fileTree->SetItemTextColour(id, wxColour(255, 0, 0));
+    } // if
+    else
+    {
+        if (*sp == NULL)
+            this->fileTree->AppendItem(item, wxT("(none)"));
+        else
+        {
+            char **i;
+            for (i = sp; *i != NULL; i++)
+                this->fileTree->AppendItem(item, wxString(*i, wxConvUTF8));
+        } // else
+        PHYSFS_freeList(sp);
+    } // else
+
+    // Now fill in the filesystem...
+
+    this->fsItem = this->fileTree->AppendItem(root, wxT("Filesystem"));
+    this->fillFileSystemTree("/", this->fsItem);
+    this->fileTree->Expand(this->fsItem);
+} // WxTestPhysfsFrame::rebuildTree
+
+
+void WxTestPhysfsFrame::doInit(const char *argv0)
+{
+    if (!this->err(PHYSFS_init(argv0)))
+        ::wxMessageBox(wxT("PHYSFS_init() failed!"), wxT("wxTestPhysfs"));
+    this->rebuildTree();
+} // WxTestPhysfsFrame::doInit
+
+
+void WxTestPhysfsFrame::doDeinit()
+{
+    if (!this->err(PHYSFS_deinit()))
+        ::wxMessageBox(wxT("PHYSFS_deinit() failed!"), wxT("wxTestPhysfs"));
+    this->rebuildTree();
+} // WxTestPhysfsFrame::doDeinit
+
+
+void WxTestPhysfsFrame::onMenuInit(wxCommandEvent &evt)
+{
+    wxString argv0(wxGetApp().argv[0] == NULL ? wxT("") : wxGetApp().argv[0]);
+    wxString str(wxGetTextFromUser(wxT("PHYSFS_init"),
+                 wxT("argv[0]? (cancel for NULL)"), argv0));
+    char *cstr = str.IsEmpty() ? NULL : newutf8(str);
+    this->doInit(cstr);
+    delete[] cstr;
+} // WxTestPhysfsFrame::onMenuInit
+
+
+void WxTestPhysfsFrame::onMenuDeinit(wxCommandEvent &evt)
+{
+    this->doDeinit();
+} // WxTestPhysfsFrame::onMenuDeinit
+
+
+void WxTestPhysfsFrame::onMenuAddArchive(wxCommandEvent &evt)
+{
+    wxString arc = wxFileSelector(wxT("Choose archive to add"));
+    if (!arc.IsEmpty())
+    {
+        char *cstr = newutf8(arc);
+        // !!! FIXME: add to start/end?
+        if (!this->err(PHYSFS_addToSearchPath(cstr, 1)))
+            ::wxMessageBox(wxT("PHYSFS_addToSearchPath() failed!"), wxT("wxTestPhysfs"));
+        delete[] cstr;
+        this->rebuildTree();
+    } // if
+} // WxTestPhysfsFrame::onMenuAddArchive
+
+
+void WxTestPhysfsFrame::onMenuGetCDs(wxCommandEvent &evt)
+{
+    this->rebuildTree();  // This will call PHYSFS_getCdRomDirs()...
+} // WxTestPhysfsFrame::onMenuGetCDs
+
+
+void WxTestPhysfsFrame::onMenuPermitSymLinks(wxCommandEvent &evt)
+{
+    PHYSFS_permitSymbolicLinks(evt.IsChecked() ? 1 : 0);
+    this->rebuildTree();
+} // WxTestPhysfsFrame::onMenuPermitSymLinks
+
+
+
+IMPLEMENT_APP(WxTestPhysfsApp)
+
+bool WxTestPhysfsApp::OnInit()
+{
+    #if PLATFORM_MACOSX
+    // This lets a stdio app become a GUI app. Otherwise, you won't get
+    //  GUI events from the system and other things will fail to work.
+    // Putting the app in an application bundle does the same thing.
+    //  TransformProcessType() is a 10.3+ API. SetFrontProcess() is 10.0+.
+    if (TransformProcessType != NULL)  // check it as a weak symbol.
+    {
+        ProcessSerialNumber psn = { 0, kCurrentProcess };
+        TransformProcessType(&psn, kProcessTransformToForegroundApplication);
+        SetFrontProcess(&psn);
+    } // if
+    #endif
+
+    this->mainWindow = new WxTestPhysfsFrame(this->argv[0]);
+    this->mainWindow->Show(true);
+    SetTopWindow(this->mainWindow);
+    return true;
+} // WxTestPhysfsApp::OnInit
+
+// end of wxtest_physfs.cpp ...
+