gecko/xpfe/bootstrap/appleevents/nsAECompare.cpp

533 lines
13 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 <StringCompare.h>
#include "nsAEUtils.h"
#include "nsAECompare.h"
// ----------------------------------------------------------------------------------------
Boolean AEComparisons::CompareTexts(DescType oper, const AEDesc *desc1, const AEDesc *desc2)
{
Boolean result = false;
short compareResult;
Handle lhsHandle = 0, rhsHandle = 0;
char *lhs;
char *rhs;
long lhsSize;
long rhsSize;
// FIXME: this can leak lhsHandle if second conversion fails.
if (DescToTextHandle(desc1, &lhsHandle) != noErr || DescToTextHandle(desc2, &rhsHandle) != noErr)
goto fail;
lhsSize = GetHandleSize(lhsHandle);
HLock(lhsHandle);
lhs = *(lhsHandle);
rhsSize = GetHandleSize(rhsHandle);
HLock(rhsHandle);
rhs = *(rhsHandle);
compareResult = ::CompareText(lhs, rhs, lhsSize, rhsSize, nil);
switch (oper)
{
case kAEEquals:
result = (compareResult == 0);
break;
case kAELessThan:
result = (compareResult < 0);
break;
case kAELessThanEquals:
result = (compareResult <= 0);
break;
case kAEGreaterThan:
result = (compareResult > 0);
break;
case kAEGreaterThanEquals:
result = (compareResult >= 0);
break;
case kAEBeginsWith:
if (rhsSize > lhsSize)
{
result = false;
}
else
{
// compare only the number of characters in rhs
// begin comparing at the beginning of lhs
compareResult = CompareText(lhs, rhs, rhsSize, rhsSize, nil);
result = (compareResult == 0);
}
break;
case kAEEndsWith:
if (rhsSize > lhsSize)
{
result = false;
}
else
{
// compare only the number of characters in rhs
// begin comparing rhsSize characters from the end of lhs
// start
lhs += (lhsSize - rhsSize);
compareResult = CompareText(lhs, rhs, rhsSize, rhsSize, nil);
result = (compareResult == 0);
}
break;
case kAEContains:
// Here I use an inefficient search strategy, but we're dealing with small amounts
// of text and by using CompareText(), we're doing the same style of comparison
// as in the other cases above.
result = false;
while (lhsSize >= rhsSize)
{
compareResult = CompareText(lhs, rhs, rhsSize, rhsSize, nil);
if (compareResult == 0)
{
result = true;
break;
}
lhs++;
lhsSize--;
}
break;
default:
ThrowOSErr(errAEBadTestKey);
}
fail:
if (lhsHandle) DisposeHandle(lhsHandle);
if (rhsHandle) DisposeHandle(rhsHandle);
return result;
}
// ----------------------------------------------------------------------------------------
Boolean AEComparisons::CompareEnumeration(DescType oper, const AEDesc *desc1, const AEDesc *desc2)
{
OSErr err = noErr;
Boolean result = false;
long lhs;
long rhs;
StAEDesc charDesc;
// Make each number is a long integer (in case it's a short integer or other integer type)
// before extracting the data */
err = AECoerceDesc(desc1, typeChar, &charDesc);
ThrowIfOSErr(err);
lhs = **(long **)(charDesc.dataHandle);
AEDisposeDesc(&charDesc);
err = AECoerceDesc(desc2, typeChar, &charDesc);
ThrowIfOSErr(err);
rhs = **(long **)charDesc.dataHandle;
AEDisposeDesc(&charDesc);
switch (oper)
{
case kAEEquals:
result = (lhs == rhs); // equality is the only test that makes sense for enumerators
break;
default:
ThrowOSErr(errAEBadTestKey);
}
return result;
}
// ----------------------------------------------------------------------------------------
Boolean AEComparisons::CompareInteger(DescType oper, const AEDesc *desc1, const AEDesc *desc2)
{
OSErr err = noErr;
Boolean result = false;
long lhs;
long rhs;
StAEDesc longDesc;
// Make each number is a long integer (in case it's a short integer or other integer type)
// before extracting the data */
err = AECoerceDesc(desc1, typeLongInteger, &longDesc);
ThrowIfOSErr(err);
lhs = **(long **)(longDesc.dataHandle);
AEDisposeDesc(&longDesc);
err = AECoerceDesc(desc2, typeLongInteger, &longDesc);
ThrowIfOSErr(err);
rhs = **(long **)longDesc.dataHandle;
AEDisposeDesc(&longDesc);
switch (oper)
{
case kAEEquals:
result = (lhs == rhs);
break;
case kAELessThan:
result = (lhs < rhs);
break;
case kAELessThanEquals:
result = (lhs <= rhs);
break;
case kAEGreaterThan:
result = (lhs > rhs);
break;
case kAEGreaterThanEquals:
result = (lhs >= rhs);
break;
default:
ThrowOSErr(errAEBadTestKey);
}
return result;
}
// ----------------------------------------------------------------------------------------
Boolean AEComparisons::CompareFixed(DescType oper, const AEDesc *desc1, const AEDesc *desc2)
{
OSErr err = noErr;
Boolean result = false;
Fixed lhs;
Fixed rhs;
err = DescToFixed(desc1, &lhs);
ThrowIfOSErr(err);
err = DescToFixed(desc2, &rhs);
ThrowIfOSErr(err);
switch (oper)
{
case kAEEquals:
result = (lhs == rhs);
break;
case kAELessThan:
result = (lhs < rhs);
break;
case kAELessThanEquals:
result = (lhs <= rhs);
break;
case kAEGreaterThan:
result = (lhs > rhs);
break;
case kAEGreaterThanEquals:
result = (lhs >= rhs);
break;
default:
ThrowOSErr(errAEBadTestKey);
}
return result;
}
// ----------------------------------------------------------------------------------------
Boolean AEComparisons::CompareFloat(DescType oper, const AEDesc *desc1, const AEDesc *desc2)
{
OSErr err = noErr;
Boolean result = false;
float lhs;
float rhs;
err = DescToFloat(desc1, &lhs);
ThrowIfOSErr(err);
err = DescToFloat(desc2, &rhs);
ThrowIfOSErr(err);
switch (oper)
{
case kAEEquals:
result = (lhs == rhs);
break;
case kAELessThan:
result = (lhs < rhs);
break;
case kAELessThanEquals:
result = (lhs <= rhs);
break;
case kAEGreaterThan:
result = (lhs > rhs);
break;
case kAEGreaterThanEquals:
result = (lhs >= rhs);
break;
default:
ThrowOSErr(errAEBadTestKey);
}
return result;
}
// ----------------------------------------------------------------------------------------
// Apple events defines a boolean as a 1-byte value containing 1 for TRUE and 0 for FALSE
Boolean AEComparisons::CompareBoolean(DescType oper, const AEDesc *desc1, const AEDesc *desc2)
{
Boolean result = false;
Boolean bool1 = ((**(char **)desc1->dataHandle) != 0);
Boolean bool2 = ((**(char **)desc2->dataHandle) != 0);
if (oper == kAEEquals)
result = (bool1 == bool2);
else
ThrowOSErr(errAEBadTestKey); // No other tests make sense
return result;
}
// ----------------------------------------------------------------------------------------
Boolean AEComparisons::CompareRGBColor(DescType oper, const AEDesc *desc1, const AEDesc *desc2)
{
OSErr err = noErr;
Boolean result = false;
RGBColor lhs;
RGBColor rhs;
err = DescToRGBColor(desc1, &lhs);
ThrowIfOSErr(err);
err = DescToRGBColor(desc2, &rhs);
ThrowIfOSErr(err);
if (oper == kAEEquals)
result = EqualRGB(lhs, rhs);
else
ThrowOSErr(errAEBadTestKey); // No other tests make sense
return result;
}
// ----------------------------------------------------------------------------------------
Boolean AEComparisons::ComparePoint(DescType oper, const AEDesc *desc1, const AEDesc *desc2)
{
OSErr err = noErr;
Boolean result = false;
Point lhs;
Point rhs;
err = DescToPoint(desc1, &lhs);
ThrowIfOSErr(err);
err = DescToPoint(desc2, &rhs);
ThrowIfOSErr(err);
switch (oper)
{
case kAEEquals:
result = (lhs.h = rhs.h && lhs.v == rhs.v);
break;
case kAELessThan:
result = (lhs.h < rhs.h && lhs.v < rhs.v);
break;
case kAELessThanEquals:
result = (lhs.h <= rhs.h && lhs.v <= rhs.v);
break;
case kAEGreaterThan:
result = (lhs.h > rhs.h && lhs.v > rhs.v);
break;
case kAEGreaterThanEquals:
result = (lhs.h >= rhs.h && lhs.v >= rhs.v);
break;
default:
ThrowOSErr(errAEBadTestKey); // No other tests make sense
}
return result;
}
// ----------------------------------------------------------------------------------------
Boolean AEComparisons::CompareRect(DescType oper, const AEDesc *desc1, const AEDesc *desc2)
{
OSErr err = noErr;
Boolean result = false;
Rect lhs;
Rect rhs;
err = DescToRect(desc1, &lhs);
ThrowIfOSErr(err);
err = DescToRect(desc2, &rhs);
ThrowIfOSErr(err);
switch (oper)
{
// compare size AND location
case kAEEquals:
result = ((lhs.top == rhs.top) && (lhs.left == rhs.left) && (lhs.bottom == rhs.bottom) && (lhs.right == rhs.right));
break;
// compare size only on the rest of the tests
case kAELessThan:
result = (((lhs.bottom - lhs.top) < (rhs.bottom - rhs.top)) && ((lhs.right - lhs.left) < (lhs.right - rhs.left)));
break;
case kAELessThanEquals:
result = (((lhs.bottom - lhs.top) < (rhs.bottom - rhs.top)) && ((lhs.right - lhs.left) < (lhs.right - rhs.left)));
break;
case kAEGreaterThan:
result = (((lhs.bottom - lhs.top) < (rhs.bottom - rhs.top)) && ((lhs.right - lhs.left) < (lhs.right - rhs.left)));
break;
case kAEGreaterThanEquals:
result = (((lhs.bottom - lhs.top) < (rhs.bottom - rhs.top)) && ((lhs.right - lhs.left) < (lhs.right - rhs.left)));
break;
case kAEContains:
// Note: two identical Rects contain each other, according to this test:
result = ((lhs.top <= rhs.top) && (lhs.left <= rhs.left) && (lhs.bottom >= rhs.bottom) && (lhs.right >= rhs.right));
break;
default:
ThrowOSErr(errAEBadTestKey); // No other tests make sense
}
return result;
}
#pragma mark -
/*----------------------------------------------------------------------------
TryPrimitiveComparison
----------------------------------------------------------------------------*/
Boolean AEComparisons::TryPrimitiveComparison(DescType comparisonOperator, const AEDesc *desc1, const AEDesc *desc2)
{
Boolean result = false;
// This has to handle all the data types used in the application's
// object model implementation.
switch (desc1->descriptorType)
{
case typeChar:
result = CompareTexts(comparisonOperator, desc1, desc2);
break;
case typeShortInteger: // also covers typeSMInt 'shor'
case typeLongInteger: // also covers typeInteger 'long'
case typeMagnitude: // 'magn'
result = CompareInteger(comparisonOperator, desc1, desc2);
break;
case typeEnumerated:
result = CompareEnumeration(comparisonOperator, desc1, desc2);
break;
case typeFixed:
result = CompareFixed(comparisonOperator, desc1, desc2);
break;
case typeFloat:
result = CompareFloat(comparisonOperator, desc1, desc2);
break;
case typeBoolean:
result = CompareBoolean(comparisonOperator, desc1, desc2);
break;
case typeRGBColor:
result = CompareRGBColor(comparisonOperator, desc1, desc2);
break;
case typeQDRectangle:
result = CompareRect(comparisonOperator, desc1, desc2);
break;
case typeQDPoint:
result = ComparePoint(comparisonOperator, desc1, desc2);
break;
default:
ThrowOSErr(errAEWrongDataType);
}
return result;
}