home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / OpenDoc 1.2b2c1 / Implementation / Utilities / ODNewObj.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-13  |  9.2 KB  |  386 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        ODNewObj.cpp
  3.  
  4.     Contains:    Abstract wrapper for instantiating objects by class-name
  5.  
  6.     Owned by:    Jens Alfke
  7.  
  8.     Copyright:    © 1994 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.         <11>     9/18/96    TJ        Fixed the Last Checkin Comment.
  13.         <10>     9/18/96    TJ        Included TempObj.h
  14.          <9>     9/17/96    RA        1364628: Leak in ODNewObj
  15.          <8>     8/13/96    DM        1377223: instantiating parts in shell
  16.                                     plugins
  17.          <7>      7/2/96    TJ        Only load fragments of the current arc.
  18.          <6>     6/27/96    TJ        T10003 Load editors of type oded also.
  19.          <5>     6/27/96    jpa        1361886: Return error string
  20.          <4>     6/21/96    jpa        T10002: Don't check app heap space if
  21.                                     NewPtr override exists.
  22.          <3>     1/23/96    VL        1170098: Put back the CFM loading code
  23.                                     removed in the last checkin. The code was
  24.                                     used for debugging and getting CFM errors.
  25.          <2>     1/16/96    VL        1170098: Removed code for GetSharedLibrary.
  26.  
  27.     To Do:
  28. */
  29.  
  30.  
  31. #ifndef _ODMEMORY_
  32. #include "ODMemory.h"
  33. #endif
  34.  
  35. #ifndef _BARRAY_
  36. #include <BArray.h>
  37. #endif
  38.  
  39. #ifndef SOM_ODBinding_xh
  40. #include <ODBindng.xh>
  41. #endif
  42.  
  43. #ifndef _BNDNSUTL_
  44. #include "BndNSUtl.h"
  45. #endif
  46.  
  47. #ifndef _ODNEWOBJ_
  48. #include "ODNewObj.h"
  49. #endif
  50.  
  51. #ifndef _PLFMDEF_
  52. #include "PlfmDef.h"
  53. #endif
  54.  
  55. #ifndef _MEMMGR_
  56. #include <MemMgr.h>
  57. #endif
  58.  
  59. #ifndef _EXCEPT_
  60. #include "Except.h"
  61. #endif
  62.  
  63. #ifndef _ODDEBUG_
  64. #include "ODDebug.h"
  65. #endif
  66.  
  67. #ifndef _ODUTILS_
  68. #include <ODUtils.h>
  69. #endif
  70.  
  71. #ifndef _PASCLSTR_
  72. #include <PasclStr.h>
  73. #endif
  74.  
  75. #ifndef _UTILERRS_
  76. #include "UtilErrs.h"
  77. #endif
  78.  
  79. #ifndef __SOM__
  80. #include <som.xh>
  81. #endif
  82.  
  83. #ifndef SOM_SOMClassMgr_xh
  84. #include <somcm.xh>
  85. #endif
  86.  
  87. #ifndef _ISOSTR_
  88. #include "ISOStr.h"
  89. #endif
  90.  
  91. #ifndef _TEMPOBJ_
  92. #include "TempObj.h"
  93. #endif
  94.  
  95. #ifdef _PLATFORM_MACINTOSH_
  96.  
  97.     #ifndef __STRINGS__
  98.     #include <strings.h>
  99.     #endif
  100.     
  101.     #include <CodeFragments.h>
  102.     
  103.     #ifndef __FILES__
  104.     #include <Files.h>
  105.     #endif
  106.  
  107.     #define LOAD_UNDER_ASSUMED_NAME   1
  108.     /*    SOM requires that the library name (in the 'cfrg') be of the form "Module::ClassName".
  109.         This obviously won't match the library's SYM file name. This causes problems for source
  110.         level debuggers; they can't associate the two and you end up not being able to debug
  111.         the library.
  112.         To work around this, we give the library two names (two 'cfrg' entries), the second of
  113.         which is just the classname. Then if the SYM file name matches the classname, we can first
  114.         load the library by the classname, which will signal the debugger that it can link the
  115.         library up with the similarly-named SYM file.
  116.         Got that?? Off we go!!
  117.     */
  118. #endif
  119.  
  120. #ifndef _ODDEBUG_
  121. #include "ODDebug.h"
  122. #endif
  123.  
  124.  
  125. const ODSize kMinAppFreeSpace =        48 * 1024;    // Only if we can't override NewPtr
  126. const ODSize kMinAppContigSpace =     8 * 1024;
  127.  
  128. const unsigned char kMemoryLibName[]        = "\pMemory Manager",
  129.                     kMemoryOverrideOnName[] = "\pMMOverridePlatform",
  130.                     kMemoryOverrideOffName[]= "\pMMEndOverridePlatform";
  131.  
  132. extern "C" {
  133.     typedef void (*MemoryOverrideProcPtr)( MMBoolean ptrs, MMBoolean handles );
  134. }
  135.  
  136. static somTD_SOMError            *gOld_SOMError;
  137.  
  138.  
  139. static ODBoolean    TryToOverrideNewPtr( ODBoolean onoff );
  140.  
  141.  
  142. extern "C" {
  143.     static void
  144.     Temp_GetClass_SOMError( int error, corbastring filename, int linenum );
  145. }
  146.  
  147.  
  148. static void
  149. Temp_GetClass_SOMError( int error, corbastring filename, int linenum )
  150. {
  151.     int severity = error % 10;
  152.     if( severity == SOM_Fatal ) {
  153.         WARN("Fatal SOM err %d caught during GetClass; throwing...",error);
  154.         THROW(error);
  155.     } else if( gOld_SOMError )
  156.         gOld_SOMError(error,filename,linenum);
  157. }
  158.  
  159.  
  160. static SOMClass*
  161. GetClass( const char *className, Str255 errorString = kODNULL )
  162. {
  163.     char libname[64];
  164. #if PRAGMA_ALIGN_SUPPORTED
  165. #pragma options align=mac68k
  166. #endif
  167.  
  168.     struct FragDesc {
  169.         ResType codeType;
  170.         long ignore[5];
  171.         long offsetToFrag;
  172.         long lengthOfFrag;
  173.         long moreIgnore[2];
  174.         short recordLength;
  175.         Str63 name;
  176.     };
  177.     
  178.     struct CFRGResource {
  179.         long ignore[7];
  180.         long numFrags;
  181.         struct FragDesc firstDesc;
  182.     };
  183.  
  184. #if PRAGMA_ALIGN_SUPPORTED
  185. #pragma options align=reset
  186. #endif
  187.  
  188. #if LOAD_UNDER_ASSUMED_NAME
  189.     // First grab everything after the last colon in className:
  190.     const char *lastcolon = strrchr(className,':');
  191.     if (lastcolon == nil) {
  192.         // Hack to load Bento:
  193.         if( strcmp(className,"ODFileContainer")==0 ||
  194.             strcmp(className,"ODMemContainer")==0 ||
  195.             strcmp(className,"ODEmbeddedContainer")==0 )
  196.                 strcpy(libname, "OpenDoc Bento");
  197.         else
  198.                 strcpy(libname, className);
  199.     }
  200.     else {
  201.         strncpy(libname,lastcolon+1,sizeof(libname)-1);
  202.         libname[sizeof(libname)-1] = '\0';
  203.     }
  204. #else
  205.     strcpy(libname,className);
  206. #endif /*LOAD_UNDER_ASSUMED_NAME*/
  207.  
  208.     if( errorString ) errorString[0] = '\0';
  209.     
  210.     c2pstr(libname);
  211.  
  212.     CFragConnectionID connID;
  213.     Ptr mainAddr;
  214.     Str255 errName;
  215.     ODBoolean unloadLib = kODFalse;
  216.     
  217.     // Either override NewPtr or at least make sure there's memory available:
  218.     ODBoolean override = TryToOverrideNewPtr(kODTrue);
  219.     if( !override )
  220.         ODRequireFreeSpace(kMinAppFreeSpace,kMinAppContigSpace,kODTrue);
  221.     
  222.     // First see if the library is already loaded:
  223.     OSErr err = GetSharedLibrary((StringPtr)libname, kCurrentCFragArch,
  224.                                 kFindCFrag, &connID,&mainAddr,errName);
  225.                                 
  226.     if( err == fragLibNotFound || err==fragLibConnErr ) 
  227.     {
  228.         // Nope, need to load it:
  229.         TempODByteArrayStruct ba;
  230.         Environment* ev = somGetGlobalEnvironment();
  231.         ODFileSpec* fsspecPtr = kODNULL;
  232.         if (GetgBinding()->GetODFileSpecFromEditor(ev,ODISOStrFromCStr(className),ba))
  233.         {
  234.             fsspecPtr = (ODFileSpec*)(ba->_buffer);
  235.             short refNum = HOpenResFile( fsspecPtr->vRefNum, fsspecPtr->parID,
  236.             fsspecPtr->name, fsRdPerm );
  237.             short saveRefNum = CurResFile();
  238.             WASSERT(ResError()==noErr);
  239.             if (refNum != -1)
  240.             {
  241.                 UseResFile( refNum );            
  242.                 struct CFRGResource** cfrgHandle =
  243.                     (struct CFRGResource**)Get1Resource( 'cfrg', 0 );
  244.                 if ( cfrgHandle )
  245.                 {
  246.                     long entryCount = (*cfrgHandle)->numFrags;
  247.                     struct FragDesc* oneEntryPtr = &(*cfrgHandle)->firstDesc;
  248.                     while ( entryCount-- )
  249.                     {
  250.                     if ( oneEntryPtr->codeType == kCurrentCFragArch &&
  251.                         EqualPascalStrings((StringPtr)libname,oneEntryPtr->name))
  252.                         {
  253.                             err = GetDiskFragment(fsspecPtr, oneEntryPtr->offsetToFrag,
  254.                             oneEntryPtr->lengthOfFrag,NULL,
  255.                                   kLoadCFrag, &connID,&mainAddr,errName);
  256.                             break;
  257.                         }
  258.                         else
  259.                             oneEntryPtr = (FragDesc*)(oneEntryPtr->recordLength
  260.                                 + (char*)oneEntryPtr);
  261.  
  262.                     }
  263.                 }
  264.             }
  265.             CloseResFile( refNum );
  266.             UseResFile( saveRefNum );
  267.         }
  268.         else
  269.             err = GetSharedLibrary((StringPtr)libname, kCurrentCFragArch,
  270.                                 kLoadCFrag, &connID, &mainAddr, errName);
  271.     
  272.         if( err==noErr && !override && !ODHaveFreeSpace(kMinAppFreeSpace,
  273.                                                         kMinAppContigSpace,kODTrue) ) {
  274.             CloseConnection(&connID);
  275.             err = fragNoMem;
  276.     #if ODDebug
  277.             CopyPascalString(errName,"\pOD free space too low");
  278.     #endif
  279.         }
  280.         else
  281.             unloadLib = kODTrue;
  282.     }
  283.     
  284.     if( override )
  285.         TryToOverrideNewPtr(kODFalse);            // turn off override
  286.  
  287.     if( err ) {
  288.         if( errorString )
  289.             CopyPascalString(errorString,errName);
  290.         p2cstr(errName);
  291.         WARN("Can't load lib '%s'; error %hd, '%s'",
  292.                 p2cstr((StringPtr)libname),err,errName);
  293.         THROW(err,(char*)errName);
  294.     }
  295.     
  296.     /* Now try to load the class. Install a temporary error handler that
  297.         converts a fatal SOM error into a THROW, in case SOM runs out of
  298.         memory. */
  299.     SOMClass *c;
  300.     gOld_SOMError = SOMError;
  301.     SOMError = &Temp_GetClass_SOMError;
  302.     TRY{
  303.         long majorVersion = 0;
  304.         long minorVersion = 0;
  305.         somId id = somIdFromString((corbastring)className);
  306.         c = somGetDynamicClassReference(id,majorVersion,minorVersion, kODNULL);
  307.         SOMFree(id);
  308.         if (unloadLib)
  309.         {
  310.             unloadLib = kODFalse;
  311.             CloseConnection(&connID);
  312.         }
  313.     }CATCH_ALL{
  314.         if (unloadLib)
  315.             CloseConnection(&connID);
  316.         SOMError = gOld_SOMError;
  317.         RERAISE;
  318.     }ENDTRY
  319.     SOMError = gOld_SOMError;
  320.         
  321.     
  322.     if( !c )
  323.         THROW(kODErrCantLoadSOMClass);
  324.     return c;
  325. }
  326.  
  327.  
  328. SOMObject*
  329. ODNewObject( const char *className, Str255 errorString )
  330. {
  331.     SOMClass *cls = GetClass(className,errorString);
  332.     THROW_IF_NULL (cls);  // would have thrown anyway...
  333.     SOMObject* obj = cls->somNew();
  334.     somReleaseClassReference(cls); // must release class reference
  335.     THROW_IF_NULL (obj); // similar to new ODObject, must throw if nil
  336.     return obj;
  337. }
  338.  
  339.  
  340. ODBoolean
  341. ODClassExists( const char *className )
  342. {
  343.     /* This function will now propagate errors if the library _does_ exist
  344.        but just couldn't be loaded due to e.g. insufficient memory or missing
  345.        imports. This allows for better error display to the user since otherwise
  346.        the error would be eaten and replaced with a simple Boolean return value. */
  347.     
  348.     ODBoolean result = kODTrue;
  349.     TRY
  350.         SOMClass *cls = GetClass(className);
  351.         somReleaseClassReference ( cls );
  352.     CATCH_ALL
  353.         if( ErrorCode()==kODErrCantLoadSOMClass || ErrorCode()==fragLibNotFound )
  354.             result = kODFalse;
  355.         else
  356.             RERAISE;
  357.     ENDTRY
  358.     return result;
  359. }
  360.  
  361.  
  362. static ODBoolean
  363. TryToOverrideNewPtr( ODBoolean onoff )
  364. {
  365.     Str255 errName;
  366.     CFragConnectionID connID;
  367.     Ptr mainAddr;
  368.     OSErr err = GetSharedLibrary(kMemoryLibName, kCurrentCFragArch,
  369.                                 kLoadCFrag, &connID,&mainAddr,errName);
  370.     if( err ) {
  371.         WARN("Couldn't find Memory Mgr?? %d, %s", err,p2cstr(errName));
  372.         return kODFalse;
  373.     }
  374.     
  375.     MemoryOverrideProcPtr proc;
  376.     CFragSymbolClass type;
  377.     err= FindSymbol(connID, onoff ?kMemoryOverrideOnName :kMemoryOverrideOffName, (Ptr*)&proc, &type);
  378.     if( err ) {
  379.         WASSERT(err==fragSymbolNotFound);
  380.         return kODFalse;
  381.     }
  382.     
  383.     (*proc)(true,false);        // Call proc
  384.     return kODTrue;
  385. }
  386.