this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

CoreServices: Almost complete Carbon Resources API impl

+1264 -22
+1 -1
src/frameworks/CoreServices/CMakeLists.txt
··· 1 1 project(CoreServices) 2 2 3 - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 3 + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") 4 4 5 5 include_directories(BEFORE ${CMAKE_SOURCE_DIR}/src/external/libcxx/include) 6 6 include_directories(
+142 -6
src/frameworks/CoreServices/MacMemory.cpp
··· 1 - #include "MacMemory.h" 1 + /* 2 + This file is part of Darling. 3 + 4 + Copyright (C) 2020 Lubos Dolezel 5 + 6 + Darling is free software: you can redistribute it and/or modify 7 + it under the terms of the GNU General Public License as published by 8 + the Free Software Foundation, either version 3 of the License, or 9 + (at your option) any later version. 10 + 11 + Darling is distributed in the hope that it will be useful, 12 + but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + GNU General Public License for more details. 15 + 16 + You should have received a copy of the GNU General Public License 17 + along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #include <CoreServices/MacMemory.h> 2 21 #include <cstring> 22 + #include <stdint.h> 3 23 #include <cstdlib> 24 + 25 + struct PtrInternal 26 + { 27 + uintptr_t size; 28 + uint8_t data[]; 29 + }; 4 30 5 31 void BlockMove(const void* src, void* dst, size_t count) 6 32 { ··· 34 60 35 61 Ptr NewPtr(long len) 36 62 { 37 - return (Ptr) malloc(len); 63 + PtrInternal* ptr = (PtrInternal*) malloc(len + sizeof(uintptr_t)); 64 + ptr->size = len; 65 + return (Ptr) ptr->data; 38 66 } 39 67 40 68 Ptr NewPtrClear(long len) 41 69 { 42 - return (Ptr) calloc(1, len); 70 + PtrInternal* ptr = (PtrInternal*) calloc(1, len + sizeof(uintptr_t)); 71 + ptr->size = len; 72 + return (Ptr) ptr->data; 43 73 } 44 74 45 - void DiposePtr(Ptr p) 75 + void DisposePtr(Ptr p) 46 76 { 47 - free(p); 77 + free(((uint8_t*)p) - sizeof(uintptr_t)); 48 78 } 49 79 50 80 void DisposeHandle(Handle handle) 51 81 { 52 - free(*handle); 82 + DisposePtr(*handle); 53 83 free(handle); 54 84 } 85 + 86 + Size GetHandleSize(Handle h) 87 + { 88 + if (!*h) 89 + return 0; 90 + return GetPtrSize(*h); 91 + } 92 + 93 + void EmptyHandle(Handle h) 94 + { 95 + if (*h) 96 + { 97 + DisposePtr(*h); 98 + *h = nullptr; 99 + } 100 + } 101 + 102 + OSErr PtrToHand(const void* srcPtr, Handle* dstHndl, long size) 103 + { 104 + *dstHndl = NewHandle(size); 105 + memcpy(**dstHndl, srcPtr, size); 106 + return noErr; 107 + } 108 + 109 + OSErr PtrToXHand(const void* srcPtr, Handle dstHndl, long size) 110 + { 111 + SetHandleSize(dstHndl, size); 112 + memcpy(*dstHndl, srcPtr, size); 113 + return noErr; 114 + } 115 + 116 + Handle NewHandle(long size) 117 + { 118 + Handle h = (Handle) malloc(sizeof(Handle)); 119 + *h = NewPtr(size); 120 + return h; 121 + } 122 + 123 + Handle NewHandleClear(long size) 124 + { 125 + Handle h = (Handle) malloc(sizeof(Handle)); 126 + *h = NewPtrClear(size); 127 + return h; 128 + } 129 + 130 + Handle NewEmptyHandle(void) 131 + { 132 + Handle h = (Handle) malloc(sizeof(Handle)); 133 + *h = nullptr; 134 + return h; 135 + } 136 + 137 + long GetPtrSize(Ptr ptr) 138 + { 139 + PtrInternal* internal = (PtrInternal*)(((char*) ptr) - sizeof(uintptr_t)); 140 + return internal->size; 141 + } 142 + 143 + void SetPtrSize(Ptr ptr, long newSize) 144 + { 145 + PtrInternal* internal = (PtrInternal*)(((char*) ptr) - sizeof(uintptr_t)); 146 + if (newSize < internal->size) 147 + internal->size = newSize; 148 + else 149 + { 150 + // This is not possible with a non-relocatable block 151 + } 152 + } 153 + 154 + void SetHandleSize(Handle h, long newSize) 155 + { 156 + if (!*h) 157 + *h = NewPtr(newSize); 158 + else if (!newSize) 159 + { 160 + DisposePtr(*h); 161 + *h = nullptr; 162 + } 163 + else 164 + { 165 + PtrInternal* internal = (PtrInternal*)(((char*) *h) - sizeof(uintptr_t)); 166 + 167 + internal = (PtrInternal*) realloc(internal, newSize + sizeof(uintptr_t)); 168 + internal->size = newSize; 169 + 170 + *h = (Ptr) internal->data; 171 + } 172 + } 173 + 174 + void ReallocateHandle(Handle h, Size byteCount) 175 + { 176 + SetHandleSize(h, 0); 177 + SetHandleSize(h, byteCount); 178 + } 179 + 180 + void HLock(Handle h) 181 + { 182 + } 183 + 184 + void HLockHi(Handle h) 185 + { 186 + } 187 + 188 + void HUnlock(Handle h) 189 + { 190 + }
-1
src/frameworks/CoreServices/MacMemory.h
··· 1 - include/CoreServices/MacMemory.h
+706 -6
src/frameworks/CoreServices/Resources.cpp
··· 21 21 #include <unordered_map> 22 22 #include <mutex> 23 23 #include <limits> 24 + #include <set> 25 + #include <algorithm> 24 26 #include "ResourcesImpl.h" 25 27 26 28 // Documentation: 27 29 // http://web.archive.org/web/20040603192835/http://developer.apple.com/documentation/Carbon/Reference/Resource_Manager/index.html 30 + // https://developer.apple.com/library/archive/documentation/mac/pdf/MoreMacintoshToolbox.pdf 28 31 29 32 // Usage example: 30 33 // https://github.com/nathanday/ndalias/blob/master/Classes/NDResourceFork.m 31 34 32 35 static std::unordered_map<ResFileRefNum, Resources*> g_resources; 33 36 static std::mutex g_resourcesLock; 37 + 38 + static Resources* g_currentResources = nullptr; 34 39 static ResFileRefNum g_currentResFile = kResFileNotOpened; 35 40 static ResFileRefNum g_nextRefNum = 1; 36 41 37 - ResFileRefNum FSOpenResFile(const FSRef* ref, SInt8 permission) 42 + static OSErr g_lastError = noErr; 43 + 44 + static void clearCaches(); 45 + 46 + ResFileRefNum FSOpenResFile(const FSRef* ref, SInt8 permissions) 38 47 { 39 48 HFSUniStr255 forkName; 40 49 FSGetDataForkName(&forkName); 41 50 42 51 ResFileRefNum refNum; 43 - OSErr err = FSOpenResourceFile(ref, forkName.length, forkName.unicode, permission, &refNum); 52 + OSErr err = FSOpenResourceFile(ref, forkName.length, forkName.unicode, permissions, &refNum); 44 53 45 54 if (err != noErr) 46 55 return kResFileNotOpened; ··· 51 60 OSErr FSOpenResourceFile(const FSRef* ref, UniCharCount forkNameLength, const UniChar* forkName, SInt8 permissions, ResFileRefNum* refNum) 52 61 { 53 62 bool resourceFork = false; 54 - const bool readOnly = permissions == fsRdPerm; 55 63 56 64 if (forkNameLength != 0) 57 65 { ··· 70 78 if (rv != noErr) 71 79 throw rv; 72 80 73 - Resources* r = new Resources(path, readOnly, resourceFork); 81 + Resources* r = new Resources(path, permissions, resourceFork); 74 82 75 83 std::unique_lock<std::mutex> l(g_resourcesLock); 76 84 while (g_resources.find(g_nextRefNum) != g_resources.end()) ··· 84 92 g_resources.insert(std::make_pair(g_nextRefNum, r)); 85 93 *refNum = g_nextRefNum; 86 94 g_nextRefNum++; 95 + clearCaches(); 87 96 88 97 return noErr; 89 98 } ··· 94 103 } 95 104 } 96 105 106 + OSErr ResError(void) 107 + { 108 + return g_lastError; 109 + } 110 + 97 111 ResFileRefNum CurResFile(void) 98 112 { 99 113 return g_currentResFile; ··· 103 117 { 104 118 std::unique_lock<std::mutex> l(g_resourcesLock); 105 119 106 - if (g_resources.find(ref) != g_resources.end()) 120 + if (auto it = g_resources.find(ref); it != g_resources.end()) 121 + { 107 122 g_currentResFile = ref; 123 + g_currentResources = it->second; 124 + g_lastError = noErr; 125 + } 126 + else 127 + g_lastError = resFNotFound; 108 128 } 109 129 110 130 void CloseResFile(ResFileRefNum refNum) 111 131 { 132 + std::unique_lock<std::mutex> l(g_resourcesLock); 112 133 if (g_currentResFile == refNum) 134 + { 113 135 g_currentResFile = kResFileNotOpened; 136 + g_currentResources = nullptr; 137 + } 114 138 115 - std::unique_lock<std::mutex> l(g_resourcesLock); 116 139 auto it = g_resources.find(refNum); 117 140 118 141 if (it != g_resources.end()) 119 142 { 120 143 delete it->second; 121 144 g_resources.erase(it); 145 + g_lastError = noErr; 146 + clearCaches(); 122 147 } 148 + else 149 + g_lastError = resFNotFound; 150 + } 151 + 152 + static std::set<ResType> allTypesCache; 153 + static std::set<ResType>& allTypes() 154 + { 155 + std::set<ResType>& resTypes = allTypesCache; 156 + 157 + if (resTypes.empty()) 158 + { 159 + for (auto const& [refNum, resources] : g_resources) 160 + { 161 + for (auto const& [type, data] : resources->data()) 162 + resTypes.insert(type); 163 + } 164 + } 165 + 166 + return resTypes; 167 + } 168 + 169 + ResourceCount CountTypes(void) 170 + { 171 + std::unique_lock<std::mutex> l(g_resourcesLock); 172 + std::set<ResType>& resTypes = allTypes(); 173 + 174 + return resTypes.size(); 175 + } 176 + 177 + ResourceCount Count1Types(void) 178 + { 179 + std::unique_lock<std::mutex> l(g_resourcesLock); 180 + 181 + if (!g_currentResources) 182 + { 183 + g_lastError = resFNotFound; 184 + return 0; 185 + } 186 + 187 + g_lastError = noErr; 188 + return g_currentResources->data().size(); 189 + } 190 + 191 + static Resources::ResourceData* findResourceDataByHandle(Handle res, Resources** resOut = nullptr) 192 + { 193 + for (auto const& [refNum, resources] : g_resources) 194 + { 195 + Resources::ResourceData* rv = resources->dataByHandle(res); 196 + if (rv) 197 + { 198 + if (resOut) 199 + *resOut = resources; 200 + return rv; 201 + } 202 + } 203 + 204 + g_lastError = resNotFound; 205 + return nullptr; 206 + } 207 + 208 + ResAttributes GetResAttrs(Handle res) 209 + { 210 + std::unique_lock<std::mutex> l(g_resourcesLock); 211 + auto data = findResourceDataByHandle(res); 212 + 213 + if (!data) 214 + return 0; 215 + 216 + g_lastError = noErr; 217 + return data->attributes; 218 + } 219 + 220 + void GetResInfo(Handle res, ResID* resId, ResType* type, Str255 name) 221 + { 222 + std::unique_lock<std::mutex> l(g_resourcesLock); 223 + auto data = findResourceDataByHandle(res); 224 + 225 + if (!data) 226 + { 227 + *resId = 0; 228 + *type = 0; 229 + name[0] = 0; 230 + return; 231 + } 232 + 233 + g_lastError = noErr; 234 + *resId = data->id; 235 + *type = data->type; 236 + 237 + // Pascal string 238 + name[0] = std::min<uint8_t>(254, data->name.length()); 239 + memcpy(name+1, data->name.c_str(), name[0]); 240 + } 241 + 242 + void SetResInfo(Handle res, ResID theID, ConstStr255Param name) 243 + { 244 + std::unique_lock<std::mutex> l(g_resourcesLock); 245 + Resources* resources; 246 + auto data = findResourceDataByHandle(res, &resources); 247 + 248 + if (!data) 249 + { 250 + g_lastError = resNotFound; 251 + return; 252 + } 253 + 254 + g_lastError = noErr; 255 + if (data->id != theID) 256 + { 257 + auto it = resources->data().find(data->type); 258 + if (it != resources->data().end()) 259 + { 260 + Resources::ResourceTypeData& rtd = it->second; 261 + rtd.idMap.erase(data->id); 262 + rtd.idMap.insert({ theID, data }); 263 + } 264 + 265 + data->id = theID; 266 + } 267 + 268 + // Pascal string 269 + std::string cname((char*) &name[1], name[0]); 270 + if (data->name != cname) 271 + { 272 + auto it = resources->data().find(data->type); 273 + if (it != resources->data().end()) 274 + { 275 + Resources::ResourceTypeData& rtd = it->second; 276 + rtd.nameMap.erase(data->name); 277 + rtd.nameMap.insert({ cname, data }); 278 + } 279 + 280 + data->name = cname; 281 + } 282 + } 283 + 284 + void SetResAttrs(Handle res, ResAttributes attrs) 285 + { 286 + std::unique_lock<std::mutex> l(g_resourcesLock); 287 + auto data = findResourceDataByHandle(res); 288 + 289 + if (!data) 290 + { 291 + g_lastError = resNotFound; 292 + return; 293 + } 294 + 295 + g_lastError = noErr; 296 + data->attributes = attrs; 297 + } 298 + 299 + void GetIndType(ResType* type, ResourceIndex index) 300 + { 301 + std::unique_lock<std::mutex> l(g_resourcesLock); 302 + std::set<ResType>& resTypes = allTypes(); 303 + 304 + if (index < 1 || index > resTypes.size()) 305 + { 306 + g_lastError = inputOutOfBounds; 307 + *type = 0; 308 + return; 309 + } 310 + 311 + auto it = resTypes.begin(); 312 + std::advance(it, index-1); 313 + 314 + *type = *it; 315 + g_lastError = noErr; 316 + } 317 + 318 + void Get1IndType(ResType* type, ResourceIndex index) 319 + { 320 + std::unique_lock<std::mutex> l(g_resourcesLock); 321 + 322 + if (!g_currentResources) 323 + { 324 + g_lastError = resFNotFound; 325 + *type = 0; 326 + return; 327 + } 328 + 329 + auto it = g_currentResources->data().begin(); 330 + if (index < 1 || index > g_currentResources->data().size()) 331 + { 332 + g_lastError = inputOutOfBounds; 333 + *type = 0; 334 + return; 335 + } 336 + 337 + std::advance(it, index-1); 338 + 339 + *type = it->first; 340 + g_lastError = noErr; 341 + } 342 + 343 + static std::vector<Resources::ResourceData*> resourcesOfTypeCache; 344 + static ResType resourcesOfTypeCacheType = -1; 345 + static std::vector<Resources::ResourceData*>& resourcesOfType(ResType type) 346 + { 347 + std::vector<Resources::ResourceData*>& rv = resourcesOfTypeCache; 348 + 349 + if (resourcesOfTypeCacheType != type) 350 + { 351 + for (auto const& [refNum, resources] : g_resources) 352 + { 353 + auto it = resources->data().find(type); 354 + if (it == resources->data().end()) 355 + continue; 356 + 357 + for (auto& d : it->second.resources) 358 + rv.push_back(d.get()); 359 + } 360 + resourcesOfTypeCacheType = type; 361 + } 362 + 363 + return rv; 364 + } 365 + 366 + static std::unordered_map<ResID,Resources::ResourceData*> resourcesOfTypeMapCache; 367 + static ResType resourcesOfTypeMapCacheType = -1; 368 + static std::unordered_map<ResID,Resources::ResourceData*>& resourcesOfTypeMap(ResType type) 369 + { 370 + std::unordered_map<ResID,Resources::ResourceData*>& rv = resourcesOfTypeMapCache; 371 + 372 + if (resourcesOfTypeMapCacheType != type) 373 + { 374 + for (auto const& [refNum, resources] : g_resources) 375 + { 376 + auto it = resources->data().find(type); 377 + if (it == resources->data().end()) 378 + continue; 379 + 380 + rv.insert(it->second.idMap.begin(), it->second.idMap.end()); 381 + } 382 + 383 + resourcesOfTypeMapCacheType = type; 384 + } 385 + 386 + return rv; 387 + } 388 + 389 + static std::unordered_map<std::string,Resources::ResourceData*> resourcesOfTypeNameMapCache; 390 + static ResType resourcesOfTypeNameMapCacheType = -1; 391 + static std::unordered_map<std::string,Resources::ResourceData*>& resourcesOfTypeNameMap(ResType type) 392 + { 393 + std::unordered_map<std::string,Resources::ResourceData*>& rv = resourcesOfTypeNameMapCache; 394 + 395 + if (resourcesOfTypeMapCacheType != type) 396 + { 397 + for (auto const& [refNum, resources] : g_resources) 398 + { 399 + auto it = resources->data().find(type); 400 + if (it == resources->data().end()) 401 + continue; 402 + 403 + rv.insert(it->second.nameMap.begin(), it->second.nameMap.end()); 404 + } 405 + 406 + resourcesOfTypeNameMapCacheType = type; 407 + } 408 + 409 + return rv; 410 + } 411 + 412 + ResourceCount CountResources(ResType type) 413 + { 414 + std::unique_lock<std::mutex> l(g_resourcesLock); 415 + auto& allRes = resourcesOfType(type); 416 + 417 + return allRes.size(); 418 + } 419 + 420 + ResourceCount Count1Resources(ResType type) 421 + { 422 + std::unique_lock<std::mutex> l(g_resourcesLock); 423 + 424 + if (!g_currentResources) 425 + { 426 + g_lastError = resFNotFound; 427 + return 0; 428 + } 429 + 430 + g_lastError = noErr; 431 + 432 + auto it = g_currentResources->data().find(type); 433 + if (it == g_currentResources->data().end()) 434 + return 0; 435 + 436 + return it->second.resources.size(); 437 + } 438 + 439 + Handle GetIndResource(ResType type, ResourceIndex index) 440 + { 441 + std::unique_lock<std::mutex> l(g_resourcesLock); 442 + auto& allRes = resourcesOfType(type); 443 + 444 + if (index < 1 || index > allRes.size()) 445 + { 446 + g_lastError = inputOutOfBounds; 447 + return nullptr; 448 + } 449 + 450 + return allRes[index-1]->getHandle(); 451 + } 452 + 453 + Handle Get1IndResource(ResType type, ResourceIndex index) 454 + { 455 + std::unique_lock<std::mutex> l(g_resourcesLock); 456 + 457 + if (!g_currentResources) 458 + { 459 + g_lastError = resFNotFound; 460 + return nullptr; 461 + } 462 + 463 + auto it = g_currentResources->data().find(type); 464 + if (it == g_currentResources->data().end()) 465 + { 466 + g_lastError = resNotFound; 467 + return nullptr; 468 + } 469 + 470 + if (index < 1 || index > it->second.resources.size()) 471 + { 472 + g_lastError = inputOutOfBounds; 473 + return nullptr; 474 + } 475 + 476 + g_lastError = noErr; 477 + 478 + return it->second.resources[index-1]->getHandle(); 479 + } 480 + 481 + Handle GetResource(ResType type, ResID resId) 482 + { 483 + std::unique_lock<std::mutex> l(g_resourcesLock); 484 + auto& allRes = resourcesOfTypeMap(type); 485 + 486 + auto it = allRes.find(resId); 487 + if (it == allRes.end()) 488 + { 489 + g_lastError = resNotFound; 490 + return nullptr; 491 + } 492 + 493 + return it->second->getHandle(); 494 + } 495 + 496 + Handle Get1Resource(ResType type, ResID resId) 497 + { 498 + std::unique_lock<std::mutex> l(g_resourcesLock); 499 + 500 + if (!g_currentResources) 501 + { 502 + g_lastError = resFNotFound; 503 + return nullptr; 504 + } 505 + 506 + auto itType = g_currentResources->data().find(type); 507 + if (itType == g_currentResources->data().end()) 508 + { 509 + g_lastError = resNotFound; 510 + return nullptr; 511 + } 512 + 513 + auto it = itType->second.idMap.find(resId); 514 + if (it == itType->second.idMap.end()) 515 + { 516 + g_lastError = resNotFound; 517 + return nullptr; 518 + } 519 + 520 + return it->second->getHandle(); 521 + } 522 + 523 + Handle GetNamedResource(ResType type, ConstStr255Param name) 524 + { 525 + std::unique_lock<std::mutex> l(g_resourcesLock); 526 + auto& allRes = resourcesOfTypeNameMap(type); 527 + 528 + std::string cname((char*) &name[1], name[0]); 529 + auto it = allRes.find(cname); 530 + if (it == allRes.end()) 531 + { 532 + g_lastError = resNotFound; 533 + return nullptr; 534 + } 535 + 536 + g_lastError = noErr; 537 + return it->second->getHandle(); 538 + } 539 + 540 + Handle Get1NamedResource(ResType type, ConstStr255Param name) 541 + { 542 + std::unique_lock<std::mutex> l(g_resourcesLock); 543 + 544 + if (!g_currentResources) 545 + { 546 + g_lastError = resFNotFound; 547 + return nullptr; 548 + } 549 + 550 + auto itType = g_currentResources->data().find(type); 551 + if (itType == g_currentResources->data().end()) 552 + { 553 + g_lastError = resNotFound; 554 + return nullptr; 555 + } 556 + 557 + std::string cname((char*) &name[1], name[0]); 558 + auto it = itType->second.nameMap.find(cname); 559 + if (it == itType->second.nameMap.end()) 560 + { 561 + g_lastError = resNotFound; 562 + return nullptr; 563 + } 564 + 565 + g_lastError = noErr; 566 + return it->second->getHandle(); 567 + } 568 + 569 + ResFileAttributes GetResFileAttrs(ResFileRefNum refNum) 570 + { 571 + std::unique_lock<std::mutex> l(g_resourcesLock); 572 + auto it = g_resources.find(refNum); 573 + 574 + if (it == g_resources.end()) 575 + { 576 + g_lastError = resFNotFound; 577 + return 0; 578 + } 579 + 580 + g_lastError = noErr; 581 + return it->second->attributes(); 582 + } 583 + 584 + void SetResFileAttrs(ResFileRefNum refNum, ResFileAttributes attrs) 585 + { 586 + std::unique_lock<std::mutex> l(g_resourcesLock); 587 + auto it = g_resources.find(refNum); 588 + 589 + if (it == g_resources.end()) 590 + { 591 + g_lastError = resFNotFound; 592 + return; 593 + } 594 + 595 + g_lastError = noErr; 596 + it->second->setAttributes(attrs); 597 + } 598 + 599 + void ChangedResource(Handle res) 600 + { 601 + std::unique_lock<std::mutex> l(g_resourcesLock); 602 + auto data = findResourceDataByHandle(res); 603 + data->dataChanged(); 604 + } 605 + 606 + void SetResourceSize(Handle res, long size) 607 + { 608 + SetHandleSize(res, size); 609 + } 610 + 611 + static void clearCaches() 612 + { 613 + resourcesOfTypeMapCache.clear(); 614 + resourcesOfTypeMapCacheType = -1; 615 + resourcesOfTypeCache.clear(); 616 + resourcesOfTypeCacheType = -1; 617 + resourcesOfTypeNameMapCache.clear(); 618 + resourcesOfTypeNameMapCacheType = -1; 619 + allTypesCache.clear(); 620 + } 621 + 622 + void WriteResource(Handle res) 623 + { 624 + std::unique_lock<std::mutex> l(g_resourcesLock); 625 + Resources* resources; 626 + auto data = findResourceDataByHandle(res, &resources); 627 + 628 + if (!data) 629 + { 630 + g_lastError = resNotFound; 631 + return; 632 + } 633 + 634 + g_lastError = noErr; 635 + resources->save(); 636 + } 637 + 638 + void UpdateResFile(ResFileRefNum refNum) 639 + { 640 + std::unique_lock<std::mutex> l(g_resourcesLock); 641 + auto it = g_resources.find(refNum); 642 + 643 + if (it == g_resources.end()) 644 + { 645 + g_lastError = resFNotFound; 646 + return; 647 + } 648 + 649 + g_lastError = noErr; 650 + it->second->save(); 651 + } 652 + 653 + void DetachResource(Handle res) 654 + { 655 + std::unique_lock<std::mutex> l(g_resourcesLock); 656 + Resources* resources; 657 + auto data = findResourceDataByHandle(res, &resources); 658 + 659 + data->releaseHandle(false); 660 + } 661 + 662 + void RemoveResource(Handle res) 663 + { 664 + std::unique_lock<std::mutex> l(g_resourcesLock); 665 + 666 + if (!g_currentResources) 667 + { 668 + g_lastError = resFNotFound; 669 + return; 670 + } 671 + 672 + if (!res) 673 + { 674 + g_lastError = rmvResFailed; 675 + return; 676 + } 677 + 678 + g_currentResources->remove(res); 679 + } 680 + 681 + void ReleaseResource(Handle res) 682 + { 683 + std::unique_lock<std::mutex> l(g_resourcesLock); 684 + Resources* resources; 685 + auto data = findResourceDataByHandle(res, &resources); 686 + 687 + data->releaseHandle(true); 688 + } 689 + 690 + void SetResLoad(Boolean load) 691 + { 692 + Resources::setCreateHandles(load); 693 + } 694 + 695 + void AddResource(Handle data, ResType type, ResID resId, ConstStr255Param name) 696 + { 697 + std::unique_lock<std::mutex> l(g_resourcesLock); 698 + 699 + if (!g_currentResources) 700 + { 701 + g_lastError = resFNotFound; 702 + return; 703 + } 704 + 705 + if (!data) 706 + { 707 + g_lastError = addResFailed; 708 + return; 709 + } 710 + 711 + auto existingData = findResourceDataByHandle(data); 712 + if (existingData != nullptr) 713 + { 714 + g_lastError = addResFailed; 715 + return; 716 + } 717 + 718 + std::string cname((char*) &name[1], name[0]); 719 + g_currentResources->add(type, resId, cname.c_str(), data); 720 + } 721 + 722 + void ReadPartialResource(Handle res, long offset, void* buffer, long count) 723 + { 724 + std::unique_lock<std::mutex> l(g_resourcesLock); 725 + Size resLen = 0; 726 + if (res) 727 + resLen = GetHandleSize(res); 728 + 729 + if (offset + count > resLen) 730 + { 731 + g_lastError = inputOutOfBounds; 732 + return; 733 + } 734 + 735 + memcpy(buffer, *res + offset, count); 736 + g_lastError = noErr; 737 + } 738 + 739 + void WritePartialResource(Handle res, long offset, const void* buffer, long count) 740 + { 741 + std::unique_lock<std::mutex> l(g_resourcesLock); 742 + if (!res) 743 + { 744 + g_lastError = resNotFound; 745 + return; 746 + } 747 + 748 + Resources* rr; 749 + auto existingData = findResourceDataByHandle(res, &rr); 750 + 751 + if (!existingData) 752 + { 753 + g_lastError = resNotFound; 754 + return; 755 + } 756 + 757 + g_lastError = noErr; 758 + if (offset + count > GetHandleSize(res)) 759 + { 760 + SetHandleSize(res, offset+count); 761 + g_lastError = writingPastEnd; 762 + } 763 + 764 + memcpy(*res + offset, buffer, count); 765 + rr->save(); 766 + } 767 + 768 + ResID UniqueID(ResType type) 769 + { 770 + std::unique_lock<std::mutex> l(g_resourcesLock); 771 + std::set<ResID> allIds; 772 + 773 + for (auto const& [refNum, resources] : g_resources) 774 + { 775 + auto it = resources->data().find(type); 776 + if (it == resources->data().end()) 777 + { 778 + g_lastError = noErr; 779 + return 128; 780 + } 781 + 782 + for (auto const& [id, rd] : it->second.idMap) 783 + allIds.insert(id); 784 + } 785 + 786 + for (ResID i = 128; i < std::numeric_limits<ResID>::max(); i++) 787 + { 788 + if (allIds.find(i) == allIds.end()) 789 + { 790 + g_lastError = noErr; 791 + return i; 792 + } 793 + } 794 + return 0; 795 + } 796 + 797 + ResID Unique1ID(ResType type) 798 + { 799 + std::unique_lock<std::mutex> l(g_resourcesLock); 800 + 801 + if (!g_currentResources) 802 + { 803 + g_lastError = resFNotFound; 804 + return 0; 805 + } 806 + 807 + auto it = g_currentResources->data().find(type); 808 + if (it == g_currentResources->data().end()) 809 + { 810 + g_lastError = noErr; 811 + return 128; 812 + } 813 + 814 + for (ResID i = 128; i < std::numeric_limits<ResID>::max(); i++) 815 + { 816 + if (it->second.idMap.find(i) == it->second.idMap.end()) 817 + { 818 + g_lastError = noErr; 819 + return i; 820 + } 821 + } 822 + return 0; 123 823 }
+315 -2
src/frameworks/CoreServices/ResourcesImpl.cpp
··· 18 18 */ 19 19 #include "ResourcesImpl.h" 20 20 #include <stdexcept> 21 + #include <sys/mman.h> 22 + #include <fcntl.h> 23 + #include <unistd.h> 24 + #include <sys/xattr.h> 25 + #include <memory> 21 26 22 27 // File format documentation: 23 28 // https://developer.apple.com/library/archive/documentation/mac/MoreToolbox/MoreToolbox-99.html 24 29 25 - Resources::Resources(const char* file, bool readOnly, bool resourceFork) 26 - : m_file(file), m_readOnly(readOnly), m_resourceFork(resourceFork) 30 + // All is big endian! 31 + struct ResourcesHeader 32 + { 33 + uint32_t resourceDataOffset; 34 + uint32_t resourceMapOffset; 35 + uint32_t resourceDataLength; 36 + uint32_t resourceMapLength; 37 + }; 38 + 39 + struct ResourceMapHeader 40 + { 41 + ResourcesHeader _copy; 42 + uint32_t _handleNextMap; 43 + uint16_t _fileRefNumber; 44 + ResFileAttributes attributes; 45 + uint16_t typeListOffset; // from this 46 + uint16_t nameListOffset; // from this 47 + uint16_t numOfTypesMinusOne; 48 + }; 49 + 50 + struct ResourceType 51 + { 52 + uint32_t resourceType; 53 + uint16_t numOfThisTypeMinusOne; 54 + uint16_t referenceListOffset; // from this 55 + }; 56 + 57 + struct ReferenceListItem 58 + { 59 + ResID resourceID; 60 + uint16_t resourceNameListOffset; 61 + // Since this bitfield values have full byte sized values, 62 + // order change for BE/LE is not needed. 63 + uint32_t attributes : 8; 64 + uint32_t resourceDataOffset : 24; 65 + uint32_t _handle; 66 + }; 67 + 68 + // Resource data is prefixed with a 4-byte length 69 + // Resource name is prefixed with a 1-byte length 70 + 71 + bool Resources::m_createHandles = true; 72 + 73 + Resources::Resources(const char* file, SInt8 openMode, bool resourceFork) 74 + : m_file(file), m_openMode(openMode), m_resourceFork(resourceFork) 75 + { 76 + if (openMode != fsWrPerm) 77 + { 78 + // Load existing resources 79 + loadResources(); 80 + } 81 + } 82 + 83 + void Resources::loadResources() 84 + { 85 + if (!m_resourceFork) 86 + { 87 + int fd = ::open(m_file.c_str(), O_RDONLY); 88 + if (fd == -1) 89 + throw OSErr(fnfErr); 90 + 91 + off_t size = ::lseek(fd, 0, SEEK_END); 92 + 93 + if (size == 0) 94 + { 95 + ::close(fd); 96 + throw OSErr(eofErr); 97 + } 98 + 99 + void* map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); 100 + ::close(fd); 101 + 102 + if (map == MAP_FAILED) 103 + throw OSErr(fnfErr); 104 + 105 + try 106 + { 107 + loadResources(static_cast<uint8_t*>(map), size); 108 + ::munmap(map, size); 109 + } 110 + catch(...) 111 + { 112 + ::munmap(map, size); 113 + throw; 114 + } 115 + } 116 + else 117 + { 118 + ssize_t s = ::getxattr(m_file.c_str(), "com.apple.ResourceFork", nullptr, 0, 0, 0); 119 + if (s < 0) 120 + throw OSErr(eofErr); 121 + 122 + std::unique_ptr<uint8_t[]> buf(new uint8_t[s]); 123 + s = ::getxattr(m_file.c_str(), "com.apple.ResourceFork", buf.get(), s, 0, 0); 124 + if (s < 0) 125 + throw OSErr(eofErr); 126 + 127 + loadResources(buf.get(), s); 128 + } 129 + } 130 + 131 + Resources::ResourceData::ResourceData(ResourceData&& that) 132 + { 133 + id = that.id; 134 + name = std::move(that.name); 135 + dataBacking = std::move(that.dataBacking); 136 + attributes = that.attributes; 137 + data = that.data; 138 + that.data = nullptr; 139 + } 140 + 141 + Resources::ResourceData::ResourceData(Handle inData) 142 + { 143 + this->data = inData; 144 + dataChanged(); 145 + } 146 + 147 + Resources::ResourceData::~ResourceData() 148 + { 149 + if (data) 150 + DisposeHandle(data); 151 + } 152 + 153 + Handle Resources::ResourceData::getHandle() 154 + { 155 + if (!data) 156 + { 157 + PtrToHand(dataBacking.data(), &data, dataBacking.size()); 158 + parent->m_handleMap.insert({ data, this }); 159 + } 160 + return data; 161 + } 162 + 163 + void Resources::ResourceData::releaseHandle(bool freeMemory) 164 + { 165 + if (data) 166 + { 167 + if (freeMemory) 168 + DisposeHandle(data); 169 + parent->m_handleMap.erase(data); 170 + data = nullptr; 171 + } 172 + } 173 + 174 + void Resources::ResourceData::dataChanged() 175 + { 176 + if (data) 177 + dataBacking.assign(*data, *data + GetHandleSize(data)); 178 + } 179 + 180 + #ifdef __LITTLE_ENDIAN__ 181 + # define SWAP(x) x = _bswap(x) 182 + 183 + static inline uint16_t _bswap(uint16_t v) { return __builtin_bswap16(v); } 184 + static inline int16_t _bswap(int16_t v) { return __builtin_bswap16(v); } 185 + static inline uint32_t _bswap(uint32_t v) { return __builtin_bswap32(v); } 186 + 187 + #else 188 + # define SWAP(x) 189 + #endif 190 + 191 + void Resources::loadResources(const uint8_t* mem, size_t length) 27 192 { 193 + m_resourceTypes.clear(); 194 + m_attributes = 0; 195 + 196 + if (length < sizeof(ResourcesHeader)) 197 + throw OSErr(eofErr); 198 + 199 + // TODO: Do more bounds checking 200 + 201 + ResourcesHeader header = *reinterpret_cast<const ResourcesHeader*>(mem); 202 + 203 + SWAP(header.resourceDataOffset); 204 + SWAP(header.resourceMapOffset); 205 + SWAP(header.resourceDataLength); 206 + SWAP(header.resourceMapLength); 207 + 208 + if (header.resourceDataOffset + header.resourceDataLength > length 209 + || header.resourceMapOffset + header.resourceMapLength > length) 210 + { 211 + throw OSErr(eofErr); 212 + } 213 + 214 + ResourceMapHeader resourceMapHeader = *reinterpret_cast<const ResourceMapHeader*>(mem + header.resourceMapOffset); 215 + SWAP(resourceMapHeader.attributes); 216 + SWAP(resourceMapHeader.typeListOffset); 217 + SWAP(resourceMapHeader.nameListOffset); 218 + SWAP(resourceMapHeader.numOfTypesMinusOne); 219 + 220 + m_attributes = resourceMapHeader.attributes; 221 + 222 + const ResourceType* t = reinterpret_cast<const ResourceType*>(mem + header.resourceMapOffset + resourceMapHeader.typeListOffset); 223 + for (int i = 0; i <= resourceMapHeader.numOfTypesMinusOne; i++, t++) 224 + { 225 + ResourceType type = *t; 226 + 227 + SWAP(type.resourceType); 228 + SWAP(type.numOfThisTypeMinusOne); 229 + SWAP(type.referenceListOffset); 230 + 231 + const ReferenceListItem* rli = reinterpret_cast<const ReferenceListItem*>( 232 + reinterpret_cast<const uint8_t*>(t) + type.referenceListOffset 233 + ); 234 + 235 + ResourceTypeData resourceTypeData; 236 + resourceTypeData.type = type.resourceType; 237 + 238 + for (int j = 0; j <= type.numOfThisTypeMinusOne; j++, rli++) 239 + { 240 + ReferenceListItem refListItem = *rli; 241 + ResourceData res; 242 + 243 + SWAP(refListItem.resourceID); 244 + SWAP(refListItem.resourceNameListOffset); 245 + SWAP(refListItem.resourceDataOffset); 246 + 247 + const char* pascalStringName = reinterpret_cast<const char*>(mem + header.resourceMapOffset + resourceMapHeader.nameListOffset + refListItem.resourceNameListOffset); 248 + 249 + const uint8_t* dataHeader = mem + header.resourceDataOffset + refListItem.resourceDataOffset; 250 + uint32_t dataLength = *reinterpret_cast<const uint32_t*>(dataHeader); 251 + 252 + SWAP(dataLength); 253 + 254 + res.name.assign(pascalStringName+1, *pascalStringName); 255 + 256 + res.dataBacking.assign(dataHeader + 4, dataHeader + 4 + dataLength); 257 + 258 + res.id = refListItem.resourceID; 259 + res.attributes = refListItem.attributes; 260 + res.type = resourceTypeData.type; 261 + res.parent = this; 28 262 263 + resourceTypeData.resources.emplace_back(std::make_unique<ResourceData>(std::move(res))); 264 + 265 + ResourceData* d = resourceTypeData.resources.back().get(); 266 + resourceTypeData.idMap.insert({ res.id, d }); 267 + resourceTypeData.nameMap.insert({ res.name, d }); 268 + 269 + if (m_createHandles) 270 + d->getHandle(); 271 + } 272 + 273 + m_resourceTypes.insert({ type.resourceType, std::move(resourceTypeData) }); 274 + } 275 + } 276 + 277 + void Resources::setCreateHandles(bool create) 278 + { 279 + m_createHandles = create; 280 + } 281 + 282 + void Resources::add(ResType type, ResID id, const char* name, Handle data) 283 + { 284 + auto itType = m_resourceTypes.find(type); 285 + if (itType == m_resourceTypes.end()) 286 + { 287 + itType = m_resourceTypes.insert({ type, ResourceTypeData{ type } }).first; 288 + } 289 + 290 + ResourceData rd(data); 291 + 292 + rd.id = id; 293 + rd.type = type; 294 + rd.name = name; 295 + rd.attributes = 0; 296 + rd.parent = this; 297 + 298 + itType->second.resources.push_back(std::make_unique<ResourceData>(std::move(rd))); 299 + 300 + ResourceData* rdPtr = itType->second.resources.back().get(); 301 + itType->second.idMap.insert({ id, rdPtr }); 302 + itType->second.nameMap.insert({ name, rdPtr }); 303 + m_handleMap.insert({ data, rdPtr }); 304 + } 305 + 306 + void Resources::remove(Handle data) 307 + { 308 + auto it = m_handleMap.find(data); 309 + if (it == m_handleMap.end()) 310 + return; 311 + 312 + auto itType = m_resourceTypes.find(it->second->type); 313 + if (itType == m_resourceTypes.end()) 314 + return; 315 + 316 + itType->second.idMap.erase(it->second->id); 317 + itType->second.nameMap.erase(it->second->name); 318 + m_handleMap.erase(data); 319 + 320 + auto& resources = itType->second.resources; 321 + for (size_t i = 0; i < resources.size(); i++) 322 + { 323 + if (resources[i].get() == it->second) 324 + { 325 + resources.erase(resources.begin() + i); 326 + break; 327 + } 328 + } 329 + } 330 + 331 + Resources::ResourceData* Resources::dataByHandle(Handle h) 332 + { 333 + auto it = m_handleMap.find(h); 334 + if (it == m_handleMap.end()) 335 + return nullptr; 336 + return it->second; 337 + } 338 + 339 + void Resources::save() 340 + { 341 + // TODO 29 342 }
+61 -2
src/frameworks/CoreServices/ResourcesImpl.h
··· 20 20 #ifndef _CS_RESOURCES_IMPL_H 21 21 #define _CS_RESOURCES_IMPL_H 22 22 #include <CoreServices/Resources.h> 23 + #include <CoreServices/MacMemory.h> 23 24 #include <string> 25 + #include <stdint.h> 26 + #include <vector> 27 + #include <list> 28 + #include <unordered_map> 24 29 25 30 class Resources 26 31 { 27 32 public: 33 + Resources(const char* file, SInt8 openMode, bool resourceFork); 28 34 29 - Resources(const char* file, bool readOnly, bool resourceFork); 35 + struct ResourceData 36 + { 37 + ResID id; 38 + ResType type; 39 + std::string name; 40 + ResAttributes attributes; 41 + std::vector<uint8_t> dataBacking; 42 + Resources* parent; 43 + 44 + ResourceData() {} 45 + ResourceData(Handle inData); 46 + ResourceData(const ResourceData& that) = delete; 47 + ResourceData(ResourceData&& that); 48 + ~ResourceData(); 49 + 50 + Handle getHandle(); 51 + void releaseHandle(bool freeMemory); 52 + void dataChanged(); 53 + private: 54 + Handle data = nullptr; 55 + }; 56 + 57 + struct ResourceTypeData 58 + { 59 + ResType type; 60 + std::vector<std::unique_ptr<ResourceData>> resources; 61 + std::unordered_map<ResID, ResourceData*> idMap; 62 + std::unordered_map<std::string, ResourceData*> nameMap; 63 + }; 64 + 65 + ResFileAttributes attributes() const { return m_attributes; } 66 + void setAttributes(ResFileAttributes a) { m_attributes = a; } 67 + 68 + std::unordered_map<ResType, ResourceTypeData>& data() { return m_resourceTypes; } 69 + ResourceData* dataByHandle(Handle h); 70 + std::unordered_map<Handle, ResourceData*>& handleMap() { return m_handleMap; } 71 + 72 + void save(); 73 + void add(ResType type, ResID id, const char* name, Handle data); 74 + void remove(Handle data); 75 + 76 + static void setCreateHandles(bool create); 30 77 private: 78 + void loadResources(); 79 + void loadResources(const uint8_t* mem, size_t length); 80 + protected: 31 81 std::string m_file; 32 - const bool m_readOnly, m_resourceFork; 82 + const bool m_resourceFork; 83 + const SInt8 m_openMode; 84 + 85 + ResFileAttributes m_attributes; 86 + 87 + std::unordered_map<ResType, ResourceTypeData> m_resourceTypes; 88 + std::unordered_map<Handle, ResourceData*> m_handleMap; 89 + static bool m_createHandles; 90 + 91 + friend struct ResourceData; 33 92 }; 34 93 35 94 #endif
+16
src/frameworks/CoreServices/include/CoreServices/MacErrors.h
··· 10 10 //#define noErr 0 11 11 #define unimpErr -4 12 12 #define fnfErr -43 // file not found 13 + #define eofErr -39 13 14 #define paramErr -50 14 15 #define handlerNotFoundErr -1856 15 16 #define kLocalesBufferTooSmallErr -30001 16 17 #define kUCOutputBufferTooSmall -25340 17 18 19 + // This must go away 18 20 #define kAudioUnitErr_InvalidProperty -10879 19 21 #define kAudioUnitErr_InvalidParameter -10878 20 22 #define kAudioUnitErr_InvalidElement -10877 ··· 48 50 retryComponentRegistrationErr = -3005, 49 51 badComponentInstance = (int)0x80008001, 50 52 badComponentSelector = (int)0x80008002, 53 + }; 54 + 55 + enum { 56 + resourceInMemory = -188, 57 + writingPastEnd = -189, 58 + inputOutOfBounds = -190, 59 + resNotFound = -191, 60 + resFNotFound = -193, 61 + addResFailed = -194, 62 + addRefFailed = -195, 63 + rmvResFailed = -196, 64 + rmvRefFailed = -197, 65 + resAttrErr = -198, 66 + mapReadErr = -199, 51 67 }; 52 68 53 69 #endif
+12 -4
src/frameworks/CoreServices/include/CoreServices/MacMemory.h
··· 16 16 17 17 Ptr NewPtr(long len); 18 18 Ptr NewPtrClear(long len); 19 - void DiposePtr(Ptr p); 19 + void DisposePtr(Ptr p); 20 20 void DisposeHandle(Handle handle); 21 21 Size GetHandleSize(Handle h); 22 22 void EmptyHandle(Handle h); 23 23 OSErr PtrToHand(const void* srcPtr, Handle* dstHndl, long size); 24 - 25 - // free and new alloc 24 + OSErr PtrToXHand(const void* srcPtr, Handle dstHndl, long size); 25 + Handle NewHandle(long size); 26 + Handle NewHandleClear(long size); 27 + Handle NewEmptyHandle(void); 28 + long GetPtrSize(Ptr ptr); 29 + void SetPtrSize(Ptr p, long newSize); 30 + void SetHandleSize(Handle h, long newSize); 31 + long GetHandleSize(Handle h); 26 32 void ReallocateHandle(Handle h, Size byteCount); 27 - // and other crap with relocatable memory blocks etc. 33 + void HLock(Handle h); 34 + void HLockHi(Handle h); 35 + void HUnlock(Handle h); 28 36 29 37 #ifdef __cplusplus 30 38 }
+11
src/frameworks/CoreServices/include/CoreServices/Resources.h
··· 33 33 kSystemResFile = 0, 34 34 }; 35 35 36 + enum { 37 + resSysHeap = 64, 38 + resPurgeable = 32, 39 + resLocked = 16, 40 + resProtected = 8, 41 + resPreload = 4, 42 + resChanged = 2, 43 + }; 44 + 36 45 typedef SInt16 ResID; 37 46 typedef SInt16 ResAttributes; 38 47 typedef SInt16 ResFileAttributes; ··· 52 61 53 62 ResourceCount CountTypes(void); 54 63 ResourceCount Count1Types(void); 64 + 65 + // NOTE: Indexes start from 1! 55 66 56 67 void GetIndType(ResType* type, ResourceIndex index); 57 68 void Get1IndType(ResType* type, ResourceIndex index);