#include "PLCore.h" #include "PLApplication.h" #include "PLPasStr.h" #include "PLKeyEncoding.h" #include "PLQDraw.h" #include "AEManager.h" #include "DisplayDeviceManager.h" #include "FileManager.h" #include "FilePermission.h" #include "FontFamily.h" #include "FontManager.h" #include "GpVOSEvent.h" #include "HostDirectoryCursor.h" #include "HostFileSystem.h" #include "HostSuspendCallArgument.h" #include "HostSuspendHook.h" #include "HostDisplayDriver.h" #include "HostSystemServices.h" #include "HostVOSEventQueue.h" #include "IGpColorCursor.h" #include "IGpDisplayDriver.h" #include "InputManager.h" #include "ResourceManager.h" #include "MacFileInfo.h" #include "MacRomanConversion.h" #include "MemoryManager.h" #include "MenuManager.h" #include "MemReaderStream.h" #include "MMHandleBlock.h" #include "RenderedFont.h" #include "ResTypeID.h" #include "RandomNumberGenerator.h" #include "PLArrayViewIterator.h" #include "PLBigEndian.h" #include "PLEventQueue.h" #include "PLKeyEncoding.h" #include "PLSysCalls.h" #include "PLTimeTaggedVOSEvent.h" #include "PLWidgets.h" #include "QDManager.h" #include "Vec2i.h" #include "WindowDef.h" #include "WindowManager.h" #include #include static bool ConvertFilenameToSafePStr(const char *str, uint8_t *pstr) { const char *strBase = str; while (*str) { const char c = *str++; if (c == '.' || c == ' ' || c == '_' || c == '\'' || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) continue; else return false; } ptrdiff_t len = str - strBase; if (len > 31) return false; memcpy(pstr + 1, strBase, static_cast(len)); pstr[0] = static_cast(len); return true; } void InitCursor() { PortabilityLayer::HostDisplayDriver::GetInstance()->SetStandardCursor(EGpStandardCursors::kArrow); } Rect BERect::ToRect() const { Rect rect; rect.top = this->top; rect.bottom = this->bottom; rect.left = this->left; rect.right = this->right; return rect; } CursHandle GetCursor(int cursorID) { return PortabilityLayer::ResourceManager::GetInstance()->GetAppResource('CURS', cursorID).ReinterpretCast(); } void HideCursor() { PortabilityLayer::HostDisplayDriver::GetInstance()->SetStandardCursor(EGpStandardCursors::kHidden); } void SetCursor(CursPtr cursor) { PL_NotYetImplemented(); } void SetBuiltinCursor(int builtinCursor) { PL_NotYetImplemented(); } void Delay(int ticks, UInt32 *endTickCount) { PLSysCalls::Sleep(ticks); if (endTickCount) *endTickCount = PortabilityLayer::DisplayDeviceManager::GetInstance()->GetTickCount(); } short FindWindow(Point point, WindowPtr *window) { short part = 0; PortabilityLayer::WindowManager::GetInstance()->FindWindow(point, window, &part); return part; } void DragWindow(WindowPtr window, Point start, Rect *bounds) { PL_NotYetImplemented(); } void SendBehind(WindowPtr window, WindowPtr behind) { PL_NotYetImplemented(); } void BringToFront(WindowPtr window) { PL_NotYetImplemented(); } bool TrackGoAway(WindowPtr window, Point point) { PL_NotYetImplemented(); return false; } Int32 GrowWindow(WindowPtr window, Point start, Rect *size) { PL_NotYetImplemented(); return 0; } bool TrackBox(WindowPtr window, Point point, int part) { PL_NotYetImplemented(); return false; } void ZoomWindow(WindowPtr window, int part, bool bringToFront) { PL_NotYetImplemented(); } void HiliteWindow(WindowPtr window, bool highlighted) { PL_NotYetImplemented(); } void DisposeWindow(WindowPtr window) { PL_NotYetImplemented(); } void GetWindowBounds(WindowPtr window, WindowRegionType windowRegion, Rect *rect) { if (windowRegion == kWindowContentRgn) *rect = window->m_surface.m_port.GetRect(); else { PL_NotYetImplemented(); } } WindowPtr GetNewCWindow(int resID, void *storage, WindowPtr behind) { Handle windowResource = PortabilityLayer::ResourceManager::GetInstance()->GetAppResource('WIND', resID); if (!windowResource) return nullptr; long resSize = GetHandleSize(windowResource); PortabilityLayer::MemReaderStream stream(*windowResource, resSize); PortabilityLayer::WindowDef def; if (!def.Deserialize(&stream)) return nullptr; WindowPtr window = PortabilityLayer::WindowManager::GetInstance()->CreateWindow(def); if (window) PortabilityLayer::WindowManager::GetInstance()->PutWindowBehind(window, behind); return window; } WindowPtr NewCWindow(void *storage, const Rect *bounds, const PLPasStr &title, Boolean visible, int wdef, WindowPtr behind, Boolean hasCloseBox, long userdata) { PL_NotYetImplemented(); return nullptr; } WindowPtr NewWindow(void *storage, const Rect *bounds, const PLPasStr &title, Boolean visible, int wdef, WindowPtr behind, Boolean hasCloseBox, long userdata) { PL_NotYetImplemented(); return nullptr; } void SizeWindow(WindowPtr window, int width, int height, Boolean addToUpdateRegion) { PortabilityLayer::WindowManager::GetInstance()->ResizeWindow(window, width, height); } void MoveWindow(WindowPtr window, int x, int y, Boolean moveToFront) { PortabilityLayer::WindowManager *windowManager = PortabilityLayer::WindowManager::GetInstance(); windowManager->MoveWindow(window, x, y); if (moveToFront != 0) windowManager->PutWindowBehind(window, windowManager->GetPutInFrontSentinel()); } void ShowWindow(WindowPtr window) { PortabilityLayer::WindowManager::GetInstance()->ShowWindow(window); } void SetWTitle(WindowPtr window, const PLPasStr &title) { PL_NotYetImplemented_TODO("Editor"); } long MenuSelect(Point point) { int16_t menuID = 0; uint16_t menuItem = 0; PortabilityLayer::MenuManager::GetInstance()->MenuSelect(PortabilityLayer::Vec2i(point.h, point.v), &menuID, &menuItem); return (static_cast(menuID) << 16) | (static_cast(menuItem)); } long MenuKey(int charCode) { PL_NotYetImplemented(); return PLErrors::kNone; } long TickCount() { return PortabilityLayer::DisplayDeviceManager::GetInstance()->GetTickCount(); } short LoWord(Int32 v) { return ((v ^ 0x8000) & 0xffff) - 0x8000; } short HiWord(Int32 v) { return (((v >> 16) ^ 0x8000) & 0xffff) - 0x8000; } void NumToString(long number, unsigned char *str) { unsigned char *firstChar = str + 1; unsigned char *outChar = firstChar; unsigned char *firstDigitLoc = firstChar; int firstDigit = 0; if (number == LONG_MIN) { *outChar = '-'; outChar++; firstDigitLoc++; // Non-negatable number const long halfAbsNumberDiv2 = (number >> 1) & ~(static_cast(1) << (sizeof(long) * 8 - 1)); const long halfAbsNumberDiv5 = halfAbsNumberDiv2 / 5; const long halfAbsNumberMod5 = halfAbsNumberDiv2 % 5; firstDigit = static_cast(halfAbsNumberMod5) * 2; number = halfAbsNumberDiv5; } else if (number < 0) { *outChar = '-'; outChar++; firstDigitLoc++; number = -number; firstDigit = static_cast(number % 10); number /= 10; } else { firstDigit = static_cast(number % 10); number /= 10; } *outChar = '0' + firstDigit; outChar++; while (number > 0) { const int digit = number % 10; number /= 10; *outChar = '0' + digit; *outChar++; } const ptrdiff_t strLength = outChar - firstChar; const size_t numDigits = static_cast(outChar - firstDigitLoc); const size_t halfNumDigits = numDigits / 2; // Swap to MSD order for (size_t i = 0; i < halfNumDigits; i++) std::swap(firstDigitLoc[i], *(outChar - 1 - i)); str[0] = static_cast(strLength); } PLError_t AEProcessAppleEvent(EventRecord *evt) { PL_NotYetImplemented(); return PLErrors::kNone; } void GetIndString(unsigned char *str, int stringsID, int fnameIndex) { if (fnameIndex < 1) { str[0] = 0; return; } THandle istrRes = PortabilityLayer::ResourceManager::GetInstance()->GetAppResource('STR#', stringsID).StaticCast(); if (istrRes && *istrRes) { const uint8_t *contentsBytes = *istrRes; const uint8_t *endPos = contentsBytes + istrRes.MMBlock()->m_size; const uint8_t *lineStart = contentsBytes; const uint8_t *lineEnd = contentsBytes; for (;;) { if (contentsBytes == endPos) { if (fnameIndex == 1) { lineEnd = contentsBytes; break; } else { str[0] = 0; return; } } const uint8_t lchar = contentsBytes[0]; if (lchar == '\n') { if (fnameIndex == 1) { lineEnd = contentsBytes; break; } else { fnameIndex--; contentsBytes++; lineStart = lineEnd = contentsBytes; } } else contentsBytes++; } ptrdiff_t strLength = lineEnd - lineStart; if (strLength < 0 || strLength > 255) strLength = 255; str[0] = static_cast(strLength); memcpy(str + 1, lineStart, strLength); } } VFileSpec MakeVFileSpec(PortabilityLayer::VirtualDirectory_t dir, const PLPasStr &fileName) { VFileSpec spec; assert(fileName.Length() < sizeof(spec.m_name)); spec.m_dir = dir; spec.m_name[0] = static_cast(fileName.Length()); memcpy(spec.m_name + 1, fileName.UChars(), fileName.Length()); return spec; } PLError_t FSpGetFInfo(const VFileSpec &spec, VFileInfo &finfo) { PortabilityLayer::MacFileProperties mfp; if (!PortabilityLayer::FileManager::GetInstance()->ReadFileProperties(spec.m_dir, spec.m_name, mfp)) return PLErrors::kFileNotFound; finfo.m_type = PortabilityLayer::ResTypeID(mfp.m_fileType); finfo.m_creator = PortabilityLayer::ResTypeID(mfp.m_fileCreator); return PLErrors::kNone; } DirectoryFileListEntry *GetDirectoryFiles(PortabilityLayer::VirtualDirectory_t dirID) { PortabilityLayer::MemoryManager *mm = PortabilityLayer::MemoryManager::GetInstance(); PortabilityLayer::HostFileSystem *fs = PortabilityLayer::HostFileSystem::GetInstance(); PortabilityLayer::HostDirectoryCursor *dirCursor = fs->ScanDirectory(dirID); DirectoryFileListEntry *firstDFL = nullptr; DirectoryFileListEntry *lastDFL = nullptr; if (!dirCursor) return nullptr; const char *filename; char fnCopy[256]; while (dirCursor->GetNext(filename)) { const size_t fnLen = strlen(filename); if (fnLen < 5 || fnLen > 255) continue; memcpy(fnCopy, filename, fnLen + 1); if (!strcmp(&filename[fnLen - 4], ".gpf")) { const size_t dotPos = fnLen - 4; PortabilityLayer::IOStream *stream = fs->OpenFile(dirID, filename, false, GpFileCreationDispositions::kOpenExisting); if (!stream) continue; PortabilityLayer::MacFileProperties mfp; PortabilityLayer::MacFilePropertiesSerialized mfs; const size_t gpfSize = stream->Read(mfs.m_data, PortabilityLayer::MacFilePropertiesSerialized::kSize); stream->Close(); if (gpfSize != PortabilityLayer::MacFilePropertiesSerialized::kSize) continue; mfs.Deserialize(mfp); fnCopy[dotPos] = '\0'; DirectoryFileListEntry tempDFL; tempDFL.finderInfo.fdType = PortabilityLayer::ResTypeIDCodec::Decode(mfp.m_fileType); tempDFL.finderInfo.fdCreator = PortabilityLayer::ResTypeIDCodec::Decode(mfp.m_fileCreator); tempDFL.nextEntry = nullptr; if (!ConvertFilenameToSafePStr(fnCopy, tempDFL.name)) continue; DirectoryFileListEntry *dfl = static_cast(mm->Alloc(sizeof(DirectoryFileListEntry))); if (!dfl) { if (firstDFL) DisposeDirectoryFiles(firstDFL); return nullptr; } new (dfl) DirectoryFileListEntry(tempDFL); dfl->nextEntry = nullptr; if (lastDFL) lastDFL->nextEntry = dfl; else firstDFL = dfl; lastDFL = dfl; } } dirCursor->Destroy(); return firstDFL; } void DisposeDirectoryFiles(DirectoryFileListEntry *firstDFL) { PortabilityLayer::MemoryManager *mm = PortabilityLayer::MemoryManager::GetInstance(); DirectoryFileListEntry *dfl = firstDFL; while (dfl) { DirectoryFileListEntry *nextDFL = dfl->nextEntry; mm->Release(dfl); dfl = nextDFL; } } void GetMouse(Point *point) { PL_NotYetImplemented(); } Boolean Button() { PL_NotYetImplemented(); return false; } Boolean StillDown() { PL_NotYetImplemented(); return false; } Boolean WaitMouseUp() { PL_NotYetImplemented(); return false; } short Random() { // Should return with range -32767..32767 uint32_t bits = PortabilityLayer::RandomNumberGenerator::GetInstance()->GetNextAndAdvance(); uint16_t rWord = (bits & 0xffff); if (rWord == 0) { rWord = (bits >> 16) & 0xffff; if (rWord == 0) return 0; // This should be extremely rare } return static_cast(static_cast(rWord) - 0x8000); } void GetTime(DateTimeRec *dateTime) { unsigned int year; unsigned int month; unsigned int day; unsigned int hour; unsigned int minute; unsigned int second; PortabilityLayer::HostSystemServices::GetInstance()->GetLocalDateTime(year, month, day, hour, minute, second); dateTime->month = month; dateTime->hour = hour; dateTime->minute = minute; } UInt32 GetDblTime() { PL_NotYetImplemented_Minor(); return 30; } void FlushEvents(int mask, int unknown) { PortabilityLayer::EventQueue *queue = PortabilityLayer::EventQueue::GetInstance(); while (queue->Dequeue(nullptr)) { } } void ExitToShell() { PL_NotYetImplemented(); } void InvalWindowRect(WindowPtr window, const Rect *rect) { PL_NotYetImplemented(); } Handle NewHandle(Size size) { PortabilityLayer::MMHandleBlock *hBlock = PortabilityLayer::MemoryManager::GetInstance()->AllocHandle(size); if (!hBlock) return nullptr; return &hBlock->m_contents; } long GetHandleSize(Handle handle) { if (!handle) return 0; return handle.MMBlock()->m_size; } PLError_t PtrAndHand(const void *data, Handle handle, Size size) { PL_NotYetImplemented(); return PLErrors::kNone; } PLError_t SetHandleSize(Handle hdl, Size newSize) { PortabilityLayer::MemoryManager *mm = PortabilityLayer::MemoryManager::GetInstance(); if (!mm->ResizeHandle(hdl.MMBlock(), newSize)) return PLErrors::kOutOfMemory; return PLErrors::kNone; } void *NewPtr(Size size) { return PortabilityLayer::MemoryManager::GetInstance()->Alloc(size); } void *NewPtrClear(Size size) { void *data = NewPtr(size); if (data != nullptr && size != 0) memset(data, 0, size); return data; } void DisposePtr(void *ptr) { PortabilityLayer::MemoryManager::GetInstance()->Release(ptr); } void BlockMove(const void *src, void *dest, Size size) { memcpy(dest, src, size); } bool WaitForEvent(TimeTaggedVOSEvent *eventOut, uint32_t ticks) { for (;;) { if (PortabilityLayer::EventQueue::GetInstance()->Dequeue(eventOut)) return true; Delay(1, nullptr); if (ticks == 0) break; ticks--; } return false; } void DrawControls(WindowPtr window) { PL_NotYetImplemented(); } void DrawGrowIcon(WindowPtr window) { PL_NotYetImplemented(); } void DebugStr(const PLPasStr &str) { PL_NotYetImplemented(); } void PL_NotYetImplemented() { assert(false); } void PL_NotYetImplemented_Minor() { } void PL_NotYetImplemented_TODO(const char *category) { (void)category; } void PL_Init() { PortabilityLayer::FontManager::GetInstance()->Init(); PortabilityLayer::MemoryManager::GetInstance()->Init(); PortabilityLayer::ResourceManager::GetInstance()->Init(); PortabilityLayer::DisplayDeviceManager::GetInstance()->Init(); PortabilityLayer::AEManager::GetInstance()->Init(); PortabilityLayer::QDManager::GetInstance()->Init(); PortabilityLayer::MenuManager::GetInstance()->Init(); } WindowPtr PL_GetPutInFrontWindowPtr() { return PortabilityLayer::WindowManager::GetInstance()->GetPutInFrontSentinel(); } Window::Window() : m_surface(PortabilityLayer::QDPortType_Window) , m_wmX(0) , m_wmY(0) , m_widgets(nullptr) , m_numWidgets(0) { } Window::~Window() { if (m_widgets) { for (size_t i = 0; i < m_numWidgets; i++) m_widgets[i]->Destroy(); PortabilityLayer::MemoryManager::GetInstance()->Release(m_widgets); } } DrawSurface *Window::GetDrawSurface() const { return const_cast(&m_surface); } Point Window::MouseToLocal(const GpMouseInputEvent &evt) const { return Point::Create(evt.m_x - m_wmX, evt.m_y - m_wmY); } Point Window::TopLeftCoord() const { return Point::Create(m_wmX, m_wmY); } bool Window::AddWidget(PortabilityLayer::Widget *widget) { if (m_widgets == nullptr) { m_widgets = static_cast(PortabilityLayer::MemoryManager::GetInstance()->Alloc(sizeof(PortabilityLayer::Widget *))); if (m_widgets == nullptr) return false; } else { void *newBuffer = PortabilityLayer::MemoryManager::GetInstance()->Realloc(m_widgets, (m_numWidgets + 1) * sizeof(PortabilityLayer::Widget*)); if (newBuffer == nullptr) return false; m_widgets = static_cast(newBuffer); } m_widgets[m_numWidgets++] = widget; return true; } void Window::DrawControls() { DrawSurface *surface = GetDrawSurface(); for (size_t i = 0; i < m_numWidgets; i++) { PortabilityLayer::Widget *widget = m_widgets[i]; if (widget->IsVisible()) widget->DrawControl(surface); } }