From 08e5f10ce4b8d309a97c81e95bff328ebee42a4c Mon Sep 17 00:00:00 2001 From: Dietrich Epp Date: Sat, 6 May 2023 21:36:33 -0400 Subject: [PATCH] Parse project file header On opening a project, SyncFiles will now parse the project header and present an error message if there are any problems with the header. --- macos/main.c | 7 ++- macos/project.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++ macos/project.h | 3 ++ 3 files changed, 123 insertions(+), 2 deletions(-) diff --git a/macos/main.c b/macos/main.c index 9fb37f0..1fea277 100644 --- a/macos/main.c +++ b/macos/main.c @@ -26,9 +26,12 @@ static const OSType kFileTypes[] = {kTypeProject}; // HandleOpen handles the Open menu command. static void HandleOpen(void) { - StandardFileReply sfreply; + StandardFileReply reply; - StandardGetFile(NULL, ARRAY_COUNT(kFileTypes), kFileTypes, &sfreply); + StandardGetFile(NULL, ARRAY_COUNT(kFileTypes), kFileTypes, &reply); + if (reply.sfGood) { + ProjectOpen(&reply.sfFile, reply.sfScript); + } } // HandleClose handles a request to close the given window. diff --git a/macos/project.c b/macos/project.c index e6aefb3..53dd02f 100644 --- a/macos/project.c +++ b/macos/project.c @@ -47,6 +47,8 @@ boundary. This is just to make it easier to read hexdumps. #define kVersion 0x10000 +#define kMaxChunkCount 32 + // clang-format off // Magic cookie that identifies project files. @@ -199,6 +201,119 @@ void ProjectNew(void) ProjectCreateWindow(project); } +// ProjectReadError displays an error message encountered when trying to read a +// project. +static void ProjectReadError(ProjectHandle project, ErrorCode err, OSErr osErr) +{ + StrFileName name; + + memcpy(name, (*project)->fileSpec.name, sizeof(StrFileName)); + ShowError(kErrCouldNotReadProject, err, osErr, name); +} + +// ProjectRead reads the project from disk. Returns true on success. +static Boolean ProjectRead(ProjectHandle project) +{ + struct ProjectHeader header; + struct ProjectChunk **chunks; + short fileRef; + long count, size; + ErrorCode err; + OSErr osErr; + int nchunks; + UInt32 headerCRC, gotCRC; + + chunks = NULL; + err = kErrNone; + osErr = 0; + + fileRef = (*project)->fileRef; + osErr = SetFPos(fileRef, fsFromStart, 0); + if (osErr != 0) { + goto error; + } + count = sizeof(header); + osErr = FSRead(fileRef, &count, &header); + if (osErr != 0) { + goto error; + } + if (count < sizeof(header) || + memcmp(header.magic, kMagic, sizeof(kMagic)) != 0 || + header.chunkCount > kMaxChunkCount) { + err = kErrProjectDamaged; + goto error; + } + headerCRC = header.crc32; + header.crc32 = 0; + gotCRC = CRC32Update(0, &header, sizeof(header)); + nchunks = header.chunkCount; + if (nchunks > 0) { + size = sizeof(struct ProjectChunk) * nchunks; + chunks = (struct ProjectChunk **)NewHandle(size); + if (chunks == NULL) { + err = kErrOutOfMemory; + osErr = MemError(); + goto error; + } + count = size; + osErr = FSRead(fileRef, &count, *chunks); + if (osErr != 0) { + goto error; + } + if (count < size) { + err = kErrProjectDamaged; + goto error; + } + gotCRC = CRC32Update(gotCRC, *chunks, size); + } + if (headerCRC != gotCRC) { + err = kErrProjectDamaged; + goto error; + } + + // TODO: read project data + + if (chunks != NULL) { + DisposeHandle((Handle)chunks); + } + return true; + +error: + if (chunks != NULL) { + DisposeHandle((Handle)chunks); + } + ProjectReadError(project, err, osErr); + return false; +} + +void ProjectOpen(FSSpec *spec, ScriptCode script) +{ + ProjectHandle project; + struct Project *projectp; + short fileRef; + OSErr err; + + err = FSpOpenDF(spec, fsRdWrPerm, &fileRef); + if (err != noErr) { + ShowError(kErrCouldNotReadProject, kErrNone, err, spec->name); + return; + } + project = ProjectNewObject(); + if (project == NULL) { + FSClose(fileRef); + return; + } + projectp = *project; + projectp->fileRef = fileRef; + memcpy(&projectp->fileSpec, spec, sizeof(FSSpec)); + projectp->fileScript = script; + + ProjectRead(project); + + ProjectDelete(project); + // ProjectCreateWindow(project); +} + void ProjectAdjustMenus(ProjectHandle project, MenuHandle fileMenu) { (void)project; diff --git a/macos/project.h b/macos/project.h index 6d1e460..f467235 100644 --- a/macos/project.h +++ b/macos/project.h @@ -10,6 +10,9 @@ typedef struct Project **ProjectHandle; // ProjectNew creates a new empty synchronization project. void ProjectNew(void); +// ProjectOpen opens an existing synchronization project. +void ProjectOpen(FSSpec *spec, ScriptCode script); + // ProjectAdjustMenus adjusts menus before selecting a menu item. void ProjectAdjustMenus(ProjectHandle project, MenuHandle fileMenu);