Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!sdd.hp.com!elroy.jpl.nasa.gov!ncar!gatech!udel!haven.umd.edu!ni.umd.edu!ni.umd.edu!zben From: zben@ni.umd.edu (Ben Cranston) Newsgroups: comp.sys.mac.programmer Subject: MPW tool to patch resources or files Keywords: MPW Patch Message-ID: <1991Apr27.010549.20391@ni.umd.edu> Date: 27 Apr 91 01:05:49 GMT Sender: usenet@ni.umd.edu (USENET News System) Organization: University of Maryland at College Park Lines: 369 Nntp-Posting-Host: ni.umd.edu There were some simple example MPW tools in this month's MacTutor. I had never realized it was that easy to write a tool! Here is a tool that can be used to "patch" a resource or a data fork with either inline hex data, the contents of another resource, or the contents of another data fork. For example, the "command-F" patches for LaserWriter 6.0.1 can be done with this command: Patch LaserWriter PDEF(125) $c78:51 $c7c:50 $c84:50 $c8c:51 $c9a:50 $e9e:6038 $1860:60 Some of the diagnostics are a bit wrong but I think a diagnostic is given for every error case. Also there is some debug printout you can take out when you trust it. There is a neat hex dump routine buried in here too! /* MPW tool to "Patch" data or resource fork of file * * For usage notes see below... * * Ben Cranston * University of Maryland at College Park * 910419 */ #include #include #include #include #include #include #include #define P(x) fprintf(stderr,"%s%s\n",progname,x); #define Q(x) fprintf(stderr,"%s\n",x); char *progname; usage() { P(": Usage: ") P(" file offset:hexdata ") P(" file offset infile inoffset:length ") P(" file offset infile resource ") Q(""); P(" file resource offset:hexdata ") P(" file resource offset infile inoffset:length ") P(" file resource offset infile resource ") Q(""); Q("where resource is restype(resnum) or restype@resname ") } /* * Test for valid hexadecimal digit. */ #define ishex(x) (isascii(x)&&isxdigit(x)) /* * Integer value (0-15) for hexadecimal digit. */ #define toint(x) ((x)<='9'?(x)-'0':(x)<='F'?(x)-'A'+10:(x)-'a'+10) /* * Print out system string for a particular error code. */ syserr(short errcode) { char errmsg[256]; GetSysErrText(errcode,errmsg); fprintf(stderr,"# %s\n",errmsg); } /* * Diagnose syntax error on call to this tool. */ syntax(char *s) { fprintf(stderr,"%s - %s\n",progname,s); exit(1); } /* * Diagnose file access problems. */ cant(char *diag, char *fname, short errcode) { fprintf(stderr,"# %s - Can't %s : %P\n",progname,diag,fname); syserr(errcode); exit(2); } /* * Show arguments to this program. */ dumpargs(int argc, char **argv) { short i; fprintf(stderr,"argc = %d\n",argc); for (i=0 ; i= (status = sp-sfield) ) { rstype = (OSType) ' '; BlockMove(sfield,(char *)&rstype,status); } else syntax("bad resource type field"); SetResLoad(false); (*rfnum) = OpenRFPerm(fname,0,perms); SetResLoad(true); if (0 > (*rfnum) ) cant("open (resource fork of) file",fname,ResError()); if (which) (*rshand) = Get1Resource(rstype,rsnum); else (*rshand) = Get1NamedResource(rstype,rsname); if (0 == (*rshand) ) { *(OSType *)&buffer = rstype; buffer[4] = 0; if (which) fprintf(stderr,"# %s - Can't load resource : %P %s %d\n", progname,fname,buffer,rsnum); else fprintf(stderr,"# %s - Can't load resource : %P %s %P\n", progname,fname,buffer,rsname); if (0 == (status=ResError()) ) fprintf(stderr,"# No ResError worth mentioning...\n"); else syserr(status); exit(2); } return(1); } main(int argc, char **argv) { short rfnum, rrfnum, status; char *sp; int length, offset, roffset, xflen; char fname[256]; char bigbuf[1024]; Handle rshand, rrshand; /* dumpargs(argc,argv); */ progname = argv[0]; argc--, argv++; if (argc < 2) { usage(); exit(1); } fname[0] = strlen(argv[0]); BlockMove(argv[0],&fname[1],fname[0]); /* * Open file (and possibly resource) to be patched */ if ( getres(fname,argv[1],fsRdWrPerm,&rfnum,&rshand) ) argc--, argv++; else { if ( 0 > (status = FSOpen(fname,0,&rfnum)) ) cant("open (data fork of) file",fname,status); rshand = (Handle) 0; } argc--, argv++; do { /* * Get patch */ if (0 > argc) syntax("missing patch field!"); if (sp = strchr(argv[0],':') ) { *sp = 0; offset = getnum(argv[0],0); length = 0; while ( *(sp+1) ) { if (ishex(*(sp+1)) && ishex(*(sp+2))) { bigbuf[length++] = (toint(*(sp+1))<<4) + toint(*(sp+2)); sp += 2; } else syntax("error in hex input data"); } } else { offset = getnum(argv[0],0); argc--, argv++; if (0 > argc) syntax("missing patch file!"); fname[0] = strlen(argv[0]); BlockMove(argv[0],&fname[1],fname[0]); if ( getres(fname,argv[1],fsRdPerm,&rrfnum,&rrshand) ) { length = GetHandleSize(rrshand); if ( sizeof(bigbuf) < length ) syntax("resource too big!!!"); BlockMove(*rrshand,bigbuf,length); CloseResFile(rrfnum); } else if (sp = strchr(argv[1],':') ) { *sp = 0; roffset = getnum(argv[1],0); length = getnum(sp+1,0); if (0 > (status = FSOpen(fname,0,&rrfnum)) ) cant("open (data fork of) file",fname,status); if (0 > (status = SetFPos(rrfnum,fsFromStart,roffset)) ) cant("reposition within file",fname,status); xflen = length; if (0 > (status = FSRead(rrfnum,&xflen,bigbuf)) ) cant("read (data fork of) file",fname,status); if (xflen != length) { fprintf(stderr,"data short read %d\n",xflen); length = xflen; } if (0 > (status = FSClose(rrfnum)) ) cant("close (data fork of) file",fname,status); } else syntax("missing : in offset:length field"); argc--, argv++; } argc--, argv++; fprintf(stderr,"offset = %d\n",offset); fprintf(stderr,"length = %d\n",length); hexdump(length,bigbuf); /* * Apply patch */ if (rshand) { if ( (offset+length) > GetHandleSize(rshand) ) { SetHandleSize(rshand,offset+length); if (noErr != (status=MemError()) ) { fprintf(stderr,"# Could not expand handle\n"); syserr(status); exit(2); } } BlockMove(bigbuf,(offset+*rshand),length); } else { if (0 > (status = SetFPos(rfnum,fsFromStart,offset)) ) cant("reposition within file",fname,status); xflen = length; if (0 > (status = FSWrite(rfnum,&xflen,bigbuf)) ) cant("write to (data fork of) file",fname,status); if (xflen != length) fprintf(stderr,"data short write %d\n",xflen); } fprintf(stderr,"at end, argc = %d\n",argc); } while (0 < argc); /* * Close file and/or resource fork */ if (rshand) { ChangedResource(rshand); CloseResFile(rfnum); } else { if (0 > (status = FSClose(rfnum)) ) cant("close (data fork of) file",fname,status); } exit(0); }