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 / Development / 3DMF parser / 0.9 version / MF3D.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-24  |  18.1 KB  |  620 lines  |  [TEXT/MPS ]

  1. /*==============================================================================
  2.  *
  3.  *    File:        MF3D.C
  4.  *
  5.  *    Function:    QuickDraw 3D Metafile Read/Write API routines
  6.  *
  7.  *    Author(s):    Rick Wong (RWW), Duet Development Corp.
  8.  *
  9.  *    Copyright:    (c) 1995 by Apple Computer, Inc., all rights reserved.
  10.  *
  11.  *    Change History (most recent first):
  12.  *        Fabio    Changed file name to 8 characters
  13.  *        F3A_RWW    All basic types working.
  14.  *        F2S_RWW    BeginGroup changes.
  15.  *        F2R_RWW    Change to simple object theory.
  16.  *        F29_RWW    File created.
  17.  *==============================================================================
  18.  */
  19.  
  20. #include "MF3D.H"
  21.  
  22. #include <string.h>                            /* memcpy */
  23.  
  24. #include "MFERRORS.H"
  25. #include "MFINT64.H"
  26. #include "MFSTDCHK.H"
  27. #include "MFASSERT.H"
  28. #include "MFFILE.H"
  29. #include "MFGROUPS.H"
  30. #include "MFINTOBJ.H"
  31. #include "MFMACROS.H"
  32. #include "MFMEMORY.H"
  33. #include "MFOBJTYP.H"
  34. #include "MFPRIMTV.H"
  35. #include "MFRSLNTN.H"
  36. #include "MFTEXTRD.H"
  37. #include "MFTEXTWR.H"
  38.  
  39. /*==============================================================================
  40.  *    MF3DOpenInput
  41.  *
  42.  *    Open a metafile for parsing using caller-defined file-handling routines.
  43.  *
  44.  *    Set outMF3DFilePtr to NULL on failure.
  45.  *==============================================================================
  46.  */
  47. MF3DErr
  48. MF3DOpenInput(
  49.     MF3DUserOpenDataPtr    inUserDataPtr,        /* In:  user-defined file info    */
  50.     MF3DProcsPtr        inUserIOProcsPtr,    /* In:  user-defined I/O procs    */
  51.     MF3D_FilePtr *        outMF3DFilePtr)        /* Out: MF3D file structure        */
  52. {
  53.     MF3D_FilePtr    fileRecord;
  54.     MF3DUserFilePtr    userFilePtr;
  55.     MF3DObjType        headerSignature;
  56.     MF3DErr            result;
  57.     MF3DBoolean        fileOpened;
  58.  
  59.     result = kMF3DNoErr;
  60.  
  61.     MF3D_Allocate(fileRecord);
  62.  
  63.     if (result == kMF3DNoErr)
  64.     {    /*
  65.          * Because it is unknown at this moment whether we have
  66.          * a text file or a binary file, open it as binary.
  67.          */
  68.         result = (*inUserIOProcsPtr->openProc)(kMF3DFormatBinary,
  69.                 inUserDataPtr, &userFilePtr);
  70.     }
  71.  
  72.     if (result == kMF3DNoErr)
  73.     {    fileOpened = kMF3DBooleanTrue;
  74.         /* Read object type to determine file type */
  75.         result = (*inUserIOProcsPtr->readProc)(userFilePtr,
  76.                 sizeof(headerSignature), (char *)&headerSignature);
  77.     }
  78.  
  79.     if (result == kMF3DNoErr)
  80.     {    if (headerSignature == kMF3DObjMetafile)
  81.         {    fileRecord->dataFormat = kMF3DFormatBinary;
  82.         }
  83.         else if (headerSignature == kMF3DObjMetafileSwapped)
  84.         {    fileRecord->dataFormat = kMF3DFormatSwappedBinary;
  85.         }
  86.         else
  87.         {    /* Assume text */
  88.             fileRecord->dataFormat = kMF3DFormatText;
  89.         }
  90.     }
  91.  
  92.     /* Close and reopen as correct type
  93.      * This is unnecessary for binary files, but has the side effect
  94.      * of resetting the file offset to 0.
  95.      */
  96.     if (result == kMF3DNoErr)
  97.     {    (*inUserIOProcsPtr->closeProc)(userFilePtr);
  98.         fileOpened = kMF3DBooleanFalse;
  99.         result = (*inUserIOProcsPtr->openProc)(fileRecord->dataFormat,
  100.                 inUserDataPtr, &userFilePtr);
  101.     }
  102.  
  103.     if (result == kMF3DNoErr)
  104.     {    fileOpened = kMF3DBooleanTrue;
  105.         result = MF3D_GetPrimitivesAccessor(fileRecord->dataFormat,
  106.                 &fileRecord->primitives);
  107.     }
  108.  
  109.     if (result == kMF3DNoErr)
  110.     {    fileRecord->readWrite = MF3D_MetafileRead;
  111.         fileRecord->readBuffer.buf = NULL;
  112.         fileRecord->inContainer = 0;
  113.         fileRecord->userFilePtr = userFilePtr;
  114.         memcpy(&fileRecord->procsRec, inUserIOProcsPtr, sizeof(MF3DProcsRec));
  115.         fileRecord->resStuff.resState = MF3D_NotResolvingReference;
  116.         fileRecord->resStuff.reference = NULL;
  117.         fileRecord->resStuff.parent = NULL;
  118.         SetInt64ToZero(fileRecord->resStuff.returnLoc);
  119.         fileRecord->typeTable.nTypes = 0;
  120.         fileRecord->typeTable.types = MF3D_Malloc(0);
  121.  
  122.         result = MF3D_InitGroup(fileRecord);
  123.     }
  124.  
  125.     /* Prepare the file for reading */
  126.     if (result == kMF3DNoErr)
  127.         result = MF3D_PreprocessFile(fileRecord);
  128.  
  129.     if (result == kMF3DNoErr)
  130.     {    *outMF3DFilePtr = fileRecord;
  131.     }
  132.     else
  133.     {    if (fileOpened == kMF3DBooleanTrue)
  134.             (*inUserIOProcsPtr->closeProc)(userFilePtr);
  135.         if (fileRecord != NULL)
  136.             MF3D_Free(fileRecord);
  137.         *outMF3DFilePtr = NULL;
  138.     }
  139.  
  140.     return result;
  141. }
  142.  
  143. /*==============================================================================
  144.  *    MF3DOpenInputStdCFile
  145.  *
  146.  *    Open a metafile for parsing using standard C routines.
  147.  *
  148.  *    This routine just calls MF3DOpenInput with inUserDataPtr = inFilename
  149.  *    and inUserIOProcsPtr set to call fopen, fread, NULL, ftell, fseek,
  150.  *    and fclose.
  151.  *==============================================================================
  152.  */
  153. MF3DErr
  154. MF3DOpenInputStdCFile(
  155.     const char *    inFilename,            /* In:  C-string filename            */
  156.     MF3D_FilePtr *    outMF3DFilePtr)        /* Out: MF3D file structure            */
  157. {
  158.     MF3DProcsRec        procsRecord;
  159.     MF3DStdCOpenData    stdCOpenData;
  160.  
  161.     procsRecord.openProc = MF3DStdCOpenHook;
  162.     procsRecord.readProc = MF3DStdCReadHook;
  163.     procsRecord.writeProc = NULL;
  164.     procsRecord.tellProc = MF3DStdCTellHook;
  165.     procsRecord.seekProc = MF3DStdCSeekHook;
  166.     procsRecord.closeProc = MF3DStdCCloseHook;
  167.  
  168.     stdCOpenData.filename = (char *)inFilename;
  169.     stdCOpenData.permission = kMF3DStdCReadPerm;
  170.  
  171.     return MF3DOpenInput((MF3DUserOpenDataPtr)&stdCOpenData, &procsRecord,
  172.             outMF3DFilePtr);
  173. }
  174.  
  175. /*==============================================================================
  176.  *    MF3DReadAnObject
  177.  *
  178.  *    Retrieve the next metafile object in an open metafile.
  179.  *
  180.  *    Metafile objects are defined in <MFOBJCTS.H>. They can be recognized
  181.  *        by checking the fObjectType field and casting the object pointer
  182.  *        appropriately.
  183.  *
  184.  *    Objects returned by MF3DReadAnObject should be disposed using
  185.  *        MF3DDisposeObject when they are no longer needed. If an error occurs,
  186.  *        NULL will be returned (MF3DDisposeObject ignores NULL parameters).
  187.  *
  188.  *    Returns:
  189.  *        kMF3DNoErr                object was successfully read
  190.  *        kMF3DNoMoreObjects        the end of the file has been reached
  191.  *==============================================================================
  192.  */
  193. MF3DErr
  194. MF3DReadAnObject(
  195.     MF3D_FilePtr    inMF3DFilePtr,        /* In:  MF3D file structure            */
  196.     MF3DVoidObjPtr    *outMF3DObjPtr)        /* Out: metafile object                */
  197. {
  198.     MF3DEndContainerObjPtr    endContainerObj;
  199.     MF3DErr                    result;
  200.  
  201.     if (inMF3DFilePtr == NULL || outMF3DObjPtr == NULL)
  202.         return kMF3DErrInvalidParameter;
  203.  
  204.     if (inMF3DFilePtr->resStuff.reference != NULL)
  205.     {    /* If we are resolving a reference, jump to the referenced file */
  206.         return MF3DReadAnObject(inMF3DFilePtr->resStuff.reference,
  207.                 outMF3DObjPtr);
  208.     }
  209.     
  210.     /*
  211.      * Special upfront check for EndContainer
  212.      */
  213.     if (inMF3DFilePtr->readBuffer.buf != NULL)
  214.     {    result = MF3D_EndRead(inMF3DFilePtr);
  215.         if (result == kMF3DNoErr)
  216.         {    /* We got an end paren; it should be an EndContainer marker */
  217.             if (inMF3DFilePtr->inContainer == 0)
  218.                 result = kMF3DErrTooManyEndContainers;
  219.             else
  220.             {    --inMF3DFilePtr->inContainer;
  221.                 MF3D_Allocate(endContainerObj);
  222.             }
  223.             if (result == kMF3DNoErr)
  224.             {    endContainerObj->objectType = kMF3DObjEndContainer;
  225.                 endContainerObj->refInfo = NULL;
  226.                 *outMF3DObjPtr = (MF3DVoidObjPtr) endContainerObj;
  227.  
  228.                 /* If we were resolving a container reference, we may
  229.                  * be able to stop now.
  230.                  */
  231.                 if (inMF3DFilePtr->resStuff.resState >= MF3D_ResolvingReference)
  232.                 {    --inMF3DFilePtr->resStuff.resState;
  233.                     if (inMF3DFilePtr->resStuff.resState ==
  234.                             MF3D_ResolvingReference)
  235.                     {    MFASSERT(inMF3DFilePtr->resStuff.resState >=
  236.                                 MF3D_ResolvingReference);
  237.                         result = MF3D_PopResolution(inMF3DFilePtr);
  238.                     }
  239.                 }
  240.             }
  241.             return result;                    /* ### INTERNAL EXIT ### */
  242.         }
  243.     }
  244.  
  245.     /* This case should not happen */
  246.     MFASSERT(!(MF3DIsTextFormat(inMF3DFilePtr->dataFormat) &&
  247.             inMF3DFilePtr->readBuffer.buf != NULL));
  248.     if (MF3DIsTextFormat(inMF3DFilePtr->dataFormat) &&
  249.             inMF3DFilePtr->readBuffer.buf != NULL)
  250.     {    return kMF3DErrCantParse;            /* ### INTERNAL EXIT ### */
  251.     }
  252.  
  253.     /* Now, we want to skip TOC objects.
  254.      * NOTE: The easiest way to do this is to continue reading objects
  255.      * until we get a non-TOC object and a non-Type object.
  256.      * This is not necessarily the _best_ way.
  257.      */
  258.     do
  259.     {    result = MF3D_IntReadObject(inMF3DFilePtr, outMF3DObjPtr);
  260.         if (*outMF3DObjPtr != NULL)
  261.         {    if ((*outMF3DObjPtr)->objectType == kMF3DObjTableOfContents)
  262.                 MF3DDisposeObject(*outMF3DObjPtr);
  263.             else
  264.                 break;                        /* ### NORMAL LOOP EXIT ### */
  265.         }
  266.     } while (result == kMF3DNoErr);
  267.  
  268.     return result;
  269. }
  270.  
  271. /*==============================================================================
  272.  *    MF3DDisposeObject
  273.  *
  274.  *    Dispose a metafile object.
  275.  *    If inMF3DObjPtr is NULL, nothing happens.
  276.  *==============================================================================
  277.  */
  278. MF3DErr
  279. MF3DDisposeObject(
  280.     MF3DVoidObjPtr    inMF3DObjPtr)        /* In:  metafile object                */
  281. {
  282.     MF3D_ObjStuffPtr    objStuff;
  283.     MF3DErr                result;
  284.  
  285.     result = kMF3DNoErr;
  286.  
  287.     if (inMF3DObjPtr != NULL)
  288.     {    result = MF3D_FindObjectFromType(inMF3DObjPtr->objectType,
  289.             &objStuff);
  290.  
  291.         if (inMF3DObjPtr->refInfo != NULL)
  292.         {    MF3D_Free(inMF3DObjPtr->refInfo->refName);
  293.             MF3D_Free(inMF3DObjPtr->refInfo);
  294.         }
  295.  
  296.         if (result == kMF3DNoErr)
  297.             result = (*objStuff->disposer) (inMF3DObjPtr);
  298.     }
  299.  
  300.     return result;
  301. }
  302.  
  303. /*==============================================================================
  304.  *    MF3DResolveReference
  305.  *
  306.  *    Set up an MF3D file so that it will read the object pointed to by
  307.  *    a reference object. The next call to MF3DReadAnObject will then read
  308.  *    the referenced object, and the MF3D file will then be reset to read the
  309.  *    object that would have been read if MF3DResolveReference had not been
  310.  *    called.
  311.  *
  312.  *    If MF3DResolveReference resolves to a group object, the entire group will
  313.  *    be read before the MF3D file is reset.
  314.  *
  315.  *    If inStoragePtr is not NULL, the reference is in an external file.
  316.  *==============================================================================
  317.  */
  318. MF3DErr
  319. MF3DResolveReference(
  320.     MF3D_FilePtr        inMF3DFilePtr,         /* In:  MF3D file structure        */
  321.     MF3DReferenceObjPtr    inMF3DRefObjPtr,     /* In:  reference object        */
  322.     MF3DStorageObjPtr    inExternalFilePtr)    /* In:    external storage object    */
  323. {
  324.     MF3DErr    result;
  325.  
  326.     if (inMF3DFilePtr == NULL || inMF3DRefObjPtr == NULL)
  327.         return kMF3DErrInvalidParameter;
  328.  
  329.     result = kMF3DNoErr;
  330.  
  331.     if (inMF3DRefObjPtr->objectType != kMF3DObjReference)
  332.         result = kMF3DErrNotAReferenceObj;
  333.  
  334.     if (result == kMF3DNoErr)
  335.     {    result = MF3D_PushResolution(inMF3DFilePtr, inMF3DRefObjPtr,
  336.                 inExternalFilePtr);
  337.     }
  338.  
  339.     return result;
  340. }
  341.  
  342. /*==============================================================================
  343.  *    MF3DClose
  344.  *
  345.  *    Close the metafile.
  346.  *
  347.  *    If inMF3DFilePtr is NULL, nothing happens.
  348.  *==============================================================================
  349.  */
  350. MF3DErr
  351. MF3DClose(
  352.     MF3D_FilePtr    inMF3DFilePtr)        /* In:  MF3D file structure            */
  353. {
  354.     MF3D_TypeListPtr    tempPtr;
  355.     MF3DUns32            numUserDefinedTypes;
  356.     MF3DErr                result, closeResult;
  357.  
  358.     if (inMF3DFilePtr == NULL)
  359.         return kMF3DNoErr;
  360.  
  361.     result = kMF3DNoErr;
  362.  
  363.     /* Free the user types table */
  364.     for (numUserDefinedTypes = inMF3DFilePtr->typeTable.nTypes,
  365.             tempPtr = inMF3DFilePtr->typeTable.types;
  366.             numUserDefinedTypes > 0;
  367.             --numUserDefinedTypes, ++tempPtr)
  368.     {    MF3D_Free(tempPtr->name);
  369.     }
  370.     MF3D_Free(inMF3DFilePtr->typeTable.types);
  371.  
  372.     if (inMF3DFilePtr->readWrite == MF3D_MetafileRead)
  373.     {    MF3D_DisposeGroup(inMF3DFilePtr);
  374.         MF3D_PostprocessFile(inMF3DFilePtr);
  375.         /* Close any files we opened to resolve a reference */
  376.         if (inMF3DFilePtr->resStuff.reference != NULL)
  377.             result = MF3D_PopResolution(inMF3DFilePtr->resStuff.reference);
  378.         
  379.         closeResult = MF3D_CloseReadBuffer(inMF3DFilePtr);
  380.  
  381.         if (result == kMF3DNoErr)
  382.             result = closeResult;
  383.     }
  384.     else if (inMF3DFilePtr->readWrite == MF3D_MetafileWrite)
  385.     {    MF3DVoidObj    fakeTOCObj;
  386.  
  387.         if (inMF3DFilePtr->tocStuff.refSeed > 1 ||
  388.                 inMF3DFilePtr->tocStuff.typeSeed < -1)
  389.         {    result = MF3D_BackpatchTOCLocation(inMF3DFilePtr);
  390.  
  391.             if (result == kMF3DNoErr)
  392.             {    /* Fake a TOC object to force it to get written */
  393.                 fakeTOCObj.objectType = kMF3DObjTableOfContents;
  394.                 fakeTOCObj.refInfo = NULL;
  395.                 result = MF3DWriteAnObject(inMF3DFilePtr, &fakeTOCObj);
  396.             }
  397.         }
  398.         MF3D_DisposeTOCStuff(inMF3DFilePtr);
  399.     }
  400.  
  401.     closeResult =
  402.             (*inMF3DFilePtr->procsRec.closeProc)(inMF3DFilePtr->userFilePtr);
  403.  
  404.     MF3D_Free(inMF3DFilePtr);
  405.  
  406.     if (result == kMF3DNoErr)
  407.         result = closeResult;
  408.  
  409.     return result;
  410. }
  411.  
  412. /*==============================================================================
  413.  *    MF3DOpenOutput
  414.  *
  415.  *    Open a metafile for writing using caller-defined file-handling routines.
  416.  *
  417.  *    Set *outMF3DFilePtr to NULL on error.
  418.  *==============================================================================
  419.  */
  420. MF3DErr
  421. MF3DOpenOutput(
  422.     MF3DDataFormatEnum    inMF3DDataFormat,    /* In:  binary or text            */
  423.     MF3DUserOpenDataPtr    inUserDataPtr,        /* In:  user-defined file info    */
  424.     MF3DProcsPtr        inUserIOProcsPtr,    /* In:  user-defined I/O procs    */
  425.     MF3D_FilePtr *        outMF3DFilePtr)        /* Out: MF3D file structure        */
  426. {
  427.     MF3D_FilePtr    fileRecord;
  428.     MF3DUserFilePtr    userFilePtr;
  429.     MF3DBoolean        fileOpened;
  430.     MF3DErr            result;
  431.  
  432.     result = kMF3DNoErr;
  433.  
  434.     MF3D_Allocate(fileRecord);
  435.  
  436.     fileOpened = kMF3DBooleanFalse;
  437.     if (result == kMF3DNoErr)
  438.     {    memcpy(&fileRecord->procsRec, inUserIOProcsPtr, sizeof(MF3DProcsRec));
  439.  
  440.         result = (*fileRecord->procsRec.openProc)(inMF3DDataFormat,
  441.                 inUserDataPtr, &userFilePtr);
  442.     }
  443.  
  444.     if (result == kMF3DNoErr)
  445.     {    fileOpened = kMF3DBooleanTrue;
  446.         result = MF3D_GetPrimitivesAccessor(inMF3DDataFormat,
  447.                 &fileRecord->primitives);
  448.     }
  449.  
  450.     if (result == kMF3DNoErr)
  451.     {    fileRecord->dataFormat = inMF3DDataFormat;
  452.         fileRecord->readWrite = MF3D_MetafileWrite;
  453.         fileRecord->userFilePtr = userFilePtr;
  454.         fileRecord->inContainer = 0;
  455.         SetInt64ToZero(fileRecord->tocLocation);
  456.         fileRecord->writeStack = NULL;
  457.         fileRecord->indent = 0;
  458.         fileRecord->tocStuff.tocLabelName = NULL;
  459.         fileRecord->tocStuff.refSeed = 1;
  460.         fileRecord->tocStuff.typeSeed = -1;
  461.         fileRecord->tocStuff.numReferences = 0;
  462.         fileRecord->tocStuff.references = MF3D_Malloc(0);
  463.         fileRecord->tocStuff.needToUpdate = kMF3DBooleanFalse;
  464.         fileRecord->typeTable.nTypes = 0;
  465.         fileRecord->typeTable.types = MF3D_Malloc(0);
  466.     }
  467.  
  468.     if (result == kMF3DNoErr)
  469.     {    *outMF3DFilePtr = fileRecord;
  470.     }
  471.     else
  472.     {    if (fileOpened)
  473.             (inUserIOProcsPtr->closeProc)(userFilePtr);
  474.         if (fileRecord != NULL)
  475.             MF3D_Free(fileRecord);
  476.         *outMF3DFilePtr = NULL;
  477.     }
  478.  
  479.     return result;
  480. }
  481.  
  482. /*==============================================================================
  483.  *    MF3DOpenOutputStdCFile
  484.  *
  485.  *    Open a metafile for writing using standard C routines.
  486.  *
  487.  *    This routine just calls MF3DOpenOutput with inUserDataPtr = inFilename
  488.  *    and inUserIOProcsPtr set to call fopen, fread, fwrite, ftell, fseek,
  489.  *    and fclose.
  490.  *==============================================================================
  491.  */
  492. MF3DErr    MF3DOpenOutputStdCFile(
  493.     MF3DDataFormatEnum    inMF3DDataFormat,    /* In:  binary or text            */
  494.     const char *        inFilename,            /* In:  C-string filename        */
  495.     MF3D_FilePtr *        outMF3DFilePtr)        /* Out: MF3D file structure        */
  496. {
  497.     MF3DProcsRec        procsRecord;
  498.     MF3DStdCOpenData    stdCOpenData;
  499.  
  500.     procsRecord.openProc = MF3DStdCOpenHook;
  501.     procsRecord.readProc = MF3DStdCReadHook;
  502.     procsRecord.writeProc = MF3DStdCWriteHook;
  503.     procsRecord.tellProc = MF3DStdCTellHook;
  504.     procsRecord.seekProc = MF3DStdCSeekHook;
  505.     procsRecord.closeProc = MF3DStdCCloseHook;
  506.  
  507.     stdCOpenData.filename = (char *)inFilename;
  508.     stdCOpenData.permission = kMF3DStdCWritePerm;
  509.  
  510.     return MF3DOpenOutput(inMF3DDataFormat, (MF3DUserOpenDataPtr)&stdCOpenData,
  511.             &procsRecord, outMF3DFilePtr);
  512. }
  513.  
  514. /*==============================================================================
  515.  *    MF3DWriteAnObject
  516.  *
  517.  *    Write a metafile object to an open metafile.
  518.  *==============================================================================
  519.  */
  520. MF3DErr
  521. MF3DWriteAnObject(
  522.     MF3D_FilePtr    inMF3DFilePtr,            /* In:  MF3D file structure        */
  523.     MF3DVoidObjPtr    inMF3DObjPtr)            /* In:  metafile object            */
  524. {
  525.     MF3D_ObjStuffPtr        objStuff;
  526.     MF3DBinaryFilePosition    location;
  527.     MF3DErr                    beginResult, writerResult, endResult;
  528.  
  529.     if (inMF3DFilePtr == NULL || inMF3DObjPtr == NULL)
  530.         return kMF3DErrInvalidParameter;
  531.  
  532.     beginResult = kMF3DNoErr;
  533.  
  534.     /* If the last object was a labeled container, set the object type
  535.      * of that label to this (the root) object.
  536.      */
  537.     if (inMF3DFilePtr->tocStuff.needToUpdate == kMF3DBooleanTrue)
  538.     {    inMF3DFilePtr->tocStuff.references[
  539.                 inMF3DFilePtr->tocStuff.numReferences - 1].type =
  540.                 inMF3DObjPtr->objectType;
  541.         inMF3DFilePtr->tocStuff.needToUpdate = kMF3DBooleanFalse;
  542.     }
  543.  
  544.     if (inMF3DObjPtr->refInfo != NULL)
  545.     {    beginResult = MF3DTellPosition(inMF3DFilePtr, &location);
  546.         if (beginResult == kMF3DNoErr)
  547.         {    beginResult = MF3D_LabelWrite(inMF3DFilePtr,
  548.                     inMF3DObjPtr->refInfo, location, inMF3DObjPtr->objectType);
  549.         }
  550.     }
  551.  
  552.     if (beginResult == kMF3DNoErr &&
  553.             inMF3DObjPtr->objectType == kMF3DObjUnknownType)
  554.     {    /* User is trying to write a new type */
  555.         beginResult = MF3D_TypeObjWrite(inMF3DFilePtr, inMF3DObjPtr);
  556.     }
  557.  
  558.     if (beginResult == kMF3DNoErr)
  559.         beginResult = MF3D_BeginWrite(inMF3DFilePtr, inMF3DObjPtr, &objStuff);
  560.  
  561.     if (beginResult == kMF3DNoErr)
  562.         writerResult = (*objStuff->writer) (inMF3DFilePtr, inMF3DObjPtr);
  563.  
  564.     /* Write the closing paren, even if writer failed */
  565.     if (beginResult == kMF3DNoErr)
  566.         endResult = MF3D_EndWrite(inMF3DFilePtr, inMF3DObjPtr);
  567.  
  568.     /* Ignore error when writing newline here */
  569.     if (beginResult == kMF3DNoErr)
  570.         MF3D_WriteNewLine(inMF3DFilePtr);
  571.  
  572.     return beginResult == kMF3DNoErr ?
  573.                 (writerResult == kMF3DNoErr ? endResult : writerResult) :
  574.                 beginResult;
  575. }
  576.  
  577. /*==============================================================================
  578.  *    MF3DTellPosition
  579.  *
  580.  *    Retrieve the position of an open metafile.
  581.  *==============================================================================
  582.  */
  583. MF3DErr
  584. MF3DTellPosition(
  585.     MF3D_FilePtr                inMF3DFilePtr,    /* In:  MF3D file structure    */
  586.     MF3DBinaryFilePosition *    outMF3DPosPtr)    /* Out: file offset            */
  587. {
  588.     MF3DErr                    result;
  589.     MF3DBinaryFilePosition    position;
  590.  
  591.     if (inMF3DFilePtr == NULL)
  592.         return kMF3DErrInvalidParameter;
  593.  
  594.     result = (*inMF3DFilePtr->procsRec.tellProc)(
  595.             inMF3DFilePtr->userFilePtr, &position);
  596.  
  597.     if (result == kMF3DNoErr)
  598.         *outMF3DPosPtr = position;
  599.  
  600.     return result;
  601. }
  602.  
  603. /*==============================================================================
  604.  *    MF3DSeekPosition
  605.  *
  606.  *    Set the position of an open metafile.
  607.  *==============================================================================
  608.  */
  609. MF3DErr
  610. MF3DSeekPosition(
  611.     MF3D_FilePtr            inMF3DFilePtr,    /* In:  MF3D file structure        */
  612.     MF3DBinaryFilePosition    inMF3DPosition)    /* In:  file offset                */
  613. {
  614.     if (inMF3DFilePtr == NULL)
  615.         return kMF3DErrInvalidParameter;
  616.  
  617.     return (*inMF3DFilePtr->procsRec.seekProc)(
  618.             inMF3DFilePtr->userFilePtr, inMF3DPosition);
  619. }
  620.