home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc™ Source Code / Storage / Bento / EmbedHdr.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-28  |  15.2 KB  |  540 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        EmbedHdr.cpp
  3.  
  4.     Contains:    Class definition for ODEmbeddedHandlers class.
  5.  
  6.     Owned by:    Vincent Lo
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <3>      5/1/96    JA        1213332: Use 68k alignment for persistent
  13.                                     structs.
  14.          <2>     1/15/96    TJ        Cleaned Up
  15.          <8>    10/24/95    jpa        1293441: Bento memory reserve & fatal
  16.                                     container err.
  17.          <7>     5/26/95    VL        1251403: Multithreading naming support.
  18.          <6>     5/11/95    EL        1245113: fix bug of writing out garbage
  19.                                     with buffering.
  20.          <5>      4/7/95    EL        1213321: Use a different buffering scheme.
  21.          <4>    11/14/94    VL        1188257: Use Bento errors in BenotDef.h.
  22.          <3>     8/26/94    EL        #1182275 Allows writing embeded value in
  23.                                     large block to decrease fragmentation.
  24.                                     #1182308 Allows non-byte swapping
  25.                                     format/extract
  26.          <2>     6/18/94    MB        Correct memory includes
  27.          <1>     5/27/94    VL        first checked in
  28.  
  29.     In Progress:
  30.         
  31. */
  32.  
  33. #ifndef    _ODTYPES_
  34. #include "ODTypes.h"
  35. #endif
  36.  
  37. #ifndef _BENTOHDR_
  38. #include "BentoHdr.h"
  39. #endif
  40.  
  41. #ifndef _EMBEDHDR_
  42. #include "EmbedHdr.h"
  43. #endif
  44.  
  45. #ifndef _SESSHDR_
  46. #include "SessHdr.h"
  47. #endif
  48.  
  49. #ifndef _INDHDR_
  50. #include "IndHdr.h"
  51. #endif
  52.  
  53. #ifndef _EXCEPT_
  54. #include "Except.h"
  55. #endif
  56.  
  57. #ifndef _FLIPEND_
  58. #include "FlipEnd.h"
  59. #endif
  60.  
  61. #ifndef __CM_API__
  62. #include "CMAPI.h"
  63. #endif
  64.  
  65. #ifndef _ODMEMORY_
  66. #include "ODMemory.h"
  67. #endif
  68.  
  69. #ifndef _ERRORDEF_
  70. #include "ErrorDef.xh"
  71. #endif
  72.  
  73. #ifndef __STRING__
  74. #include "string.h"        // For strcpy and strcmp
  75. #endif
  76.  
  77. #ifndef _BENTODEF_
  78. #include "BentoDef.h"
  79. #endif
  80.  
  81. #ifndef _SESSHDR_
  82. #include "SessHdr.h"
  83. #endif
  84.  
  85. //==============================================================================
  86. // Scalar Types
  87. //==============================================================================
  88.  
  89. #if PRAGMA_ALIGN_SUPPORTED
  90. #pragma options align=mac68k
  91. #endif
  92.  
  93. struct ContainerLabelFmt {            /* Layout of a container label:            */
  94.  ODUByte magicBytes[8];                /* 8 bytes: the magic byte identifier    */
  95.  ODUShort flags;                    /* 2    the label flag                    */
  96.  ODUShort bufSize;                    /* 2    TOC buffer size / 1024            */
  97.  ODUShort majorVersion;                /* 2    major format version number        */
  98.  ODUShort minorVersion;                /* 2    minor format version number        */
  99.  ODULong tocOffset;                    /* 4    offset to start of TOC            */
  100.  ODULong tocSize;                    /* 4    total byte size of the TOC        */
  101. };
  102. typedef struct ContainerLabelFmt ContainerLabelFmt;
  103.  
  104. #if PRAGMA_ALIGN_SUPPORTED
  105. #pragma options align=reset
  106. #endif
  107.  
  108.  
  109. #pragma segment EmbedHdr
  110.  
  111. static void ODFlipMove(ODPtr from, ODPtr to, ODULong size)
  112. {
  113.     char    *dest = (char *)to + size - 1;
  114.     char    *src = (char *)from;
  115.     
  116.     while (size--)
  117.         *dest-- = *src++;            
  118. }
  119.  
  120. //==============================================================================
  121. // ODEmbeddedHandlers
  122. //==============================================================================
  123.  
  124. ODEmbeddedHandlers::ODEmbeddedHandlers(CMSession session, CMValue parentValue)
  125. {
  126.     fParentValue = parentValue;
  127.     fSession = session;
  128. }
  129.  
  130. ODEmbeddedHandlers::~ODEmbeddedHandlers()
  131. {
  132. }
  133.  
  134. void ODEmbeddedHandlers::Initialize()
  135. {
  136.     ODSByte    typeName[kBentoTypeNameSize];
  137.     
  138.     CMContainer    container   = CMGetValueContainer(fParentValue);
  139.     CMSession    sessionData = CMGetSession(container);
  140.     
  141.     if (sessionData != fSession)
  142.         THROW(kODErrBentoErr);
  143.  
  144.     ODSessionMustHaveCMAllocReserve(container);
  145.     
  146.     CMSetMetaHandler(fSession, kODEmbeddedContainerTypeName, (CMMetaHandler) containerMetahandler);
  147.     
  148.     CMGetContainerInfo(container, kODNULL, kODNULL, kODNULL, typeName, kODNULL);
  149.     
  150.     fReverseEndian = 0;                        /* assume same endian-ness            */
  151.     fPosition    = 0;                        /* container not "open" yet            */
  152.     fSize    = 0;                            /* don't know size yet                */
  153. #if kLargeEmbeddedBlock
  154.     fBufferBegin = 0;
  155.     fBuffer = kODNULL;
  156. #endif
  157.     strcpy(fTypeName, typeName);            /* copy in the container typeName    */
  158.  
  159.     ODSessionRestoreCMAllocReserve(container);
  160. }
  161.  
  162. CMSession ODEmbeddedHandlers::GetCMSession()
  163. {
  164.     return fSession;
  165. }
  166.  
  167. CMRefCon ODEmbeddedHandlers::OpenHandler(CMOpenMode mode)
  168. {
  169.     /* Get the size of the value.  For writing it better be 0 and for reading non-zero...    */
  170.     
  171.     fSize = (ODULong) CMGetValueSize(fParentValue);
  172. #if kLargeEmbeddedBlock
  173.     fBufferBegin = fSize;
  174.     fBuffer = (ODSByte *)ODNewPtr(kEmbeddedBlockSize);
  175. #endif    
  176.     /* Check the open mode and do appropriate checks on size. Set appropriate position...    */
  177.     
  178.     if (strcmp((ODSByte*) mode, "wb+") == 0) {                /* writing...    */
  179.         if (fSize != 0) {                                    /* size must be zero    */
  180.             CMError(fSession, "Cannot create embedded container (type \"^0\") for a value that already has data!", fTypeName);
  181.             return (kODNULL);
  182.         }
  183.         fPosition = 0;                                    /* position to 1st free byte    */
  184.     } else if (strcmp((ODSByte*) mode, "rb") == 0) {         /* reading...                    */
  185.         if (fSize == 0) {                                    /* size must be non-zero        */
  186.             CMError(fSession, "Cannot read embedded container (type \"^0\") for a value that doesn't have data!", fTypeName);
  187.             return (kODNULL);
  188.         }
  189.         fPosition = 0;                                    /* position to 1st byte to read            */
  190.     } else if (strcmp((char *)mode, "rb+") == 0)              /* converting or updating...            */
  191.         fPosition = fSize;                                /* size can be anything(position at end)*/
  192.     else {                                                                                /* bad mode...                                                    */
  193.         CMError(fSession, "Invalid embedded container (type \"^0\") open mode (\"^1\")!", fTypeName, (char *)mode);
  194.         return (kODNULL);
  195.     }
  196.     
  197.     return ((CMRefCon) this);
  198. }
  199.  
  200. void ODEmbeddedHandlers::CloseHandler()
  201. {
  202. #if kLargeEmbeddedBlock
  203.     if (fBuffer != kODNULL) {
  204.         (void) this->FlushHandler();
  205.         ODDisposePtr(fBuffer);
  206.         fBuffer = kODNULL;
  207.     }
  208. #endif
  209. }
  210.  
  211. CMSize ODEmbeddedHandlers::FlushHandler()
  212. {
  213. #if kLargeEmbeddedBlock
  214.     /* write out the data in the buffer */
  215.     if (fBufferBegin != fSize) {
  216.         CMWriteValueData(fParentValue, fBuffer, fBufferBegin, (CMSize) (fSize - fBufferBegin));
  217.         fBufferBegin = fSize;
  218.     }
  219. #endif
  220.     return ((CMSize) 0);
  221. }
  222.  
  223. CMSize ODEmbeddedHandlers::SeekHandler(CM_LONG posOff, CMSeekMode mode)
  224. {
  225.     if (mode == kCMSeekSet)
  226.         fPosition = (ODULong) posOff;
  227.     else if (mode == kCMSeekEnd)
  228.         fPosition = (ODSLong) fSize + posOff;
  229.     else
  230.         fPosition = (ODSLong) fPosition + posOff;
  231.             
  232.     return 0;
  233. }
  234.  
  235. CMSize ODEmbeddedHandlers::TellHandler()
  236. {    
  237.     return fPosition;
  238. }
  239.  
  240. CMSize ODEmbeddedHandlers::ReadHandler(CMPtr buffer, CMSize elementSize, CMCount theCount)
  241. {
  242.     ODULong    tryToRead = (ODULong) elementSize * (ODULong) theCount;
  243.  
  244. #if kLargeEmbeddedBlock
  245.     ODULong    amountRead = 0;
  246.     
  247.     if (fPosition < fBufferBegin) {
  248.         /* at least some of it on disk */
  249.         if (tryToRead > (fBufferBegin - fPosition)) {
  250.             /* first read from disk, later read from buffer */
  251.             amountRead = (ODULong) CMReadValueData(fParentValue, buffer, fPosition, 
  252.                                                       (CMSize) (fBufferBegin - fPosition));
  253.             if (amountRead != (fBufferBegin - fPosition)) {
  254.                 /* trouble, don't continue */
  255.                 fPosition += amountRead;            /* update position by amount read                */
  256.                 
  257.                 tryToRead = 0;        
  258.             }
  259.             else {
  260.                 fPosition += amountRead;            /* update position by amount read                */
  261.                 tryToRead -= amountRead;
  262.                 buffer = (CMPtr)((char *)buffer + amountRead);
  263.             }
  264.         }
  265.         else { /* it should all be from disk */
  266.             amountRead = (ODULong) CMReadValueData(fParentValue, buffer, fPosition, 
  267.                                                       (CMSize) tryToRead);
  268.             fPosition += amountRead;            /* update position by amount read                */
  269.             
  270.             return ((CMSize) amountRead);        
  271.         }
  272.     }
  273.  
  274.     if ((tryToRead) && (fPosition >= fBufferBegin)) {                /* it may be in the buffer                */
  275.         if (tryToRead > (fSize - fPosition))
  276.             tryToRead = fSize - fPosition;
  277.         ODBlockMove(fBuffer+fPosition-fBufferBegin, buffer, tryToRead);
  278.         amountRead += tryToRead;
  279.         fPosition += tryToRead;
  280.     }
  281.     
  282.     return ((CMSize) amountRead);        
  283.     
  284. #else
  285.     tryToRead = (ODULong) CMReadValueData(fParentValue,     
  286.                                             buffer,
  287.                                             fPosition, 
  288.                                             (CMSize) tryToRead);
  289.     
  290.     fPosition += tryToRead;                        /* update position by amount read                */
  291.     
  292.     return ((CMSize) tryToRead);        
  293. #endif
  294. }
  295.  
  296. CMSize ODEmbeddedHandlers::WriteHandler(CMPtr buffer, CMSize elementSize, CMCount theCount)
  297. {
  298.     ODULong tryWriteAmount = (ODULong) elementSize * (ODULong) theCount;
  299. #if kLargeEmbeddedBlock
  300.     ODULong amountWritten = 0;
  301.     
  302.     /* if there is any data in the portion that is already on disk, write those out first */
  303.     if (fPosition < fBufferBegin) {
  304.         if ((fPosition + tryWriteAmount) > fBufferBegin) { /* it goes over to the buffer */
  305.             amountWritten = fBufferBegin - fPosition;
  306.             tryWriteAmount -= amountWritten;
  307.         }
  308.         else {
  309.             amountWritten = tryWriteAmount;
  310.             tryWriteAmount = 0;
  311.         }
  312.         CMWriteValueData(fParentValue, buffer, fPosition, amountWritten);
  313.         fPosition += amountWritten;
  314.         buffer = (CMPtr)((char *)buffer + amountWritten);
  315.     }
  316.     
  317.     /* if there is any that should go into the buffer or extend to the buffer, move them there */
  318.     
  319.     while (tryWriteAmount > 0) {
  320.         if ((fPosition + tryWriteAmount) <= (fBufferBegin + kEmbeddedBlockSize)) {
  321.             /* we can put everything into the buffer                                        */
  322.             ODBlockMove(buffer, fBuffer + fPosition - fBufferBegin, tryWriteAmount);
  323.             amountWritten += tryWriteAmount;
  324.             fPosition += tryWriteAmount;
  325.             if (fPosition > fSize)
  326.                 fSize = fPosition;
  327.             tryWriteAmount = 0;        /* so we are done */            
  328.         }
  329.         else {
  330.             /* we go beyond the end of the buffer, so we cannot put there directly */
  331.             if (fBufferBegin < fSize) {
  332.                 /* if there are data in the buffer, flush it first, maybe there is room afterwards */
  333.                 (void) this->FlushHandler();
  334.             }
  335.             else {
  336.                 /* there is no data in buffer, yet it does not fit, so just write it out directly */
  337.                 CMWriteValueData(fParentValue, buffer, fPosition, (CMSize) tryWriteAmount);
  338.                 amountWritten += tryWriteAmount;
  339.                 fPosition += tryWriteAmount;
  340.                 fSize = fPosition;
  341.                 fBufferBegin = fSize;
  342.                 tryWriteAmount = 0;        /* so we are done */            
  343.             }
  344.         }
  345.     }
  346.     return amountWritten;
  347. #else
  348.     CMWriteValueData(fParentValue, buffer, fPosition, (CMSize) tryWriteAmount);
  349.     fPosition += tryWriteAmount;                    /* update position by amount written    */
  350.  
  351.     if (fPosition > fSize)                        /* if writing past end of value...        */
  352.         fSize = fPosition;                        /* ...set new value size                */
  353.     
  354.     return tryWriteAmount;
  355. #endif
  356.     
  357. }
  358.  
  359. CMEofStatus ODEmbeddedHandlers::EOFHandler()
  360. {
  361.     return ((CMEofStatus) kODFalse);
  362. }
  363.  
  364. CMBoolean ODEmbeddedHandlers::TruncHandler(CMSize containerSize)
  365. {
  366.     if ((ODULong)containerSize <= fSize) {
  367. #if kLargeEmbeddedBlock
  368.         /* only need actually to delete if end result is nothing in the buffer */
  369.         if ((ODULong)containerSize <= fBufferBegin) {
  370.             ODULong    amountToDelete;
  371.             if (fSize > fBufferBegin)
  372.                 amountToDelete = fBufferBegin - (ODULong) containerSize;        /* don't delete amount in buffer */
  373.             else
  374.                 amountToDelete = fSize - (ODULong) containerSize;            /* else delete from end */
  375.             CMDeleteValueData(fParentValue,  (CMCount) containerSize, (CMSize) amountToDelete);
  376.             fBufferBegin = (ODULong) containerSize;        /* so it would match fSize => empty buffer */
  377.         }
  378. #else
  379.     CMDeleteValueData(fParentValue,                                         
  380.                         (CMCount) containerSize,
  381.                         (CMSize) (fSize - (ODULong) containerSize));
  382. #endif
  383.         fSize    = (ODULong) containerSize;    
  384.     
  385.         return kODTrue;
  386.     }
  387.     else
  388.         return kODFalse;
  389. }
  390.  
  391. CMSize ODEmbeddedHandlers::ContainerSizeHandler()
  392. {
  393.     fPosition = fSize;                        /* moral equivalent of seek/tell    */
  394.     
  395.     return ((CMSize) fSize);
  396. }
  397.  
  398. void ODEmbeddedHandlers::ReadLabelHandler(CMMagicBytes magicByteSequence,
  399.                                      CMContainerFlags *flags, CM_USHORT *bufSize,
  400.                                      CM_USHORT *majorVersion, CM_USHORT *minorVersion,
  401.                                      CMSize *tocOffset, CMSize *tocSize)
  402. {
  403.     ODULong            labelSize;
  404.     ContainerLabelFmt    theLabel;
  405.  
  406.     /* Seek to the end of the label at the end of the value and read it...                                */
  407.     
  408.     this->SeekHandler(-(ODSLong)sizeof(ContainerLabelFmt), kCMSeekEnd);
  409.     labelSize = (ODULong) this->ReadHandler((CMPtr) &theLabel,
  410.                                                 (CMSize) sizeof(ODUByte),
  411.                                                 (CMCount) sizeof(ContainerLabelFmt));
  412.     
  413.     if (labelSize != sizeof(ContainerLabelFmt)) {        /* must have read it all!                            */
  414.         CMError(fSession, "Embedded container (type \"^0\") label could not be read!", fTypeName);
  415.         return;
  416.     }
  417.     
  418.     /* Return all the label info...                                                                                                                */
  419.     
  420.     ODBlockMove(theLabel.magicBytes, magicByteSequence, 8);
  421. #if kCMDefaultEndian
  422.     /* little endian machine */
  423.     if ((theLabel.flags & kCMLittleEndianTwin) == 0) {
  424. #else
  425.     /* big endian machine */
  426.     if (theLabel.flags & kCMLittleEndianTwin) {
  427. #endif
  428.         fReverseEndian = kODTrue;
  429.         *flags = ODFlipShort(theLabel.flags);
  430.         *bufSize = ODFlipShort(theLabel.bufSize);
  431.         *majorVersion = ODFlipShort(theLabel.majorVersion);
  432.         *minorVersion = ODFlipShort(theLabel.minorVersion);
  433.         *tocOffset = ODFlipLong(theLabel.tocOffset);
  434.         *tocSize = ODFlipLong(theLabel.tocSize);
  435.     }
  436.     else {
  437.         *flags = (CMContainerFlags)theLabel.flags;
  438.         *bufSize = (CM_USHORT)theLabel.bufSize;
  439.         *majorVersion = (CM_USHORT)theLabel.majorVersion;
  440.         *minorVersion = (CM_USHORT)theLabel.minorVersion;
  441.         *tocOffset = (CMSize)theLabel.tocOffset;
  442.         *tocSize = (CMSize)theLabel.tocSize;
  443.     }
  444. }
  445.  
  446. void ODEmbeddedHandlers::WriteLabelHandler(CMMagicBytes magicByteSequence,
  447.                                         CMContainerFlags flags, CM_USHORT bufSize,
  448.                                         CM_USHORT majorVersion, CM_USHORT minorVersion,
  449.                                         CMSize tocOffset, CMSize tocSize)
  450. {
  451.     ODULong            labelSize;
  452.     ContainerLabelFmt    theLabel;
  453.  
  454.     /* Fill in the label buffer with the info...                                                                                    */
  455.     
  456.     flags = (CMContainerFlags) ((CM_USHORT)flags & ~kCMLittleEndianTwin);    /* ignore what is passed in */
  457.     if (fReverseEndian) {
  458.         theLabel.flags = ODFlipShort(flags | (kCMLittleEndianTwin & ~kCMDefaultEndian));
  459.         theLabel.bufSize = ODFlipShort(bufSize);
  460.         theLabel.majorVersion = ODFlipShort(majorVersion); 
  461.         theLabel.minorVersion = ODFlipShort(minorVersion);
  462.         theLabel.tocOffset = ODFlipLong(tocOffset);
  463.         theLabel.tocSize = ODFlipLong(tocSize);
  464.     }
  465.     else {
  466.         theLabel.flags = (ODUShort)(flags | kCMDefaultEndian);
  467.         theLabel.bufSize = (ODUShort)bufSize;
  468.         theLabel.majorVersion = (ODUShort)majorVersion; 
  469.         theLabel.minorVersion = (ODUShort)minorVersion;
  470.         theLabel.tocOffset = (ODULong)tocOffset;
  471.         theLabel.tocSize = (ODULong)tocSize;
  472.     }
  473.     
  474.     ODBlockMove(magicByteSequence, theLabel.magicBytes, 8);
  475.  
  476.     /* Write the label to the end of the embedded container value...*/
  477.     
  478.     this->SeekHandler(0, kCMSeekEnd);
  479.     labelSize = (ODULong) this->WriteHandler((CMPtr) &theLabel,
  480.                                             (CMSize) sizeof(unsigned char),
  481.                                             (CMCount) sizeof(ContainerLabelFmt));
  482.  
  483.     if (labelSize != sizeof(ContainerLabelFmt))
  484.         THROW(kODErrBentoErr);
  485. }
  486.  
  487. CMValue ODEmbeddedHandlers::ReturnParentValueHandler()
  488. {
  489.     return fParentValue;
  490. }
  491.  
  492. CM_UCHAR* ODEmbeddedHandlers::ReturnContainerNameHandler()
  493. {
  494.     return ((CM_UCHAR *) fTypeName);
  495. }
  496.  
  497. CMType ODEmbeddedHandlers::ReturnTargetTypeHandler(CMContainer container)
  498. {
  499.     CMType indirectType;
  500.     
  501.     CMSetMetaHandler(fSession,
  502.                     kODIndirectValueGlobalName,
  503.                     IndirectDynamicValueMetahandler);
  504.     indirectType = CMRegisterType(container, kODIndirectValueGlobalName);
  505.                         
  506.     return indirectType;
  507. }
  508.  
  509. void ODEmbeddedHandlers::ExtractDataHandler(CMDataBuffer buffer,
  510.                                                  CMSize size, CMPrivateData data)
  511. {
  512.     ODBoolean    reverseEndian = fReverseEndian;
  513.     
  514.     if ((long)size < 0) {    /* this means it is endian-ness netural    */
  515.         size = -(long)size;
  516.         reverseEndian = kODFalse;
  517.     }
  518.     
  519.     if (reverseEndian)
  520.         ODFlipMove(buffer, data, (size_t)size);
  521.     else
  522.         ODBlockMove(buffer, data, (size_t)size);
  523. }
  524.  
  525. void ODEmbeddedHandlers::FormatDataHandler(CMDataBuffer buffer,
  526.                                      CMSize size, CMPrivateData data)
  527. {
  528.     ODBoolean    reverseEndian = fReverseEndian;
  529.     
  530.     if ((long)size < 0) {    /* this means it is endian-ness netural    */
  531.         size = -(long)size;
  532.         reverseEndian = kODFalse;
  533.     }
  534.     
  535.     if (reverseEndian)
  536.         ODFlipMove(data, buffer, (size_t)size);
  537.     else
  538.         ODBlockMove(data, buffer, (size_t)size);
  539. }
  540.