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.
This commit is contained in:
Dietrich Epp 2023-05-06 21:36:33 -04:00
parent f8c84387ca
commit 08e5f10ce4
3 changed files with 123 additions and 2 deletions

View File

@ -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.

View File

@ -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;

View File

@ -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);