Mac OS 9 Discussion > Development & Programming
Pascal strings in struct for reading a resource
tenfifty2:
Hi guys!
I'm not a super great C programmer, but I'm trying to knock out a "simple" MPW Tool to print the data contained in the 'ckid' resource that gets created by Projector when you check out a file. Unfortunately, most of the data I want is in Pascal strings.
The format of the 'ckid' resource is documented in Appendix A in the "Bldg & Mng Progs in MPW 2ed.pdf" file that comes with MPW. But the data structure is only described in Pascal format. Here is a C struct that I made that seems to me like it should be equivalent:
--- Code: ---#include <time.h>
typedef unsigned long uLong;
typedef unsigned short uShort;
typedef struct{
uLong checkSum; // checkSum
long LOC; // location identifier
short version; // ckid version number
short readOnly; // checkout state; 0=modifiable
char branch; // if modifiable & byte not 0, then branch was made on checkout
Boolean modifyReadOnly; // Did user execute "ModifyReadOnly"?
uShort history; // 1 if history present, 0 if not
uShort commentLength; // length of current comment if history is present
time_t checkoutDate; // date and time of checkout
time_t modificationDate; // modification date of file
uLong PIDa; // PID.a
uLong PIDb; // PID.b
short userID; // user ID
short fileID; // file ID
short revisionID; // revision ID
Str255 projectPath; // project path
char pad1;
Str255 userName; // user name
char pad2;
Str255 revisionNum; // revision number
char pad3;
Str255 fileName; // filename
char pad4;
Str255 taskDesc; // task
char pad5;
Str255 comment; // comment
char pad6;
} CKIDRec, *CKIDPtr, **CKIDHandle;
--- End code ---
In the program, I do something like this (Again, not sure this is the best, but it sort of works):
--- Code: ---Handle ResHandle;
CKIDRec CkidRecord;
refnum = openresfile(argv[1]);
ResHandle = Get1Resource('ckid',128);
HLock(ResHandle);
CkidRecord = **(CKIDRec **)ResHandle;
--- End code ---
This works pretty well, and I can access everything up to projectPath using CkidRecord.checkSum, etc. But once I try to get to the Str255's, it starts returning garbage or crashing.
So I found another example for dealing with Pascal strings, and added this:
--- Code: ---StringPtr projectPathPtr, userNamePtr;
Str255 projectPath, userName;
Size bytes;
projectPathPtr = (**(CKIDHandle)ResHandle).projectPath;
bytes = (**(CKIDHandle)ResHandle).projectPath[0] + 1;
BlockMove(projectPathPtr, projectPath, bytes);
userNamePtr = (**(CKIDHandle)ResHandle).userName;
bytes = (**(CKIDHandle)ResHandle).userName[0] + 1;
BlockMove(userNamePtr, userName, bytes);
--- End code ---
After that, 'projectPath' contains the Project Path, but there's garbage in front of and behind it. 'userName' always contains garbage. I can view what should be the correct data using ResEdit, however.
I wonder if it would be easier to take everything in the struct after revisionID as one big chunk and then manually parse through it, but I've tried that a few times and haven't come up with a scheme that works and doesn't crash my machine.
Does all that make sense? Does anyone have any suggestions or examples of code that uses a similar stucture and how to deal with it? Or am I looking at this all wrong?
Many thanks in advance!
Daniel:
Here's all 4 possible string moves. Pick whichever one makes sense for your situation (and maybe add bounds checks or null pointer checks if needed). BlockMoveData is backward compatible with BlockMove (it sets a flag in the A-Line trap which is ignored by BlockMove implementations which don't check it) but is only for data guaranteed to not be 68k code. This means it doesn't have to flush caches (for later 680x0 CPUs) or invalidate the 68k Emulator's JIT cache (for PowerMacs). Which can speed things up.
--- Code: ---void CStrToCStr(char * src, char * dst) {
int len = strlen(src);
BlockMoveData(src, dst, len+1);
}
void PStrToPStr(Str255 src, Str255 dst) {
int len = src[0];
BlockMoveData(src, dst, len+1);
}
void CStrToPStr(char * src, Str255 dst) {
int len = strlen(src);
BlockMoveData(src, dst+1, len);
dst[0] = (char)len;
}
void PStrToCStr(Str255 src, char * dst) {
int len = src[0];
BlockMoveData(src+1, dst, len);
dst[len] = 0;
}
--- End code ---
tenfifty2:
Hi Daniel!
Thank you very much for the reply!
I'm not certain how to incorporate those.
Looking at the struct I posted, I'm first of all not quite certain it's right, but let's assume it is for the purposes of this question. In C, a Str255 is really just a 256-byte string, right? Ok, so let's say we have some data in projectPath that's not quite that long. Now we want to access the next relevant field, userName. How does C know where to get it from, because according to the struct that should be 257 bytes later, right? But it's not, because projectPath is a Pascal string and starts with the length, then the data, then the \0, and then the pad, right?
Is it even possible to use a C struct to handle this data?
Thank you so much for the help!
joevt:
Is a Str255 defined as char[256] in C? (char should be unsigned)
The first byte is the length. The length is followed by room for 255 characters.
The total length is 256 bytes, so you don't need padding bytes.
tenfifty2:
Str255 is defined in MacTypes.h as:
--- Code: ---typedef unsigned char Str255[256];
--- End code ---
That being said, I based the struct in my first post on the Pascal structure defined in the PDF I referenced. It definitely has pad bytes, and you can see them in ResEdit too, where there appears to be two ^^'s between each data field.
Still not sure what to do here... should I be able to get this to work with C structures, or should I try and parse through it one character at a time?
Thank you!
Navigation
[0] Message Index
[#] Next page
Go to full version