home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / opendc12.zip / od124os2.exe / od12osr1.exe / src / DynValus.c < prev    next >
Text File  |  1997-03-21  |  90KB  |  1,705 lines

  1. /* @(#)Z 1.4 com/src/cm/DynValus.c, odstorage, od96os2, odos29712d 97/03/21 17:19:35 (96/10/29 09:17:53) */
  2. /*====START_GENERATED_PROLOG======================================
  3.  */
  4. /*
  5.  *   COMPONENT_NAME: odstorage
  6.  *
  7.  *   CLASSES: none
  8.  *
  9.  *   ORIGINS: 82,27
  10.  *
  11.  *
  12.  *   (C) COPYRIGHT International Business Machines Corp. 1995,1996
  13.  *   All Rights Reserved
  14.  *   Licensed Materials - Property of IBM
  15.  *   US Government Users Restricted Rights - Use, duplication or
  16.  *   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  17.  *       
  18.  *   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  19.  *   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  20.  *   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  21.  *   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  22.  *   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  23.  *   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
  24.  *   OR PERFORMANCE OF THIS SOFTWARE.
  25.  */
  26. /*====END_GENERATED_PROLOG========================================
  27.  */
  28.  
  29. /*
  30.     File:        DynValus.c
  31.  
  32.     Contains:    xxx put contents here xxx
  33.  
  34.     Written by:    Ira L. Ruben
  35.  
  36.     Owned by:    Ed Lai
  37.  
  38.     Copyright:    ⌐ 1992-1994 by Apple Computer, Inc., all rights reserved.
  39.  
  40.     Change History (most recent first):
  41.  
  42.          <2>     8/26/94    EL        #1181622 Ownership update.
  43.          <1>      2/3/94    EL        first checked in
  44.  
  45.     To Do:
  46. */
  47.  
  48. /*---------------------------------------------------------------------------*
  49.  |                                                                           |
  50.  |                          <<<   DynValus.c    >>>                          |
  51.  |                                                                           |
  52.  |                 Container Manager Dynamic Value Routines                  |
  53.  |                                                                           |
  54.  |                               Ira L. Ruben                                |
  55.  |                                  5/5/92                                   |
  56.  |                                                                           |
  57.  |                     Copyright Apple Computer, Inc. 1992-1994              |
  58.  |                           All rights reserved.                            |
  59.  |                                                                           |
  60.  *---------------------------------------------------------------------------*
  61.  
  62.  Dynamic values are special values which "know" how to manipulate on their own value data.
  63.  They do this through a set of value operation handlers which are expected to be
  64.  semantically the same as the standard API value operations.
  65.  
  66.  The following value operations are expected to be supported by these handlers:
  67.  
  68.  CMSize CMGetValueSize(CMValue value);
  69.  CMSize CMReadValueData(CMValue value, CMPtr buffer, CMCount offset, CMSize maxSize);
  70.  void CMWriteValueData(CMValue value, CMPtr buffer, CMCount offset, CMSize size);
  71.  void CMInsertValueData(CMValue value, CMPtr buffer, CMCount offset, CMSize size);
  72.  void CMDeleteValueData(CMValue value, CMCount offset, CMSize size);
  73.  void CMGetValueInfo(CMValue value, CMContainer *container, CMObject *object,
  74.                                          CMProperty *property, CMType *type, CMGeneration *generation);
  75.  void CMSetValueType(CMValue value, CMType type);
  76.  void CMSetValueGeneration(CMValue value, CMGeneration generation);
  77.  void CMReleaseValue(CMValue);
  78.  
  79.  Whenever a dynamic value is passed to a standard API value routine corresponding to the
  80.  above handlers, the handler is called instead.  That is why the handler must be
  81.  semantically identical.
  82.  
  83.  Basically, dynamic values are similar to C++ objects where the handlers are the object's
  84.  methods.  They are dynamic in the sense that they only exist from creation (discussed
  85.  below) and last until until they are released (CMReleaseValue()).
  86.  
  87.  A dynamic value can have its own data (similar to C++ class fields).  The data is
  88.  generally used to create the handler's refCon during dynamic value creation.
  89.   
  90.  A dynamic value results when a value is created by to CMNewValue() or attempted to be
  91.  used by CMUseValue(), and the following two conditions occur:
  92.  
  93.      1. The type, or any of its base types (if any, created by CMAddBaseType()), are for
  94.           global names that have associated metahandlers registered by CMRegisterType().
  95.          
  96.     2. The metahandlers support the operation type to return a "use value" handler, and
  97.          in addition for CMNewValue(), a "new value" handler.
  98.  
  99.  The "new value" handlers are used to define initialization data for the "use value"
  100.  handlers.  The "use value" handlers are called to set up and return refCons.  Another
  101.  metahandler address is also returned.  This is used to get the address of the value
  102.  operation handlers corresponding to the standard API CM... value routines mentioned above.
  103.  
  104.  Just like C++, dynamic values may be "subclassed" via their (base) types.  If a handler
  105.  for a particular operation is not defined for a value, its "base value" is used to get the
  106.  "inherited" handler.  This continues up a dynamic value's chain of base values, up to the
  107.  original "real" value that spawned the base values from the CMNewValue() or CMUseValue().
  108.  
  109.  Thus for each dynamic value, there is a vector of handler addresses.    DynValus.h   
  110.  defines the layout of that vector.  Also defined there are the other interfaces needed to
  111.  process a dynamic value by the API routines themselves.  The routines themselves are in
  112.  this file.
  113.  
  114.  The vector becomes part of a set of "extensions" to the dynamic value header.  The
  115.  extensions struct is defined in  TOCEnts.h   along with the other value header
  116.  definitions.  The dynamic value stuff is kept separate because it is sufficiently
  117.  distinct.
  118.  
  119.  
  120.                                                      The Data Structures for Dynamic Values
  121.                                                     --------------------------------------
  122.  
  123.  The following diagram shows the pointer relationships among the various data structures
  124.  descending from an object for dynamic values.  Most of this is basically the same as
  125.  shown in TOCEntries.[ch], so some of the superfluous pointers are removed to just show
  126.  the pointers of interest.
  127.  
  128.  
  129.  *----------*     *--------------------*               *---------------------*
  130.  | *Object* |<--->|     *Property1*    |<------------->|     *Property2*     |
  131.  *----------*  +->| (for these values) |           +-->|   (dynamic values)  |
  132.                |  *--------------------*           |   *---------------------*
  133.                |                                   |
  134.                |                                   |
  135.                +-->*-------------------*           +-->*--------------------*
  136.                    |    *ValueHdr1*    |<--------------| *Dynamic ValueHdr* |
  137.                    | (a "real" value)  |----+    +---->|   (bottom layer)   |
  138.                +-->| (value not shown) |    |    |  +->|(on property chain) |
  139.                |   *-------------------*    |    |  |  *--------------------*
  140.                |                            |    |  |  |   *extensions*     |
  141.                |                            |    |  |  |[DynamicValueVector]|
  142.                |                            |    |  |  *--------------------*
  143.                |                            |    |  |
  144.                |                            |    |  +---------------*--------------------*
  145.                |                            |    |                  | *Dynamic ValueHdr* |
  146.                |                            |    |             +--->|   (middle layer)   |
  147.                |                            |    |             |    *--------------------*
  148.                |                            |    |             |    |   *extensions*     |
  149.                |                            |    |             |    |[DynamicValueVector]|
  150.                |                            |    |             |    *--------------------*
  151.                |                            |    |             |
  152.                |                            |    |             +---*---------------------*
  153.                |                            +---------------------->| *Dynamic ValueHdr* |
  154.                |                                 |                  |    (top layer)     |
  155.                |                                 |                  *--------------------*
  156.                |                                 |                  |   *extensions*     |
  157.                |                                 |                  |[DynamicValueVector]|
  158.                |                                 |                  *--------------------*
  159.                |                                 |
  160.                |                                 |
  161.                |   *-------------------*         |     *--------------------*
  162.                +-->|    *ValueHdr2*    |         +---->| *Dynamic ValueHdr* |
  163.                    | (a "real" value)  |<------------->|   (single layer)   |
  164.                    | (value not shown) |               |(on property chain) |
  165.                    *-------------------*               *--------------------*
  166.                                                        |   *extensions*     |
  167.                                                        |[DynamicValueVector]|
  168.                                                        *--------------------*
  169.  
  170.  
  171.  As usual, for each object we have a list of properties, and each property has a list of
  172.  value headers (the value segment lists are not shown).  Real values that spawn dynamic
  173.  values cause a special property used only to contain the dynamic value headers.
  174.  
  175.  In the above diagram there are two "real" values that spawned dynamic values; "ValueHdr1"
  176.  and "ValueHdr2".  "ValueHdr1" generated a three-layer dynamic value.  This results from
  177.  the subclassing of types (subclassing is discussed later). "ValueHdr2" has only a single 
  178.  layer dynamic value.
  179.  
  180.  The link structure is such that the "real" value always points to the top-most dynamic
  181.  value layer.  That, in turn, points to its base value.  This continues until the bottom-
  182.  most base value. It always points back to the "real" value.
  183.  
  184.  Note, the bottom-most layer (the one who has the "real" value as its base) is the ONLY
  185.  value header on the dynamic property chain.  All higher layers for it are NOT part of the
  186.  property chain.
  187.  
  188.  Note also that dynamic value headers never have value segment lists.  No data is ever 
  189.  written to a dynamic value because these headers are removed when the value is released
  190.  using a CMReleaseValue().  If there is any data, it must be associated with a "real"
  191.  value -- the real value associated with a dynamic value or some place else (how this can
  192.  happen is described later).
  193.  
  194.  In each value header there is a pointer (a union called "dynValueData" with alternative
  195.  fields called "dynValue" and "extensions") that contains three possible values:
  196.  
  197.          1. dynValueData is NULL for "real" value headers that don't have a corresponding
  198.              dynamic value.
  199.         
  200.         2. dynValueData.dynValue is a pointer to the top-most layer if it is a "real" value
  201.              that does have a corresponding dynamic value header.
  202.              
  203.       3. dynValueData.extensions is a pointer to the extensions if it is itself a dynamic
  204.              value header.
  205.         
  206.  The value header's flags determine how to interpret the pointer.
  207.  
  208.  The extensions is the interesting part.  It contains the vector of function pointers to
  209.  the value handlers mentioned earlier (not unlike a C++ v-table).
  210.  
  211.  When a dynamic value is spawned by CMNewValue() or CMUseValue(), the pointer to the top-
  212.  most dynamic value header is returned as the refNum.  That means whenever the user passes
  213.  it to an API value routine, it will check to see if the refNum is a dynamic value.  If it
  214.  is, it initiates the call to the corresponding value handler using the vector in the
  215.  extensions.  That may cause a search up the base value chain to look for the "inherited"
  216.  value routine.  In the limit, we end up using the original API value routine if no handler
  217.  is supplied and we reach the "real" value in the chain.  That's how data could get in
  218.  there.
  219.         
  220.  Assuming you're still with me, the following diagram is provided to simplify the
  221.  notation.  We use this simplification of the diagram above so you can understand the
  222.  meaning.  We will need this to notation to describe how dynamic values are spawned and
  223.  layers created.  There is no need now to show all the details as above.
  224.  
  225.  
  226.                   *---*     *---*      *-----*
  227.                   | O |-----| P |------| DVP |
  228.                   *---*     *---*      *-----*
  229.                               |           |
  230.                               |           |
  231.                            *-----*     *-----*       *-----*       *-----*
  232.                            | VH  |<----| DVH |<------| DVH |<------| DVH |
  233.                            *-----*     *-----*       *-----*   +-->*-----*
  234.                               |  |        |                    |
  235.                               |  |        |                    | 
  236.                               |  +-----------------------------+
  237.                               |           |
  238.                               |           |
  239.                            *-----*     *-----*
  240.                            | VH  |<--->| DVH |
  241.                            *-----*     *-----*
  242.  
  243.  Here "O" is object, "P" is property, "VH" real value header, "DVP" the dynamic value
  244.  property, and "DVH" a dynamic value.
  245.  
  246.  
  247.                                   Spawning Dynamic Values
  248.                                                                     -----------------------
  249.                                                                     
  250.  When a CMNewValue() or CMUseValue() is almost done, a check is made on the value's type,
  251.  and all of its base types (if any) to see if it has an associated registered metahandler.
  252.  If it does, it is called with a "use value" operation type to see if a "use value" handler
  253.  exists for the type.  If it does, we spawn the dynamic value.
  254.  
  255.  To summarize, if CMNewValue() or CMUseValue() sees any (base) type that has an associated
  256.  "use value" handler, it will spawn a dynamic value.
  257.  
  258.  The spawning is done, leaving out some confusing details, by calling the "use value"
  259.  handler.  It is expected to set up a refCon to pass among the value handlers and a pointer
  260.  to another metahandler.  These are returned to CMNewValue() or CMUseValue() which uses
  261.  newDynamicValue() (defined in this file) to do the actual creation of the dynamic value.
  262.  The extensions are initialized, the metahandler pointer saved, and also the refCon.  The
  263.  pointer to the created dynamic value header is what CMNewValue() or CMUseValue()() returns
  264.  to the user as the refNum.
  265.  
  266.  Now, when the user attempts to do a value operation using this refNum, a check is made
  267.  that the refNum is for a dynamic value.  If it is, the corresponding handler routine will
  268.  be called. The vector entries are set on first use of a value operation.  It may mean
  269.  searching up the base value chain, but once found, we save the handler address in the top
  270.  layer vector (associated with the refNum) so we don't have to do the search again.
  271.  
  272.  Note that if we indeed do have to search up the base value chain then we must save the 
  273.  dynamic value refNum (pointer) in addition to the handler address.  This is very much like
  274.  C++ classes, where inherited methods are called and the appropriate "this" must also be
  275.  passed.  The "this" in this case is the refNum.
  276.  
  277.  
  278.                                                                 Layering Dynamic Values
  279.                                                                 -----------------------
  280.  
  281.  The best way to describe layering is in terms of C++.  Say we have the following class
  282.  types (using a somewhat abbreviated notation -- don't get picky here):
  283.  
  284.   class Layer1 {                                                                // a base class
  285.          <layer1 data>                                                                // possible data (fields)
  286.         Layer1(<layer1 args>);                                            // constructor to init the data
  287.         other methods...                                                        // value operations in our case
  288.   };
  289.  
  290.   class Layer2 {                                                                // another base class
  291.          <layer2 data>                                                                // possible data (fields)
  292.         Layer2(<layer2 args>);                                            // constructor to init the data
  293.         other methods...                                                        // value operations in our case
  294.   };
  295.     
  296.     class T: Layer1, Layer2 {                                            // the class of interest!
  297.         <T data>                                                                        // possible data (fields)
  298.         T(<T args>, <layer1 args>, <layer2 args>);    // constructor to init the data and bases
  299.         other methods...                                                        // value operations in our case
  300.     };
  301.  
  302.  In Container Manager terminology, T is to be a registered type with other registered 
  303.  types as base types (classes).  All type objects are created using the standard API call
  304.  CMRegisterType().  Base types can be added to a type by using CMAddBaseType().  This
  305.  defines a form of inheritance like the C++ classes.  
  306.  
  307.  Type T would be registered with its base types as follows:
  308.  
  309.  layer1 = CMRegisterType(container, "Layer1");
  310.  layer2 = CMRegisterType(container, "Layer2");
  311.  
  312.  t = CMRegisterType(container, "T");
  313.  CMAddBaseType(t, layer1);
  314.  CMAddBaseType(t, layer2);
  315.  
  316.  Internally, the t object looks something like the following:
  317.  
  318.                   *---*     *-------*         *-------*
  319.                   | t |-----| P[gn] |---------| P[bt] |
  320.                   *---*     *-------*         *-------*
  321.                                 |                 |
  322.                                 |                 |
  323.                              *-----*  *---*    *-----*  *--------*  *--------*
  324.                              | VH  |--|"T"|    | VH  |--|"layer1"|--|"layer2"|
  325.                              *-----*  *---*    *-----*  *--------*  *--------*
  326.  
  327.  The value data segments are shown here with the data the segment will point to in the
  328.  container.
  329.  
  330.  For the t object, the global name property and value are created as usual by  
  331.  CMRegisterType(container, "T").  The CMAddBaseType() calls add the base types.  These are
  332.  recorded as the object ID's for each base type in the order created as separate value
  333.  segments for a special "base type" property belonging to the type object.
  334.  
  335.  As mentioned above, CMNewValue() or CMUseValue() spawn dynamic values if the original type
  336.  or any of its base types have an associated "use value" handler.  Assume that was done for
  337.  "T" in the above example.  What happens is that CMNewValue() or CMUseValue() will look at
  338.  its type object (t here) to see if the base type property is present.  If it is, it will
  339.  follow each type "down" to leaf types using a depth-first search.
  340.  
  341.  In the example, "layer1" will be visited, then "layer2", and finally the original type
  342.  "T" itself.  If the "layer1" type object had base types of its own, they would be visited
  343.  before using "layer1" itself.  Hence the depth-first search down to the leaf types.
  344.  
  345.  For each type processed, if it has a "use value" handler of its own, it will be called
  346.  to get a refCon and value handler metahandler.  These are passed to newDynamicValue()
  347.  to create a dynamic value for the original "real" value.  newDynamicValue() always
  348.  returns its refNum which will be the dynamic value it created.  The first layer will
  349.  create the dynamic value property and put the dynamic value header on its value header
  350.  list.  All further calls to newDynamicValue() will pass the most recent refNum returned
  351.  from it.  newDynamicValue() then chains these off the first dynamic value header.  This
  352.  produces the desired layering result.
  353.  
  354.  Note that this scheme allows total freedom for the user to mix types.  For example, type
  355.  T1 could have base types T2 and T3.  Alternatively, T1 could just have base type T2 and
  356.  T2 have T3 as its base type!
  357.  
  358.  
  359.                                                                  Data For Dynamic Values
  360.                                                                  -----------------------
  361.  
  362.  In the C++ class types shown above, note that each class could have its own data along
  363.  with its own constructor.  The T class has a constructor that calls the constructors of
  364.  all of its base classes.  We can carry this simile with the Container Manager just so far!
  365.  Here's is where it starts to break down.
  366.  
  367.  The problem here is that C++ class types are declared statically.  A C++ compiler can see
  368.  all the base classes and can tell what data gets inherited and who goes with what class.
  369.  In the Container Manager, all "classes" (i.e., our type objects) are created dynamically!
  370.  So the problem is we need some way to tell what data "belongs" to what type.
  371.  
  372.  The solution is yet another special handler, which returns a "format specification",
  373.  called "metadata".  The handler is the "metadata" handler whose address is determined
  374.  by the Container Manager from the same metahandler that returns the "new value" and "use
  375.  value" handler addresses.
  376.  
  377.  Metadata is very similar to C printf() format descriptions, and as will be described
  378.  shortly, for similar purposes.  The next section will describe the metadata in detail.
  379.  But, for now, it is sufficient to know that it tells CMNewValue() how to interpret its
  380.  "..." parameters.  The rest of this section will discuss how this is done to dynamically
  381.  create data. 
  382.  
  383.  As with C++ classes, the data is created when a new value is created, i.e., with a
  384.  CMNewValue() call.  The data will be saved in the container, so CMUseValue() uses the
  385.  type format descriptions to extract the data for each dynamic value layer (actually,
  386.  cmFollowTypes() in this file which is called by CMNewValue()).
  387.  
  388.  CMNewValue() is defined as follows:
  389.  
  390.        CMValue CMNewValue(CMObject object, CMProperty property, CMType type, ...);
  391.  
  392.  The "..." is an arbitrary number of parameters used to create the data.  Metadata,
  393.  accessed from the "metadata" handler, tells CMNewValue() how to interpret these parameters
  394.  just like a printf() format tells it how to use its arguments.
  395.  
  396.  The ORDER of the parameters is important!  Because base types are done with a depth-first
  397.  search through the types down to their leaves, the CMNewValue() "..." parameters MUST be
  398.  ordered for the "deepest" type first.  For example, given the following type inheritance
  399.  hierarchy (read these as T1 inherits from T2 and T3, and so on):
  400.  
  401.                                       T4      T5
  402.                                         *    *
  403.                                          *  *
  404.                                   T2      T3
  405.                                     *    *
  406.                                      *  *
  407.                                       T1
  408.                             
  409.  The depth-first search, starting at T1, yields the sequence: T2 T4 T5 T3 T1.  Then this
  410.  is the order the CMNewValue() "..." parameters must be in.
  411.  
  412.  Note what's happening here is you are supplying all the constructor data just like T
  413.  constructor class example above.
  414.   
  415.  The way the data gets written is with special handler, called the "new value" handler.
  416.  After CMNewValue() calls the "metadata" handler, it uses the metadata to extract the next
  417.  set of CMNewValue() "..." parameters.  CMNewValue() then passes the parameters along in
  418.  the form of a data packet to the "new value" handler.  The "new value" handler is then
  419.  expected to use this data (which it can extract with CMScanDataPacket()) to WRITE data
  420.  to its BASE value.  It is the data written by the "new value" handler that the "use value"
  421.  handler will read to create its refCon. 
  422.  
  423.  Only CMNewValue() does this.  The "new value" handler is only for new values, but the "use
  424.  value" handler is used by both CMNewValue() and CMUseValue().
  425.  
  426.  In the simplest case, with only one dynamic value, you can see that the data is written 
  427.  to the "real" value.  Now if you layer another dynamic value on to this, the next chunk
  428.  of data is written using that layer's base value and hence through its handlers.  The
  429.  second layer will thus use the first layers handlers.  That may or may not end up writing
  430.  to the "real" value depending on the kind of layer it is.  If it's some sort of indirect
  431.  handler (i.e., it reads and writes somewhere else), the second layer data will probably
  432.  not go to the "real" value.
  433.   
  434.  The "use value" handler is called both for CMNewValue() and CMUseValue().  The "use value"
  435.  handler reads the data from its base value to create its refCon.  If the user comes back
  436.  the next day and does a CMUseValue(), only the "use value" handler is called.  Again
  437.  it reads the data from its base value to construct the refCon and we're back as we were
  438.  before in the CMNewValue() case.
  439.  
  440.  It should be pointed out here that the "matadata" and "new value" handlers will always
  441.  be executed with a Container Manager running on some particular hardware (obviously).  The
  442.  data packet built from the CMNewValue() "..." parameters is stored as a function of the
  443.  hardware implementation on which it is run (i.e., whatever the sizes are for bytes, words,
  444.  longs, etc.).  How it is stored is a function of the metadata returned from the "metadata"
  445.  handler.  In other terms, the "new value" handler has a "contract" with both the Container
  446.  Manager and the "metadata" handler on the meaning of the parameter data. 
  447.  
  448.  Note, however, it is NOT required that you be on the same hardware when you come back the
  449.  next day and call CMUseValue() that leads to the "use value" handler call.  The handler
  450.  writer must keep this in mind.  Specifically, the "use value" handler MUST know the
  451.  attributes (bytes size, big/little endian, etc.) of the data written out by the
  452.  "new value" handler so it knows how to use that info.  In other words, the "use value"
  453.  handler has a (separate) "contract" with its own "new value" handler on the meaning of the
  454.  data written to the base value.
  455.  
  456.  There is another, relatively minor, thing to keep in mind.  That is that the value
  457.  handlers for any one layer must take into account the size of its own data when
  458.  manipulating additional data created by its handlers for CMReadValueData(),
  459.  CMWriteValueData(), etc.  This simply offsets the write and read value data operations
  460.  by the proper amount.  Remember all operations are on their base values.  So if a "new
  461.  value" handler writes data, this basically prefixes the "real" stuff being written by the
  462.  handler operations.
  463.  
  464.  
  465.                                                                           Metadata
  466.                                                                          --------
  467.  
  468.  As mentioned above, the metadata directs CMNewValue() on how to interpret its "..."
  469.  parameters to build data packets passed to "new value" handlers.
  470.  
  471.  The format string is a sequence of characters containing data format specifications. 
  472.  Unlike printf(), anything other than the data format specifications are ignored.  They
  473.  are assumed to be comments.
  474.  
  475.  The data format specifications indicate to CMNewValue() how to interpret its data
  476.  initialization parameters.  Each specification uses (consumes) the next corresponding
  477.  "..." parameter to CMNewValue().  This is similar to the behavior of printf().
  478.   
  479.  A data format specification begins with a "%" sign.  Immediately following the % is a 
  480.  required data size layout specification, expressed as a sequence of characters.  The data
  481.  size specification sequences are as follows:
  482.  
  483.         c                    A character or byte [note 1].
  484.         
  485.         d                    A short [note 1].
  486.         
  487.         l[d]            A long (the "d" is optional) [note 1].
  488.         
  489.         [*]s            A C string (i.e., null delimited).  Optionally a "*" indicates that only the
  490.                             first n characters of the string are to be used.  The "*" consumes an
  491.                             additional CMNewValue() "..." parameter of type CMSize [notes 3, 4, and 5].    
  492.                              
  493.         i                    An object, property, or type ID.  This is defined as the same size as "ld"
  494.                             [note 1].
  495.         
  496.         p                    A pointer [notes 1 and 2].
  497.      
  498.         o                    A CMObject, CMProperty, or CMType object refNum.  This is defined as the
  499.                             same size as "p" [notes 1 and 2].
  500.         
  501.         v                    A CMValue refNum.  This is defined as the same size as "p" [notes 1 and 2].
  502.  
  503.  Notes:
  504.         
  505.         1. The CMNewValue() "..." parameters are converted to a packet of data using the 
  506.              hardware implementation defined sizes for bytes, words, longs, etc., as directed by
  507.              the metadata returned from the "metadata" handler. Thus the "metadata" handler has
  508.              a contract with the "new value" handler that CMNewValue() calls.  The data that the
  509.              "new value" handler writes to its base value is in terms of a "contract" it has with
  510.              its "use value" handler.  It is the one that will read that base value data to
  511.              create its refCon.  If CMUseValue() is expected to be run on different hardware with 
  512.              different byte sizes, endianess, etc., then that is between the "new value" handler
  513.              and its "use value" handler.  The Container Manager is independent of that.
  514.              
  515.         2. Pointers can be passed to CMNewValue() to convey special information to the "use
  516.              value" handler.  You shouldn't, of course, write these as data.  RefNums can be
  517.              passed to extract object ID's or other read value data.  It is permissible  to
  518.              write object ID's to data.  But this will put a restriction on such references that
  519.              they shouldn't be moved or deleted.
  520.             
  521.         3. For "%*s", the value corresponding to the "*" is copied to the packet data
  522.              immediately in front of the string.  This is somewhat (not quite) equivalent to
  523.              "%l%s", where the %l is the length, n, and %s is an n byte string.  Note however,
  524.              this string is NOT null delimited.
  525.      
  526.         4. Caution, the string will be COPIED from the string pointed to in the CMNewValue()
  527.              "..." parameter list to the packet.  It you intend to pass a pointer to the string,
  528.              rather than the string itself, %p should be used.  Frankly, it is expected that %s
  529.              will not be used much!
  530.         
  531.         5. For symmetry, CMScanDataPacket() returns the value of string length to an explicit
  532.              distinct parameter pointer.  Thus the parameter pointer list passed to
  533.              CMScanDataPacket() should be identical to the "..." parameters passed to a
  534.              CMNewValue() "..." parameter list (at least the portion corresponding to this type).
  535.              
  536.  
  537.                                     The "Metadata", "New Value", and "Use Value" Handlers
  538.                                    -----------------------------------------------------
  539.  
  540.  The "metadata" handler is only needed for CMNewValue() so that the proper number of
  541.  CMNewValue() "..." parameters can be placed into a data packet for the "new value"
  542.  handler.
  543.  
  544.  The "metadata" handler should have the following prototype:
  545.  
  546.  CMMetaData metaData_Handler(CMType type);
  547.  
  548.  where, 
  549.  
  550.         type = the (base) type layer whose metadata is to be defined
  551.  
  552.  The "metadata" handler simply returns a C string containing the metadata using the format
  553.  descriptions described above.
  554.  
  555.  The type is passed as a convenience.  It may or may not be needed.  It is possible for
  556.  a type object to contain OTHER data for other properties.  Types, after all, are ordinary
  557.  objects.  There is nothing prohibiting the creation of additional properties and their
  558.  values.  This fact could be used to add additional (static and private) information to a
  559.  type to be used elsewhere.
  560.  
  561.  Note, as in printf(), if the metadata handlers "lie" about the metadata format, or if 
  562.  there aren't enough parameters supplied to CMNewValue(), the results will be
  563.  unpredictable! 
  564.  
  565.  The "new value" handler should have the following prototype:
  566.  
  567.  CMBoolean newValue_Handler(CMValue baseValue, CMType type, CMDataPacket dataPacket);
  568.  
  569.  where, 
  570.      
  571.         baseValue  = the base value which is to be used to write the refCon data for the
  572.                                   "use value" handler
  573.         
  574.         type             = the type corresponding to this "new value" handler
  575.         
  576.         dataPacket = the pointer to the data packet, created from the CMNewValue() "..."
  577.                                  parameters according the types metadata format description
  578.  
  579.  The type is passed again as a convenience just as in the "metadata" handler.  It can also
  580.  be used here to pass to CMScanDataPacket() to extract the dataPacket back into variables
  581.  that exactly correspond to that portion of the CMNewValue() "..." parameters that
  582.  correspond to the type.  It is not required, however that CMScanDataPacket() be used.
  583.   
  584.  The "use value" handler is called for both the CMUseValue() and CMNewValue() cases.  If
  585.  it's companion "new value" handler wrote data to its base value, the "use value" handler
  586.  will probably read the data to create its refCon.  The refCon will be passed to all
  587.  value handlers.  The "use value" handler returns its refCon along with another
  588.  metahandler address that is used to get the value operation handler addresses.  These are
  589.  then used to create the dynamic value.
  590.  
  591.  The "use value" handler should have the following prototype:
  592.  
  593.  CMBoolean useValue_Handler(CMValue baseValue, CMType type, CMMetaHandler *metahandler, 
  594.                                                           CMRefCon *refCon);
  595.                                                 
  596.  where,
  597.          
  598.         baseValue   = the base value which is to be used to write the refCon data for the
  599.                                    "use value" handler.
  600.         
  601.         type              = the type corresponding to this "new value" handler
  602.  
  603.         metahandler = a pointer to the value operations metahandler which is RETURNED by the
  604.                                     "use value" handler to its caller
  605.                                     
  606.         refCon            = a reference constant built by the "use value" handler and RETURNED to
  607.                                   its caller
  608.  
  609.  The baseValue and type are identical to the ones passed to the "new value" handler.  The
  610.  type may or may not be needed in the "use value" handler.  Like the "use value" handler,
  611.  it could be used to supply additional information from other type object properties.
  612.  
  613.  It is expected that the "use value" handler will read data from its base value to
  614.  construct its refCon.  The refCon is then returned along with a pointer to another
  615.  metahandler that is used by the Container Manager to get the addresses of the value
  616.  operation routines.
  617.   
  618.  Note, both the "new value" and "use value" handlers return a CMBoolean to indicate 
  619.  success or failure.  Failure means (or it is assumed) that the handlers reported some
  620.  kind of error condition or failure.  As documented, error reporters are not supposed to
  621.  return.  But in case they do, we use the CMBoolean to know what happened.   It should 
  622.  return 0 to indicate failure and nonzero for success.
  623.  
  624.  
  625.                                                             Value Operation Handlers
  626.                                                             ------------------------
  627.                                                             
  628.  The value operation routines can do a CMGetValueRefCon() on the value passed to get at the
  629.  refCon set up by the "use value" handler.  This provides a communication path among the
  630.  value handlers.  Further, the value handler should usually do their operations in terms of
  631.  their base value.  This is accessed using CMGetBaseValue() on the passed value.
  632.  
  633.  There is one exception to this rule; the release handler.  A set of one or more dynamic
  634.  value layers are spawned as a result of a single CMUseValue() or CMNewValue().  The layers
  635.  result from the specified type having base types.  From the caller's point of view s/he
  636.  is doing one CMUseValue() or CMNewValue() with no consideration of the base types.  That
  637.  implies that the returned dynamic value should have a single CMRelaseValue() done on it.
  638.  The handlers have no business doing CMReleaseValue() on their base value.  This is
  639.  detected and treated as an error.
  640.  
  641.  A count is kept by the Container Manager of every CMUseValue() and CMNewValue().  Calling 
  642.  CMReleaseValue() reduces this count by one.  When the last release is done on the dynamic
  643.  value (its count goes to 0), the release handler will be called.  It is the Container
  644.  Manager who calls the release handler for all the layers, not the handler.  The Container
  645.  Manager created them as a result of the original type.   It is therefore responsible for
  646.  releasing them.
  647.  
  648.  The reason the Container Manager is so insistent on forcing a release for every use of a
  649.  dynamic value is mainly to enforce cleanup.  Most value operation handlers will, at a
  650.  minimum, use a refCon that was memory allocated by the "use value" handler.  Release
  651.  handlers would then be responsible for freeing that memory.  In another example, if any
  652.  files were open by the "use value" handler, the releases would close those files.
  653.  
  654.  Note, if all a value operation does is get its base value and call back the API routine
  655.  to do its operation (again except for the release handler), then what it is basically
  656.  doing is invoking the "inherited" method ('er, sorry, value operation).  In this case,
  657.  the value operation could be OMITTED entirely.  That is, don't define a routine address
  658.  in the value operations metahandler (returned by the "use value" handler).  The Container
  659.  Manager uses that as the signal to search up the dynamic value inheritance chain to find
  660.  the first handler defined for the routine.  In the limit, it will end up using the
  661.  original "real" value.
  662.  
  663.  
  664.                              Possible Limitations and Considerations On Value Operations
  665.                             -----------------------------------------------------------
  666.                              
  667.  As presented, the model for type inheritance described above only allows for inheriting
  668.  value operations that would otherwise be processed via the API.  A non-obvious fact of
  669.  this is that value operations are basically limited to stream operations.  That is,
  670.  you read or write a chunk of stuff linearly from a specified offset.  In addition, there
  671.  are insert and delete operations (CMInsertValueData() and CMDeleteValueData()).  These two
  672.  cause potential problems!
  673.  
  674.  The reason they are a problem is that base types may want to do certain transformations
  675.  on their data that depend on what has occurred previously in that stream of data.  For
  676.  example, encryption, using a cyclic key, or compression, which can be thought of as a form
  677.  of encryption, generally cannot be done simply by looking at a chunk of data starting at
  678.  some random offset.  A cyclic key encryption can be deterministic if you can always
  679.  determine where to start in the key as a function of offset. But you can see that inserts
  680.  and deletes will change the offsets of following data.  You would not know where to start
  681.  in the key.
  682.  
  683.  What all this means is that certain data transformations only make sense if you are
  684.  willing to refuse to support the insert/delete operations.  Basically only data
  685.  transformations that are position independent can be fully supported.
  686.  
  687.  Even simple I/O to a file may create problems, since most file systems do not support
  688.  inserts and deletes in the middle of a file.  If you do want to support inserts and
  689.  deletes, then you should consider the potential for data intensive and/or computationally
  690.  intensive operations.
  691.  
  692.  Consider yourself warned!
  693.  
  694.  Well, that's all there is to dynamic values.  Aren't they fun?  I am sorry about this
  695.  long winded explanation, but there is no short way to describe this stuff.  Would you
  696.  rather I didn't?
  697. */
  698.  
  699.  
  700. #include <stddef.h>
  701. #include <string.h>
  702. #include <stdio.h>
  703. #include <stdarg.h>
  704.  
  705. #ifndef __CMTYPES__
  706. #include "CMTypes.h"
  707. #endif
  708. #ifndef __CM_API_TYPES__
  709. #include "CMAPITyp.h"
  710. #endif
  711. #ifndef __CM_API__
  712. #include "CMAPI.h"
  713. #endif
  714. #ifndef __LISTMGR__
  715. #include "ListMgr.h"
  716. #endif
  717. #ifndef __TOCENTRIES__
  718. #include "TOCEnts.h"   
  719. #endif
  720. #ifndef __TOCOBJECTS__
  721. #include "TOCObjs.h"   
  722. #endif
  723. #ifndef __GLOBALNAMES__
  724. #include "GlbNames.h"   
  725. #endif
  726. #ifndef __CONTAINEROPS__
  727. #include "Containr.h"  
  728. #endif
  729. #ifndef __HANDLERS__
  730. #include "Handlers.h"
  731. #endif
  732. #ifndef __DYNAMICVALUES__
  733. #include "DynValus.h"     
  734. #endif
  735. #ifndef __SESSIONDATA__
  736. #include "Session.h"          
  737. #endif
  738. #ifndef __ERRORRPT__
  739. #include "ErrorRpt.h"      
  740. #endif
  741. #ifndef __UTILITYROUTINES__
  742. #include "Utility.h"        
  743. #endif
  744.  
  745.                                                                     CM_CFUNCTIONS
  746.  
  747. /* The following generates a segment directive for Mac only due to 32K Jump Table             */
  748. /* Limitations.  If you don't know what I'm talking about don't worry about it.  The        */
  749. /* default is not to generate the pragma.  Theoritically unknown pragmas in ANSI won't    */
  750. /* choke compilers that don't recognize them.  Besides why would they be looked at if        */
  751. /* it's being conditionally skipped over anyway?  I know, famous last words!                        */
  752.  
  753. #if CM_MPW
  754. #pragma segment CMValueOps
  755. #endif
  756.  
  757. /* Note, this is the same segment used by  CMValOps.c  intentionally.                                        */
  758.  
  759.  
  760. /* For generality (or whatever), the following define all the fields of a metadata             */
  761. /* format description...                                                                                                                                */
  762.     
  763. #define Meta_Trigger         '%'                        /* all formats are triggered by this                            */
  764. #define Meta_Ptr                 'p'                        /* pointers                                                                                */
  765. #define Meta_Object         'o'                        /* CMObject, CMProperty, or CMType object refNum    */
  766. #define Meta_Value             'v'                        /* CMValue refNum                                                                    */
  767. #define Meta_ID                 'i'                        /* object, property, or type ID                                        */
  768. #define Meta_Char             'c'                        /* character or byte                                                            */
  769. #define Meta_Short             'd'                        /* short                                                                                    */
  770. #define Meta_Long             'l'                        /* long ("%ld" also allowed)                                            */
  771. #define Meta_LongSuffix 'd'                        /* optional "long" suffix                                                    */
  772. #define Meta_Star             '*'                        /* string of n characters (uses as "*s")                    */
  773. #define Meta_String         's'                        /* C string                                                                                */
  774.  
  775.  
  776. /*-------------------------------------------------------------------------------*
  777.  | hasUseValueHandler - check a base type to see if it has a "use value" handler |
  778.  *-------------------------------------------------------------------------------*
  779.  
  780.  This routine takes a value (header) checks to see if the value type is a global name.  If
  781.  it is (what else?), and if there is a metahandler associated with the name (as defined by
  782.  an earlier CMSetMetaHandler() call), then that metahandler is called with a "use value"
  783.  operation type.  If the methandler returns the address of a "use value" handler, the
  784.  function returns that address as its result.  If newValueHandler is not NULL then the
  785.  "new value" handler address AND a "metadata" handler address are also required and
  786.  returned.  NULL is returned if the metahandler or "use value" handler do not exist.
  787.  
  788.  Note, the "new value" and "metadata" handlers are requested only for CMNewValue() creation
  789.  of dynamic values.  That is the only time newValueHandler is specified.  Thus an error
  790.  will be  reported from here, and SessionSuccess (a session global status switch) returned
  791.  false, if the "new value" or "metadata" handler is not present when requested.  Otherwise
  792.  SessionSuccess is always retured as true.
  793. */
  794.  
  795. static CMHandlerAddr CM_NEAR hasUseValueHandler(TOCValueHdrPtr baseValueHdr,
  796.                                                                                                 TOCObjectPtr type, 
  797.                                                                                                 CMHandlerAddr *newValueHandler,
  798.                                                                                                 CMHandlerAddr *metaDataHandler)
  799. {
  800.     ContainerPtr      container = baseValueHdr->container;
  801.     CM_CHAR                  *typeName;
  802.     MetaHandlerPtr metaHandler;
  803.     CMHandlerAddr  useValueHandler;
  804.     
  805.     SessionSuccess = true;                                            /* assume success                                                    */
  806.     
  807.     /* Check to see if the type object is for a global type name...                                                */
  808.     
  809.     if ((typeName = cmIsGlobalNameObject(type, CM_StdObjID_GlobalTypeName)) == NULL) 
  810.         return (NULL);                                                        /* no dynamic value for this type                    */
  811.         
  812.     /* Check to see if the type name has an associated metahandler...                                            */
  813.         
  814.     metaHandler = cmLookupMetaHandler((CM_UCHAR *)typeName, container->sessionData);
  815.     if (!SessionSuccess) {                                            /* if allocation error...                                    */
  816.         ERROR1(CM_err_HandlerError, typeName);        /* ...yell                                                                */
  817.         metaHandler = NULL;
  818.     }
  819.     
  820.     /* If there is a metahandler, check to see if the metahandler has a "use value"             */
  821.     /* handler...                                                                                                                                                    */
  822.  
  823.     if (metaHandler == NULL || metaHandler->metaHandler == NULL)
  824.         return (NULL);
  825.         
  826.     useValueHandler = (CMHandlerAddr)(*metaHandler->metaHandler)(NULL, (CMGlobalName)CMUseValueOpType);
  827.  
  828.     if (useValueHandler == NULL)                                 /* no "use value" handler ==> not dynamic    */
  829.         return (NULL);
  830.     
  831.     /* If the caller requested the "use value" handler, and we didn't find one, we assume */
  832.     /* the type is NOT for a dynamic value.  If we have the "use value" handler and the        */
  833.     /* new value handler is not needed, simply return the "use value" handler as the             */
  834.     /* function result.  However, if the "new value" handler is requested, and it's not     */
  835.     /* there, we have an error.  Note that if the "new value" handler is needed, then the    */
  836.     /* "metadata" handler will be also.  It's both or neither.  The "metadata" handler is    */
  837.     /* always required just the "new value" handler for CMNewValue().                                            */
  838.     
  839.     if (newValueHandler == NULL)                                 /* if "new value" handler not needed...        */
  840.         return (useValueHandler);                                    /* ...return "use value" handler                    */
  841.     
  842.     *newValueHandler = (CMHandlerAddr)(*metaHandler->metaHandler)(NULL, (CMGlobalName)CMNewValueOpType);
  843.     if (*newValueHandler == NULL) {                         /* return "new value" handler if we got it*/
  844.         ERROR1(CM_err_NoNewValueHandler,typeName);/* ...yell again                                                    */
  845.         SessionSuccess = false;
  846.         return (NULL);
  847.     }
  848.     
  849.     *metaDataHandler = (CMHandlerAddr)(*metaHandler->metaHandler)(NULL, (CMGlobalName)CMDefineMetaDataOpType);
  850.     if (*metaDataHandler == NULL) {                         /* return "metadata" handler if we got it    */
  851.         ERROR1(CM_err_NoMetaDataHandler,typeName);/* ...yell again and again                                */
  852.         SessionSuccess = false;
  853.         return (NULL);
  854.     }
  855.     
  856.     return (useValueHandler);                                        /* tell cmFollowTypes() it's dynamic             */
  857. }
  858.  
  859.  
  860. /*---------------------------------------------------------------------------------------*
  861.  | createDataPacket - allocate data packet for "new value" handler using type's metadata |
  862.  *---------------------------------------------------------------------------------------*
  863.  
  864.  For a given type, its "metadata" (determined by the type's "metadata" handler) is used to
  865.  consume constructorData parameters (a CMNewValue() "..." parameter list).  The parameters
  866.  are used to construct a data packet which will be passed to a "new value" handler.
  867.  
  868.  The packet is allocated using the memory allocator handler.  The caller (cmFollowTypes())
  869.  is expected to free the allocation.  The pointer to the packet is returned as the
  870.  function result.  The constructorData is updated to point at the first "..." parameter
  871.  not consumed (if any).
  872.  
  873.  Note, a null byte is added to the end of the data packet to make life a little easier for
  874.  cmVScanDataPacket() if that is used to extract the data into variables.
  875.  
  876.  NULL is returned if no packet is allocated because there is no metadata.
  877.  
  878.  SessionSuccess, a session global status switch, is returned false if an allocation error
  879.  or inconsistency data check is reported.  It is returned true otherwise.
  880. */
  881.  
  882. static CM_UCHAR *CM_NEAR createDataPacket(TOCObjectPtr type, CM_CHAR *metaData, va_list *constructorData)
  883. {
  884.     ContainerPtr      container = type->container;
  885.     CM_UCHAR             c, *s, *dataPacket, *dp;
  886.     CM_CHAR                 *mp, m, *typeName, insert[10];
  887.     CM_ULONG             packetSize, l;
  888.     CM_USHORT             d;
  889.     CMSize                 n;
  890.     void                     *p;
  891.     va_list                 ap;
  892.     
  893.     SessionSuccess = true;                                    /* assume success                                                            */
  894.     
  895.     /* If there is no metadata, return NULL to indicate there's no data packet...                    */
  896.     
  897.     if (metaData == NULL || *metaData == '\0') return (NULL);
  898.     
  899.     /* Prescan the metaData to see how large it is.  We must keep in sync with the                 */
  900.     /* CMNewValue() "..." parameters because some of the metadata refer may refer to             */
  901.     /* strings (%s and %*s).  Thus the size is not a simple function of metadata length.    */
  902.     
  903.     packetSize = 0;                                                    /* sum packet size in here                                        */
  904.     mp = metaData;                                                    /* mp will be metaData pointer                                */
  905.     ap = *constructorData;                                    /* leave original constructorData ptr alone        */
  906.     
  907.     while ((CMBoolean)(m = *mp++)) {                    /* scan the metaData...                                                */
  908.         if (m != Meta_Trigger) continue;            /* if not format specification, loop                    */
  909.         
  910.         switch ((CMBoolean)(m = *mp++)) {
  911.             case Meta_Value:                                                                                /* %v                                            */
  912.             case Meta_Object:                                                                                /* %o                                            */
  913.             case Meta_Ptr:        p = va_arg(ap, void *);                                /* %p                                            */
  914.                                                 packetSize += sizeof(void *);
  915.                                                 continue;
  916.             
  917.             case Meta_Char:        c = va_arg(ap, CM_UCHAR);                            /* %c                                            */
  918.                                                 packetSize += sizeof(CM_UCHAR);
  919.                                                 continue;
  920.             
  921.             case Meta_Short:    d = va_arg(ap, CM_USHORT);                        /* %d                                            */
  922.                                                 packetSize += sizeof(CM_USHORT);
  923.                                                 continue;
  924.             
  925.             case Meta_Long:     if (*mp == Meta_LongSuffix) ++mp;            /* %l[d]                                    */
  926.             case Meta_ID:            l = va_arg(ap, CM_ULONG);                /* %i                                            */
  927.                                                 packetSize += sizeof(CM_ULONG);
  928.                                                 continue;
  929.             
  930.             case Meta_Star:        if ((m = *mp++) != Meta_String) {            /* %*s                                        */
  931.                                                     insert[0] = '*';
  932.                                                     insert[1] = m;
  933.                                                     insert[2] = '\0';
  934.                                                     typeName = cmIsGlobalNameObject(type, CM_StdObjID_GlobalTypeName);
  935.                                                     ERROR3(CM_err_BadMetaSpec, insert, typeName, CONTAINERNAME);
  936.                                                     return (NULL);
  937.                                                 }
  938.                                                 n = va_arg(ap, CMSize);
  939.                                                 s = va_arg(ap, CM_UCHAR *);
  940.                                                 packetSize += n + sizeof(CMSize);
  941.                                                 continue;
  942.                                                 
  943.             case Meta_String:    s = va_arg(ap, CM_UCHAR *);                        /* %s                                            */
  944.                                                 packetSize += strlen((CM_CHAR *)s) + 1;
  945.                                                 continue;
  946.             
  947.             default:                    insert[0] = m;                                                /* oops!                                    */
  948.                                                 insert[1] = '\0';
  949.                                                 typeName = cmIsGlobalNameObject(type, CM_StdObjID_GlobalTypeName);
  950.                                                 ERROR3(CM_err_BadMetaSpec, insert, typeName, CONTAINERNAME);
  951.                                                 SessionSuccess = false;
  952.                                                 return (NULL);
  953.         } /* switch */
  954.     } /* while */
  955.     
  956.     /* Now that we got the size, and we're happy with the metaData, allocate the packet...*/
  957.     
  958.     dataPacket = (CM_UCHAR *)CMmalloc(packetSize + 1);    /* we add a null to the end        */
  959.     if (dataPacket == NULL) {
  960.         typeName = cmIsGlobalNameObject(type, CM_StdObjID_GlobalTypeName);
  961.         ERROR2(CM_err_NoDataPacket, typeName, CONTAINERNAME);
  962.         SessionSuccess = false;
  963.         return (NULL);
  964.     }
  965.     
  966.     /* Rescan the metadata and put the data into the newly allocated data packet.  Note,    */
  967.     /* data alignment is not assumed here.  We use memmove() to build the packet.                    */
  968.     
  969.     mp = metaData;                                                    /* mp will be metaData pointer again                    */
  970.     dp = dataPacket;                                                /* enter each data item at dp                                    */
  971.     ap = *constructorData;                                    /* set to consume parameters again                        */
  972.     
  973.     while ((CMBoolean)(m = *mp++)) {                    /* rescan the metaData...                                            */
  974.         if (m != Meta_Trigger) continue;            /* if not format specification, loop                    */
  975.         
  976.         switch ((CMBoolean)(m = *mp++)) {
  977.             case Meta_Value:                                                                                /* %v                                            */
  978.             case Meta_Object:                                                                                /* %o                                            */
  979.             case Meta_Ptr:        p = va_arg(ap, void *);                                /* %p                                            */
  980.                                                 memmove(dp, &p, sizeof(void *));
  981.                                                 dp += sizeof(void *);
  982.                                                 continue;
  983.             
  984.             case Meta_Char:        c = va_arg(ap, CM_UCHAR);                            /* %c                                            */
  985.                                                 memmove(dp, &c, sizeof(CM_UCHAR));
  986.                                                 dp += sizeof(CM_UCHAR);
  987.                                                 continue;
  988.             
  989.             case Meta_Short:    d = va_arg(ap, CM_USHORT);                        /* %d                                            */
  990.                                                 memmove(dp, &d, sizeof(CM_USHORT));
  991.                                                 dp += sizeof(CM_USHORT);
  992.                                                 continue;
  993.             
  994.             case Meta_Long:     if (*mp == Meta_LongSuffix) ++mp;            /* %l[d]                                    */
  995.             case Meta_ID:            l = va_arg(ap, CM_ULONG);                /* %i                                            */
  996.                                                 memmove(dp, &l, sizeof(CM_ULONG));
  997.                                                 dp += sizeof(CM_ULONG);
  998.                                                 continue;
  999.             
  1000.             case Meta_Star:        ++mp;                                                                    /* %*s                                        */
  1001.                                                 n = va_arg(ap, int);                                    
  1002.                                                 s = va_arg(ap, CM_UCHAR *);
  1003.                                                 memmove(dp, &n, sizeof(CMSize));            /* (prefix with "*")            */
  1004.                                                 dp += sizeof(CMSize);                                
  1005.                                                 memmove(dp, s, (size_t)n);
  1006.                                                 dp += n;
  1007.                                                 continue;
  1008.                                                 
  1009.             case Meta_String:    s = va_arg(ap, CM_UCHAR *);            /* %s                                            */
  1010.                                                 strcpy((CM_CHAR *)dp, (CM_CHAR *)s);
  1011.                                                 dp += strlen((CM_CHAR *)s) + 1;
  1012.                                                 continue;
  1013.         } /* switch */
  1014.     } /* while */
  1015.     
  1016.     *dp = (CM_UCHAR)0;                                            /* add null byte for cmVScanDataPacket()            */
  1017.     
  1018.     *constructorData = ap;                                    /* point constructorData at next set of args    */
  1019.     
  1020.     return (dataPacket);                                        /* return data packet to the caller                        */
  1021. }
  1022.  
  1023.  
  1024. /*---------------------------------------------------------*
  1025.  | newDynamicValue - create a new "dynamic" value (header) |
  1026.  *---------------------------------------------------------*
  1027.  
  1028.  This routine is called only by cmFollowTypes() to do the actual construction of the
  1029.  dynamic value for the specified base value.  The type is the type that is causing this
  1030.  dynamic value to be created.  If the base value is a "real" value, then the dynamic value
  1031.  is added to a "dynamic values" property for the object who owns the value.  The "dynamic
  1032.  value"s property is created for the first dynamic value for that object.  All further
  1033.  dynamic values with "real" value bases are simply added as values (headers) to that
  1034.  property.  If the base value is itself a dynamic value, then the newly created dynamic
  1035.  value is chained to the base (dynamic) value.  It is only a backward link from the new
  1036.  dynamic value.
  1037.  
  1038.  The pointer to the new dynamic value is returned.  NULL is returned if any errors are
  1039.  reported.  Note, the newOrUseValueName parameter is the string "CMNewValue" or
  1040.  "CMUseValue" and only used for some of the error inserts.
  1041.  
  1042.  By passing the returned dynamic value pointer as the base value to succeeding 
  1043.  newDynamicValue() calls, layers of dynamic values are constructed.
  1044.  
  1045.  See the dynamic value documentation at the start of this file for details on the data
  1046.  structures.
  1047. */
  1048.  
  1049. static TOCValueHdrPtr CM_NEAR newDynamicValue(TOCValueHdrPtr baseValueHdr,
  1050.                                                                                             TOCObjectPtr type,
  1051.                                                                                             CMMetaHandler metaHandler,
  1052.                                                                                                CMRefCon refCon,
  1053.                                                                                             CM_CHAR *newOrUseValueName)
  1054. {
  1055.     ContainerPtr            container = baseValueHdr->container;
  1056.     TOCObjectPtr           theObject;
  1057.     TOCValueHdrPtr       theDynamicValueHdr, theRealValueHdr;
  1058.     DynValueHdrExtPtr extensions;
  1059.     CMBoolean                    firstDynamicValue;
  1060.     CM_CHAR                     *typeName;
  1061.     
  1062.     if (metaHandler == NULL) {                                                /* we must have a metahandler!            */
  1063.         typeName = cmIsGlobalNameObject(type, CM_StdObjID_GlobalTypeName);
  1064.         ERROR2(CM_err_NoMetahandler, typeName, CONTAINERNAME);
  1065.         return (NULL);
  1066.     }
  1067.     
  1068.     /* It is an error for layered dynamic values to pass as the base value any other             */
  1069.     /* value header other than the most recent.  The code near the end of this routine         */
  1070.     /* chains layered dynamic values together with each value pointing back to its base.     */
  1071.     /* The original "real" value gets a pointer to the last one (in the dynValue union         */
  1072.     /* field of the value header). So by searching back up the chain to the "real" value     */
  1073.     /* we can get at this pointer to see if the base value passed is equal to it and             */
  1074.     /* report an error if it is not. Of course, the first time the "real" value is passed */
  1075.     /* and the dynValue will be NULL.  So we will know this case too.                                            */
  1076.     
  1077.     theRealValueHdr = baseValueHdr;                                        /* start with the current base            */
  1078.     while (IsDynamicValue(theRealValueHdr))                     /* loop back till we find 1st value    */
  1079.         theRealValueHdr = DYNEXTENSIONS(theRealValueHdr)->baseValue;/*that not dynamic value*/
  1080.     
  1081.     firstDynamicValue = (CMBoolean)(theRealValueHdr->dynValueData.dynValue == NULL);
  1082.     
  1083.     if (!firstDynamicValue &&                                                    /* do the base check...                            */
  1084.             theRealValueHdr->dynValueData.dynValue != baseValueHdr) {
  1085.         ERROR2(CM_err_BadRealValue, newOrUseValueName, CONTAINERNAME);        /* ...oops!                */
  1086.         return (NULL);
  1087.     }
  1088.     
  1089.     /* Create the dynamic value, i.e., a value (header) that is belongs to a special             */
  1090.     /* property of the caller's object that owns the base value.  The object "owning" the    */
  1091.     /* dynamic value is flagged to indicate there are dynamic values present in that             */
  1092.     /* object.  This protects it from premature deletion.  The flag is cleared when the     */
  1093.     /* last dynamic value for for the object is released.  We don't use the "protected"        */
  1094.     /* flag, which is used for similar purposes, just to be general.  Maybe we could             */
  1095.     /* someday have a protected object with dynamic values!                                                             */
  1096.     
  1097.     /* Note, the type we give the dynamic value is that of the type that caused this             */
  1098.     /* dynamic value to be generated.  We never use that fact.  But we got to give it         */
  1099.     /* something and it could aid in debugging this turkey! Do you really think I am             */
  1100.     /* going to get all this right the first time?  Want to buy a bridge?                                    */
  1101.         
  1102.     theObject = cmDefineObject(container, baseValueHdr->theProperty->theObject->objectID,
  1103.                                                          CM_StdObjID_DynamicValues,
  1104.                                                          0, /* 0 stops dup checks, was "type->objectID"                            */
  1105.                                                          NULL, container->generation, kCMDynValue, 
  1106.                                                          ObjectObject, &theDynamicValueHdr);
  1107.     if (theObject == NULL) return (NULL);
  1108.     theDynamicValueHdr->typeID = type->objectID;        /* give the type ID something valid        */
  1109.     theObject->objectFlags |= DynamicValuesObject;    /* make sure object is flagged                */
  1110.     
  1111.     /* The dynValueData field in the value header is a union with two alternatives.  The    */
  1112.     /* "dynValue" alternative is a pointer from the base value header to its dynamic            */
  1113.     /* value.  The "extensions" alternative is for the dynamic value header itself and        */
  1114.     /* points to the additional information, i.e., extensions, needed to accompany a             */
  1115.     /* dynamic value header.  A cmDefineObject() call always initializes the union field    */
  1116.     /* to NULL on the assumption a "normal" value header is being created.  Only in here    */
  1117.     /* do we create dynamic value headers.  Thus only in here do we fill in these fields. */
  1118.     /* We just got done creating the dynamic value header.  So the first thing to do is     */
  1119.     /* to allocate its extensions data.  So here goes...                                                                    */
  1120.         
  1121.     if ((extensions = (DynValueHdrExtPtr)CMmalloc(sizeof(DynValueHdrExt))) == NULL) {
  1122.         typeName = cmIsGlobalNameObject(type, CM_StdObjID_GlobalTypeName);
  1123.         ERROR2(CM_err_NoDynExtensions, typeName, CONTAINERNAME);
  1124.         return (NULL);
  1125.     }
  1126.     
  1127.     /* Point the extensions union alternative at the extensions space we just alloacted.    */
  1128.     /* Also, while we're screwing around in the dynamic value save the refCon passed in.    */
  1129.     /* The valueRefCon field is convenient so that CMGetValueRefCon() will be able to be    */
  1130.     /* used by the dynamic value handlers just as it would with normal values.                        */
  1131.     
  1132.     DYNEXTENSIONS(theDynamicValueHdr) = extensions;        /* point at the extensions data            */
  1133.     theDynamicValueHdr->valueRefCon     = refCon;                /* remember the refCon                            */
  1134.     theDynamicValueHdr->useCount        = 1;                        /* set use count to 1st use                    */
  1135.     
  1136.     /* We now must init the extensions fields.  Among the fields are the dynamic value        */
  1137.     /* handler pointer vector (our "v-table").  It consists of the pointers to the                */
  1138.     /* corresponding value operation handler, a "protect-from-recursive-use" flag, and        */
  1139.     /* the value "this" pointer.  We init all this stuff to NULL and "not called".  The        */
  1140.     /* metahandler passed to this routine will be used to fill in the handler pointers on    */
  1141.     /* first use (see cmGetDynHandlerAddress()).  It will set the "this" pointer too.            */
  1142.     /* To make it easier to init in the vector, the following macro is used:                            */
  1143.     
  1144.     #define InitDynVector(h) extensions->dynValueVector.h.handler     = NULL;  \
  1145.                                                      extensions->dynValueVector.h.thisValue = NULL;     \
  1146.                                                      extensions->dynValueVector.h.active       = false;
  1147.     
  1148.     InitDynVector(cmGetValueSize);                                        /* prepare handler vector...                */
  1149.     InitDynVector(cmReadValueData);
  1150.     InitDynVector(cmWriteValueData);
  1151.     InitDynVector(cmInsertValueData);
  1152.     InitDynVector(cmDeleteValueData);
  1153.     InitDynVector(cmGetValueInfo);
  1154.     InitDynVector(cmSetValueType);
  1155.     InitDynVector(cmSetValueGen);
  1156.     InitDynVector(cmReleaseValue);
  1157.     
  1158.     extensions->metaHandler = metaHandler;                        /* remember metahandler address            */
  1159.     extensions->baseValue      = baseValueHdr;                        /* point dyn value hdr to its base    */
  1160.     
  1161.     /* For layering dynamic values, a backward chain of dynamic value headers is formed     */
  1162.     /* from the new dynamic value header back to the original "real" value header.  The      */
  1163.     /* link is the baseValue extensions field set above. It always points to its base         */
  1164.     /* value (it is also used by CMGetBaseValue()).  As mentioned above, the dynValue         */
  1165.     /* union alternative in a "real" value header always points to the last dynamic             */
  1166.     /* value of the chain.  A CMUseValue() or CMNewValue() will always return the pointer */
  1167.     /* to the dynamic value at the end of the chain.  So, we always want to set the             */
  1168.     /* dynValue pointer to the new dynamic value header we created above.  Note also we        */
  1169.     /* use this pointer to make sure the value passed as a base to us here is indeed the    */
  1170.     /* pointer to the end of the chain.  We did this check near the start of this routine.*/
  1171.     /* From that check we get the pointer to the original "real" value.  So now we can         */
  1172.     /* set that pointer to the new end of chain.                                                                                    */
  1173.     
  1174.     theRealValueHdr->dynValueData.dynValue = theDynamicValueHdr;
  1175.     
  1176.     /* Layered dynamic values, i.e., dynamic values that have a dynamic value base are         */
  1177.     /* NOT treated as distinct values for special property whose chain we put them on when*/
  1178.     /* we did the cmDefineObject() above.  This means we must take such a value OFF the        */
  1179.     /* special property chain.  It's not getting lost though.  Remember we just got done     */
  1180.     /* pointing the "real" value dynValue at it.  Note, we flag this value header as           */
  1181.     /* being off the chain.  This makes it a simple test later when we want to delete         */
  1182.     /* these puppies off the layering chain (done by CMReleaseValue()).                                        */
  1183.     
  1184.     if (!firstDynamicValue) {                                                    /* do only if not the first time        */
  1185.         cmDeleteListCell(&theDynamicValueHdr->theProperty->valueHdrList, theDynamicValueHdr);
  1186.         cmNullListLinks(theDynamicValueHdr);
  1187.         theDynamicValueHdr->valueFlags |= ValueOffPropChain; /* mark as off the prop. chain    */
  1188.     } else                                                                                        /* if we have a NEW dynamic value...*/
  1189.         ++container->targetContainer->nbrOfDynValues;        /* ...keep count in targetContainer    */
  1190.     
  1191.     return (theDynamicValueHdr);                                            /* give caller the dynamic value        */
  1192. }
  1193.  
  1194.  
  1195. /*----------------------------------------------------------------------------------*
  1196.  | cmDeleteAllDynamicValueLayers - free memory for a single dynamic value layer set |
  1197.  *----------------------------------------------------------------------------------*
  1198.  
  1199.  This routine is used in two contexts; first, for error recovery to free all the memory
  1200.  for a newly allocated dynamic value layer set, and second, when freeing the entire TOC
  1201.  to make usre all memory for any "dangling" dynamic values are freed.
  1202.  
  1203.  The current top-most dynamic value layer is passed in theValueHdr.  The layers are
  1204.  back-linked up to the base "real" value.  All the dynamic value memory on this chain are
  1205.  freed.  If freeValueHdr is true, then we were creating dynamic values for CMNewValue().
  1206.  In that case, the real value itself is freed.  Really freed!  Not marked free as is the
  1207.  usual case.
  1208.  
  1209.  The cmMarkValueDeleted() is called to free the real value.  Its parameters are such that
  1210.  the value header memory will be freed rather than being put on its deleted values list.
  1211.  That routine will also delete the property if the value is the only one for its property.
  1212. */
  1213.  
  1214. void cmDeleteAllDynamicValueLayers(TOCValueHdrPtr theValueHdr, CMBoolean freeValueHdr)
  1215. {
  1216.     TOCValueHdrPtr nextLayer;
  1217.     TOCPropertyPtr theProperty;
  1218.     ContainerPtr      container = theValueHdr->container;
  1219.  
  1220.     if (IsDynamicValue(theValueHdr)) {
  1221.         theProperty = theValueHdr->theProperty;                        /* clear obj flag if last dyn valu*/
  1222.         if (cmCountListCells(&theProperty->valueHdrList) == 1)
  1223.             theProperty->theObject->objectFlags &= ~DynamicValuesObject;
  1224.         
  1225.         if (container->targetContainer->nbrOfDynValues>0) /* adjust total dyn value count        */
  1226.             --container->targetContainer->nbrOfDynValues;            
  1227.  
  1228.         while (IsDynamicValue(theValueHdr)) {                            /* free all these dyn values...        */
  1229.             nextLayer=DYNEXTENSIONS(theValueHdr)->baseValue;/* ...remember the next layer up    */
  1230.                 
  1231.             if ((theValueHdr->valueFlags & ValueOffPropChain) == 0) /* ...del. from property    */
  1232.                 cmDeleteListCell(&theProperty->valueHdrList, theValueHdr); /*(bottom layer only)*/
  1233.         
  1234.             CMfree(DYNEXTENSIONS(theValueHdr));                            /* ...free the extensions...            */
  1235.             CMfree(theValueHdr);                                                        /* ...and the header itself                */
  1236.             
  1237.             theValueHdr = nextLayer;                                                /*    loop up to the "real" value        */
  1238.         } /* while */
  1239.     }
  1240.     
  1241.     if (freeValueHdr)                                                                        /* if CMNewValue() or freeing TOC    */
  1242.         cmMarkValueDeleted(theValueHdr->container, theValueHdr, true);/* free new real value*/
  1243. }
  1244.  
  1245.  
  1246. /*-------------------------------------------------------------*
  1247.  | cmFollowTypes - follow a type through all of its base types |
  1248.  *-------------------------------------------------------------*
  1249.  
  1250.  This routine creates a dynamic value layers for the passed type and all of its base types,
  1251.  if any of these types have a "use value" handler.  This routine is only called by
  1252.  CMNewValue() or CMUseValue().  For CMNewValue(), "metadata" and "new value"  handlers are
  1253.  also required.  The top-most dynamic value header pointer is returned.  This should be
  1254.  returned from CMUseValue() or CMNewValue().  NULL is returned if an error is reported.
  1255.  The original "real" value is returned if no dynamic values are created.
  1256.     
  1257.  For CMUseValue(), isNewValue should be set to false.  It should only be set to true for
  1258.  CMNewValue().  Also for CMNewValue(), the constructorData must point at the CMNewValue()
  1259.  "..." parameters.  These are consumed as the base type metadata (returned from the 
  1260.  "metadata" handler) describes how to create data packets from the "..." parameters.  The
  1261.  packets, in turn, are passed to the "new value" handlers.  A "new value" handler uses its
  1262.  data packet to write (possibly different) data to its base value.  This written data will
  1263.  then be read and used by the "use value" handler.
  1264.  
  1265.  The "use value" handler is called for both the CMUseValue() and CMNewValue() cases.  If
  1266.  it's companion "new value" handler wrote data to its base value, the "use value" handler
  1267.  will probably read the data to create its refCon.  The refCon will be passed to all
  1268.  value handlers.  The "use value" handler returns its refCon along with another
  1269.  metahandler address that is used to get the value handler addresses.  These are then
  1270.  used to create the dynamic value.
  1271.  
  1272.  See dynamic value documentation at the start of this file for a description of the
  1273.  prototypes for the "metadata", "new value", and "use value" handlers, as well as the
  1274.  description of the metadata itself.
  1275.  
  1276.  To produce all the required dynamic values, cmFollowTypes() recursively follows the types,
  1277.  looking for base types as defined by CMAddBaseType().  Each type can have any number of
  1278.  base types.  The recursion effectively produces a depth-first search of all the base
  1279.  types.
  1280.  
  1281.  As each type is completed (i.e., no more base types for it), a dynamic value is created
  1282.  as described above.  That is, for CMNewValue(), a type's "metadata" handler instructs us
  1283.  on how many CMNewValue() "..." parameters to consume and how to construct their packet.
  1284.  That is passed to the "new value" handler so it can write some appropriate data to the
  1285.  base value.  The "use value" is called in all cases which reads the data written by "new
  1286.  value" to construct its refCon.  The refCon is returned here along with the metahandler
  1287.  address that will yield the value handler routine addresses.
  1288.  
  1289.  The refCon and metahandler address are passed to newDynamicValue() to construct one
  1290.  dynamic value (layer).  The resulting dynamic value is used as the base value for the
  1291.  next layer.  This produces the desired data structures.
  1292.  
  1293.  Note, because this routine searches through the types down to their leaves, and then
  1294.  generates the dynamic values on the way back "up", the CMNewValue() "..." parameters
  1295.  must be ordered for the "deepest" type first.  For example, given the following type
  1296.  inheritance heirarchy (read these as T1 inherits from T2 and T3, and so on):
  1297.  
  1298.                                       T4      T5
  1299.                                         *    *
  1300.                                          *  *
  1301.                                   T2      T3
  1302.                                     *    *
  1303.                                      *  *
  1304.                                       T1
  1305.                             
  1306.  The depth-first search, starting at T1, yields the sequence: T2 T4 T5 T3 T1.  Then this
  1307.  is the order the CMNewValue() "..." parameters must be in.  It is also the order the
  1308.  dynamic value layers are generated.  T1 is the top layer, and T2 the bottom.  T1 would be
  1309.  the dynamic value returned from CMUseValue() or CMNewValue().
  1310. */
  1311.  
  1312. TOCValueHdrPtr cmFollowTypes(TOCValueHdrPtr baseValueHdr, TOCObjectPtr type,
  1313.                                                          CMBoolean isNewValue, va_list *constructorData)
  1314. {
  1315.     ContainerPtr      container = baseValueHdr->container;
  1316.     TOCObjectPtr     baseType;
  1317.     TOCPropertyPtr baseTypeProperty;
  1318.     TOCValueHdrPtr theValueHdr, baseValueHdr0;
  1319.     TOCValuePtr      theValue;
  1320.     CMHandlerAddr     useValueHandler, newValueHandler, metaDataHandler; 
  1321.     CM_UCHAR             *dataPacket;
  1322.     CM_CHAR                 *newOrUseValueName, *metaData, *typeName;
  1323.     CMRefCon             refCon;
  1324.     CMMetaHandler  metaHandler;
  1325.     CMBoolean             success;
  1326.     
  1327.     /* If any errors are reported, and the error handler returns, we NULL out the base        */
  1328.     /* value.  That essentialy "puts the breaks" on the dynamic value generation.  The         */
  1329.     /* NULL result will work ist way back to CMNewValue() or CMUseValue() which it will        */
  1330.     /* return.                                                                                                                                                         */
  1331.     
  1332.     /* Note, as soon as we detect an error in here, we free all the dynamic values we          */
  1333.     /* created for the "real" value.  That should put things back the way they were             */
  1334.     /* originally.  Of course, error reporters are not suppose to return.  We're being        */
  1335.     /* "kind" here just in case they do.                                                                                                    */
  1336.     
  1337.     if (baseValueHdr == NULL) return (NULL);
  1338.     
  1339.     baseValueHdr0 = baseValueHdr;                                /* save current baseValueHdr for errors        */
  1340.     
  1341.     /* If the current type has any base types, call cmFollowTypes() recursively for each    */
  1342.     /* of those base types.  That brings us back to here where we will check each of             */
  1343.     /* those base types for base types of their own.  This process continues down to the    */
  1344.     /* "bottom", i.e., leaf types, where we bypass this piece of code. The types are then */
  1345.     /* processed as the recursion unwinds.  It is this code, then the effects the depth-    */
  1346.     /* first processing of the base types.                                                                                                 */
  1347.     
  1348.     baseTypeProperty = cmGetObjectProperty(type, CM_StdObjID_BaseTypes);
  1349.     
  1350.     if (baseTypeProperty != NULL) {                            /* process this type's base types                    */
  1351.         theValueHdr = (TOCValueHdrPtr)cmGetListHead(&baseTypeProperty->valueHdrList);
  1352.         
  1353.         if (theValueHdr != NULL) {                                /* double check for value hdr                            */
  1354.             theValue = (TOCValuePtr)cmGetListHead(&theValueHdr->valueList); /* 1st base ID        */
  1355.             
  1356.             while (theValue != NULL) {
  1357.                 baseType = cmFindObject(container->toc, theValue->value.imm.ulongValue);
  1358.                 if (baseType) {
  1359.                     baseValueHdr = cmFollowTypes(baseValueHdr, baseType, isNewValue, constructorData);
  1360.                     if (baseValueHdr == NULL) return (NULL);
  1361.                 }
  1362.             
  1363.                 theValue = (TOCValuePtr)cmGetNextListCell(theValue); /* look at next base type    */
  1364.             } /* while */
  1365.         
  1366.         } /* theValueHdr */
  1367.     } /* baseTypeProperty */
  1368.     
  1369.     /* We are now at a type which has either has no base types or that had all of its base*/
  1370.     /* types processed (again through here).  This is where we determine whether the type    */
  1371.     /* will spawn a dynamic value.  We call hasUseValueHandler() that checks for the            */
  1372.     /* the "use value" handler for the type.  It also checks for the "metadata" and "new     */
  1373.     /* value" handlers if we were originally called from CMNewValue().  If it doesn't pass*/
  1374.     /* the tests we return the original base value unchanged.  If it does pass the tests, */
  1375.     /* we create a new dynamic value (layer).                                                                                         */
  1376.     
  1377.     /* As descibed in the documentation at front of this file, we call the "metadata" and    */
  1378.     /* "new value" handlers first only for CMNewValue(). For CMNewValue() or CMUseValue() */
  1379.     /* we then call the "use value handler.  For the "new value" call we must first build */
  1380.     /* the data packet from the CMNewValue() "..." parameters using the metadata returned    */
  1381.     /* from the "metadata" handler.  The packet is sent to the "new value" handler. There */
  1382.     /* it can use CMScanDataPacket() to extract the packet back into variables.                        */
  1383.     
  1384.     /* Note, as the packets for the layers are created, the constructorData parameter            */
  1385.     /* pointer marches across the CMNewValue() "..." parameters.  Since we are building        */
  1386.     /* the layers as we move up the inheritance hierarchy, from bottom to top, that is         */
  1387.     /* what determines the parameter specifications discussed above.  Further, it is also    */
  1388.     /* why the constructorData is a va_list*.  The higher layers must know what the                */
  1389.     /* current parameter pointer is.  If we had built the hierarchy from top to bottom we    */
  1390.     /* wouldn't have needed the "*".                                                                                                            */
  1391.     
  1392.     /* And speaking of layers -- the newDynamicValue() call is the one responsible for        */
  1393.     /* creating a layer.  It builds upon the current baseValueHdr and returns a new one.    */
  1394.     /* they are passed up the recursive calls as the function result to build the layer     */
  1395.     /* chain.  The final, top-most layer, is the one eventually returned to CMNewValue()    */
  1396.     /* or CMUseValue(), who then returns it to the user.                                                                    */
  1397.     
  1398.     useValueHandler = hasUseValueHandler(baseValueHdr, type, isNewValue ? &newValueHandler : NULL, &metaDataHandler);
  1399.     if (!SessionSuccess) return (NULL);
  1400.     
  1401.     if (useValueHandler) {                                            /* if dynamic value layer is to be created*/
  1402.         if (isNewValue) {                                                    /* extra stuff for CMNewValue()...                */
  1403.             
  1404.             /* Here we're doing a CMNewValue() -- call the "metadata" handler to get this         */
  1405.             /* type's metadata.  We can then use that to build a data packet.                                    */
  1406.             
  1407.             metaData = (*(CM_CHAR *(*)(CMType))metaDataHandler)((CMType)type);
  1408.             
  1409.             dataPacket = createDataPacket(type,metaData,constructorData); /*create data pkt...*/
  1410.             if (!SessionSuccess) {                                                                        /* ...if it failed...        */
  1411.                 cmDeleteAllDynamicValueLayers(baseValueHdr0,isNewValue);/* ...delete all layers    */
  1412.                 return (NULL);                                                                                    /* ...abort creation        */
  1413.             }
  1414.             
  1415.             /* Call the "new value" handler.  It should use the data packet to write data to    */
  1416.             /* its base value.                                                                                                                                */
  1417.             
  1418.             success = (*(CMBoolean (*)(CMValue, CMType, CMDataPacket))newValueHandler)((CMValue)baseValueHdr, (CMType)type, (CMDataPacket)dataPacket);
  1419.             
  1420.             if (dataPacket != NULL) CMfree(dataPacket);                                /* free the packet            */
  1421.             newOrUseValueName = "CMNewValue";
  1422.         } else {
  1423.             newOrUseValueName = "CMUseValue";
  1424.             success = true;
  1425.         }
  1426.         
  1427.         /* In all cases we call the "use value" handler. It should read the data written by */
  1428.         /* the "new value" handler to create its refCon.  It returns the refCon and a             */
  1429.         /* methandler pointer    that we will use to get the value operation handler addresses.*/
  1430.         /* This is then passed to newDynamicValue() to build the new dynamic value (layer). */
  1431.         
  1432.         if (success) {
  1433.             metaHandler = NULL;                                            /* "use value" must set this or error            */
  1434.             success = (*(CMBoolean (*)(CMValue, CMType, CMMetaHandler*, CMRefCon*))useValueHandler)((CMValue)baseValueHdr, (CMType)type, &metaHandler, &refCon);
  1435.             if (success) {
  1436.                 if (metaHandler == NULL) {                        /* we must get a methandler back!                    */
  1437.                     typeName = cmIsGlobalNameObject(type, CM_StdObjID_GlobalTypeName);
  1438.                     ERROR2(CM_err_NoDynMetahandler, typeName, CONTAINERNAME);
  1439.                     success = false;
  1440.                 } else
  1441.                     baseValueHdr = newDynamicValue(baseValueHdr, type, metaHandler, refCon, newOrUseValueName);
  1442.             }
  1443.         }
  1444.         
  1445.         if (!success || baseValueHdr == NULL) {        /* if something went wrong...                            */
  1446.             cmDeleteAllDynamicValueLayers(baseValueHdr0, isNewValue); /* ...free the layers        */
  1447.             baseValueHdr = NULL;                                        /* this will abort the recursion                    */
  1448.         }
  1449.     }
  1450.     
  1451.     return (baseValueHdr);                                            /* return dynamic value layer                            */
  1452. }
  1453.  
  1454.  
  1455. /*--------------------------------------------------------------*
  1456.  | cmGetDynHandlerAddress - get a dynamic value handler address |
  1457.  *--------------------------------------------------------------*
  1458.  
  1459.  A dynamic value handler is callable if it exists (of course!) and it is not being used
  1460.  recursively.  The vectorEntry points to the dynamic value entry in its vector belonging
  1461.  to the extensions of the passed dynamic value.  If this is not the first use of the
  1462.  handler, the vector entry contains the handler address and its associated ("this") value
  1463.  (discussed below).  If it is first use, cmGetDynHandlerAddress() must find the
  1464.  ("inherited") handler address and its associated "this" value.
  1465.  
  1466.  No matter which case it is, the "this" value is returned as the function result.  NULL
  1467.  is returned if an error is reported (discussed later).
  1468.   
  1469.  The returned value, and the one saved in the vector entry may not be the same.  They are
  1470.  if the passed value has a handler.  If it doesn't, an "inherited" handler, from one of
  1471.  the dynamic value's base values is used. The value associated for whoever has the handler 
  1472.  is the "owning" value.  In C++ terms, it is the "this" pointer.
  1473.  
  1474.  In the limit, we could end up using the original "real" value that spawned the dynamic
  1475.  value(s).  In that is indeed the case, we end up using the calling routine which will
  1476.  always be an API value operation (see   DynValus.h    to see how we use the macros that
  1477.  call this routine).
  1478.  
  1479.  The found handler address and "this" pointer are saved in the passed dynamic value's
  1480.  vector entry so we don't have to do the search on successive uses.  The "this" pointer
  1481.  and handler address are also saved in the vector entry corresponding to "this" (unless,
  1482.  of course, it is the "real" value).
  1483.   
  1484.  In the vector entry there is also a boolean flag that tells us whether the handler is
  1485.  currently active, i.e., in the call chain.  If it is we have a recursion attempt.  This
  1486.  causes an error report and NULL to be returned.  Since we will always find the handler
  1487.  or use the "real" value, we can never get an error from that.  The recursion is the only
  1488.  error condition.
  1489.     
  1490.                                              Caution -- Implementation/portability Note
  1491.  
  1492.  In order to get at the corresponding dynamic vector in the vector of the final "this"
  1493.  value, we convert the original vectorEntry to an offset in the value header extensions,
  1494.  i.e., offset to the vector entry within a DynValueHdrExt struct.  This is used to
  1495.  "relocate" to the corresponding vector entry.  I point this out only to make you aware of
  1496.  this "trick" (s it really a trick?).  It appears to be standard ANSI C because fields in
  1497.  a struct are supposed to be ordered by ascending address.  In other words it is NOT
  1498.  implementation defined how to lay out fields in a struct (except for alignment).  If your
  1499.  compiler thinks otherwise, this will be a problem area.  I just thought you would like to
  1500.  know!  
  1501.  
  1502.  Oh, by the way, the code we're talking about here is near the end of the routine.
  1503. */
  1504.  
  1505. CMValue cmGetDynHandlerAddress(CMValue value, DynamicValueVectorEntriesPtr vectorEntry,
  1506.                                                              CMconst_CMGlobalName operationType, CM_CHAR *routineName)
  1507. {
  1508.     CM_LONG             entryOffset;
  1509.     CMValue              origValue;
  1510.     ContainerPtr     container;
  1511.     CMHandlerAddr    handler;
  1512.  
  1513.     /* It's an error to attempt a recursive call...                                                                                */
  1514.     
  1515.     if (vectorEntry->active) {                                                /* error if recursing...                        */
  1516.         container = ((TOCValueHdrPtr)value)->container;
  1517.         ERROR2(CM_err_HandlerRecursed, routineName, CONTAINERNAME);
  1518.         return (NULL);
  1519.     }
  1520.     
  1521.     /* We are not recursing and this is not the first time we're using this handler, just    */
  1522.     /* return the "this" pointer associated with the handler we found on an earlier call.    */
  1523.     /* They were initialized to NULL when the vector was allocated.  We cannot test the        */
  1524.     /* handler pointer because it will not be set if the "this" pointer is for a base            */
  1525.     /* "real" value.                                                                                                                                            */
  1526.     
  1527.     if (vectorEntry->thisValue != NULL) return (vectorEntry->thisValue);
  1528.     
  1529.     /* This is the first call to the handler.  We now must search up the dynamic value         */
  1530.     /* chain, starting with the passed dynamic value, looking for the first dynamic value */
  1531.     /* that supplies the handler. The handler is accessed in the usual way via its dynamic*/
  1532.     /* value metahandler.                                                                                                                                     */
  1533.     
  1534.     origValue = value;                                                                /* remember starting dynamic value    */
  1535.     
  1536.     for (;;) {                                                                                /* loop till we find the handler...    */
  1537.         handler = (CMHandlerAddr)(*DYNEXTENSIONS(value)->metaHandler)(NULL, operationType);
  1538.         if (handler != NULL) break;                                            /* break when we find the handler        */
  1539.         
  1540.         /* If not found, we must get the current value's base value.  We can do this until    */
  1541.         /* we reach the original "real" value. If we do reach it, then that stops the search*/
  1542.         /* and it is the "real" value we return. In that case, there is no handler because    */
  1543.         /* the calling API value routine will directly operate on the value.  Thus we leave    */
  1544.         /* the handler address in the original value alone.  Of course we set the "this"        */
  1545.         /* pointer.  The next time the dynamic value is used, we will return the "real"         */
  1546.         /* value.  As discussed in   DynValus.h   , the caller tests the returned value         */
  1547.         /* to see if it is still a dynamic value.  If it isn't, the handler use is bypassed.*/
  1548.         
  1549.         value = (CMValue)(DYNEXTENSIONS(value)->baseValue);/* basically a CMGetBaseValue()    */
  1550.         if (!IsDynamicValue(value)) {                                        /* if we reached the "real" value...*/
  1551.             vectorEntry->thisValue = value;                                /* save "this" value for next time    */
  1552.             return (value);                                                                /* return the "real" value as "this"*/
  1553.         }
  1554.     } /* for */
  1555.     
  1556.     /* Set the "this" pointer and handler address in the original vector entry for the        */
  1557.     /* next time we use it.  Note that we can only exit the above "for" loop if we find     */
  1558.     /* the handler.  If we loop up to the "real" value without finding it, we exit the         */
  1559.     /* routine from inside the loop after saving the "this" pointer as we do here.                */
  1560.     
  1561.     vectorEntry->thisValue = value;                                        /* remember "this"                                    */
  1562.     vectorEntry->handler     = handler;                                    /* remember its handler address            */
  1563.     
  1564.     /* Just to be safe, we want to copy the "this" pointer and handler address in the            */
  1565.     /* vector entry corresponding to "this". Of course we only need to do this if we             */
  1566.     /* "inherited" a handler (i.e., we looped up to a base dynamic (but not real) value.    */
  1567.     /* Note, this is where we do the struct offset relocation warned about earlier.                */
  1568.     
  1569.     if (value != origValue) {                                                    /* if "inherited"...                                */
  1570.         entryOffset = (CM_CHAR *)vectorEntry - (CM_CHAR *)DYNEXTENSIONS(origValue); /* relocate...*/
  1571.         vectorEntry  = (DynamicValueVectorEntriesPtr)((CM_CHAR *)DYNEXTENSIONS(value) + entryOffset);
  1572.         vectorEntry->thisValue = value;                                    /* set "this"s vector entry                    */
  1573.         vectorEntry->handler     = handler;
  1574.     }
  1575.     
  1576.     return (value);                                                                        /* return "this"                                        */
  1577. }
  1578.  
  1579.  
  1580. /*-------------------------------------------------------------*
  1581.  | cmVScanDataPacketGuts - extract the data from a data packet |
  1582.  *-------------------------------------------------------------*
  1583.  
  1584.  This routine is the "guts" of the routine CMScanDataPacket().  It is used to extract the
  1585.  fields of a data packet created from CMNewValue() "..." parameters according to the
  1586.  specified metadata and place it in the "dataInitParams" parameters.  Each dataInitParams
  1587.  parameter must be a pointer; extracted data read from the data packet are stored into the
  1588.  locations pointed to by the pointers.
  1589.  
  1590.  The Container Manager accesses the metadata through a "metadata" handler for the type to
  1591.  build the data packet.  cmVScanDataPacket() inverts the operation and allows a "new
  1592.  value" handler to extract the data back into distinct variables. The "new value" handler
  1593.  can use its own "metadata" handler to pass to the CMScanDataPacket() routine to extract
  1594.  the data.
  1595.  
  1596.  The function returns the number of data items extracted and assigned to the parameters.
  1597.  This could be 0 if the type does not have any metadata (or if an error is reported).
  1598.  
  1599.  NULL may be passed as the dataPacket or metaData pointer to indicate there is no
  1600.  metadata.  
  1601.   
  1602.  The metadata format is discussed in the documentation at the start of this file.  The only
  1603.  special case is for the "%*s" format specification.  This generates a fixed length string
  1604.  (not null terminated) of n characters, where n is determined from a parameter in the
  1605.  CMNewValue() "..." paramters.  The value of n is explicitly written to the packet data in
  1606.  front of the string.  For symmetry (and so we can determine the number of characters to
  1607.  extract from the packet data), we return the value of n to an explict parameter pointer
  1608.  passed here.  Thus the parameter pointer list passed to this routine should be identical
  1609.  to the "..." parameters passed to a CMNewValue() "..." parameter list (at least the
  1610.  portion corresponding to this type).
  1611.  
  1612.  Here's a word of caution about "%s" -- watch it!  As discussed in note 4 of the format
  1613.  specification comments, we COPY the string from the packet to the place pointed to by the
  1614.  corresponding dataInitParams parameter.  This is a pitfall (I fell into it, hence these
  1615.  comments).  C strings are thought of as pointers (at least I think of them that way). So there is a
  1616.  tendency to use "%s" like you would in "printf()".  WRONG!  What you really want is a
  1617.  pointer, so use "%p"!
  1618. */
  1619.  
  1620. CM_ULONG cmVScanDataPacketGuts(TOCObjectPtr type, CM_CHAR *metaData,
  1621.                                                                         CM_UCHAR *dataPacket, va_list dataInitParams)
  1622. {
  1623.     ContainerPtr      container = type->container;
  1624.     CM_UCHAR           *dp, *p;
  1625.     CM_CHAR                 *mp, m, *typeName, insert[10];
  1626.     CM_ULONG              nbrAssigned;
  1627.     CMSize                 n;
  1628.     
  1629.     /* If there is not data packet or not metaData, there is nothing to do...                            */
  1630.  
  1631.     if (dataPacket == NULL || metaData == NULL || *metaData == '\0')
  1632.         return (0);
  1633.         
  1634.     /* Scan the metaData and extract the dataPacket fields according to the that metadata.*/
  1635.     /* Each field is put into the location pointed to by the next dataInitParams                    */
  1636.     /* parameter.                                                                                                                                                    */
  1637.     
  1638.     nbrAssigned = 0;                                                                /* count nbr of parameters assigned        */
  1639.     mp = metaData;                                                                    /* mp will be encoding pointer                */
  1640.     dp = dataPacket;                                                                /* each data packet item starts at dp    */
  1641.     
  1642.     while ((CMBoolean)(m = *mp++))    {                                    /* scan the encoding...                                */
  1643.         if (m != Meta_Trigger) continue;                            /* if not format specification, loop    */
  1644.         
  1645.         p = va_arg(dataInitParams, CM_UCHAR *);                /* point at next parameter                        */
  1646.         
  1647.         switch ((CMBoolean)(m = *mp++)) {
  1648.             case Meta_Value:                                                                                    /* %v                                        */
  1649.             case Meta_Object:                                                                                    /* %o                                        */
  1650.             case Meta_Ptr:        memmove(p, dp, sizeof(void *));                    /* %p                                        */
  1651.                                                 dp += sizeof(void *);
  1652.                                                 ++nbrAssigned;
  1653.                                                 continue;
  1654.                                 
  1655.             case Meta_Char:        memmove(p, dp, sizeof(CM_UCHAR));    /* %c                                        */
  1656.                                                 dp += sizeof(CM_UCHAR);
  1657.                                                 ++nbrAssigned;
  1658.                                                 break;
  1659.                                 
  1660.             case Meta_Short:    memmove(p, dp, sizeof(CM_USHORT));            /* %d                                        */
  1661.                                                 dp += sizeof(CM_USHORT);
  1662.                                                 ++nbrAssigned;
  1663.                                                 continue;
  1664.             
  1665.             case Meta_Long:     if (*mp == Meta_LongSuffix) ++mp;                /* %l[d]                                */
  1666.             case Meta_ID:            memmove(p, dp, sizeof(CM_ULONG));                /* %i                                        */
  1667.                                                 dp += sizeof(CM_ULONG);
  1668.                                                 ++nbrAssigned;
  1669.                                                 continue;
  1670.             
  1671.             case Meta_Star:        if ((m = *mp++) != Meta_String) {                /* %*s                                    */
  1672.                                                     insert[0] = '*';
  1673.                                                     insert[1] = m;
  1674.                                                     insert[2] = '\0';
  1675.                                                     typeName = cmIsGlobalNameObject(type, CM_StdObjID_GlobalTypeName);
  1676.                                                     ERROR3(CM_err_BadMetaSpec, insert, typeName, CONTAINERNAME);
  1677.                                                     return (0);
  1678.                                                 }
  1679.                                                 memmove(&n, dp, sizeof(CMSize));
  1680.                                                 memmove(p,  dp, sizeof(CMSize));
  1681.                                                 dp += sizeof(CMSize);
  1682.                                                 ++nbrAssigned;
  1683.                                                 p = va_arg(dataInitParams, CM_UCHAR *);
  1684.                                                 memmove(p, dp, (size_t)n);
  1685.                                                 dp += n;
  1686.                                                 ++nbrAssigned;
  1687.                                                 continue;
  1688.                                                 
  1689.             case Meta_String:    strcpy((CM_CHAR *)p, (CM_CHAR *)dp);        /* %s                                        */
  1690.                                                 ++nbrAssigned;                                                    /* see caution comments!*/
  1691.                                                 continue;
  1692.         
  1693.             default:                    insert[0] = m;                                                    /* oops!                                */
  1694.                                                 insert[1] = '\0';
  1695.                                                 typeName = cmIsGlobalNameObject(type, CM_StdObjID_GlobalTypeName);
  1696.                                                 ERROR3(CM_err_BadMetaSpec, insert, typeName, CONTAINERNAME);
  1697.                                                 return (0);
  1698.         } /* switch */
  1699.     } /* while */
  1700.  
  1701.     return (nbrAssigned);
  1702. }
  1703.                                                           
  1704.                                                             CM_END_CFUNCTIONS
  1705.