diff --git a/src/frameworks/CoreServices/CMakeLists.txt b/src/frameworks/CoreServices/CMakeLists.txt index 54fa69401..e5833615a 100644 --- a/src/frameworks/CoreServices/CMakeLists.txt +++ b/src/frameworks/CoreServices/CMakeLists.txt @@ -1,6 +1,6 @@ project(CoreServices) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-rtti -fno-exceptions") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") include_directories(BEFORE ${CMAKE_SOURCE_DIR}/src/external/libcxx/include) include_directories( @@ -35,6 +35,9 @@ set(CoreServices_SRCS LSApplicationWorkspace.m constants.m ComponentManager.cpp + Files.cpp + Resources.cpp + ResourcesImpl.cpp ) set(DYLIB_COMPAT_VERSION "1.0.0") diff --git a/src/frameworks/CoreServices/Files.cpp b/src/frameworks/CoreServices/Files.cpp new file mode 100644 index 000000000..f835b8e01 --- /dev/null +++ b/src/frameworks/CoreServices/Files.cpp @@ -0,0 +1,37 @@ +/* +This file is part of Darling. + +Copyright (C) 2020 Lubos Dolezel + +Darling is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Darling is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Darling. If not, see . +*/ +#include +#include + +OSErr FSGetDataForkName(HFSUniStr255* dataForkName) +{ + dataForkName->length = 0; + return noErr; +} + +OSErr FSGetResourceForkName(HFSUniStr255* rsrcForkName) +{ + const char name[] = "RESOURCE_FORK"; + rsrcForkName->length = sizeof(name) - 1; + + for (int i = 0; i < sizeof(name) - 1; i++) + rsrcForkName->unicode[i] = name[i]; + + return noErr; +} diff --git a/src/frameworks/CoreServices/Resources.cpp b/src/frameworks/CoreServices/Resources.cpp index 03804e5c8..c22b58bd8 100644 --- a/src/frameworks/CoreServices/Resources.cpp +++ b/src/frameworks/CoreServices/Resources.cpp @@ -18,6 +18,106 @@ along with Darling. If not, see . */ #include +#include +#include +#include +#include "ResourcesImpl.h" + +// Documentation: +// http://web.archive.org/web/20040603192835/http://developer.apple.com/documentation/Carbon/Reference/Resource_Manager/index.html // Usage example: // https://github.com/nathanday/ndalias/blob/master/Classes/NDResourceFork.m + +static std::unordered_map g_resources; +static std::mutex g_resourcesLock; +static ResFileRefNum g_currentResFile = kResFileNotOpened; +static ResFileRefNum g_nextRefNum = 1; + +ResFileRefNum FSOpenResFile(const FSRef* ref, SInt8 permission) +{ + HFSUniStr255 forkName; + FSGetDataForkName(&forkName); + + ResFileRefNum refNum; + OSErr err = FSOpenResourceFile(ref, forkName.length, forkName.unicode, permission, &refNum); + + if (err != noErr) + return kResFileNotOpened; + return refNum; +} + +// Should return eofErr if given fork doesn't exist / is empty +OSErr FSOpenResourceFile(const FSRef* ref, UniCharCount forkNameLength, const UniChar* forkName, SInt8 permissions, ResFileRefNum* refNum) +{ + bool resourceFork = false; + const bool readOnly = permissions == fsRdPerm; + + if (forkNameLength != 0) + { + HFSUniStr255 rsrcForkName; + FSGetResourceForkName(&rsrcForkName); + + if (rsrcForkName.length == forkNameLength && memcmp(forkName, rsrcForkName.unicode, 2 * forkNameLength) == 0) + resourceFork = true; + } + + try + { + char path[4096]; + + OSErr rv = FSRefMakePath(ref, (UInt8*) path, sizeof(path) - 1); + if (rv != noErr) + throw rv; + + Resources* r = new Resources(path, readOnly, resourceFork); + + std::unique_lock l(g_resourcesLock); + while (g_resources.find(g_nextRefNum) != g_resources.end()) + { + if (g_nextRefNum == std::numeric_limits::max()) + g_nextRefNum = 1; + else + g_nextRefNum++; + } + + g_resources.insert(std::make_pair(g_nextRefNum, r)); + *refNum = g_nextRefNum; + g_nextRefNum++; + + return noErr; + } + catch (OSErr e) + { + *refNum = kResFileNotOpened; + return e; + } +} + +ResFileRefNum CurResFile(void) +{ + return g_currentResFile; +} + +void UseResFile(ResFileRefNum ref) +{ + std::unique_lock l(g_resourcesLock); + + if (g_resources.find(ref) != g_resources.end()) + g_currentResFile = ref; +} + +void CloseResFile(ResFileRefNum refNum) +{ + if (g_currentResFile == refNum) + g_currentResFile = kResFileNotOpened; + + std::unique_lock l(g_resourcesLock); + auto it = g_resources.find(refNum); + + if (it != g_resources.end()) + { + delete it->second; + g_resources.erase(it); + } +} diff --git a/src/frameworks/CoreServices/ResourcesImpl.cpp b/src/frameworks/CoreServices/ResourcesImpl.cpp new file mode 100644 index 000000000..5f49ae09b --- /dev/null +++ b/src/frameworks/CoreServices/ResourcesImpl.cpp @@ -0,0 +1,29 @@ +/* +This file is part of Darling. + +Copyright (C) 2020 Lubos Dolezel + +Darling is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Darling is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Darling. If not, see . +*/ +#include "ResourcesImpl.h" +#include + +// File format documentation: +// https://developer.apple.com/library/archive/documentation/mac/MoreToolbox/MoreToolbox-99.html + +Resources::Resources(const char* file, bool readOnly, bool resourceFork) +: m_file(file), m_readOnly(readOnly), m_resourceFork(resourceFork) +{ + +} diff --git a/src/frameworks/CoreServices/ResourcesImpl.h b/src/frameworks/CoreServices/ResourcesImpl.h new file mode 100644 index 000000000..f9bf33b67 --- /dev/null +++ b/src/frameworks/CoreServices/ResourcesImpl.h @@ -0,0 +1,36 @@ +/* +This file is part of Darling. + +Copyright (C) 2020 Lubos Dolezel + +Darling is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Darling is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Darling. If not, see . +*/ + +#ifndef _CS_RESOURCES_IMPL_H +#define _CS_RESOURCES_IMPL_H +#include +#include + +class Resources +{ +public: + + Resources(const char* file, bool readOnly, bool resourceFork); +private: + std::string m_file; + const bool m_readOnly, m_resourceFork; +}; + +#endif + diff --git a/src/frameworks/CoreServices/include/CoreServices/FileManager.h b/src/frameworks/CoreServices/include/CoreServices/FileManager.h index 015b3e1e5..813894557 100644 --- a/src/frameworks/CoreServices/include/CoreServices/FileManager.h +++ b/src/frameworks/CoreServices/include/CoreServices/FileManager.h @@ -45,6 +45,7 @@ struct HFSUniStr255 uint16_t length; uint16_t unicode[255]; }; +typedef struct HFSUniStr255 HFSUniStr255; struct FSSpec; typedef struct FSSpec* FSSpecPtr; diff --git a/src/frameworks/CoreServices/include/CoreServices/Files.h b/src/frameworks/CoreServices/include/CoreServices/Files.h index a08d44fc6..e4c366bcb 100644 --- a/src/frameworks/CoreServices/include/CoreServices/Files.h +++ b/src/frameworks/CoreServices/include/CoreServices/Files.h @@ -21,6 +21,11 @@ along with Darling. If not, see . #ifndef _CS_FILES_H #define _CS_FILES_H #include +#include + +#ifdef __cplusplus +extern "C" { +#endif #if __LP64__ typedef int FSIORefNum; @@ -28,4 +33,19 @@ along with Darling. If not, see . typedef SInt16 FSIORefNum; #endif +enum { + fsCurPerm = 0, + fsRdPerm = 1, + fsWrPerm = 2, + fsRdWrPerm = 3, + dsRdWrShPerm = 4, +}; + +OSErr FSGetDataForkName(HFSUniStr255* dataForkName); +OSErr FSGetResourceForkName(HFSUniStr255* rsrcForkName); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/frameworks/CoreServices/include/CoreServices/Resources.h b/src/frameworks/CoreServices/include/CoreServices/Resources.h index e5498c576..279e3ea94 100644 --- a/src/frameworks/CoreServices/include/CoreServices/Resources.h +++ b/src/frameworks/CoreServices/include/CoreServices/Resources.h @@ -46,6 +46,10 @@ ResFileRefNum CurResFile(void); ResFileRefNum HomeResFile(Handle resource); void UseResFile(ResFileRefNum ref); +// NOTE: What's the difference between CountTypes() and Count1Types()? +// CountTypes() applies to *all* open resource files. +// Count1Types() applies to CurResFile() only. + ResourceCount CountTypes(void); ResourceCount Count1Types(void);