mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
1099 lines
29 KiB
C++
1099 lines
29 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is Mozilla Communicator client code.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Simon Fraser <sfraser@netscape.com>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
#include "nsAETokens.h"
|
|
#include "nsAEUtils.h"
|
|
|
|
static OSErr AECoerceDescData(const AEDesc *theAEDesc, DescType typeCode, void *dataPtr, Size maximumSize);
|
|
|
|
/*----------------------------------------------------------------------------
|
|
CreateAliasAEDesc
|
|
|
|
Create an AE descriptor for an alias
|
|
----------------------------------------------------------------------------*/
|
|
|
|
OSErr CreateAliasAEDesc(AliasHandle theAlias, AEDesc *ioDesc)
|
|
{
|
|
char state = HGetState((Handle)theAlias);
|
|
OSErr err;
|
|
|
|
HLock((Handle)theAlias);
|
|
err = AECreateDesc(typeAlias, *theAlias, GetHandleSize((Handle)theAlias), ioDesc);
|
|
HSetState((Handle)theAlias, state);
|
|
return err;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
GetTextFromAEDesc
|
|
|
|
Get a text handle from an AEDesc
|
|
----------------------------------------------------------------------------*/
|
|
OSErr GetTextFromAEDesc(const AEDesc *inDesc, Handle *outTextHandle)
|
|
{
|
|
Handle textHandle = nil;
|
|
Size textLength;
|
|
OSErr err;
|
|
|
|
textLength = AEGetDescDataSize(inDesc);
|
|
|
|
err = MyNewHandle(textLength, &textHandle);
|
|
if (err != noErr) return err;
|
|
|
|
MyHLock(textHandle);
|
|
err = AECoerceDescData(inDesc, typeChar, *textHandle, textLength);
|
|
MyHUnlock(textHandle);
|
|
|
|
if (err != noErr)
|
|
goto exit;
|
|
|
|
*outTextHandle = textHandle;
|
|
return noErr;
|
|
|
|
exit:
|
|
MyDisposeHandle(textHandle);
|
|
return err;
|
|
}
|
|
|
|
|
|
#if !TARGET_CARBON
|
|
|
|
/*----------------------------------------------------------------------------
|
|
AEGetDescData
|
|
|
|
Get a copy of the data from the AE desc. The will attempt to coerce to the
|
|
requested type, returning an error on failure.
|
|
----------------------------------------------------------------------------*/
|
|
|
|
OSErr AEGetDescData(const AEDesc *theAEDesc, void *dataPtr, Size maximumSize)
|
|
{
|
|
OSErr err = noErr;
|
|
|
|
if (theAEDesc->dataHandle)
|
|
{
|
|
Size dataLength = GetHandleSize(theAEDesc->dataHandle);
|
|
BlockMoveData(*theAEDesc->dataHandle, dataPtr, Min(dataLength, maximumSize));
|
|
}
|
|
else
|
|
err = paramErr;
|
|
|
|
return err;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
AEGetDescDataSize
|
|
|
|
Get the size of the datahandle.
|
|
----------------------------------------------------------------------------*/
|
|
Size AEGetDescDataSize(const AEDesc *theAEDesc)
|
|
{
|
|
Size dataSize = 0;
|
|
|
|
if (theAEDesc->dataHandle)
|
|
dataSize = GetHandleSize(theAEDesc->dataHandle);
|
|
|
|
return dataSize;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
AEReplaceDescData
|
|
|
|
Replace the data in the descriptor
|
|
----------------------------------------------------------------------------*/
|
|
OSErr AEReplaceDescData(DescType typeCode, const void *dataPtr, Size dataSize, AEDesc* theAEDesc)
|
|
{
|
|
AEDisposeDesc(theAEDesc);
|
|
return AECreateDesc(typeCode, dataPtr, dataSize, theAEDesc);
|
|
}
|
|
|
|
#endif //TARGET_CARBON
|
|
|
|
static OSErr AECoerceDescData(const AEDesc *theAEDesc, DescType typeCode, void *dataPtr, Size maximumSize)
|
|
{
|
|
OSErr err;
|
|
|
|
if (theAEDesc->descriptorType != typeCode)
|
|
{
|
|
AEDesc coercedDesc = { typeNull, nil };
|
|
err = AECoerceDesc(theAEDesc, typeCode, &coercedDesc);
|
|
if (err != noErr) return err;
|
|
|
|
err = AEGetDescData(&coercedDesc, dataPtr, maximumSize);
|
|
AEDisposeDesc(&coercedDesc);
|
|
return err;
|
|
}
|
|
else
|
|
{
|
|
return AEGetDescData(theAEDesc, dataPtr, maximumSize);
|
|
}
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
CreateThreadAEInfo
|
|
|
|
Allocate a block for the thread info, and fill it.
|
|
----------------------------------------------------------------------------*/
|
|
OSErr CreateThreadAEInfo(const AppleEvent *event, AppleEvent *reply, TThreadAEInfoPtr *outThreadAEInfo)
|
|
{
|
|
TThreadAEInfo *threadAEInfo = nil;
|
|
OSErr err;
|
|
|
|
err = MyNewBlockClear(sizeof(TThreadAEInfo), (void**)&threadAEInfo);
|
|
if (err != noErr) return err;
|
|
|
|
threadAEInfo->mAppleEvent = *event;
|
|
threadAEInfo->mReply = *reply;
|
|
threadAEInfo->mGotEventData = event && reply;
|
|
threadAEInfo->mSuspendCount = nil;
|
|
|
|
*outThreadAEInfo = threadAEInfo;
|
|
return noErr;
|
|
|
|
exit:
|
|
MyDisposeBlock(threadAEInfo);
|
|
return err;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
DisposeThreadAEInfo
|
|
|
|
Dispose of the thread AE info
|
|
----------------------------------------------------------------------------*/
|
|
void DisposeThreadAEInfo(TThreadAEInfo *threadAEInfo)
|
|
{
|
|
AE_ASSERT(threadAEInfo && threadAEInfo->mSuspendCount == 0, "Bad suspend count");
|
|
MyDisposeBlock(threadAEInfo);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
SuspendThreadAE
|
|
|
|
If this if the first suspend, suspend the event. Increment the suspend count.
|
|
----------------------------------------------------------------------------*/
|
|
OSErr SuspendThreadAE(TThreadAEInfo *threadAEInfo)
|
|
{
|
|
if (threadAEInfo == nil) return noErr;
|
|
if (!threadAEInfo->mGotEventData) return noErr;
|
|
|
|
if (threadAEInfo->mSuspendCount == 0)
|
|
{
|
|
OSErr err = AESuspendTheCurrentEvent(&threadAEInfo->mAppleEvent);
|
|
if (err != noErr) return err;
|
|
}
|
|
|
|
++ threadAEInfo->mSuspendCount;
|
|
return noErr;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
ResumeThreadAE
|
|
|
|
Decrement the suspend count. If this is the last resume, resume the event.
|
|
----------------------------------------------------------------------------*/
|
|
|
|
static OSErr AddErrorCodeToReply(TThreadAEInfo *threadAEInfo, OSErr threadError)
|
|
{
|
|
long errorValue = threadError;
|
|
|
|
if (threadError == noErr) return noErr;
|
|
|
|
return AEPutParamPtr(&threadAEInfo->mReply, keyErrorNumber, typeLongInteger, (Ptr)&errorValue, sizeof(long));
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
ResumeThreadAE
|
|
|
|
Decrement the suspend count. If this is the last resume, resume the event.
|
|
----------------------------------------------------------------------------*/
|
|
OSErr ResumeThreadAE(TThreadAEInfo *threadAEInfo, OSErr threadError)
|
|
{
|
|
if (threadAEInfo == nil) return noErr;
|
|
if (!threadAEInfo->mGotEventData) return noErr;
|
|
|
|
-- threadAEInfo->mSuspendCount;
|
|
|
|
AddErrorCodeToReply(threadAEInfo, threadError);
|
|
|
|
if (threadAEInfo->mSuspendCount == 0)
|
|
return AEResumeTheCurrentEvent(&threadAEInfo->mAppleEvent, &threadAEInfo->mReply, (AEEventHandlerUPP)kAENoDispatch, 0);
|
|
|
|
return noErr;
|
|
}
|
|
|
|
|
|
#pragma mark -
|
|
|
|
/*----------------------------------------------------------------------------
|
|
Copy ctor
|
|
|
|
this can throw
|
|
|
|
----------------------------------------------------------------------------*/
|
|
|
|
StAEDesc::StAEDesc(const StAEDesc& rhs)
|
|
{
|
|
ThrowIfOSErr(AEDuplicateDesc(&rhs, this));
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
operator =
|
|
|
|
this can throw
|
|
|
|
----------------------------------------------------------------------------*/
|
|
|
|
StAEDesc& StAEDesc::operator= (const StAEDesc& rhs)
|
|
{
|
|
ThrowIfOSErr(AEDuplicateDesc(&rhs, this));
|
|
return *this;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
Data getters
|
|
|
|
These should try to coerce when necessary also.
|
|
----------------------------------------------------------------------------*/
|
|
|
|
Boolean StAEDesc::GetBoolean()
|
|
{
|
|
Boolean result = false;
|
|
OSErr err = ::AECoerceDescData(this, typeBoolean, &result, sizeof(result));
|
|
if (err != noErr)
|
|
ThrowOSErr(errAECoercionFail);
|
|
return result;
|
|
}
|
|
|
|
SInt16 StAEDesc::GetShort()
|
|
{
|
|
SInt16 result = 0;
|
|
OSErr err = ::AECoerceDescData(this, typeShortInteger, &result, sizeof(result));
|
|
if (err != noErr)
|
|
ThrowOSErr(errAECoercionFail);
|
|
return result;
|
|
}
|
|
|
|
SInt32 StAEDesc::GetLong()
|
|
{
|
|
SInt32 result = 0;
|
|
OSErr err = ::AECoerceDescData(this, typeLongInteger, &result, sizeof(result));
|
|
if (err != noErr)
|
|
ThrowOSErr(errAECoercionFail);
|
|
return result;
|
|
}
|
|
|
|
DescType StAEDesc::GetEnumType()
|
|
{
|
|
DescType result = typeNull;
|
|
OSErr err = ::AECoerceDescData(this, typeEnumeration, &result, sizeof(result));
|
|
if (err != noErr)
|
|
ThrowOSErr(errAECoercionFail);
|
|
return result;
|
|
}
|
|
|
|
void StAEDesc::GetRect(Rect& outData)
|
|
{
|
|
OSErr err = ::AECoerceDescData(this, typeQDRectangle, &outData, sizeof(Rect));
|
|
if (err != noErr)
|
|
ThrowOSErr(errAECoercionFail);
|
|
}
|
|
|
|
|
|
void StAEDesc::GetRGBColor(RGBColor& outData)
|
|
{
|
|
OSErr err = ::AECoerceDescData(this, typeRGBColor, &outData, sizeof(RGBColor));
|
|
if (err != noErr)
|
|
ThrowOSErr(errAECoercionFail);
|
|
}
|
|
|
|
void StAEDesc::GetLongDateTime(LongDateTime& outDateTime)
|
|
{
|
|
OSErr err = ::AECoerceDescData(this, typeLongDateTime, &outDateTime, sizeof(LongDateTime));
|
|
if (err != noErr)
|
|
ThrowOSErr(errAECoercionFail);
|
|
}
|
|
|
|
void StAEDesc::GetFileSpec(FSSpec &outFileSpec)
|
|
{
|
|
OSErr err = ::AECoerceDescData(this, typeFSS, &outFileSpec, sizeof(FSSpec));
|
|
if (err != noErr)
|
|
ThrowOSErr(errAECoercionFail);
|
|
}
|
|
|
|
void StAEDesc::GetCString(char *outString, short maxLen)
|
|
{
|
|
if (descriptorType == typeChar)
|
|
{
|
|
long dataSize = GetDataSize();
|
|
dataSize = Min(dataSize, maxLen-1);
|
|
if (AEGetDescData(this, outString, dataSize) == noErr)
|
|
outString[dataSize] = '\0';
|
|
}
|
|
else
|
|
{
|
|
StAEDesc tempDesc;
|
|
if (::AECoerceDesc(this, typeChar, &tempDesc) == noErr)
|
|
{
|
|
long dataSize = tempDesc.GetDataSize();
|
|
dataSize = Min(dataSize, maxLen-1);
|
|
if (AEGetDescData(&tempDesc, outString, dataSize) == noErr)
|
|
outString[dataSize] = '\0';
|
|
}
|
|
else
|
|
ThrowOSErr(errAECoercionFail);
|
|
}
|
|
}
|
|
|
|
void StAEDesc::GetPString(Str255 outString)
|
|
{
|
|
if (descriptorType == typeChar)
|
|
{
|
|
long stringLen = GetDataSize();
|
|
if (stringLen > 255)
|
|
stringLen = 255;
|
|
AEGetDescData(this, outString+1, stringLen);
|
|
outString[0] = stringLen;
|
|
}
|
|
else
|
|
{
|
|
StAEDesc tempDesc;
|
|
if (::AECoerceDesc(this, typeChar, &tempDesc) == noErr)
|
|
{
|
|
long stringLen = tempDesc.GetDataSize();
|
|
if (stringLen > 255)
|
|
stringLen = 255;
|
|
AEGetDescData(&tempDesc, outString+1, stringLen);
|
|
outString[0] = stringLen;
|
|
}
|
|
else
|
|
ThrowOSErr(errAECoercionFail);
|
|
}
|
|
}
|
|
|
|
Handle StAEDesc::GetTextHandle()
|
|
{
|
|
Handle data = nil;
|
|
|
|
if (descriptorType == typeChar)
|
|
{
|
|
Size dataSize = GetDataSize();
|
|
data = ::NewHandle(dataSize);
|
|
if (data == NULL)
|
|
ThrowOSErr(memFullErr);
|
|
::HLock(data);
|
|
::AEGetDescData(this, *data, dataSize);
|
|
::HUnlock(data);
|
|
}
|
|
else
|
|
{
|
|
StAEDesc tempDesc;
|
|
if (::AECoerceDesc(this, typeChar, &tempDesc) == noErr)
|
|
data = tempDesc.GetTextHandle();
|
|
else
|
|
ThrowOSErr(errAECoercionFail);
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
|
|
#pragma mark -
|
|
|
|
/*----------------------------------------------------------------------------
|
|
GetFirstNonListToken
|
|
|
|
Note: make sure the result descriptor is {typeNull, nil} when it is passed in to this
|
|
|
|
----------------------------------------------------------------------------*/
|
|
OSErr AEListUtils::GetFirstNonListToken(const AEDesc *token, AEDesc *result)
|
|
{
|
|
OSErr err = noErr;
|
|
AEDesc tempToken = { typeNull, nil };
|
|
AEKeyword keyword;
|
|
long numItems;
|
|
long itemNum;
|
|
|
|
if (result->descriptorType == typeNull)
|
|
{
|
|
if (TokenContainsTokenList(token) == false)
|
|
{
|
|
err = AEDuplicateDesc(token, result);
|
|
}
|
|
else
|
|
{
|
|
err = AECountItems(token, &numItems);
|
|
|
|
for (itemNum = 1; itemNum <= numItems; itemNum++)
|
|
{
|
|
err = AEGetNthDesc((AEDescList *)token, itemNum, typeWildCard, &keyword, &tempToken);
|
|
if (err != noErr)
|
|
goto CleanUp;
|
|
|
|
err = GetFirstNonListToken(&tempToken, result);
|
|
if ((err != noErr) || (result->descriptorType != typeNull))
|
|
break;
|
|
|
|
AEDisposeDesc(&tempToken);
|
|
}
|
|
}
|
|
}
|
|
|
|
CleanUp:
|
|
if (err != noErr)
|
|
AEDisposeDesc(result);
|
|
|
|
AEDisposeDesc(&tempToken);
|
|
return err;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
FlattenAEList
|
|
|
|
----------------------------------------------------------------------------*/
|
|
OSErr AEListUtils::FlattenAEList(AEDescList *deepList, AEDescList *flatList)
|
|
{
|
|
OSErr err = noErr;
|
|
AEDesc item = {typeNull, nil};
|
|
AEKeyword keyword;
|
|
long itemNum;
|
|
long numItems;
|
|
|
|
err = AECountItems(deepList, &numItems);
|
|
if (err != noErr)
|
|
goto CleanUp;
|
|
|
|
for (itemNum = 1; itemNum <= numItems; itemNum++)
|
|
{
|
|
err = AEGetNthDesc(deepList, itemNum, typeWildCard, &keyword, &item);
|
|
if (err != noErr)
|
|
goto CleanUp;
|
|
|
|
if (item.descriptorType == typeAEList)
|
|
err = FlattenAEList(&item, flatList);
|
|
else
|
|
err = AEPutDesc(flatList, 0L, &item);
|
|
|
|
if (err != noErr)
|
|
goto CleanUp;
|
|
|
|
AEDisposeDesc(&item);
|
|
}
|
|
|
|
CleanUp:
|
|
if (err != noErr)
|
|
AEDisposeDesc(flatList);
|
|
|
|
AEDisposeDesc(&item);
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
#pragma mark -
|
|
|
|
/*----------------------------------------------------------------------------
|
|
StEventSuspender
|
|
|
|
----------------------------------------------------------------------------*/
|
|
StEventSuspender::StEventSuspender(const AppleEvent *appleEvent, AppleEvent *reply, Boolean deleteData)
|
|
: mThreadAEInfo(nil)
|
|
, mDeleteData(deleteData)
|
|
{
|
|
ThrowIfOSErr(CreateThreadAEInfo(appleEvent, reply, &mThreadAEInfo));
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
~StEventSuspender
|
|
|
|
----------------------------------------------------------------------------*/
|
|
StEventSuspender::~StEventSuspender()
|
|
{
|
|
if (mDeleteData)
|
|
DisposeThreadAEInfo(mThreadAEInfo);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
SuspendEvent
|
|
|
|
----------------------------------------------------------------------------*/
|
|
void StEventSuspender::SuspendEvent()
|
|
{
|
|
ThrowIfOSErr(SuspendThreadAE(mThreadAEInfo));
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
ResumeEvent
|
|
|
|
----------------------------------------------------------------------------*/
|
|
void StEventSuspender::ResumeEvent()
|
|
{
|
|
ThrowIfOSErr(ResumeThreadAE(mThreadAEInfo, noErr));
|
|
}
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
StHandleHolder
|
|
|
|
----------------------------------------------------------------------------*/
|
|
StHandleHolder::StHandleHolder(Handle inHandle)
|
|
: mHandle(inHandle)
|
|
, mLockCount(0)
|
|
{
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
~StHandleHolder
|
|
|
|
----------------------------------------------------------------------------*/
|
|
StHandleHolder::~StHandleHolder()
|
|
{
|
|
if (mHandle)
|
|
DisposeHandle(mHandle);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
operator=
|
|
|
|
----------------------------------------------------------------------------*/
|
|
StHandleHolder& StHandleHolder::operator=(Handle rhs)
|
|
{
|
|
AE_ASSERT(mLockCount == 0, "Bad lock count");
|
|
mLockCount = 0;
|
|
|
|
if (mHandle)
|
|
DisposeHandle(mHandle);
|
|
|
|
mHandle = rhs;
|
|
return *this;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
Lock
|
|
|
|
----------------------------------------------------------------------------*/
|
|
void StHandleHolder::Lock()
|
|
{
|
|
ThrowIfNil(mHandle);
|
|
if (++mLockCount > 1) return;
|
|
mOldHandleState = HGetState(mHandle);
|
|
HLock(mHandle);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
Unlock
|
|
|
|
----------------------------------------------------------------------------*/
|
|
void StHandleHolder::Unlock()
|
|
{
|
|
ThrowIfNil(mHandle);
|
|
AE_ASSERT(mLockCount > 0, "Bad lock count");
|
|
if (--mLockCount == 0)
|
|
HSetState(mHandle, mOldHandleState);
|
|
}
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
StAEListIterator
|
|
|
|
----------------------------------------------------------------------------*/
|
|
AEListIterator::AEListIterator(AEDesc *token)
|
|
: mNumItems(0)
|
|
, mCurItem(0)
|
|
, mIsListDesc(false)
|
|
{
|
|
ThrowIfNil(token);
|
|
mListToken = *token;
|
|
mIsListDesc = AEListUtils::TokenContainsTokenList(&mListToken);
|
|
if (mIsListDesc)
|
|
{
|
|
ThrowIfOSErr(::AECountItems(token, &mNumItems));
|
|
mCurItem = 1;
|
|
}
|
|
else
|
|
{
|
|
mCurItem = 0;
|
|
mNumItems = 1;
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
Next
|
|
|
|
----------------------------------------------------------------------------*/
|
|
Boolean AEListIterator::Next(AEDesc* outItemData)
|
|
{
|
|
if (mIsListDesc)
|
|
{
|
|
AEKeyword keyword;
|
|
|
|
if (mCurItem == 0 || mCurItem > mNumItems)
|
|
return false;
|
|
|
|
ThrowIfOSErr(::AEGetNthDesc(&mListToken, mCurItem, typeWildCard, &keyword, outItemData));
|
|
|
|
// what about nested lists?
|
|
AE_ASSERT(!AEListUtils::TokenContainsTokenList(outItemData), "Nested list found");
|
|
}
|
|
else
|
|
{
|
|
if (mCurItem > 0)
|
|
return false;
|
|
|
|
ThrowIfOSErr(::AEDuplicateDesc(&mListToken, outItemData));
|
|
}
|
|
|
|
mCurItem ++;
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
/*----------------------------------------------------------------------------
|
|
CheckForUnusedParameters
|
|
|
|
Check to see if there exist any additional required parameters in the Apple Event.
|
|
If so, return an err to the calling routine, because we didn't extract them all.
|
|
----------------------------------------------------------------------------*/
|
|
OSErr CheckForUnusedParameters(const AppleEvent* appleEvent)
|
|
{
|
|
OSErr err = noErr;
|
|
|
|
DescType actualType = typeNull;
|
|
Size actualSize = 0L;
|
|
|
|
err = AEGetAttributePtr(appleEvent,
|
|
keyMissedKeywordAttr,
|
|
typeWildCard,
|
|
&actualType,
|
|
nil,
|
|
0,
|
|
&actualSize);
|
|
|
|
if (err == errAEDescNotFound)
|
|
err = noErr;
|
|
else
|
|
err = errAEParamMissed;
|
|
|
|
return err;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
PutReplyErrorNumber
|
|
|
|
If a reply is expected, the err number is returned in the reply parameter.
|
|
----------------------------------------------------------------------------*/
|
|
OSErr PutReplyErrorNumber(AppleEvent* reply, long errorNumber)
|
|
{
|
|
OSErr err = noErr;
|
|
|
|
if (reply->dataHandle != nil && errorNumber != noErr)
|
|
{
|
|
err = AEPutParamPtr(reply,
|
|
keyErrorNumber,
|
|
typeLongInteger,
|
|
(Ptr)&errorNumber,
|
|
sizeof(long));
|
|
}
|
|
return err;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
PutReplyErrorMessage
|
|
|
|
If a reply is expected, the err message is inserted into the reply parameter.
|
|
----------------------------------------------------------------------------*/
|
|
OSErr PutReplyErrorMessage(AppleEvent* reply, char *message)
|
|
{
|
|
OSErr err = noErr;
|
|
|
|
if (reply->dataHandle != nil && message != NULL)
|
|
{
|
|
err = AEPutParamPtr(reply,
|
|
keyErrorString,
|
|
typeChar,
|
|
(Ptr)message,
|
|
strlen(message));
|
|
}
|
|
return err;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
GetObjectClassFromAppleEvent
|
|
|
|
This is used to extract the type of object that an appleevent is supposed
|
|
to work with. In the Core events, this includes:
|
|
count <reference> each <typeOfObject>
|
|
make new <typeOfObject>
|
|
save <reference> in <alias> as <typeOfObject>
|
|
---------------------------------------------------------------------------*/
|
|
OSErr GetObjectClassFromAppleEvent(const AppleEvent *appleEvent, DescType *objectClass)
|
|
{
|
|
OSErr err = noErr;
|
|
OSType typeCode; // should be typeType
|
|
long actualSize;
|
|
|
|
// Get the class of object that we will count
|
|
|
|
err = AEGetParamPtr(appleEvent,
|
|
keyAEObjectClass,
|
|
typeType,
|
|
&typeCode,
|
|
(Ptr)objectClass,
|
|
sizeof(DescType),
|
|
&actualSize);
|
|
|
|
if (typeCode != typeType)
|
|
err = errAECoercionFail;
|
|
|
|
return err;
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
/*----------------------------------------------------------------------------
|
|
DescToPString
|
|
|
|
Converts descriptor dataHandle to a pascal string
|
|
|
|
---------------------------------------------------------------------------*/
|
|
OSErr DescToPString(const AEDesc* desc, Str255 aPString, short maxLength)
|
|
{
|
|
if (desc->descriptorType == typeChar)
|
|
{
|
|
long stringLen = AEGetDescDataSize(desc);
|
|
if (stringLen > maxLength)
|
|
stringLen = maxLength;
|
|
AEGetDescData(desc, aPString+1, stringLen);
|
|
aPString[0] = stringLen;
|
|
}
|
|
else
|
|
{
|
|
StAEDesc tempDesc;
|
|
if (AECoerceDesc(desc, typeChar, &tempDesc) == noErr) {
|
|
long stringLen = tempDesc.GetDataSize();
|
|
if (stringLen > maxLength)
|
|
stringLen = maxLength;
|
|
AEGetDescData(&tempDesc, aPString+1, stringLen);
|
|
aPString[0] = stringLen;
|
|
} else
|
|
return errAECoercionFail;
|
|
}
|
|
return noErr;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
DescToCString
|
|
|
|
Converts descriptor dataHandle to a C string
|
|
|
|
--------------------------------------------------------------------------- */
|
|
OSErr DescToCString(const AEDesc* desc, CStr255 aCString, short maxLength)
|
|
{
|
|
if (desc->descriptorType == typeChar)
|
|
{
|
|
long stringLen = AEGetDescDataSize(desc);
|
|
if (stringLen >= maxLength)
|
|
stringLen = maxLength - 1;
|
|
if (AEGetDescData(desc, aCString, stringLen) == noErr)
|
|
aCString[stringLen] = '\0';
|
|
else
|
|
return errAECoercionFail;
|
|
}
|
|
else
|
|
{
|
|
StAEDesc tempDesc;
|
|
if (AECoerceDesc(desc, typeChar, &tempDesc) == noErr) {
|
|
long stringLen = AEGetDescDataSize(&tempDesc);
|
|
if (stringLen >= maxLength)
|
|
stringLen = maxLength - 1;
|
|
if (AEGetDescData(&tempDesc, aCString, stringLen) == noErr)
|
|
aCString[stringLen] = '\0';
|
|
else
|
|
return errAECoercionFail;
|
|
} else
|
|
return errAECoercionFail;
|
|
}
|
|
return noErr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Converts descriptor dataHandle to a DescType
|
|
//----------------------------------------------------------------------------------
|
|
|
|
OSErr DescToDescType(const AEDesc *desc, DescType *descType)
|
|
{
|
|
if (AEGetDescDataSize(desc) == sizeof(DescType))
|
|
return AEGetDescData(desc, descType, sizeof(DescType));
|
|
else
|
|
return errAECoercionFail;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Converts descriptor dataHandle to a boolean
|
|
//----------------------------------------------------------------------------------
|
|
|
|
OSErr DescToBoolean(const AEDesc* desc, Boolean* aBoolean)
|
|
{
|
|
return AECoerceDescData(desc, typeBoolean, aBoolean, sizeof(Boolean));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Converts descriptor dataHandle to a Fixed
|
|
//----------------------------------------------------------------------------------
|
|
|
|
OSErr DescToFixed(const AEDesc* desc, Fixed* aFixed)
|
|
{
|
|
return AECoerceDescData(desc, typeFixed, aFixed, sizeof(Fixed));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Converts descriptor dataHandle to a float
|
|
//----------------------------------------------------------------------------------
|
|
|
|
OSErr DescToFloat(const AEDesc* desc, float* aFloat)
|
|
{
|
|
return AECoerceDescData(desc, typeFloat, aFloat, sizeof(float));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Converts descriptor dataHandle to a long
|
|
//----------------------------------------------------------------------------------
|
|
|
|
OSErr DescToLong(const AEDesc* desc, long* aLong)
|
|
{
|
|
return AECoerceDescData(desc, typeLongInteger, aLong, sizeof(long));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Converts descriptor dataHandle to a RGBColor
|
|
//----------------------------------------------------------------------------------
|
|
|
|
OSErr DescToRGBColor(const AEDesc* desc, RGBColor* aRGBColor)
|
|
{
|
|
return AECoerceDescData(desc, typeRGBColor, aRGBColor, sizeof(RGBColor));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Converts descriptor dataHandle to a short.
|
|
//----------------------------------------------------------------------------------
|
|
|
|
OSErr DescToShort(const AEDesc* desc, short* aShort)
|
|
{
|
|
return AECoerceDescData(desc, typeShortInteger, aShort, sizeof(short));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Copies descriptor dataHandle to another handle, if its text
|
|
//----------------------------------------------------------------------------------
|
|
|
|
OSErr DescToTextHandle(const AEDesc* desc, Handle *text)
|
|
{
|
|
Handle data = nil;
|
|
|
|
if (desc->descriptorType == typeChar)
|
|
{
|
|
Size dataSize = ::AEGetDescDataSize(desc);
|
|
data = ::NewHandle(dataSize);
|
|
if (data == NULL)
|
|
return memFullErr;
|
|
::HLock(data);
|
|
::AEGetDescData(desc, *data, dataSize);
|
|
::HUnlock(data);
|
|
}
|
|
else
|
|
{
|
|
StAEDesc tempDesc;
|
|
if (::AECoerceDesc(desc, typeChar, &tempDesc) == noErr)
|
|
data = tempDesc.GetTextHandle();
|
|
else
|
|
return errAECoercionFail;
|
|
}
|
|
*text = data;
|
|
return noErr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Converts descriptor dataHandle to a Rectangle
|
|
//----------------------------------------------------------------------------------
|
|
|
|
OSErr DescToRect(const AEDesc* desc, Rect* aRect)
|
|
{
|
|
return AECoerceDescData(desc, typeRectangle, aRect, sizeof(Rect));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Converts descriptor dataHandle to a Point
|
|
//----------------------------------------------------------------------------------
|
|
|
|
OSErr DescToPoint(const AEDesc* desc, Point* aPoint)
|
|
{
|
|
return AECoerceDescData(desc, typeQDPoint, aPoint, sizeof(Point));
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
/*----------------------------------------------------------------------------
|
|
NormalizeAbsoluteIndex
|
|
|
|
Handles formAbsolutePosition resolution
|
|
|
|
---------------------------------------------------------------------------*/
|
|
OSErr NormalizeAbsoluteIndex(const AEDesc *keyData, long *index, long maxIndex, Boolean *isAllItems)
|
|
{
|
|
OSErr err = noErr;
|
|
|
|
*isAllItems = false; // set to true if we receive kAEAll constant
|
|
|
|
// Extract the formAbsolutePosition data, either a integer or a literal constant
|
|
|
|
switch (keyData->descriptorType)
|
|
{
|
|
case typeLongInteger: // positive or negative index
|
|
if (DescToLong(keyData, index) != noErr)
|
|
return errAECoercionFail;
|
|
|
|
if (*index < 0) // convert a negative index from end of list to a positive index from beginning of list
|
|
*index = maxIndex + *index + 1;
|
|
break;
|
|
|
|
case typeAbsoluteOrdinal: // 'abso'
|
|
DescType ordinalDesc;
|
|
if (DescToDescType((AEDesc*)keyData, &ordinalDesc) != noErr)
|
|
ThrowOSErr(errAECoercionFail);
|
|
|
|
switch (ordinalDesc)
|
|
{
|
|
case kAEFirst:
|
|
*index = 1;
|
|
break;
|
|
|
|
case kAEMiddle:
|
|
*index = (maxIndex >> 1) + (maxIndex % 2);
|
|
break;
|
|
|
|
case kAELast:
|
|
*index = maxIndex;
|
|
break;
|
|
|
|
case kAEAny:
|
|
*index = (TickCount() % maxIndex) + 1; // poor man's random
|
|
break;
|
|
|
|
case kAEAll:
|
|
*index = 1;
|
|
*isAllItems = true;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return errAEWrongDataType;
|
|
break;
|
|
}
|
|
|
|
// range-check the new index number
|
|
if ((*index < 1) || (*index > maxIndex))
|
|
{
|
|
err = errAEIllegalIndex;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Handles formRange resolution of boundary objects
|
|
|
|
OSErr ProcessFormRange(AEDesc *keyData, AEDesc *start, AEDesc *stop)
|
|
{
|
|
OSErr err = noErr;
|
|
StAEDesc rangeRecord;
|
|
StAEDesc ospec;
|
|
|
|
// coerce the range record data into an AERecord
|
|
|
|
err = AECoerceDesc(keyData, typeAERecord, &rangeRecord);
|
|
if (err != noErr)
|
|
return err;
|
|
|
|
// object specifier for first object in the range
|
|
err = AEGetKeyDesc(&rangeRecord, keyAERangeStart, typeWildCard, &ospec);
|
|
if (err == noErr && ospec.descriptorType == typeObjectSpecifier)
|
|
err = AEResolve(&ospec, kAEIDoMinimum, start);
|
|
|
|
if (err != noErr)
|
|
return err;
|
|
|
|
ospec.Clear();
|
|
|
|
// object specifier for last object in the range
|
|
|
|
err = AEGetKeyDesc(&rangeRecord, keyAERangeStop, typeWildCard, &ospec);
|
|
if (err == noErr && ospec.descriptorType == typeObjectSpecifier)
|
|
err = AEResolve(&ospec, kAEIDoMinimum, stop);
|
|
|
|
return err;
|
|
}
|