Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
CUtils.cp
/* |
Random and sundry error, file and path name utilities |
Created 29 Jan 1996 by EGH |
Copyright © 1996, Apple Computer, Inc. All rights reserved. |
*/ |
#include <FixMath.h> |
#include <fp.h> |
#include <stdio.h> |
#include <String_Utils.h> |
#include "CApp.h" |
#include "CUtils.h" |
/* GetFullPathName |
Get the full path name of the passed file, but force its length to fit into maxSize. |
It is obviously more desirable to not restrict its length, but in this case we desire |
this and "elipsize" the string by removing characters from the center. |
*/ |
void GetFullPathName( |
const FSSpec *fileSpec, |
Str255 outPathName, |
short maxSize) |
{ |
// force an upper limit to what will fit in a Str255 |
if (maxSize > sizeof (Str255) - 1) |
maxSize = sizeof (Str255) - 1; |
Int16 pathLen; |
Handle pathH; |
OSErr err = FSpGetFullPath(fileSpec, &pathLen, &pathH); |
if (err == noErr) |
{ |
ElipsedPathNameH(pathH, maxSize, outPathName, 'É'); |
::DisposeHandle(pathH); |
} |
else |
{ |
// no memory (?!) so just copy the file's name |
CopyPStr(fileSpec->name, outPathName); |
} |
} |
/* FSpGetFullPath |
Grok the full the path name of the passed file. |
Nabbed from More Files 1.4.1 from my colleagues at Apple Developer Technical Support. |
*/ |
OSErr FSpGetFullPath( |
const FSSpec *spec, |
short *fullPathLength, |
Handle *fullPath) |
{ |
OSErr result; |
FSSpec tempSpec; |
CInfoPBRec pb; |
/* Make a copy of the input FSSpec that can be modified */ |
BlockMoveData(spec, &tempSpec, sizeof(FSSpec)); |
if ( tempSpec.parID == fsRtParID ) |
{ |
/* The object is a volume */ |
/* Add a colon to make it a full pathname */ |
++tempSpec.name[0]; |
tempSpec.name[tempSpec.name[0]] = ':'; |
/* We're done */ |
result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]); |
} |
else |
{ |
/* The object isn't a volume */ |
/* Put the object name in first */ |
result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]); |
if ( result == noErr ) |
{ |
/* Get the ancestor directory names */ |
pb.dirInfo.ioNamePtr = tempSpec.name; |
pb.dirInfo.ioVRefNum = tempSpec.vRefNum; |
pb.dirInfo.ioDrParID = tempSpec.parID; |
do /* loop until we have an error or find the root directory */ |
{ |
pb.dirInfo.ioFDirIndex = -1; |
pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID; |
result = PBGetCatInfoSync(&pb); |
if ( result == noErr ) |
{ |
/* Append colon to directory name */ |
++tempSpec.name[0]; |
tempSpec.name[tempSpec.name[0]] = ':'; |
/* Add directory name to beginning of fullPath */ |
(void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1], tempSpec.name[0]); |
result = MemError(); |
} |
} while ( (result == noErr) && (pb.dirInfo.ioDrDirID != fsRtDirID) ); |
} |
} |
if ( result == noErr ) |
{ |
/* Return the length */ |
*fullPathLength = GetHandleSize(*fullPath); |
} |
else |
{ |
/* Dispose of the handle and return NULL and zero length */ |
DisposeHandle(*fullPath); |
*fullPath = NULL; |
*fullPathLength = 0; |
} |
return result; |
} |
/* ElipsedPathNameH |
Gracefully degrade the passed string by removing characters from the center |
until it fits into the passed maximum width. Inserts an elipsis character to indicate this. |
*/ |
void ElipsedPathNameH( |
Handle pathNameH, |
short maxWidth, |
Str255 elipsedName, |
char elipsis) |
{ |
long pNameLen = GetHandleSize(pathNameH); |
char saveState = HGetState(pathNameH); |
Ptr pathNameP = *pathNameH; |
HLock(pathNameH); |
if ((pNameLen <= 255) && (TextWidth(pathNameP, 0, (short)pNameLen) <= maxWidth)) |
{ |
BlockMove(pathNameP, (Ptr)(elipsedName + 1), pNameLen); |
*elipsedName = (char)pNameLen; |
} |
else |
{ |
long i, j, width = CharWidth(elipsis); |
char rightChars[128]; |
maxWidth /= 2; |
for (i = 1; (i < pNameLen) && (i < 128); i++) |
{ |
char nextChar = pathNameP[i - 1]; |
width += CharWidth(nextChar); |
if (width >= maxWidth) break; |
elipsedName[i] = nextChar; |
} |
width = 0; |
for (j = pNameLen - 1, *rightChars = 0; (j > i) && (*rightChars < 128); j--) |
{ |
char nextChar = pathNameP[j]; |
width += CharWidth(nextChar); |
if (width >= maxWidth) break; |
rightChars[++*rightChars] = nextChar; |
} |
elipsedName[(*elipsedName = (char)i)] = elipsis; |
while (*rightChars) |
{ |
elipsedName[++*elipsedName] = rightChars[(*rightChars)--]; |
} |
} |
HSetState(pathNameH, saveState); |
} |
/* ElipsedPathName |
Same as ElipsedPathNameH except uses Str255's rather than a handle. |
*/ |
void ElipsedPathName( |
Str255 pathName, |
short maxWidth, |
Str255 elipsedName, |
char elipsis) |
{ |
Int16 pNameLen = pathName[0]; |
UInt8 *pathNameP = &pathName[1]; |
Int16 textWidth; |
textWidth = ::StringWidth(pathName); |
if ((pNameLen <= 255) && (textWidth <= maxWidth)) |
{ |
BlockMove(pathNameP, (Ptr)(elipsedName + 1), pNameLen); |
*elipsedName = (char)pNameLen; |
} |
else |
{ |
long i, j, width = CharWidth(elipsis); |
char rightChars[128]; |
maxWidth /= 2; |
for (i = 1; (i < pNameLen) && (i < 128); i++) |
{ |
char nextChar = pathNameP[i - 1]; |
width += CharWidth(nextChar); |
if (width >= maxWidth) break; |
elipsedName[i] = nextChar; |
} |
width = 0; |
for (j = pNameLen - 1, *rightChars = 0; (j > i) && (*rightChars < 128); j--) |
{ |
char nextChar = pathNameP[j]; |
width += CharWidth(nextChar); |
if (width >= maxWidth) break; |
rightChars[++*rightChars] = nextChar; |
} |
elipsedName[(*elipsedName = (char)i)] = elipsis; |
while (*rightChars) |
{ |
elipsedName[++*elipsedName] = rightChars[(*rightChars)--]; |
} |
} |
} |
/* SetSizedDescriptor |
Set the descriptor of the passed pane, but gracefully degrade the |
length of the string to physically fit into the pane's frame. |
*/ |
void SetSizedDescriptor( |
LWindow *parent, |
PaneIDT inPaneID, |
StringPtr inDescStr) |
{ |
LCaption *pane = (LCaption *)parent->FindPaneByID(inPaneID); |
pane->FocusDraw(); // just to be in a valid port |
ResIDT texttraitsID = pane->GetTextTraitsID(); |
UTextTraits::SetPortTextTraits(texttraitsID); |
SDimension16 panesize; |
pane->GetFrameSize(panesize); |
Str255 elipStr; |
::ElipsedPathName(inDescStr, panesize.width, elipStr, 'É'); |
pane->SetDescriptor(elipStr); |
} |
/* ReportError |
Report an error to the user. |
*/ |
void ReportError( |
ExceptionCode inErr, |
Int16 inStrIndex) |
{ |
Str255 |
errStr = "\pAn error occurred.", |
errNumStr, |
errDescStr; |
Int16 descIndex; |
gApp->BugUserTilSwitchedIn(); |
// make some attempt to provide a description of the error |
switch (inErr) |
{ |
case iMemFullErr: |
descIndex = err_NotEnufMemory; |
break; |
case notEnoughMemoryErr: |
descIndex = err_NotEnufPhysicalMemory; |
break; |
case dirFulErr: |
case dskFulErr: |
descIndex = err_DiskFull; |
break; |
case ioErr: |
case fnOpnErr: |
case eofErr: |
case fnfErr: |
case nsvErr: |
descIndex = err_DiskError; |
break; |
case resNotFound: |
descIndex = err_NoResource; |
default: |
descIndex = err_NoDescription; |
} |
::GetIndString(errDescStr, STRx_ErrorDescs, descIndex); |
::SetCursor(&qd.arrow); |
::GetIndString(errStr, STRx_Errors, inStrIndex); |
::NumToString(inErr, errNumStr); |
::ParamText(errStr, errNumStr, errDescStr, "\p"); |
::StopAlert(ALRT_Error, nil); |
} |
OSErr GetFileParent( |
FSSpec *fileSpec, |
FSSpec *parentSpec) |
{ |
CInfoPBRec pBlock; |
OSErr result; |
pBlock.dirInfo.ioVRefNum = fileSpec-> vRefNum; |
pBlock.dirInfo.ioDrDirID = fileSpec-> parID; |
pBlock.dirInfo.ioNamePtr = parentSpec-> name; |
parentSpec-> name[0] = 0; |
pBlock.dirInfo.ioFDirIndex = -1; |
result = PBGetCatInfoSync(&pBlock); |
if (result == noErr) |
{ |
parentSpec-> vRefNum = fileSpec-> vRefNum; |
parentSpec-> parID = pBlock.dirInfo.ioDrParID; |
} |
return result; |
} |
const Int32 kPictFileHeaderSize = 512; |
#pragma options align=mac68k |
typedef struct PICT2Xheader { |
short version; |
short reserved; |
Fixed hRes; |
Fixed vRes; |
Rect srcRect; |
long reserved2; |
} PICT2Xheader; |
#pragma options align=reset |
/* ReadPictFrame |
Read a pict's rectangle. |
*/ |
void ReadPictFrame( |
const FSSpec &inPictSpec, |
Rect &outPictRect) |
{ |
LFile pictFile(inPictSpec); |
pictFile.OpenDataFork(fsRdPerm); // LFile will close the file upon failure |
// picture begins past the header |
OSErr result = ::SetFPos(pictFile.GetDataForkRefNum(), fsFromStart, kPictFileHeaderSize); |
ThrowIfOSErr_(result); |
// read a PICT2Xheader structure at 16 bytes into the pict |
char pict[sizeof (PICT2Xheader) + 16]; |
Int32 count = sizeof (PICT2Xheader) + 16; |
result = ::FSRead(pictFile.GetDataForkRefNum(), &count, &pict); |
ThrowIfOSErr_(result); |
PICT2Xheader *pic2XHeader; |
pic2XHeader = (PICT2Xheader *)&(((Ptr)(pict))[16]); |
if (pic2XHeader->version == -2) |
{ // extended type 2 |
outPictRect = pic2XHeader->srcRect; |
} |
else |
outPictRect = ((Picture *)pict)->picFrame; |
pictFile.CloseDataFork(); |
} |
void FixedToStr( |
Fixed inFixValue, |
Str255 outStr) |
{ |
// convert to double_t, then use the dec routines |
double_t value = Fix2X(inFixValue); |
decform f; |
f.style = FIXEDDECIMAL; |
f.digits = 1; |
decimal dec; |
num2dec(&f, value, &dec); |
dec2str(&f, &dec, (char *)outStr); |
c2pstr((char *)outStr); |
// alternate method using the std C lib |
//sprintf((char *)outStr, "%.1lf", value); |
//c2pstr((char *)outStr); |
} |
Fixed StrToFixed( |
StringPtr str) |
{ |
Fixed theNum; |
long lower,upper; |
short len,i,j, decPoint; |
float fraction; |
Boolean neg; |
len = str[0]; |
for (i=1; i<= len; i++) |
if (str[i] == '.') |
break; |
// No decimal point |
if (i >= len) |
{ |
StringToNum(str, &theNum); |
return (theNum << 16); |
} |
// Make into two strings |
decPoint = i; |
str[0] = i-1; |
str[decPoint] = len-i; |
StringToNum((StringPtr) str, &upper); |
if ((neg = (int)(upper < 0)) != 0) |
upper = - upper; |
StringToNum((StringPtr) str+decPoint, &lower); |
fraction = lower; |
for (j = 1; j <= (len-i) ; j++) |
fraction = fraction / 10; |
lower = fraction * 0x10000; |
// Restore orig string |
str[0] = len; |
str[decPoint] = '.'; |
return ((neg?-1:1)*((upper << 16) + lower)); |
} |
/* FindCodecName |
Search the list of codecs for a name describing the passed codec. |
*/ |
Boolean FindCodecName( |
StringPtr outName, |
CodecType inCodec) |
{ |
Boolean found = false; |
CodecNameSpecListPtr cnsp; |
OSErr result = ::GetCodecNameList(&cnsp, 1); |
if (result == noErr) |
{ |
for (Int32 i = 0; i < cnsp->count; i++) |
{ |
if (cnsp->list[i].cType == inCodec) |
{ |
found = true; // yay |
CopyPStr(cnsp->list[i].typeName, outName); |
break; |
} |
} |
::DisposeCodecNameList(cnsp); |
} |
return found; |
} |
/* SetCompressionText |
Set the passed pane's descriptor to text describing the passed image compression |
settings. |
*/ |
void SetCompressionText( |
LPane *inPane, |
CodecType inCodec, |
CodecQ inSpatialQuality) |
{ |
if (inPane != nil) |
{ |
// attempt to find a name for the current codec |
Str255 str; |
if (!FindCodecName(str, inCodec)) |
{ |
// put something in the string, however cryptic |
str[0] = 7; |
str[1] = '\''; |
*(OSType *)&str[2] = inCodec; |
str[6] = '\''; |
str[7] = ' '; |
} |
else |
str[++str[0]] = ' '; |
// create a description of the compression quality |
Str255 qstr; |
if (inSpatialQuality >= codecLosslessQuality) |
CopyPStr("\pLossless", qstr); |
else if (inSpatialQuality >= codecMaxQuality) |
CopyPStr("\pMaximum", qstr); |
else if (inSpatialQuality >= codecHighQuality) |
CopyPStr("\pHigh", qstr); |
else if (inSpatialQuality >= codecNormalQuality) |
CopyPStr("\pNormal", qstr); |
else if (inSpatialQuality > codecMinQuality) |
CopyPStr("\pLow", qstr); |
else |
CopyPStr("\pMinimum", qstr); |
ConcatPStr(str, qstr); |
ConcatPStr(str, "\p ("); |
::NumToString((((((float)inSpatialQuality)+.5) / 1024.0) * 100), qstr); |
ConcatPStr(str, qstr); |
ConcatPStr(str, "\p)"); |
inPane->SetDescriptor(str); |
} |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14