home *** CD-ROM | disk | FTP | other *** search
/ Apple WWDC 1996 / WWDC96_1996 (CD).toast / Technology Materials / QuickTime VR / MacOS / QuickDraw™ 3D 1.0.6F4 SDK / Samples / SampleCode / CustomAttribute / CustomAttribute_Lib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-02-02  |  32.7 KB  |  1,574 lines  |  [TEXT/CWIE]

  1. /*
  2.  * CustomIO_Lib.c
  3.  *
  4.  *    Demo/Template for writing custom IO functions
  5.  *    
  6.  *    Custom Attribute example
  7.  */
  8. #include <QD3D.h>
  9. #include <QD3DSet.h>
  10.  
  11. #include <QD3DIO.h>
  12. #include <QD3DString.h>
  13. #include <QD3DGeometry.h>
  14. #include <QD3DGroup.h>
  15.  
  16. #include <stdlib.h>
  17.  
  18. #include "CustomAttribute_Lib.h"
  19.  
  20. /*
  21.  *    This file contains the implementation for the following custom attributes
  22.  *    
  23.  *    name - contains a string object, can be attached to any object below shape
  24.  *    scle - scale, determines the relative scale of an object/group with 1 meter
  25.  *    upvt - up vector, determines the vertical orientation of an object/group
  26.  *    fwvt - forward vector, determines the front orientation of an object/group
  27.  *    url     - allows you to attach an URL to an object/group
  28.  */
  29.  
  30. /*
  31.  * Globals
  32.  */
  33. static TQ3ObjectClass    gNameAttributeClass = NULL,
  34.                         gScaleAttributeClass = NULL,
  35.                         gUpVectorAttributeClass = NULL,
  36.                         gForwardVectorAttributeClass = NULL,
  37.                         gW3AnchorClass = NULL,
  38.                         gW3InlineClass = NULL,
  39.                         gWWWAnchorClass = NULL;
  40.  
  41.  
  42. /*
  43.  *    These are the registration calls for the individual attributes
  44.  */
  45. TQ3Status NameAttribute_Register( void);
  46.  
  47. TQ3Status NameAttribute_Unregister( void);
  48.  
  49. TQ3Status ScaleAttribute_Register( void);
  50.     
  51. TQ3Status ScaleAttribute_Unregister( void);
  52.  
  53. TQ3Status UpVectorAttribute_Register( void);
  54.  
  55. TQ3Status UpVectorAttribute_Unregister( void);
  56.  
  57. TQ3Status ForwardDirectionAttribute_Register( void);
  58.  
  59. TQ3Status ForwardDirectionAttribute_Unregister( void);
  60.  
  61. TQ3Status W3Anchor_Register( void);
  62.  
  63. TQ3Status W3Anchor_UnRegister( void);
  64.  
  65. TQ3Status W3Anchor_Unregister( void);
  66.  
  67. TQ3Status W3Inline_Register( void);
  68.  
  69. TQ3Status W3Inline_Unregister( void);
  70.  
  71. TQ3Status WWWAnchor_Register( void );
  72.  
  73. TQ3Status WWWAnchor_Unregister( void);
  74.  
  75. /**********************************************************************************************
  76.  *
  77.  *                        PUBLIC ROUTINES FOR REGISTRATION AND UNREGISTRATION
  78.  *
  79.  **********************************************************************************************/
  80.  
  81. void RegisterAllCustomAttributes(void)
  82. {
  83.     NameAttribute_Register();
  84.  
  85.     ScaleAttribute_Register();
  86.     
  87.     UpVectorAttribute_Register();
  88.  
  89.     ForwardDirectionAttribute_Register();
  90.  
  91.     W3Anchor_Register();
  92.  
  93.     W3Inline_Register();
  94.  
  95.     WWWAnchor_Register();
  96. }
  97.  
  98.  
  99. void UnregisterAllCustomAttributes(void)
  100. {
  101.     NameAttribute_Unregister();
  102.  
  103.     ScaleAttribute_Unregister();
  104.     
  105.     UpVectorAttribute_Unregister();
  106.  
  107.     ForwardDirectionAttribute_Unregister();
  108.  
  109.     W3Anchor_Unregister();
  110.  
  111.     W3Inline_Unregister();
  112.  
  113.     WWWAnchor_Unregister();
  114. }
  115.  
  116. /**********************************************************************************************
  117.  *
  118.  *                                        NAME custom attribute
  119.  *
  120.  **********************************************************************************************/
  121.  
  122.  
  123. /*
  124.  * Utility function to add a name on an shape object, geometry object, or attribute set
  125.  */
  126.  
  127. TQ3Status    SetName(TQ3Object object, char    *name)
  128. {
  129.     TQ3StringObject    string = NULL;
  130.     TQ3AttributeSet    set = NULL;
  131.     TQ3Status        status = kQ3Success;
  132.     
  133.     if( Q3Object_IsType(object, kQ3SharedTypeShape) == kQ3True ) {
  134.         
  135.         string = Q3CString_New(name);
  136.         
  137.         if( string == NULL) {
  138.             status = kQ3Failure;
  139.             goto cleanExit;
  140.         }
  141.             
  142.         if( Q3Object_IsType(object, kQ3ShapeTypeGeometry) == kQ3True ) {
  143.             
  144.             Q3Geometry_GetAttributeSet(object, &set);
  145.             
  146.             if( set == NULL ) {
  147.                 set = Q3AttributeSet_New();
  148.                 if( set == NULL ) {
  149.                     status = kQ3Failure;
  150.                     goto cleanExit;
  151.                 }
  152.                 Q3Geometry_SetAttributeSet(object, set);
  153.             }
  154.         } else {
  155.             Q3Shape_GetSet(object, &set);
  156.             
  157.             if( set == NULL ) {
  158.                 set = Q3Set_New();
  159.                 if( set == NULL ) {
  160.                     status = kQ3Failure;
  161.                     goto cleanExit;
  162.                 }
  163.                 Q3Shape_SetSet(object, set);
  164.             }
  165.         }
  166.             
  167.         if( Q3Set_Add(set, kElementTypeName, &string) == kQ3Failure ) {
  168.             status = kQ3Failure;
  169.             goto cleanExit;
  170.         }
  171.     } else if( Q3Object_IsType(object, kQ3SharedTypeSet) == kQ3True ) {
  172.         string = Q3CString_New(name);
  173.         
  174.         if( string == NULL) {
  175.             status = kQ3Failure;
  176.             goto cleanExit;
  177.         }
  178.         
  179.         if( Q3AttributeSet_Add(object, kElementTypeName, &string) == kQ3Failure ) {
  180.             status = kQ3Failure;
  181.             goto cleanExit;
  182.         }
  183.     } else 
  184.         status = kQ3Failure;
  185.         
  186. cleanExit:
  187.     if( string )
  188.         Q3Object_Dispose(string);
  189.     if( set )
  190.         Q3Object_Dispose(set);
  191.     return status;
  192. }
  193.  
  194. /*
  195.  * Static Functions
  196.  */
  197.  
  198. static TQ3Status NameAttribute_Traverse(
  199.     TQ3Object                unused,
  200.     TQ3StringObject            *stringObject,
  201.     TQ3ViewObject            view)
  202. {
  203.     (void) unused;
  204.     
  205.     if (stringObject == NULL || *stringObject == NULL)
  206.         return kQ3Success;
  207.  
  208.     Q3View_SubmitWriteData(view,0,0,0);
  209.  
  210.     if (Q3Object_Submit( *stringObject, view) == kQ3Failure)
  211.         return kQ3Failure;
  212.  
  213.     return kQ3Success;
  214. }
  215.  
  216. static TQ3Status NameAttribute_ReadData(
  217.     TQ3SetObject            attributeSet,
  218.     TQ3FileObject            file)
  219. {
  220.     TQ3StringObject        stringObject;
  221.     TQ3Status            status;
  222.     
  223.     stringObject = Q3File_ReadObject(file);
  224.         
  225.     status = Q3Set_Add(attributeSet, kElementTypeName, &stringObject);
  226.     
  227.     Q3Object_Dispose(stringObject);
  228.  
  229.     /*
  230.         Note that the string object has a reference count of 1,
  231.         which will be taken care of in the dispose
  232.     */
  233.     return status;
  234. }
  235.  
  236. static TQ3Status NameAttribute_CopyAdd(
  237.     TQ3StringObject    *src,
  238.     TQ3StringObject    *dst)
  239. {
  240.     *dst = Q3Shared_GetReference(*src);
  241.     if (*dst == NULL) 
  242.         return kQ3Failure;
  243.     
  244.     return kQ3Success;
  245. }
  246.  
  247. static TQ3Status NameAttribute_CopyReplace(
  248.     TQ3StringObject    *src,
  249.     TQ3StringObject    *dst)
  250. {
  251.     TQ3StringObject    tempString;
  252.     
  253.     /*
  254.         It is always good form to get a reference first,
  255.         in case src and dst point to the same object
  256.     */
  257.     
  258.     tempString = Q3Shared_GetReference(*src);
  259.     if (tempString == NULL) 
  260.         return kQ3Failure;
  261.  
  262.     if( *src )
  263.         Q3Object_Dispose( *src );
  264.     
  265.     *dst = tempString;
  266.  
  267.     return kQ3Success;
  268. }
  269.  
  270. static TQ3Status NameAttribute_Delete(
  271.     TQ3StringObject    *stringObject)
  272. {
  273.     if(*stringObject)
  274.         Q3Object_Dispose(*stringObject);
  275.     return kQ3Success;
  276. }
  277.  
  278. TQ3Status NameAttribute_Unregister(
  279.     void)
  280. {
  281.     if ( gNameAttributeClass != NULL )
  282.         return    Q3ObjectClass_Unregister(gNameAttributeClass);
  283.         
  284.     return kQ3Failure;
  285. }
  286.  
  287. /*
  288.  * NameAttribute_MetaHandler
  289.  */
  290. static TQ3FunctionPointer NameAttribute_MetaHandler(
  291.     TQ3MethodType        methodType)
  292. {
  293.     switch (methodType)
  294.     {
  295.         case kQ3MethodTypeObjectTraverse:
  296.             return (TQ3FunctionPointer) NameAttribute_Traverse;
  297.         case kQ3MethodTypeObjectReadData:
  298.             return (TQ3FunctionPointer) NameAttribute_ReadData;
  299.         case kQ3MethodTypeElementCopyAdd:
  300.         case kQ3MethodTypeElementCopyGet:
  301.         case kQ3MethodTypeElementCopyDuplicate:
  302.             return (TQ3FunctionPointer) NameAttribute_CopyAdd;
  303.         case kQ3MethodTypeElementCopyReplace:
  304.             return (TQ3FunctionPointer) NameAttribute_CopyReplace;
  305.         case kQ3MethodTypeElementDelete:
  306.             return (TQ3FunctionPointer) NameAttribute_Delete;
  307.         default:
  308.             return (TQ3FunctionPointer) NULL;
  309.     }
  310. }
  311.  
  312. /*
  313.  * NameAttribute_Register
  314.  */
  315. TQ3Status NameAttribute_Register(
  316.     void)
  317. {
  318.     gNameAttributeClass = 
  319.         Q3ElementClass_Register(
  320.             kElementTypeName,
  321.             "NameAttribute",
  322.             sizeof(TQ3StringObject),
  323.             NameAttribute_MetaHandler);
  324.  
  325.     return (gNameAttributeClass == NULL ? kQ3Failure : kQ3Success);
  326. }
  327.  
  328. /**********************************************************************************************
  329.  *
  330.  *                                        SCALE custom attribute
  331.  *
  332.  **********************************************************************************************/
  333.  
  334. /*
  335.  * Utility function to add a scale on an shape object, geometry object, or attribute set
  336.  */
  337.  
  338. TQ3Status    SetScale(TQ3Object object, double scale)
  339. {
  340.     TQ3AttributeSet    set = NULL;
  341.     TQ3Status        status = kQ3Success;
  342.     
  343.     if( Q3Object_IsType(object, kQ3SharedTypeShape) == kQ3True ) {
  344.         
  345.         if( Q3Object_IsType(object, kQ3ShapeTypeGeometry) == kQ3True ) {
  346.             
  347.             Q3Geometry_GetAttributeSet(object, &set);
  348.             
  349.             if( set == NULL ) {
  350.                 set = Q3AttributeSet_New();
  351.                 if( set == NULL ) {
  352.                     status = kQ3Failure;
  353.                     goto cleanExit;
  354.                 }
  355.                 Q3Geometry_SetAttributeSet(object, set);
  356.             }
  357.         } else {
  358.             Q3Shape_GetSet(object, &set);
  359.             
  360.             if( set == NULL ) {
  361.                 set = Q3Set_New();
  362.                 if( set == NULL ) {
  363.                     status = kQ3Failure;
  364.                     goto cleanExit;
  365.                 }
  366.                 Q3Shape_SetSet(object, set);
  367.             }
  368.         }
  369.             
  370.         if( Q3Set_Add(set, kElementTypeScale, &scale) == kQ3Failure ) {
  371.             status = kQ3Failure;
  372.             goto cleanExit;
  373.         }
  374.     } else if( Q3Object_IsType(object, kQ3SharedTypeSet) == kQ3True ) {
  375.         if( Q3AttributeSet_Add(object, kElementTypeScale, &scale) == kQ3Failure ) {
  376.             status = kQ3Failure;
  377.             goto cleanExit;
  378.         }
  379.     } else 
  380.         status = kQ3Failure;
  381.         
  382. cleanExit:
  383.     if( set )
  384.         Q3Object_Dispose(set);
  385.     return status;
  386. }
  387.  
  388. /*
  389.  * ScaleAttribute_Traverse
  390.  */
  391.  
  392. static TQ3Status ScaleAttribute_Traverse(
  393.     TQ3Object                unused,
  394.     TQ3Float64                *scale,
  395.     TQ3ViewObject            view)
  396. {
  397.     (void) unused;
  398.     
  399.     if (scale == NULL)
  400.         return kQ3Success;
  401.  
  402.     return Q3View_SubmitWriteData(
  403.         view, sizeof(TQ3Float64), scale, NULL);
  404. }
  405.  
  406. /*
  407.  * ScaleAttribute_Write
  408.  */
  409.  
  410. static TQ3Status ScaleAttribute_Write(
  411.     TQ3Float64                *scale,
  412.     TQ3FileObject            file)
  413. {
  414.     return 
  415.         Q3Float64_Write(*scale, file);
  416. }
  417.  
  418. /*
  419.  * ScaleAttribute_ReadData
  420.  */
  421.  
  422. static TQ3Status ScaleAttribute_ReadData(
  423.     TQ3SetObject            attributeSet,
  424.     TQ3FileObject            file)
  425. {
  426.     double            scale;
  427.     
  428.     if( Q3Float64_Read(&scale, file) == kQ3Failure) {
  429.         return kQ3Failure;
  430.     }
  431.         
  432.     return Q3Set_Add(attributeSet, kElementTypeScale, &scale);
  433. }
  434.  
  435. /*
  436.  * ScaleAttribute_MetaHandler
  437.  */
  438. static TQ3FunctionPointer ScaleAttribute_MetaHandler(
  439.     TQ3MethodType        methodType)
  440. {
  441.     switch (methodType)
  442.     {
  443.         case kQ3MethodTypeObjectTraverse:
  444.             return (TQ3FunctionPointer) ScaleAttribute_Traverse;
  445.         case kQ3MethodTypeObjectWrite:
  446.             return (TQ3FunctionPointer) ScaleAttribute_Write;
  447.         case kQ3MethodTypeObjectReadData:
  448.             return (TQ3FunctionPointer) ScaleAttribute_ReadData;
  449.         default:
  450.             return (TQ3FunctionPointer) NULL;
  451.     }
  452. }
  453.  
  454. /*
  455.  * ScaleAttribute_Register
  456.  */
  457. TQ3Status ScaleAttribute_Register(
  458.     void)
  459. {
  460.     gScaleAttributeClass = 
  461.         Q3ElementClass_Register(
  462.             kElementTypeScale,
  463.             "ScaleAttribute",
  464.             sizeof(TQ3Float64),
  465.             ScaleAttribute_MetaHandler);
  466.  
  467.     return (gScaleAttributeClass == NULL ? kQ3Failure : kQ3Success);
  468. }
  469.  
  470. /*
  471.  * ScaleAttribute_Unregister
  472.  */
  473. TQ3Status ScaleAttribute_Unregister(
  474.     void)
  475. {
  476.     if ( gScaleAttributeClass != NULL )
  477.         return    Q3ObjectClass_Unregister(gScaleAttributeClass);
  478.         
  479.     return kQ3Failure;
  480. }
  481.  
  482. /**********************************************************************************************
  483.  *
  484.  *                                common routines for dealing with vectors
  485.  *
  486.  **********************************************************************************************/
  487.  
  488. static TQ3Status vector_Traverse(
  489.     TQ3Object                unused,
  490.     TQ3Vector3D                *upVector,
  491.     TQ3ViewObject            view)
  492. {
  493.     (void) unused;
  494.     
  495.     if (upVector == NULL)
  496.         return kQ3Success;
  497.  
  498.     return Q3View_SubmitWriteData(
  499.         view, sizeof(TQ3Vector3D), upVector, NULL);
  500. }
  501.  
  502. static TQ3Status vector_Write(
  503.     TQ3Vector3D                *upVector,
  504.     TQ3FileObject            file)
  505. {
  506.     return 
  507.         Q3Vector3D_Write(upVector, file);
  508. }
  509.  
  510. static TQ3Status vector_CopyAdd(
  511.     TQ3Vector3D    *src,
  512.     TQ3Vector3D    *dst)
  513. {
  514.     *dst = *src;
  515.     return kQ3Success;
  516. }
  517.  
  518. static TQ3Status vector_CopyReplace(
  519.     TQ3Vector3D    *src,
  520.     TQ3Vector3D    *dst)
  521. {
  522.     *dst = *src;
  523.     return kQ3Success;
  524. }
  525.  
  526. /**********************************************************************************************
  527.  *
  528.  *                                        UP VECTOR custom attribute
  529.  *
  530.  **********************************************************************************************/
  531.  
  532. /*
  533.  * Utility function to specify the up vector on a group, geometry object, or attribute set
  534.  */
  535.  
  536. TQ3Status    SetUpVector(TQ3Object object, TQ3Vector3D *upVector)
  537. {
  538.     TQ3AttributeSet    set = NULL;
  539.     TQ3Status        status = kQ3Success;
  540.     
  541.     if( Q3Object_IsType(object, kQ3ShapeTypeGeometry) == kQ3True ) {
  542.         Q3Geometry_GetAttributeSet(object, &set);
  543.         
  544.         if( set == NULL ) {
  545.             set = Q3AttributeSet_New();
  546.             if( set == NULL ) {
  547.                 status = kQ3Failure;
  548.                 goto cleanExit;
  549.             }
  550.             Q3Geometry_SetAttributeSet(object, set);
  551.         }
  552.     } else if( Q3Object_IsType(object, kQ3ShapeTypeGroup) == kQ3True ){
  553.         Q3Shape_GetSet(object, &set);
  554.         
  555.         if( set == NULL ) {
  556.             set = Q3Set_New();
  557.             if( set == NULL ) {
  558.                 status = kQ3Failure;
  559.                 goto cleanExit;
  560.             }
  561.             Q3Shape_SetSet(object, set);
  562.         }
  563.     }
  564.             
  565.     if( set ) {
  566.         if( Q3Set_Add(set, kElementTypeUpVector, &upVector) == kQ3Failure ) {
  567.             status = kQ3Failure;
  568.             goto cleanExit;
  569.         }
  570.     } else if( Q3Object_IsType(object, kQ3SharedTypeSet) == kQ3True ) {
  571.         if( Q3AttributeSet_Add(object, kElementTypeUpVector, &upVector) == kQ3Failure ) {
  572.             status = kQ3Failure;
  573.             goto cleanExit;
  574.         }
  575.     } else 
  576.         status = kQ3Failure;
  577.         
  578. cleanExit:
  579.     if( set )
  580.         Q3Object_Dispose(set);
  581.     return status;
  582. }
  583.  
  584. /*
  585.  * UpVectorAttribute_ReadData
  586.  */
  587. static TQ3Status UpVectorAttribute_ReadData(
  588.     TQ3SetObject            attributeSet,
  589.     TQ3FileObject            file)
  590. {
  591.     TQ3Vector3D        upVector;
  592.     
  593.     if( Q3Vector3D_Read(&upVector, file) == kQ3Failure) {
  594.         return kQ3Failure;
  595.     }
  596.         
  597.     return Q3Set_Add(attributeSet, kElementTypeUpVector, &upVector);
  598. }
  599.  
  600. /*
  601.  * UpVectorAttribute_MetaHandler
  602.  */
  603. static TQ3FunctionPointer UpVectorAttribute_MetaHandler(
  604.     TQ3MethodType        methodType)
  605. {
  606.     switch (methodType)
  607.     {
  608.         case kQ3MethodTypeObjectTraverse:
  609.             return (TQ3FunctionPointer) vector_Traverse;
  610.         case kQ3MethodTypeObjectWrite:
  611.             return (TQ3FunctionPointer) vector_Write;
  612.         case kQ3MethodTypeObjectReadData:
  613.             return (TQ3FunctionPointer) UpVectorAttribute_ReadData;
  614.         case kQ3MethodTypeElementCopyAdd:
  615.         case kQ3MethodTypeElementCopyGet:
  616.         case kQ3MethodTypeElementCopyDuplicate:
  617.             return (TQ3FunctionPointer) vector_CopyAdd;
  618.         case kQ3MethodTypeElementCopyReplace:
  619.             return (TQ3FunctionPointer) vector_CopyReplace;
  620.         default:
  621.             return (TQ3FunctionPointer) NULL;
  622.     }
  623. }
  624.  
  625. /*
  626.  * UpVectorAttribute_Register
  627.  */
  628. TQ3Status UpVectorAttribute_Register(
  629.     void)
  630. {
  631.     gUpVectorAttributeClass = 
  632.         Q3ElementClass_Register(
  633.             kElementTypeUpVector,
  634.             "UpVector",
  635.             sizeof(TQ3Vector3D),
  636.             UpVectorAttribute_MetaHandler);
  637.  
  638.     return (gUpVectorAttributeClass == NULL ? kQ3Failure : kQ3Success);
  639. }
  640.  
  641. /*
  642.  * UpVectorAttribute_Unregister
  643.  */
  644. TQ3Status UpVectorAttribute_Unregister(
  645.     void)
  646. {
  647.     if ( gUpVectorAttributeClass != NULL )
  648.         return    Q3ObjectClass_Unregister(gUpVectorAttributeClass);
  649.         
  650.     return kQ3Failure;
  651. }
  652.  
  653. /**********************************************************************************************
  654.  *
  655.  *                                FORWARD DIRECTION custom attribute
  656.  *
  657.  **********************************************************************************************/
  658. /*
  659.  * Utility function to add a name on a group, geometry object, or attribute set
  660.  */
  661.  
  662. TQ3Status    SetForwardDirection(TQ3Object object, TQ3Vector3D *forwardDirection)
  663. {
  664.     TQ3AttributeSet    set = NULL;
  665.     TQ3Status        status = kQ3Success;
  666.     
  667.     if( Q3Object_IsType(object, kQ3ShapeTypeGeometry) == kQ3True ) {
  668.         Q3Geometry_GetAttributeSet(object, &set);
  669.         
  670.         if( set == NULL ) {
  671.             set = Q3AttributeSet_New();
  672.             if( set == NULL ) {
  673.                 status = kQ3Failure;
  674.                 goto cleanExit;
  675.             }
  676.             Q3Geometry_SetAttributeSet(object, set);
  677.         }
  678.     } else if( Q3Object_IsType(object, kQ3ShapeTypeGroup) == kQ3True ){
  679.         Q3Shape_GetSet(object, &set);
  680.         
  681.         if( set == NULL ) {
  682.             set = Q3Set_New();
  683.             if( set == NULL ) {
  684.                 status = kQ3Failure;
  685.                 goto cleanExit;
  686.             }
  687.             Q3Shape_SetSet(object, set);
  688.         }
  689.     }
  690.             
  691.     if( set ) {
  692.         if( Q3Set_Add(set, kElementTypeForwardDirection, &forwardDirection) == kQ3Failure ) {
  693.             status = kQ3Failure;
  694.             goto cleanExit;
  695.         }
  696.     } else if( Q3Object_IsType(object, kQ3SharedTypeSet) == kQ3True ) {
  697.         if( Q3AttributeSet_Add(object, kElementTypeForwardDirection, &forwardDirection) == kQ3Failure ) {
  698.             status = kQ3Failure;
  699.             goto cleanExit;
  700.         }
  701.     } else 
  702.         status = kQ3Failure;
  703.         
  704. cleanExit:
  705.     if( set )
  706.         Q3Object_Dispose(set);
  707.     return status;
  708. }            
  709.  
  710. /*
  711.  * ForwardDirectionAttribute_ReadData
  712.  */
  713. static TQ3Status ForwardDirectionAttribute_ReadData(
  714.     TQ3SetObject            attributeSet,
  715.     TQ3FileObject            file)
  716. {
  717.     TQ3Vector3D        forwardDirection;
  718.     
  719.     if( Q3Vector3D_Read(&forwardDirection, file) == kQ3Failure) {
  720.         return kQ3Failure;
  721.     }
  722.         
  723.     return Q3Set_Add(attributeSet, kElementTypeForwardDirection, &forwardDirection);
  724. }
  725.  
  726. /*
  727.  * ForwardDirectionAttribute_MetaHandler
  728.  */
  729. static TQ3FunctionPointer ForwardDirectionAttribute_MetaHandler(
  730.     TQ3MethodType        methodType)
  731. {
  732.     switch (methodType)
  733.     {
  734.         case kQ3MethodTypeObjectTraverse:
  735.             return (TQ3FunctionPointer) vector_Traverse;
  736.         case kQ3MethodTypeObjectWrite:
  737.             return (TQ3FunctionPointer) vector_Write;
  738.         case kQ3MethodTypeObjectReadData:
  739.             return (TQ3FunctionPointer) ForwardDirectionAttribute_ReadData;
  740.         default:
  741.             return (TQ3FunctionPointer) NULL;
  742.     }
  743. }
  744.  
  745. /*
  746.  * ForwardDirectionAttribute_Register
  747.  */
  748. TQ3Status ForwardDirectionAttribute_Register(
  749.     void)
  750. {
  751.     gUpVectorAttributeClass = 
  752.         Q3ElementClass_Register(
  753.             kElementTypeForwardDirection,
  754.             "ForwardDirection",
  755.             sizeof(TQ3Vector3D),
  756.             ForwardDirectionAttribute_MetaHandler);
  757.  
  758.     return (gForwardVectorAttributeClass == NULL ? kQ3Failure : kQ3Success);
  759. }
  760.  
  761. /*
  762.  * ForwardDirectionAttribute_Unregister
  763.  */
  764. TQ3Status ForwardDirectionAttribute_Unregister(
  765.     void)
  766. {
  767.     if ( gForwardVectorAttributeClass != NULL )
  768.         return    Q3ObjectClass_Unregister(gForwardVectorAttributeClass);
  769.         
  770.     return kQ3Failure;
  771. }
  772.  
  773. /***********************************************************************************************
  774. *
  775. *    W3Anchor - This allows you attach an URL (universal resource locator) to an object or
  776. *    group.  If this attribute is attached to a group, it should be interpreted as applying
  777. *    to all the objects inside the group.
  778. *
  779. *
  780. ***********************************************************************************************/
  781.  
  782. /*
  783.  * Utility function to attach an URL reference to a group object, geometry object, or attribute set
  784.  */
  785.  
  786. TQ3Status    SetW3Anchor(TQ3Object object, char *url, char *description, W3AnchorOptions options)
  787. {
  788.     TQ3StringObject        string = NULL;
  789.     TQ3AttributeSet        set = NULL;
  790.     TQ3Status            status = kQ3Success;
  791.     W3AnchorData        W3Anchor;
  792.         
  793.     string = Q3CString_New(description);
  794.     
  795.     if( string == NULL) {
  796.         status = kQ3Failure;
  797.         goto cleanExit;
  798.     }
  799.     
  800.     W3Anchor.description = string;
  801.     W3Anchor.url = url;
  802.     W3Anchor.options = options;
  803.     
  804.     if( Q3Object_IsType(object, kQ3ShapeTypeGeometry) == kQ3True ) {
  805.         
  806.         Q3Geometry_GetAttributeSet(object, &set);
  807.         
  808.         if( set == NULL ) {
  809.             set = Q3AttributeSet_New();
  810.             if( set == NULL ) {
  811.                 status = kQ3Failure;
  812.                 goto cleanExit;
  813.             }
  814.             Q3Geometry_SetAttributeSet(object, set);
  815.         }
  816.     } else if( Q3Object_IsType(object, kQ3ShapeTypeGroup) == kQ3True ) {
  817.         Q3Shape_GetSet(object, &set);
  818.         
  819.         if( set == NULL ) {
  820.             set = Q3Set_New();
  821.             if( set == NULL ) {
  822.                 status = kQ3Failure;
  823.                 goto cleanExit;
  824.             }
  825.             Q3Shape_SetSet(object, set);
  826.         }
  827.     }
  828.     
  829.     if( set ) {        
  830.         if( Q3Set_Add(set, kElementTypeW3Anchor, &W3Anchor) == kQ3Failure ) {
  831.             status = kQ3Failure;
  832.             goto cleanExit;
  833.         }
  834.     } else if( Q3Object_IsType(object, kQ3SharedTypeSet) == kQ3True ) {
  835.         if( Q3AttributeSet_Add(object, kElementTypeW3Anchor, &W3Anchor) == kQ3Failure ) {
  836.             status = kQ3Failure;
  837.             goto cleanExit;
  838.         }
  839.     } else 
  840.         status = kQ3Failure;
  841.         
  842. cleanExit:
  843.     if( set )
  844.         Q3Object_Dispose(set);
  845.     if( string )
  846.         Q3Object_Dispose(string);
  847.     return status;
  848. }
  849.  
  850. TQ3Boolean W3Anchor_GetFromObject(
  851.     TQ3Object object,
  852.     W3AnchorData *data)
  853. {
  854.     TQ3SetObject    set, tempSet;
  855.     TQ3Boolean        result = kQ3False;
  856.     
  857.     W3Anchor_Empty (data);
  858.     data->url = NULL;
  859.     data->description = NULL;
  860.     
  861.     // must be a shape or a group
  862.     if (Q3Object_IsType(object, kQ3ShapeTypeGeometry) == kQ3True) 
  863.         Q3Geometry_GetAttributeSet(object, &set);
  864.     else if (Q3Object_IsType(object, kQ3SharedTypeShape) == kQ3True)
  865.         Q3Shape_GetSet (object, &set);
  866.     else
  867.         return kQ3False;
  868.  
  869.     if (set == NULL)
  870.         return kQ3False;    
  871.     
  872.     while (set != NULL)
  873.     {
  874.         if (Q3Set_Contains (set, kElementTypeW3Anchor) == kQ3True)
  875.         {
  876.             if (Q3Set_Get(set, kElementTypeW3Anchor, data) == kQ3Success)
  877.                 result = kQ3True;
  878.                 break;
  879.         }
  880.         else if (Q3Set_Contains (set, kQ3SharedTypeSet) == kQ3True)
  881.         {
  882.             tempSet = set;
  883.             if (Q3Set_Get (set, kQ3SharedTypeSet, &set) == kQ3Failure)
  884.                 break;
  885.             else
  886.                 Q3Object_Dispose (tempSet);
  887.         }
  888.         /* This is to get around a bug in releases prior to 1.0.4 PFF */
  889.         else if (Q3Set_Contains (set, kQ3ElementTypeUnknown) == kQ3True)
  890.         {
  891.             TQ3Object    unknownObject;
  892.             
  893.             if (Q3Set_Get (set, kQ3ElementTypeUnknown, &unknownObject) != kQ3Failure)
  894.             {
  895.                  TQ3ObjectType unknownType = Q3Object_GetLeafType (unknownObject);
  896.                 
  897.                 if (unknownType == kQ3SharedTypeSet)
  898.                 {
  899.                     Q3Object_Dispose (set);
  900.                     set = unknownObject;
  901.                 } 
  902.                 else if (unknownType == kQ3GroupTypeDisplay) 
  903.                 {
  904.                     TQ3GroupPosition        position;
  905.                     Q3Group_GetFirstPositionOfType (unknownObject, kQ3SharedTypeSet, &position);
  906.                     
  907.                     if (position)
  908.                     {
  909.                         tempSet = set;
  910.                         if (Q3Group_GetPositionObject(unknownObject, position, &set) == kQ3Success)
  911.                             Q3Object_Dispose (tempSet);
  912.                     }
  913.                     Q3Object_Dispose (unknownObject);
  914.                 }
  915.                 else
  916.                     Q3Object_Dispose (unknownObject);
  917.             }
  918.         }
  919.         else
  920.             break;
  921.     }
  922.  
  923.     // throw away the reference to the set
  924.     Q3Object_Dispose(set);
  925.     
  926.     return result;
  927. }    
  928.  
  929. TQ3Boolean W3Anchor_GetFromHitData(
  930.     const TQ3HitData *hitData, 
  931.     W3AnchorData *data)
  932. {
  933.     if (data == NULL)
  934.         return kQ3False;
  935.         
  936.     return W3Anchor_GetFromObject (hitData->object, data);
  937. }
  938.  
  939. #ifdef __cplusplus
  940. extern "C" {
  941. #endif  /* __cplusplus */
  942.  
  943. TQ3Status W3Anchor_Traverse(
  944.     TQ3Object                unused,
  945.     W3AnchorData            *URLdata,
  946.     TQ3ViewObject            view);
  947.  
  948. #ifdef __cplusplus
  949. }
  950. #endif    /* __cplusplus */
  951.  
  952. /*
  953.  * W3Anchor_Traverse
  954.  */
  955. TQ3Status W3Anchor_Traverse(
  956.     TQ3Object                unused,
  957.     W3AnchorData            *URLdata,
  958.     TQ3ViewObject            view)
  959. {
  960.     TQ3Size        size;
  961.  
  962.     (void) unused;
  963.     
  964.     if (URLdata->url == NULL)
  965.         return kQ3Success;
  966.     
  967.     size = Q3Size_Pad(strlen(URLdata->url) + 1);
  968.     size += sizeof(TQ3Uns32);
  969.     
  970.     if( Q3View_SubmitWriteData(view, size, URLdata, NULL) == kQ3Failure )
  971.         return kQ3Failure;
  972.     
  973.     if(URLdata->description) {
  974.         if( Q3Object_Submit(URLdata->description, view) == kQ3Failure )
  975.             return kQ3Failure;
  976.     }
  977.     
  978.     return kQ3Success;
  979. }
  980.  
  981. /*
  982.  * W3Anchor_Write
  983.  */
  984. static TQ3Status W3Anchor_Write(
  985.     W3AnchorData            *URLdata,
  986.     TQ3FileObject            file)
  987. {
  988.     return 
  989.         Q3String_Write(URLdata->url, file) == kQ3Success &&
  990.         Q3Uns32_Write((unsigned long) URLdata->options, file) == kQ3Success ? kQ3Success : kQ3Failure;
  991. }
  992.  
  993. /*
  994.  * W3Anchor_ReadData
  995.  */
  996. static TQ3Status W3Anchor_ReadData(
  997.     TQ3SetObject            set,
  998.     TQ3FileObject            file)
  999. {
  1000.     char                buf[kQ3StringMaximumLength];
  1001.     W3AnchorData        URLData = {NULL, NULL, kW3AnchorOptionNone};
  1002.     
  1003.     if (Q3String_Read(buf, NULL, file) == kQ3Failure)
  1004.         return kQ3Failure;
  1005.  
  1006.     URLData.url = (char *) malloc( strlen(buf) + 1);
  1007.     strcpy( URLData.url, buf);
  1008.     
  1009.     if (Q3Uns32_Read( (unsigned long *) &URLData.options, file) == kQ3Failure)
  1010.         return kQ3Failure;
  1011.     
  1012.     if( Q3File_IsEndOfContainer(file, NULL) == kQ3False ) {
  1013.         URLData.description = Q3File_ReadObject(file);
  1014.     }
  1015.     
  1016.     return Q3Set_Add(set, kElementTypeW3Anchor, &URLData);
  1017. }
  1018.  
  1019. /*
  1020.  * W3Anchor_CopyAdd
  1021.  */
  1022. static TQ3Status W3Anchor_CopyAdd(
  1023.     W3AnchorData    *src,
  1024.     W3AnchorData    *dst)
  1025. {
  1026.     long    i;
  1027.     
  1028.     if (src->url == NULL)
  1029.         return kQ3Failure;
  1030.  
  1031.     i = strlen(src->url);
  1032.     
  1033.     if (i == 0)
  1034.         return kQ3Failure;
  1035.     
  1036.     dst->url = (char *) malloc(i + 1);
  1037.     
  1038.     if (dst->url == NULL)
  1039.         return kQ3Failure;
  1040.         
  1041.     strcpy(dst->url, src->url);
  1042.     
  1043.     if( src->description ) {
  1044.         TQ3StringObject    stringReference;
  1045.         
  1046.         stringReference = Q3Shared_GetReference(src->description);
  1047.         
  1048.         if( stringReference == NULL) {
  1049.             return kQ3Failure;
  1050.         }
  1051.         
  1052.         dst->description = stringReference;
  1053.     } else
  1054.         dst->description = NULL;
  1055.         
  1056.     dst->options = src->options;
  1057.     return kQ3Success;
  1058. }
  1059.  
  1060. /*
  1061.  * W3Anchor_CopyReplace
  1062.  */
  1063. static TQ3Status W3Anchor_CopyReplace(
  1064.     W3AnchorData    *src,
  1065.     W3AnchorData    *dst)
  1066. {
  1067.     long    i;
  1068.     char    *c;
  1069.     
  1070.     if (src->url == NULL)
  1071.         return kQ3Failure;
  1072.  
  1073.     i = strlen(src->url);
  1074.     
  1075.     if (i == 0)
  1076.         return kQ3Failure;
  1077.         
  1078.     c = (char *) realloc(dst->url, i + 1);
  1079.     
  1080.     if (c == NULL)
  1081.         return kQ3Failure;
  1082.     
  1083.     dst->url = c;
  1084.         
  1085.     strcpy(dst->url, src->url);
  1086.     
  1087.     if( src->description ) {
  1088.         TQ3StringObject    stringReference;
  1089.         
  1090.         stringReference = Q3Shared_GetReference(src->description);
  1091.         
  1092.         if( stringReference == NULL) {
  1093.             return kQ3Failure;
  1094.         }
  1095.         
  1096.         if( dst->description ) {
  1097.             Q3Object_Dispose(dst->description);
  1098.         }
  1099.         
  1100.         dst->description = stringReference;
  1101.     } else
  1102.         dst->description = NULL;
  1103.         
  1104.     dst->options = src->options;
  1105.     return kQ3Success;
  1106. }
  1107.  
  1108. /*
  1109.  * W3Anchor_Delete
  1110.  */
  1111. static TQ3Status W3Anchor_Delete(
  1112.     W3AnchorData    *URLData)
  1113. {
  1114.     if (URLData->url != NULL) 
  1115.     {
  1116.         free(URLData->url);
  1117.         URLData->url = NULL;
  1118.     }
  1119.     if (URLData->description != NULL)
  1120.     {
  1121.         Q3Object_Dispose(URLData->description);
  1122.         URLData->description = NULL;
  1123.     }
  1124.  
  1125.     return kQ3Success;
  1126. }
  1127.  
  1128. /*
  1129.  * W3Anchor_MetaHandler
  1130.  */
  1131. static TQ3FunctionPointer W3Anchor_MetaHandler(
  1132.     TQ3MethodType        methodType)
  1133. {
  1134.     switch (methodType)
  1135.     {
  1136.         case kQ3MethodTypeObjectTraverse:
  1137.             return (TQ3FunctionPointer) W3Anchor_Traverse;
  1138.         case kQ3MethodTypeObjectWrite:
  1139.             return (TQ3FunctionPointer) W3Anchor_Write;
  1140.         case kQ3MethodTypeObjectReadData:
  1141.             return (TQ3FunctionPointer) W3Anchor_ReadData;
  1142.         case kQ3MethodTypeElementCopyAdd:
  1143.         case kQ3MethodTypeElementCopyGet:
  1144.         case kQ3MethodTypeElementCopyDuplicate:
  1145.             return (TQ3FunctionPointer) W3Anchor_CopyAdd;
  1146.         case kQ3MethodTypeElementCopyReplace:
  1147.             return (TQ3FunctionPointer) W3Anchor_CopyReplace;
  1148.         case kQ3MethodTypeElementDelete:
  1149.             return (TQ3FunctionPointer) W3Anchor_Delete;
  1150.         default:
  1151.             return (TQ3FunctionPointer) NULL;
  1152.     }
  1153. }
  1154.  
  1155. /*
  1156.  * W3Anchor_Register
  1157.  */
  1158. TQ3Status W3Anchor_Register(
  1159.     void)
  1160. {
  1161.     gW3AnchorClass = 
  1162.         Q3ElementClass_Register(
  1163.             kElementTypeW3Anchor,
  1164.             "W3Anchor",
  1165.             sizeof(W3AnchorData),
  1166.             W3Anchor_MetaHandler);
  1167.  
  1168.     return (gW3AnchorClass == NULL ? kQ3Failure : kQ3Success);
  1169. }
  1170.  
  1171. TQ3Status W3Anchor_Unregister(
  1172.     void)
  1173. {
  1174.     if(gW3AnchorClass)
  1175.         return Q3ObjectClass_Unregister(gW3AnchorClass);
  1176.     else
  1177.         return kQ3Success;
  1178. }
  1179.  
  1180. void W3Anchor_Empty (
  1181.     W3AnchorData *URLData)
  1182. {
  1183.     if (URLData != NULL)
  1184.         W3Anchor_Delete (URLData);
  1185. }
  1186.  
  1187.  
  1188. /***********************************************************************************************
  1189. *
  1190. *    W3Inline - Attach this to a proxy group or geometry
  1191. *
  1192. *
  1193. ***********************************************************************************************/
  1194.  
  1195. /*
  1196.  * Utility function to add a name on a group object, geometry object, or attribute set
  1197.  */
  1198.  
  1199. TQ3Status    SetW3Inline(TQ3Object object, char *url)
  1200. {
  1201.     TQ3AttributeSet        set = NULL;
  1202.     TQ3Status            status = kQ3Success;
  1203.     W3InlineData        W3Inline;
  1204.     
  1205.     W3Inline.url = url;
  1206.  
  1207.     if( Q3Object_IsType(object, kQ3ShapeTypeGeometry) == kQ3True ) {
  1208.         Q3Geometry_GetAttributeSet(object, &set);
  1209.         
  1210.         if( set == NULL ) {
  1211.             set = Q3AttributeSet_New();
  1212.             if( set == NULL ) {
  1213.                 status = kQ3Failure;
  1214.                 goto cleanExit;
  1215.             }
  1216.             Q3Geometry_SetAttributeSet(object, set);
  1217.         }
  1218.     } else     if( Q3Object_IsType(object, kQ3ShapeTypeGroup ) == kQ3True ) {
  1219.         Q3Shape_GetSet(object, &set);
  1220.         
  1221.         if( set == NULL ) {
  1222.             set = Q3Set_New();
  1223.             if( set == NULL ) {
  1224.                 status = kQ3Failure;
  1225.                 goto cleanExit;
  1226.             }
  1227.             Q3Shape_SetSet(object, set);
  1228.         }
  1229.     }
  1230.         
  1231.     if( set ) {    
  1232.         if( Q3Set_Add(set, kElementTypeW3Inline, &W3Inline) == kQ3Failure ) {
  1233.             status = kQ3Failure;
  1234.             goto cleanExit;
  1235.         }
  1236.     } else if( Q3Object_IsType(object, kQ3SharedTypeSet) == kQ3True ) {
  1237.         if( Q3AttributeSet_Add(object, kElementTypeW3Inline, &W3Inline) == kQ3Failure ) {
  1238.             status = kQ3Failure;
  1239.             goto cleanExit;
  1240.         }
  1241.     } else 
  1242.         status = kQ3Failure;
  1243.         
  1244. cleanExit:
  1245.     if( set )
  1246.         Q3Object_Dispose(set);
  1247.     return status;
  1248. }
  1249.  
  1250. /*
  1251.  * Static Functions
  1252.  */
  1253. static TQ3Status W3Inline_Traverse(
  1254.     TQ3Object                unused,
  1255.     W3InlineData            *inlineData,
  1256.     TQ3ViewObject            view)
  1257. {
  1258.     TQ3Size        size;
  1259.     
  1260.     (void) unused;
  1261.  
  1262.     if (inlineData->url == NULL)
  1263.         return kQ3Success;
  1264.     
  1265.     size = Q3Size_Pad(strlen(inlineData->url) + 1);
  1266.     
  1267.     return
  1268.         Q3View_SubmitWriteData(view, size, inlineData, NULL);
  1269. }
  1270.  
  1271. static TQ3Status W3Inline_Write(
  1272.     W3InlineData            *inlineData,
  1273.     TQ3FileObject            file)
  1274. {
  1275.     return 
  1276.         Q3String_Write(inlineData->url, file) == kQ3Success &&
  1277.         Q3Comment_Write("url", file) == kQ3Success ? kQ3Success : kQ3Failure;
  1278. }
  1279.  
  1280. static TQ3Status W3Inline_ReadData(
  1281.     TQ3SetObject            set,
  1282.     TQ3FileObject            file)
  1283. {
  1284.     char                buf[kQ3StringMaximumLength];
  1285.     W3InlineData        inlineData;
  1286.     
  1287.     if (Q3String_Read(buf, NULL, file) == kQ3Failure)
  1288.         return kQ3Failure;
  1289.  
  1290.     inlineData.url = buf;
  1291.     
  1292.     return Q3Set_Add(set, kElementTypeW3Inline, &inlineData);
  1293. }
  1294.  
  1295. static TQ3Status W3Inline_CopyAdd(
  1296.     W3InlineData    *src,
  1297.     W3InlineData    *dst)
  1298. {
  1299.     long    i;
  1300.     
  1301.     if (src->url == NULL)
  1302.         return kQ3Failure;
  1303.  
  1304.     i = strlen(src->url);
  1305.     
  1306.     if (i == 0)
  1307.         return kQ3Failure;
  1308.         
  1309.     dst->url = (char *) malloc(i + 1);
  1310.     
  1311.     if (dst->url == NULL)
  1312.         return kQ3Failure;
  1313.         
  1314.     strcpy(dst->url, src->url);
  1315.     
  1316.     return kQ3Success;
  1317. }
  1318.  
  1319. static TQ3Status W3Inline_CopyReplace(
  1320.     W3InlineData    *src,
  1321.     W3InlineData    *dst)
  1322. {
  1323.     long    i;
  1324.     char    *c;
  1325.     
  1326.     if (src->url == NULL)
  1327.         return kQ3Failure;
  1328.  
  1329.     i = strlen(src->url);
  1330.     
  1331.     if (i == 0)
  1332.         return kQ3Failure;
  1333.         
  1334.     c = (char *) realloc(dst->url, i + 1);
  1335.     
  1336.     if (c == NULL)
  1337.         return kQ3Failure;
  1338.     
  1339.     dst->url = c;
  1340.         
  1341.     strcpy(dst->url, src->url);
  1342.     
  1343.     return kQ3Success;
  1344. }
  1345.  
  1346. static TQ3Status W3Inline_Delete(
  1347.     W3InlineData    *src)
  1348. {
  1349.     if (src->url != NULL) 
  1350.         free(src->url);
  1351.  
  1352.     return kQ3Success;
  1353. }
  1354.  
  1355. /*
  1356.  * W3Inline_MetaHandler
  1357.  */
  1358. static TQ3FunctionPointer W3Inline_MetaHandler(
  1359.     TQ3MethodType        methodType)
  1360. {
  1361.     switch (methodType)
  1362.     {
  1363.         case kQ3MethodTypeObjectTraverse:
  1364.             return (TQ3FunctionPointer) W3Inline_Traverse;
  1365.         case kQ3MethodTypeObjectWrite:
  1366.             return (TQ3FunctionPointer) W3Inline_Write;
  1367.         case kQ3MethodTypeObjectReadData:
  1368.             return (TQ3FunctionPointer) W3Inline_ReadData;
  1369.         case kQ3MethodTypeElementCopyAdd:
  1370.         case kQ3MethodTypeElementCopyGet:
  1371.         case kQ3MethodTypeElementCopyDuplicate:
  1372.             return (TQ3FunctionPointer) W3Inline_CopyAdd;
  1373.         case kQ3MethodTypeElementCopyReplace:
  1374.             return (TQ3FunctionPointer) W3Inline_CopyReplace;
  1375.         case kQ3MethodTypeElementDelete:
  1376.             return (TQ3FunctionPointer) W3Inline_Delete;
  1377.         default:
  1378.             return (TQ3FunctionPointer) NULL;
  1379.     }
  1380. }
  1381.  
  1382. /*
  1383.  * W3Inline_Register
  1384.  */
  1385. TQ3Status W3Inline_Register(
  1386.     void)
  1387. {
  1388.     gW3InlineClass = 
  1389.         Q3ElementClass_Register(
  1390.             kElementTypeW3Inline,
  1391.             "W3Inline",
  1392.             sizeof(W3InlineData),
  1393.             W3Inline_MetaHandler);
  1394.  
  1395.     return (gW3InlineClass == NULL ? kQ3Failure : kQ3Success);
  1396. }
  1397.  
  1398. TQ3Status W3Inline_Unregister(
  1399.     void)
  1400. {
  1401.     return Q3ObjectClass_Unregister(gW3InlineClass);
  1402. }
  1403.  
  1404.  
  1405. /***********************************************************************************************
  1406. *
  1407. *    This one is obsolete.  The code below will convert to the new type on reading and writing
  1408. *
  1409. *
  1410. ***********************************************************************************************/
  1411.  
  1412. /*
  1413.  * Static Functions
  1414.  */
  1415. static TQ3Status WWWAnchor_Traverse(
  1416.     TQ3Object                unused,
  1417.     WWWAnchorData            *wwwdata,
  1418.     TQ3ViewObject            view)
  1419. {
  1420.     TQ3Size        size;
  1421.  
  1422.     (void)unused;
  1423.     if (wwwdata->url == NULL)
  1424.         return kQ3Success;
  1425.     
  1426.     size = Q3Size_Pad(strlen(wwwdata->url) + 1);
  1427.     
  1428.     return
  1429.         Q3View_SubmitWriteData(view, size, wwwdata, NULL);
  1430. }
  1431.  
  1432. static TQ3Status WWWAnchor_Write(
  1433.     WWWAnchorData            *wwwdata,
  1434.     TQ3FileObject            file)
  1435. {
  1436.     return 
  1437.         Q3String_Write(wwwdata->url, file) == kQ3Success &&
  1438.         Q3Comment_Write("url", file) == kQ3Success ? kQ3Success : kQ3Failure;
  1439. }
  1440.  
  1441. static TQ3Status WWWAnchor_ReadData(
  1442.     TQ3SetObject            set,
  1443.     TQ3FileObject            file)
  1444. {
  1445.     char                buf[kQ3StringMaximumLength];
  1446.     WWWAnchorData        wwwdata;
  1447.     W3AnchorData        W3Anchor;
  1448.     
  1449.     if (Q3String_Read(buf, NULL, file) == kQ3Failure)
  1450.         return kQ3Failure;
  1451.  
  1452.     wwwdata.url = (char *) malloc(strlen(buf) + 1);
  1453.     strcpy(wwwdata.url, buf);
  1454.  
  1455.     W3Anchor.url = (char *) malloc(strlen(buf) + 1);
  1456.     strcpy(W3Anchor.url, buf);
  1457.      
  1458.      W3Anchor.description = NULL;
  1459.      W3Anchor.options = kW3AnchorOptionNone;
  1460.      
  1461.      Q3Set_Add(set, kElementTypeW3Anchor, &W3Anchor);
  1462.      
  1463.     return Q3Set_Add(set, kElementTypeWWWAnchor, &wwwdata);
  1464. }
  1465.  
  1466. static TQ3Status WWWAnchor_CopyAdd(
  1467.     WWWAnchorData    *src,
  1468.     WWWAnchorData    *dst)
  1469. {
  1470.     long    i;
  1471.     
  1472.     if (src->url == NULL)
  1473.         return kQ3Failure;
  1474.  
  1475.     i = strlen(src->url);
  1476.     
  1477.     if (i == 0)
  1478.         return kQ3Failure;
  1479.         
  1480.     dst->url = (char *) malloc(i + 1);
  1481.     
  1482.     if (dst->url == NULL)
  1483.         return kQ3Failure;
  1484.         
  1485.     strcpy(dst->url, src->url);
  1486.     
  1487.     return kQ3Success;
  1488. }
  1489.  
  1490. static TQ3Status WWWAnchor_CopyReplace(
  1491.     WWWAnchorData    *src,
  1492.     WWWAnchorData    *dst)
  1493. {
  1494.     long    i;
  1495.     char    *c;
  1496.     
  1497.     if (src->url == NULL)
  1498.         return kQ3Failure;
  1499.  
  1500.     i = strlen(src->url);
  1501.     
  1502.     if (i == 0)
  1503.         return kQ3Failure;
  1504.         
  1505.     c = (char *) realloc(dst->url, i + 1);
  1506.     
  1507.     if (c == NULL)
  1508.         return kQ3Failure;
  1509.     
  1510.     dst->url = c;
  1511.         
  1512.     strcpy(dst->url, src->url);
  1513.     
  1514.     return kQ3Success;
  1515. }
  1516.  
  1517. static TQ3Status WWWAnchor_Delete(
  1518.     WWWAnchorData    *src)
  1519. {
  1520.     if (src->url != NULL) 
  1521.         free(src->url);
  1522.  
  1523.     return kQ3Success;
  1524. }
  1525.  
  1526. /*
  1527.  * WWWAnchor_MetaHandler
  1528.  */
  1529. static TQ3FunctionPointer WWWAnchor_MetaHandler(
  1530.     TQ3MethodType        methodType)
  1531. {
  1532.     switch (methodType)
  1533.     {
  1534.         case kQ3MethodTypeObjectTraverse:
  1535.             return (TQ3FunctionPointer) WWWAnchor_Traverse;
  1536.         case kQ3MethodTypeObjectWrite:
  1537.             return (TQ3FunctionPointer) WWWAnchor_Write;
  1538.         case kQ3MethodTypeObjectReadData:
  1539.             return (TQ3FunctionPointer) WWWAnchor_ReadData;
  1540.         case kQ3MethodTypeElementCopyAdd:
  1541.         case kQ3MethodTypeElementCopyGet:
  1542.         case kQ3MethodTypeElementCopyDuplicate:
  1543.             return (TQ3FunctionPointer) WWWAnchor_CopyAdd;
  1544.         case kQ3MethodTypeElementCopyReplace:
  1545.             return (TQ3FunctionPointer) WWWAnchor_CopyReplace;
  1546.         case kQ3MethodTypeElementDelete:
  1547.             return (TQ3FunctionPointer) WWWAnchor_Delete;
  1548.         default:
  1549.             return (TQ3FunctionPointer) NULL;
  1550.     }
  1551. }
  1552.  
  1553. /*
  1554.  * WWWAnchor_Register
  1555.  */
  1556. TQ3Status WWWAnchor_Register(
  1557.     void)
  1558. {
  1559.     gWWWAnchorClass = 
  1560.         Q3ElementClass_Register(
  1561.             kElementTypeWWWAnchor,
  1562.             kElementNameWWWAnchor,
  1563.             sizeof(WWWAnchorData),
  1564.             WWWAnchor_MetaHandler);
  1565.  
  1566.     return (gWWWAnchorClass == NULL ? kQ3Failure : kQ3Success);
  1567. }
  1568.  
  1569. TQ3Status WWWAnchor_Unregister(
  1570.     void)
  1571. {
  1572.     return Q3ObjectClass_Unregister(gWWWAnchorClass);
  1573. }
  1574.