Back to index

lightning-sunbird  0.9+nobinonly
nsAEClassIterator.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Simon Fraser <sfraser@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 
00040 #include "nsAEUtils.h"
00041 #include "nsAETokens.h"
00042 
00043 #include "nsAEClassIterator.h"
00044 
00045 
00046 const AEClassIterator::ItemRef            AEClassIterator::kNoItemRef = -1;
00047 const AEClassIterator::ItemID             AEClassIterator::kNoItemID = -1;
00048 
00049 /*----------------------------------------------------------------------------
00050        GetItemFromContainer 
00051        
00052 ----------------------------------------------------------------------------*/
00053 void AEClassIterator::GetItemFromContainer(             DescType                    desiredClass,
00054                                                                       const AEDesc*        containerToken,
00055                                                                       DescType                    containerClass, 
00056                                                                       DescType                    keyForm,
00057                                                                       const AEDesc*        keyData,
00058                                                                       AEDesc*                     resultToken)
00059 {
00060        OSErr                       err    = noErr;
00061        
00062        CStr255                            itemName;
00063        ItemRef                            itemRef = kNoItemRef;
00064        ItemID                      itemID = kNoItemID;
00065        DescType                           keyDataType   = keyData->descriptorType;
00066 
00067        Boolean                            wantsAllItems = false;
00068 
00069        StAEDesc                           startObject;  // These are used to resolve formRange
00070        StAEDesc                           stopObject;
00071               
00072        CoreTokenRecord             token;
00073        
00074        long                               numItems = GetNumItems(containerToken);
00075        TAEListIndex                itemIndex;
00076        
00077        CheckKeyFormSupport(keyForm);             // throws on error
00078        
00079        switch (keyForm)
00080        {
00081               case formName:                                                                                                                // item by name
00082                      if (DescToCString(keyData, itemName, 255) != noErr)
00083                             ThrowIfOSErr(errAECoercionFail);
00084 
00085                      itemRef = GetNamedItemReference(containerToken, itemName);
00086                      if (itemRef == kNoItemRef)
00087                             ThrowIfOSErr(errAENoSuchObject);
00088                      break;
00089               
00090               case formAbsolutePosition:                                                                                             // item by number
00091                      itemIndex = NormalizeAbsoluteIndex(keyData, numItems, &wantsAllItems);
00092                      if (wantsAllItems == false)
00093                      {
00094                             if (itemIndex == 0 || itemIndex > numItems)
00095                                    ThrowOSErr(errAEIllegalIndex);
00096                      }
00097                      itemRef = GetIndexedItemReference(containerToken, itemIndex);
00098                      if (itemRef == kNoItemRef)
00099                             ThrowOSErr(errAENoSuchObject);
00100                      break; 
00101               
00102               case formRelativePosition:
00103                      itemRef = ProcessFormRelativePostition(containerToken, keyData);
00104                      break; 
00105               
00106               case formRange:
00107                      switch (keyDataType)
00108                      {             
00109                             case typeRangeDescriptor:
00110                                    {
00111                                           ProcessFormRange((AEDesc *)keyData, &startObject, &stopObject);
00112                                           
00113                                           ConstAETokenDesc     startToken(&startObject);
00114                                           ConstAETokenDesc     stopToken(&stopObject);
00115                                           DescType             startType = startToken.GetDispatchClass();
00116                                           DescType             stopType  = stopToken.GetDispatchClass();
00117         
00118                                           if (startType != mClass || stopType != mClass)
00119                                                  ThrowOSErr(errAEWrongDataType);
00120                                    }
00121                                    break;
00122 
00123                             default:
00124                                    ThrowOSErr(errAEWrongDataType);
00125                                    break; 
00126                      }
00127                      break; 
00128               
00129               default:
00130                      ThrowIfOSErr(errAEEventNotHandled);
00131        }
00132        
00133        // if user asked for all items, and there aren't any,
00134        // we'll be kind and return an empty list.
00135 
00136        if (wantsAllItems && (err == errAENoSuchObject || err == errAEIllegalIndex))
00137        {
00138               err = AECreateList(nil, 0, false, (AEDescList*)resultToken);
00139               ThrowIfOSErr(err);
00140               return;
00141        }
00142 
00143        ThrowIfOSErr(err);
00144 
00145        // fill in the result token
00146        token.dispatchClass  = GetClass();
00147        token.objectClass    = GetClass();
00148        token.propertyCode   = typeNull;
00149        
00150        if (wantsAllItems)
00151        {
00152               err = AECreateList(NULL, 0, false, (AEDescList*)resultToken);
00153               ThrowIfOSErr(err);
00154               
00155               for (TAEListIndex index = 1; index <= numItems; index++)
00156               {
00157                      ItemID        itemID = GetIndexedItemID(containerToken, index);
00158                      if (itemID != kNoItemID)
00159                      {
00160                             SetItemIDInCoreToken(containerToken, &token, itemID);
00161                             err = AEPutPtr(resultToken, 0, desiredClass, &token, sizeof(token));
00162                             ThrowIfOSErr(err);
00163                      }
00164               }
00165        }
00166        else if (keyForm == formRange)
00167        {
00168               ConstAETokenDesc            startToken(&startObject);
00169               ConstAETokenDesc            stopToken(&stopObject);
00170               
00171               ItemID               beginItemID   = GetItemIDFromToken(&startObject);
00172               ItemID               endItemID            = GetItemIDFromToken(&stopObject);
00173               
00174               TAEListIndex         beginIndex           = GetIndexFromItemID(containerToken, beginItemID);
00175               TAEListIndex         endIndex             = GetIndexFromItemID(containerToken, endItemID);
00176                                                                       
00177               err = AECreateList(nil, 0, false, (AEDescList*)resultToken);
00178               ThrowIfOSErr(err);
00179                      
00180               if (beginIndex > endIndex) // swap elements
00181               {
00182                      TAEListIndex  temp = beginIndex;
00183                      beginIndex           = endIndex;
00184                      endIndex      = temp;
00185               }
00186               
00187               for (TAEListIndex i = beginIndex; i <= endIndex; i ++)
00188               {
00189                      ItemID        itemID = GetIndexedItemID(containerToken, i);
00190                      if (itemID != kNoItemID)
00191                      {
00192                             SetItemIDInCoreToken(containerToken, &token, itemID);
00193                             err = AEPutPtr(resultToken, 0, desiredClass, &token, sizeof(token));
00194                             ThrowIfOSErr(err);
00195                      }
00196               }
00197        }
00198        else
00199        {
00200               SetItemIDInCoreToken(containerToken, &token, GetIDFromReference(containerToken, itemRef));
00201               err = AECreateDesc(desiredClass, &token, sizeof(token), resultToken);
00202               ThrowIfOSErr(err);
00203        }
00204 }
00205 
00206 
00207 /*----------------------------------------------------------------------------
00208        ProcessFormRelativePostition 
00209        
00210 ----------------------------------------------------------------------------*/
00211 
00212 AEClassIterator::ItemRef AEClassIterator::ProcessFormRelativePostition(const AEDesc* anchorToken, const AEDesc *keyData)
00213 {
00214        OSErr         err = noErr;
00215        ItemID        anchorItemID = GetItemIDFromToken(anchorToken);
00216        TAEListIndex  anchorListIndex = GetIndexFromItemID(anchorToken, anchorItemID);
00217        TAEListIndex  wantedListIndex = 0;
00218        long                 numItems = GetNumItems(anchorToken);
00219        ItemRef              returnRef = kNoItemRef;
00220 
00221        if (anchorListIndex != 0)
00222        {
00223               switch (keyData->descriptorType)
00224               {
00225                  case typeEnumerated:
00226                             DescType             positionEnum; 
00227                             if (DescToDescType((AEDesc*)keyData, &positionEnum) != noErr)
00228                                    ThrowIfOSErr(errAECoercionFail);
00229 
00230                             switch (positionEnum)
00231                             {
00232                                    case kAENext:                                    // get the window behind the anchor
00233                                           wantedListIndex = anchorListIndex + 1;
00234                                           if (wantedListIndex > numItems)
00235                                                  err = errAENoSuchObject;
00236                                           break;
00237                                           
00238                                    case kAEPrevious:                                // get the document in front of the anchor
00239                                           wantedListIndex = anchorListIndex - 1;
00240                                           if (wantedListIndex < 1)
00241                                                  err = errAENoSuchObject;
00242                                           break;
00243                                           
00244                                    default:
00245                                           err = errAEEventNotHandled;
00246                                           break;
00247                             }
00248                             ThrowIfOSErr(err);
00249                             break;
00250                             
00251                      default:
00252                             err = errAECoercionFail;
00253                             break;
00254               }
00255        }
00256        
00257        ThrowIfOSErr(err);
00258        return GetIndexedItemReference(anchorToken, wantedListIndex);
00259 }
00260 
00261 
00262 /*----------------------------------------------------------------------------
00263        NormalizeAbsoluteIndex 
00264        
00265         Handles formAbsolutePosition resolution
00266        
00267 ---------------------------------------------------------------------------*/
00268 TAEListIndex AEClassIterator::NormalizeAbsoluteIndex(const AEDesc *keyData, TAEListIndex maxIndex, Boolean *isAllItems)
00269 {
00270        TAEListIndex  index;
00271        *isAllItems = false;                                                  // set to true if we receive kAEAll constant
00272        
00273        // Extract the formAbsolutePosition data, either a integer or a literal constant
00274        
00275        switch (keyData->descriptorType)
00276        {
00277               case typeLongInteger:                                          // positve or negative index
00278                      if (DescToLong(keyData, &index) != noErr)
00279                             ThrowOSErr(errAECoercionFail);
00280                             
00281                      if (index < 0)                                                 // convert a negative index from end of list to a positive index from beginning of list
00282                             index = maxIndex + index + 1;
00283                      break;
00284                      
00285           case typeAbsoluteOrdinal:                                                                      // 'abso'
00286                      DescType             ordinalDesc;
00287                      if (DescToDescType((AEDesc*)keyData, &ordinalDesc) != noErr)
00288                             ThrowOSErr(errAECoercionFail);
00289                      
00290                      switch (ordinalDesc)
00291                      {
00292                             case kAEFirst:
00293                                    index = 1;
00294                                    break;
00295                                    
00296                             case kAEMiddle:
00297                                    index = (maxIndex >> 1) + (maxIndex % 2);
00298                                    break;
00299                                           
00300                             case kAELast:
00301                                    index = maxIndex;
00302                                    break;
00303                                           
00304                             case kAEAny:
00305                                    index = (TickCount() % maxIndex) + 1;            // poor man's random
00306                                    break;
00307                                           
00308                             case kAEAll:
00309                                    index = 1;
00310                                    *isAllItems = true;
00311                                    break;
00312                      }
00313                      break;
00314 
00315               default:
00316                      ThrowOSErr(errAEWrongDataType);
00317        }
00318 
00319        // range-check the new index number
00320        if ((index < 1) || (index > maxIndex))
00321               ThrowOSErr(errAEIllegalIndex);
00322               
00323        return index;
00324 }
00325 
00326 
00327 /*----------------------------------------------------------------------------
00328        ProcessFormRange 
00329        
00330        Handles formRange resolution of boundary objects
00331 ----------------------------------------------------------------------------*/
00332 
00333 void AEClassIterator::ProcessFormRange(AEDesc *keyData, AEDesc *start, AEDesc *stop)
00334 {
00335        OSErr         err = noErr;
00336        StAEDesc             rangeRecord;
00337        StAEDesc             ospec;
00338        
00339        // coerce the range record data into an AERecord 
00340        
00341        err = AECoerceDesc(keyData, typeAERecord, &rangeRecord);
00342        ThrowIfOSErr(err);
00343         
00344        // object specifier for first object in the range
00345        err = AEGetKeyDesc(&rangeRecord, keyAERangeStart, typeWildCard, &ospec);
00346        if (err == noErr && ospec.descriptorType == typeObjectSpecifier)
00347               err = AEResolve(&ospec, kAEIDoMinimum, start);
00348               
00349        ThrowIfOSErr(err);
00350               
00351        ospec.Clear();
00352               
00353        // object specifier for last object in the range
00354        
00355        err = AEGetKeyDesc(&rangeRecord, keyAERangeStop, typeWildCard, &ospec);
00356        if (err == noErr && ospec.descriptorType == typeObjectSpecifier)
00357               err = AEResolve(&ospec, kAEIDoMinimum, stop);
00358 
00359        ThrowIfOSErr(err);
00360 }
00361 
00362 
00363 /*----------------------------------------------------------------------------
00364        CheckKeyFormSupport
00365        
00366        throws if unsupported key form
00367 ----------------------------------------------------------------------------*/
00368 void AEClassIterator::CheckKeyFormSupport(DescType keyForm)
00369 {
00370        UInt16               testMask;
00371        switch (keyForm)
00372        {
00373               case formAbsolutePosition:         testMask = eHasFormAbsolutePosition;             break;
00374               case formRelativePosition:         testMask = eHasFormRelativePosition;             break;
00375               case formTest:                                   testMask = eHasFormTest;                         break;
00376               case formRange:                           testMask = eHasFormRange;                        break;
00377               case formPropertyID:               testMask = eHasFormPropertyID;                   break;
00378               case formName:                            testMask = eHasFormName;                         break;
00379               default:
00380                      AE_ASSERT(false, "Unknown key form");
00381        }
00382        if ((mKeyFormSupport & testMask) == 0)
00383               ThrowOSErr(errAEBadKeyForm);
00384 }
00385 
00386 #pragma mark -
00387 
00388 
00389 /*----------------------------------------------------------------------------
00390        GetItemFromContainer 
00391        
00392 ----------------------------------------------------------------------------*/
00393 void AENamedClassIterator::GetItemFromContainer( DescType                    desiredClass,
00394                                                                       const AEDesc*        containerToken,
00395                                                                       DescType                    containerClass, 
00396                                                                       DescType                    keyForm,
00397                                                                       const AEDesc*        keyData,
00398                                                                       AEDesc*                     resultToken)
00399 {
00400        OSErr                       err    = noErr;
00401        
00402        CStr255                            itemName;
00403        DescType                           keyDataType   = keyData->descriptorType;
00404 
00405        Boolean                            wantsAllItems = false;
00406 
00407        StAEDesc                           startObject;  // These are used to resolve formRange
00408        StAEDesc                           stopObject;
00409               
00410        CoreTokenRecord             token;
00411        
00412        long                               numItems = GetNumItems(containerToken);
00413        
00414        CheckKeyFormSupport(keyForm);             // throws on error
00415        
00416        switch (keyForm)
00417        {
00418               case formName:                                                                                                                // item by name
00419                      if (DescToCString(keyData, itemName, 255) != noErr)
00420                             ThrowIfOSErr(errAECoercionFail);
00421 
00422                      if (!NamedItemExists(containerToken, itemName))
00423                             ThrowIfOSErr(errAENoSuchObject);
00424                      break;
00425               
00426 /*
00427               case formAbsolutePosition:                                                                                             // item by number
00428                      DescType             ordinalDesc;
00429                      if (DescToDescType((AEDesc*)keyData, &ordinalDesc) != noErr)
00430                             ThrowOSErr(errAECoercionFail);
00431 
00432                      if (ordinalDesc != kAEAll)
00433                             ThrowOSErr(errAEWrongDataType);
00434 
00435                      wantsAllItems = true;
00436                      break; 
00437 */            
00438               default:
00439                      ThrowIfOSErr(errAEEventNotHandled);
00440        }
00441        
00442        ThrowIfOSErr(err);
00443 
00444        // fill in the result token
00445        token.dispatchClass  = GetClass();
00446        token.objectClass    = GetClass();
00447        token.propertyCode   = typeNull;
00448        
00449        if (wantsAllItems)
00450        {
00451               err = AECreateList(NULL, 0, false, (AEDescList*)resultToken);
00452               ThrowIfOSErr(err);
00453               
00454               for (TAEListIndex index = 1; index <= numItems; index++)
00455               {
00456                      ItemID        itemID = GetIndexedItemID(containerToken, index);
00457                      if (itemID != kNoItemID)
00458                      {
00459                             SetItemIDInCoreToken(containerToken, &token, itemID);
00460                             err = AEPutPtr(resultToken, 0, desiredClass, &token, sizeof(token));
00461                             ThrowIfOSErr(err);
00462                      }
00463               }
00464        }
00465        else
00466        {
00467               SetNamedItemIDInCoreToken(containerToken, &token, itemName);
00468               err = AECreateDesc(desiredClass, &token, sizeof(token), resultToken);
00469               ThrowIfOSErr(err);
00470        }
00471 }
00472