// disk.c // // by John D. de Boer #include "common.h" #include "cstring.h" #include "cyber.h" #include "disk.h" static file *CurrentFile=NULL; // Utility bool samefile(const FSRef *A, const FSRef *B) { OSErr err; if (!A && !B) return 1; if (!A || !B) return 0; err=FSCompareFSRefs(A,B); if (err) return 0; return 1; } bool relfsref(const FSRef *A, const char *Path, FSRef *B) { OSErr err; int i; FSCatalogInfo Info; FSRef Dir; char *S; HFSUniStr255 UN; if (!A || !Path || !B) return 0; err=FSGetCatalogInfo(A,kFSCatInfoNodeFlags,&Info,NULL,NULL,&Dir); if (err) return 0; if (Info.nodeFlags & kFSNodeIsDirectoryMask) Dir=*A; while (S=firstocc('/',Path)) { UN.length= S - Path; for (i=0;iwrit=Write; F->pass=0; F->buff=pointer(RWBUFFSZ); F->mark= Write ? 0 : RWBUFFSZ; } static void killbuffer(file *F) { OSErr err; long M; if (!F) return; M=F->mark; if (F->writ && M) { err=FSWriteFork(F->forkref,fsAtMark,0,M,F->buff,NULL); if (err) ioerror(err); } old(F->buff); } // Creating, opening, and closing files static OSErr tempfile(FSRef *Temp, SInt16 *FORK) { OSErr err; FSRef Trash; HFSUniStr255 UN; int i; if (!Temp || !FORK) return memWZErr; err=FSFindFolder(kOnAppropriateDisk,kTemporaryFolderType,1,&Trash); if (err) return err; UN.length=10; for (i=0;i<10;i++) UN.unicode[i]= '0' + randzb(10); err=FSCreateFileUnicode(&Trash,UN.length,UN.unicode,kFSCatInfoNone,NULL,Temp,NULL); if (err) return err; err=opendatafork(Temp,FORK); return err; } bool saveas(const char *Title, const char *Name, OSType Creator, OSType Type, file *F) { OSStatus err; NavDialogCreationOptions Options; NavDialogRef Dialog; NavUserAction Action; NavReplyRecord Reply; ScriptCode Script; SInt32 count; AEKeyword KW; DescType actualType; Size actualSize; short FNL; UniChar *buf; CFRange rng; FSRef Dir; FSCatalogInfo FSCI; FileInfo *FI; if (!F) return 0; err=NavGetDefaultDialogCreationOptions(&Options); Options.windowTitle=macstring(Title); // NavServices dialog has no titlebar Options.saveFileName=macstring(Name); err=NavCreatePutFileDialog(&Options,Type,Creator,NULL,NULL,&Dialog); err=NavDialogRun(Dialog); Action=NavDialogGetUserAction(Dialog); if (Action==kNavUserActionCancel) { NavDialogDispose(Dialog); return 0; } if (Action==kNavUserActionNone) { NavDialogDispose(Dialog); return 0; } err=NavDialogGetReply(Dialog,&Reply); NavDialogDispose(Dialog); if (!Reply.validRecord) { NavDisposeReply(&Reply); return 0; } err=AECountItems(&(Reply.selection),&count); err=AEGetNthPtr(&(Reply.selection),1,typeFSRef,&KW,&actualType,&Dir,sizeof(FSRef),&actualSize); F->repl=Reply.replacing; Script=Reply.keyScript; FNL=CFStringGetLength(Reply.saveFileName); buf=pointer((FNL+1) * sizeof(UniChar));//+1 not reqr rng.location=0; rng.length=FNL; CFStringGetCharacters(Reply.saveFileName,rng,buf); err=NavDisposeReply(&Reply); if (F->repl) { err=tempfile(&(F->temp),&(F->forkref)); if (err) { ioerror(err); return 0; } err=FSMakeFSRefUnicode(&Dir,FNL,buf,kTextEncodingUnknown,&(F->fsref)); if (err) { ioerror(err); return 0; } } else { err=FSCreateFileUnicode(&Dir,FNL,buf,kFSCatInfoNone,NULL,&(F->fsref),NULL); if (err) { ioerror(err); return 0; } err=FSGetCatalogInfo(&(F->fsref),kFSCatInfoFinderInfo,&FSCI,NULL,NULL,NULL); if (err) { ioerror(err); return 0; } FI=(FileInfo *)&(FSCI.finderInfo); FI->fileType=Type; FI->fileCreator=Creator; err=FSSetCatalogInfo(&(F->fsref),kFSCatInfoFinderInfo,&FSCI); if (err) { ioerror(err); return 0; } err=opendatafork(&(F->fsref),&(F->forkref)); if (err) { ioerror(err); return 0; } } old(buf); makebuffer(F,1); return 1; } bool createfile(FSRef *Dir, const char *Name, OSType Creator, OSType Type, file *F) { OSStatus err; int i; HFSUniStr255 UN; if (!Dir || !F) return 0; //F->fsref=*Dir; //err=copyfss(FSS,&(F->fss)); //if (err && err!=fnfErr) { ioerror(err); return 0; } //err=FSGetCatalogInfo(FSR,kFSCatInfoNone,NULL,NULL,NULL,NULL); //F->repl=(err!=fnfErr); F->repl=0; //if (F->repl) { err=tempfile(&(F->temp),&(F->forkref)); // if (err) { ioerror(err); return 0; } } else { //err=FSpCreate(&(F->fss),Creator,Type,smSystemScript); UN.length=length(Name); for (i=0;ifsref),NULL); if (err) { ioerror(err); return 0; } err=opendatafork(&(F->fsref),&(F->forkref)); if (err) { ioerror(err); return 0; } makebuffer(F,1); return 1; } bool openreplacement(file *Old, file *F) { OSErr err; if (!Old || !F) return 0; F->fsref=Old->fsref; err=tempfile(&(F->fsref),&(F->forkref)); if (err) { ioerror(err); return 0; } F->repl=1; makebuffer(F,1); return 1; } static Boolean MyTextFilterProc(AEDesc *Item, void *NFFI, void *callBackUD, NavFilterModes FM) { OSErr err; NavFileOrFolderInfo *Info; FSRef FSR; //HFSUniStr255 UN; //UnicodeToTextInfo UTI; //Str255 PS; FSSpec FSS; char *S; bool Ext; if (Item->descriptorType!=typeFSRef) return 0; Info=(NavFileOrFolderInfo *)NFFI; if (Info->isFolder) return 1; err=AEGetDescData(Item,&FSR,sizeof(FSRef)); if (err) return 0; /*err=FSGetCatalogInfo(&FSR,kFSCatInfoNone,NULL,&UN,NULL,NULL); if (err) return 0; err=CreateUnicodeToTextInfoByEncoding(kUnicode16BitFormat,&UTI); if (err) return 0; err=ConvertFromUnicodeToPString(UTI,UN.length,UN.unicode,PS); if (err) { return 0; } // -8753, input buffer ends in the middle of a multibyte character, conversion stopped err=DisposeUnicodeToTextInfo(&UTI); if (err) return 0; S=cstring(PS);*/ err=FSGetCatalogInfo(&FSR,kFSCatInfoNone,NULL,NULL,&FSS,NULL); if (err) return 0; S=cstring(FSS.name); Ext=ends(S,".txt"); old(S); if (Ext) return 1; if (Info->fileAndFolder.fileInfo.finderInfo.fdType=='TEXT') return 1; return 0; } static Boolean MyAnyDocFilterProc(AEDesc *Item, void *NFFI, void *callBackUD, NavFilterModes FM) { return 1; } bool openexistingfile(OSType Type, file *F) { OSStatus err; NavDialogCreationOptions Options; NavTypeListHandle TL; NavObjectFilterUPP TextUPP; NavDialogRef Dialog; NavUserAction Action; NavReplyRecord Reply; SInt32 count; AEKeyword KW; DescType actualType; Size actualSize; FSRef FSR; if (!F) return 0; err=NavGetDefaultDialogCreationOptions(&Options); Options.optionFlags= kNavDefaultNavDlogOptions - kNavAllowMultipleFiles/* + kNavAllFilesInPopup*/; if (Type=='TEXT') { TL=NULL; TextUPP=NewNavObjectFilterUPP(&MyTextFilterProc); } else if (Type==0) { TL=NULL; TextUPP=NewNavObjectFilterUPP(&MyAnyDocFilterProc); } else { TextUPP=NULL; TL=(NavTypeListHandle)handle(sizeof(NavTypeList) + sizeof(OSType)); (*TL)->componentSignature=kNavGenericSignature; (*TL)->reserved=0; (*TL)->osTypeCount=1; (*TL)->osType[0]=Type; } err=NavCreateGetFileDialog(&Options,TL,NULL,NULL,TextUPP,NULL,&Dialog); err=NavDialogRun(Dialog); Action=NavDialogGetUserAction(Dialog); if (TL) release(TL); if (TextUPP) DisposeNavObjectFilterUPP(TextUPP); if (Action==kNavUserActionCancel) { NavDialogDispose(Dialog); return 0; } if (Action==kNavUserActionNone) { NavDialogDispose(Dialog); return 0; } err=NavDialogGetReply(Dialog,&Reply); NavDialogDispose(Dialog); if (!Reply.validRecord) { NavDisposeReply(&Reply); return 0; } err=AECountItems(&(Reply.selection),&count); if (count!=1) error("openexistingfile() error #1"); err=AEGetNthPtr(&(Reply.selection),1,typeFSRef,&KW,&actualType,&FSR,sizeof(FSRef),&actualSize); err=NavDisposeReply(&Reply); F->fsref=FSR; err=opendatafork(&(F->fsref),&(F->forkref)); if (err) { ioerror(err); return 0; } F->repl=0; makebuffer(F,0); return 1; } bool openfile(FSRef *FSR, file *F) { OSErr err; if (!FSR || !F) return 0; F->fsref=*FSR; err=opendatafork(&(F->fsref),&(F->forkref)); if (err) { ioerror(err); return 0; } F->repl=0; makebuffer(F,0); return 1; } static bool finishreplacing(file *F) { OSErr err; if (!F || !F->repl) return 0; err=FSExchangeObjects(&(F->temp),&(F->fsref)); if (err) { ioerror(err); return 0; } err=FSDeleteObject(&(F->temp)); if (err && err!=fBsyErr) { ioerror(err); return 0; } return 1; } bool closefile(file *F) { OSErr err; if (!F) return 0; killbuffer(F); err=FSCloseFork(F->forkref); if (err) { ioerror(err); return 0; } //if (F->writ) { err=FSFlushFork(F->forkref); if (err) { ioerror(err); return 0; } } // not required if fork was closed if (F->repl) finishreplacing(F); return 1; } // Basic file manipulation void setpath(file *F) { if (!F) halt("setpath() error #1"); CurrentFile=F; if (!F->buff) halt("Read/write buffer not found in setpath()"); } void allocatebytes(file *F, long LEN) { UInt64 ASK,GOT; OSStatus err; if (!F) return; ASK=LEN; err=FSAllocateFork(F->forkref,kFSAllocDefaultFlags,fsFromStart,0,ASK,&GOT); if (GOTfsref),kFSCatInfoNone,NULL,&UN,NULL,NULL); S=pointer(UN.length + 1); for (i=0;iforkref,&LOF); return LOF; } long bytespassed(file *F) { return F ? F->pass : -1; } void writebytes(const void *P, long N) { OSErr err; long Q; char *From; ByteCount SEND,WENT; if (!P || !CurrentFile) halt("writebytes() error #1"); From=(char *)P; CurrentFile->pass+=N; if (!CurrentFile->writ) halt("Writing to file opened as read-only"); while (N>0) { Q=lsr(N,RWBUFFSZ - CurrentFile->mark); if (Q>0) { BlockMove(From,CurrentFile->buff + CurrentFile->mark,Q); From+=Q; CurrentFile->mark+=Q; N-=Q; } if (CurrentFile->mark>=RWBUFFSZ) { Q=RWBUFFSZ; CurrentFile->mark=0; //err=FSWrite(CurrentFile->path,&Q,CurrentFile->buff); SEND=Q; err=FSWriteFork(CurrentFile->forkref,fsAtMark,0,SEND,CurrentFile->buff,&WENT); if (err) iohalt(err); } } } void readbytes(const void *P, long N) { OSErr err; long Q; char *Dest; ByteCount ASK,GOT; if (!P || !CurrentFile) halt("readbytes() error #1"); Dest=(char *)P; CurrentFile->pass+=N; if (CurrentFile->writ) halt("Reading from file opened as write-only"); while (N>0) { if (CurrentFile->mark>=RWBUFFSZ) { Q=RWBUFFSZ; CurrentFile->mark=0; //err=FSRead(CurrentFile->path,&Q,CurrentFile->buff); ASK=Q; err=FSReadFork(CurrentFile->forkref,fsAtMark,0,ASK,CurrentFile->buff,&GOT); if (err && !(err==eofErr && N<=GOT)) iohalt(err); } Q=lsr(N,RWBUFFSZ - CurrentFile->mark); if (Q>0) { BlockMove(CurrentFile->buff + CurrentFile->mark,Dest,Q); CurrentFile->mark+=Q; Dest+=Q; N-=Q; } } } // Determining allocation for standard structures // Variable-sized records are preceeded by a variable-sized length. static ulong lengthoflength(ulong LEN) { if (LEN<0xFF) return sizeof(char); if (LEN<0xFFFF) return sizeof(char) + sizeof(short); return sizeof(char) + sizeof(short) + sizeof(long); } ulong lengthofstring(const char *S) { ulong L; if (!S) return 1; L=length(S); return lengthoflength(L) + (L * sizeof(char)); } ulong lengthofpointer(const void *P) { ulong L; if (!P) return 1; L=GetPtrSize((void *)P); return lengthoflength(L) + L; } ulong lengthofvoidhandle(void **H) { ulong L; if (!H || !*H) return 1; L=GetHandleSize((Handle)H); return lengthoflength(L) + L; } // Writing standard structures void writechar(char C) { writebytes(&C,sizeof(char)); } void writeshort(short S) { writebytes(&S,sizeof(short)); } void writelong(long L) { writebytes(&L,sizeof(long)); } static void writelength(ulong LEN) { if (LEN<0xFF) { writechar(LEN); return; } writechar(0xFF); if (LEN<0xFFFF) { writeshort(LEN); return; } writeshort(0xFFFF); writelong(LEN); } void writestring(const char *S) { ulong L; if (!S) { error("NULL passed to writestring()"); return; } L= length(S) * sizeof(char); writelength(L); writebytes(S,L); } void writepointer(const void *P) { ulong L; if (!P) { error("NULL passed to writepointer()"); return; } L=GetPtrSize((void *)P); writelength(L); writebytes(P,L); } void writevoidhandle(void **H) { ulong L; if (!H) { error("NULL passed to writehandle()"); return; } L=GetHandleSize((Handle)H); writelength(L); lock(H); writebytes(*H,L); unlock(H); } // Reading standard structures char readchar(void) { char C; readbytes(&C,sizeof(char)); return C; } short readshort(void) { short S; readbytes(&S,sizeof(short)); return S; } long readlong(void) { long L; readbytes(&L,sizeof(long)); return L; } static ulong readlength(void) { uchar UC; ushort US; UC=readchar(); if (UC<0xFF) return UC; US=readshort(); if (US<0xFFFF) return US; return readlong(); } string readstring(void) { ulong L; char *S; L=readlength(); if (L<1) return NULL; S=pointer(L + 1); readbytes(S,L); S[L]=0; return S; } void *readpointer(void) { ulong L; void *P; L=readlength(); if (L<1) return NULL; P=pointer(L); readbytes(P,L); return P; } void **readhandle(void) { ulong L; void **H; L=readlength(); if (L<1) return NULL; H=handle(L); lock(H); readbytes(*H,L); unlock(H); return H; } // PICTs /* ulong lengthofpict(PicHandle PH) { if (!PH) return 0; return 512 + GetHandleSize((Handle)PH); } void writepict(PicHandle PH) { int i; long LEN; for (i=0;i < 512 / sizeof(long);i++) writelong(0); LEN=GetHandleSize((Handle)PH); lock(PH); writebytes(*PH,LEN); unlock(PH); } PicHandle readpict(void) { PicHandle PH; int i; long LEN; if (!CurrentFile) return NULL; LEN= filelength(CurrentFile) - 512; if (LEN<=0) return NULL; for (i=0;i < 512 / sizeof(long);i++) readlong(); PH=(PicHandle)handle(LEN); if (!PH) return NULL; lock(PH); readbytes(*PH,LEN); unlock(PH); return PH; }*/ // Writing and reading miscellaneous data structures void writetext(const char *S, char Delim) { if (S) writebytes(S,length(S)); if (Delim>0) writebytes(&Delim,1); } void writetextold(string S, char Delim) { writetext(S,Delim); old(S); } void writefig(long N, char Delim) { writetextold(fig(N),Delim); } static const int MAXDIG = 20; long readnum(void) { char C,Dig[MAXDIG]; int DIG=0; long X; do C=readchar(); while (C==' ' || C==',' || linebreak(C)); while (C && C!=' ' && C!=',' && !linebreak(C)) { if (DIG < MAXDIG - 1) Dig[DIG++]=C; C=readchar(); } Dig[DIG]=0; parseinteger(Dig,&X); return X; } string readtext(void) { char C,L,Str[512]; int N; do C=readchar(); while (C==' ' || C==',' || linebreak(C)); N=0; while (1) { Str[N++]=L=C; C=readchar(); if (C==',') { if (L!='-') return leftstr(Str,N); N--; } if (linebreak(C)) { if (L!='+') return leftstr(Str,N); N--; C=' '; } if (N>=512) return leftstr(Str,N); } } int readuline(char *Buf, int MAX) { char C; int COUNT; if (!Buf || MAX<1) return 0; MAX--; COUNT=0; while (MAX--) { C=readchar(); if (linebreak(C)) break; *(Buf++)=C; COUNT++; } *Buf=0; return COUNT; } void *newbytes(long N) { void *P; if (N<1) return NULL; P=pointer(N); readbytes(P,N); return P; } // Reading entire files without the buffer static void readbytesnobuff(void *P, long N) { OSErr err; ByteCount ASK,GOT; if (!P || !CurrentFile) halt("readbytesnobuff() error #1"); if (CurrentFile->writ) halt("Reading from file opened as write-only"); ASK=N; //err=FSRead(CurrentFile->path,&Q,P); err=FSReadFork(CurrentFile->forkref,fsAtMark,0,ASK,P,&GOT); if (err && err!=eofErr) iohalt(err); } string filetocharpointer(void) { long L; char *P; L=filelength(CurrentFile); if (L<1) return NULL; P=pointer(L + 1); readbytesnobuff(P,L); P[L]=0; return P; } char **filetocharhandle(void) { long L; char **H; L=filelength(CurrentFile); if (L<1) return NULL; H=(char **)handle(L + 1); lock(H); readbytesnobuff(*H,L); (*H)[L]=0; unlock(H); return H; } // File registry void initfilelist(filelist *L) { if (!L) return; L->num=0; L->files=(FSRef ***)handle(0); } void purgefilelist(filelist *L) { if (!L) return; while (L->num>0) old((*(L->files))[--(L->num)]); } void addfiletolist(filelist *L, const FSRef *F) { FSRef *R; if (!L || !F) return; R=pointer(sizeof(FSRef)); *R=*F; minimumsize(L->files,L->num + 1,sizeof(FSRef *)); (*(L->files))[(L->num)++]=R; } bool fileinlist(const filelist *L, const FSRef *F) { int i; if (!L || !F) return 0; for (i=0;inum;i++) if (samefile(F,(*(L->files))[i])) return 1; return 0; }