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:
parent
f8c84387ca
commit
08e5f10ce4
|
@ -26,9 +26,12 @@ static const OSType kFileTypes[] = {kTypeProject};
|
||||||
// HandleOpen handles the Open menu command.
|
// HandleOpen handles the Open menu command.
|
||||||
static void HandleOpen(void)
|
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.
|
// HandleClose handles a request to close the given window.
|
||||||
|
|
115
macos/project.c
115
macos/project.c
|
@ -47,6 +47,8 @@ boundary. This is just to make it easier to read hexdumps.
|
||||||
|
|
||||||
#define kVersion 0x10000
|
#define kVersion 0x10000
|
||||||
|
|
||||||
|
#define kMaxChunkCount 32
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
||||||
// Magic cookie that identifies project files.
|
// Magic cookie that identifies project files.
|
||||||
|
@ -199,6 +201,119 @@ void ProjectNew(void)
|
||||||
ProjectCreateWindow(project);
|
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 ProjectAdjustMenus(ProjectHandle project, MenuHandle fileMenu)
|
||||||
{
|
{
|
||||||
(void)project;
|
(void)project;
|
||||||
|
|
|
@ -10,6 +10,9 @@ typedef struct Project **ProjectHandle;
|
||||||
// ProjectNew creates a new empty synchronization project.
|
// ProjectNew creates a new empty synchronization project.
|
||||||
void ProjectNew(void);
|
void ProjectNew(void);
|
||||||
|
|
||||||
|
// ProjectOpen opens an existing synchronization project.
|
||||||
|
void ProjectOpen(FSSpec *spec, ScriptCode script);
|
||||||
|
|
||||||
// ProjectAdjustMenus adjusts menus before selecting a menu item.
|
// ProjectAdjustMenus adjusts menus before selecting a menu item.
|
||||||
void ProjectAdjustMenus(ProjectHandle project, MenuHandle fileMenu);
|
void ProjectAdjustMenus(ProjectHandle project, MenuHandle fileMenu);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue