From 40ab6d277f1b8a2dfe0a267426b545b09dfc98e7 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Mon, 2 Apr 2007 20:57:39 +0000 Subject: [PATCH] Added initial work on a wxWidgets-based test app. --- CHANGELOG.txt | 1 + CMakeLists.txt | 23 +- test/wxtest_physfs.cpp | 486 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 508 insertions(+), 2 deletions(-) create mode 100644 test/wxtest_physfs.cpp diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 8463bc33..65ec6458 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -2,6 +2,7 @@ * CHANGELOG. */ +04022007 - Added wxWidgets-based test program (incomplete). 04012007 - Added PHYSFS_isInit() and PHYSFS_symbolicLinksPermitted() functions. 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 diff --git a/CMakeLists.txt b/CMakeLists.txt index a7f00d95..4242a8f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -297,7 +297,7 @@ IF(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC) SET_TARGET_PROPERTIES(physfs-static PROPERTIES CLEAN_DIRECT_OUTPUT 1) 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) IF(PHYSFS_BUILD_TEST) 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") 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} RUNTIME DESTINATION bin 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 static library" PHYSFS_BUILD_STATIC) 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) MESSAGE_BOOL_OPTION(" Use readline in test program" HAVE_SYSTEM_READLINE) ENDIF(PHYSFS_BUILD_TEST) diff --git a/test/wxtest_physfs.cpp b/test/wxtest_physfs.cpp new file mode 100644 index 00000000..e762633e --- /dev/null +++ b/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 +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#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, "" }, + { "exists", cmd_exists, 1, "" }, + { "isdir", cmd_isdir, 1, "" }, + { "issymlink", cmd_issymlink, 1, "" }, + { "filelength", cmd_filelength, 1, "" }, + { "getlastmodtime", cmd_getlastmodtime, 1, "" }, +*/ +}; + + +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 ... +