home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / opendc12.zip / od124os2.exe / od12osr1.exe / src / FSHdr.cpp < prev    next >
C/C++ Source or Header  |  1997-03-21  |  22KB  |  672 lines

  1. /* @(#)Z 1.13 com/src/bento/FSHdr.cpp, odstorage, od96os2, odos29712d 97/03/21 17:19:18 (96/10/29 09:12:30) */
  2. //====START_GENERATED_PROLOG======================================
  3. //
  4. //
  5. //   COMPONENT_NAME: odstorage
  6. //
  7. //   CLASSES: none
  8. //
  9. //   ORIGINS: 82,27
  10. //
  11. //
  12. //   (C) COPYRIGHT International Business Machines Corp. 1995,1996
  13. //   All Rights Reserved
  14. //   Licensed Materials - Property of IBM
  15. //   US Government Users Restricted Rights - Use, duplication or
  16. //   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  17. //       
  18. //   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  19. //   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  20. //   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  21. //   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  22. //   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  23. //   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
  24. //   OR PERFORMANCE OF THIS SOFTWARE.
  25. //
  26. //====END_GENERATED_PROLOG========================================
  27. //
  28.  
  29. /*
  30.     File:        FSHdr.cpp
  31.  
  32.     Contains:    Class definition for ODFSBentoHandlers class.
  33.  
  34.     Owned by:    Vincent Lo
  35.  
  36.     Copyright:    ⌐ 1993 - 1995 by Apple Computer, Inc., all rights reserved.
  37.  
  38.     Change History (most recent first):
  39.  
  40.         <17>     8/12/95    Té        1276806 Optimization: use kODFalse instead
  41.                                     of kODTrue in comparisons
  42.         <16>     5/26/95    VL        1251403: Multithreading naming support.
  43.         <15>     5/11/95    EL        Use ODBlockMove instead of memcpy.
  44.         <14>     4/25/95    EL        1242376: Synchronize label between handler
  45.                                     and container after WriteLabel.
  46.         <13>     4/10/95    EL        1236290: No debugger warning of file not
  47.                                     properly closed for DR2.
  48.         <12>      4/7/95    EL        1225905: More ModDate stuff to container.
  49.                                     Use FlipEnd.
  50.         <11>     3/24/95    EL        1225905: Move state information such as mod
  51.                                     date from plfmFile to here
  52.         <10>     3/13/95    EL        1226127 fix bug where endOfWrite is very
  53.                                     close to end of file we need a new block
  54.                                     for the safety label.
  55.          <9>     3/10/95    EL        1223465: allocate buffer on the heap.
  56.                                     1226127 fix bug buffering code destory
  57.                                     safety label at file end. Scan backward for
  58.                                     label if file is corrupted. 1227122
  59.                                     truncate file if space was lost in crash.
  60.          <8>     2/15/95    EL        1213321: Fix buffering bug where part of
  61.                                     the read in data is not the same as data in
  62.                                     a dirty buffer.
  63.          <7>     2/10/95    VL        1205627: Make it work for readonly file.
  64.          <6>     1/31/95    EL        1213321: Buffer the Bento file I/O.
  65.          <5>    11/14/94    VL        1188257: Use Bento errors in BenotDef.h.
  66.          <4>     8/26/94    EL        #1182308 Allows non-byte swapping
  67.                                     format/extract.
  68.          <3>      8/8/94    VL        1170009: Wrong byte calculation in
  69.                                     ReadHandler.
  70.          <2>     6/18/94    MB        Correct memory includes
  71.          <1>     5/27/94    VL        first checked in
  72.  
  73.     To Do:
  74.         1) Get rid of fSession. Make it global.
  75.         2) Share ODFlipMove among handlers.
  76.         3) Make sure scan for valid label code work for document edited in both
  77.            big and little endian platform.
  78. */
  79.  
  80. #ifdef _PLATFORM_MACINTOSH_
  81. #define fsFromStart    SEEK_SET
  82. #endif
  83.  
  84. #ifndef    _ODTYPES_
  85. #include "ODTypes.h"
  86. #endif
  87.  
  88. #ifndef _FSHDR_
  89. #include "FSHdr.h"
  90. #endif
  91.  
  92. #ifndef _BENTOHDR_
  93. #include "BentoHdr.h"
  94. #endif
  95.  
  96. #ifndef _SESSHDR_
  97. #include "SessHdr.h"
  98. #endif
  99.  
  100. #ifndef _EXCEPT_
  101. #include "Except.h"
  102. #endif
  103.  
  104. #ifndef _FLIPEND_
  105. #include "FlipEnd.h"
  106. #endif
  107.  
  108. #ifndef _PLFMFILE_
  109. #include "PlfmFile.h"
  110. #endif
  111.  
  112. #ifndef __CM_API__
  113. #include "CMAPI.h"
  114. #endif
  115.  
  116. #ifndef _ODMEMORY_
  117. #include "ODMemory.h"
  118. #endif
  119.  
  120. #ifndef _ERRORDEF_
  121. #include "ErrorDef.xh"
  122. #endif
  123.  
  124. #ifndef _BENTODEF_
  125. #include "BentoDef.h"
  126. #endif
  127.  
  128. //==============================================================================
  129. // Constants
  130. //==============================================================================
  131.  
  132. const ODType    kODBentoFileTypeName = "FileCtr";
  133.  
  134. #define kInvalidBuffer 1                /* an invalid value for fBufferBegin */
  135. #define ChunkHighBitsMask    ~(fChunkSize-1)    /* mask for masking off the lower bits */
  136.  
  137. //==============================================================================
  138. // Scalar Types
  139. //==============================================================================
  140.  
  141. //struct ContainerLabelFmt {            /* Layout of a container label:            */
  142. // unsigned char  magicBytes[8];        /* 8 bytes: the magic byte identifier    */
  143. // unsigned short flags;                /* 2    as a short                        */
  144. // unsigned short bufSize;            /* 2    TOC buffer size / 1024            */
  145. // unsigned short majorVersion;        /* 2    major format version number        */
  146. // unsigned short minorVersion;        /* 2    minor format version number        */
  147. // unsigned long    tocOffset;            /* 4    offset to start of TOC            */
  148. // unsigned long    tocSize;            /* 4    total byte size of the TOC        */
  149. //};
  150. //typedef struct ContainerLabelFmt ContainerLabelFmt;
  151.  
  152.  
  153. #pragma segment FSHdr
  154.  
  155. static void ODFlipMove(ODPtr from, ODPtr to, ODULong size)
  156. {
  157.     char    *dest = (char *)to + size - 1;
  158.     char    *src = (char *)from;
  159.     
  160.     while (size--)
  161.         *dest-- = *src++;            
  162. }
  163.  
  164. //==============================================================================
  165. // ODFSBentoHandlers
  166. //==============================================================================
  167.  
  168. ODFSBentoHandlers::ODFSBentoHandlers(CMSession session, PlatformFile* file)
  169. {
  170.     fFile = file;
  171.     fSession = session;
  172.     fBuffer = kODNULL;
  173.     fReverseEndian = kODFalse;        /* assume same Endian-ness                */
  174. }
  175.  
  176. ODFSBentoHandlers::~ODFSBentoHandlers()
  177. {
  178. }
  179.  
  180. void ODFSBentoHandlers::Initialize()
  181. {
  182.     CMSetMetaHandler(fSession, kODBentoFileTypeName, (CMMetaHandler) containerMetahandler);
  183. }
  184.  
  185. CMSession ODFSBentoHandlers::GetCMSession()
  186. {
  187.     return fSession;
  188. }
  189.  
  190. CMRefCon ODFSBentoHandlers::OpenHandler(CMOpenMode mode)
  191. {
  192.     Environment* ev = somGetGlobalEnvironment();
  193.     ODULong    chunkSize;
  194.  
  195.     fFile->Open();
  196.     fFileSize = fFile->GetEndOfFile();
  197.     fPhysicalFileSize = fFileSize;    /* must set it here because used in read label */
  198.     fWriteLimit = fFileSize;        /* normally initialize in read label, but we may not have label */
  199.     fLogicalPos = 0;
  200.     fBufferBegin = kInvalidBuffer; /* buffer not loaded yet */
  201.     fBufferDirty = kODFalse;
  202.     fHasLabel = kODFalse;
  203.     chunkSize = fFile->GetAllocationBlockSize();
  204.     /* make sure it is a multiple of 2 */
  205.     for (fChunkSize = MininumChunkSize; fChunkSize < chunkSize; fChunkSize *= 2)
  206.         ;
  207.     try
  208.         {
  209.         fBuffer = (ODSByte *)ODNewPtr(fChunkSize);
  210.         }
  211.     catch ( ODException _exception)
  212.         {
  213.         /* there may be platform that returns a large chunksize to try to read     */
  214.         /* the whole file into memory. If that fails, we can try to allocate       */
  215.         /* with a default chunksize so that it can still run. In theory even       */
  216.         /* if the default chunksize memory allocation fails, we can still catch    */
  217.         /* and run without buffering, but if memory is really so short at        */
  218.         /* open time, may as well forget about it                                */
  219.                 SetErrorCode(kODNoError);
  220.         fChunkSize = DefaultChunkSize;
  221.         fBuffer = (ODSByte *)ODNewPtr(fChunkSize);    
  222.     }
  223.     if ((strcmp(mode, "rb") == 0) || fFile->IsLocked())
  224.         fOpenReadOnly = kODTrue;
  225.     else {
  226.         fOpenReadOnly = kODFalse;
  227.         if (fFileSize > sizeof(ContainerLabelFmt)) {
  228.             CM_UCHAR magicBytes[8];
  229.             CMContainerFlags flags;
  230.             CM_USHORT bufSize;
  231.             CM_USHORT majorVersion;
  232.             CM_USHORT minorVersion;
  233.             ODULong tocOffset;
  234.             ODULong tocSize;
  235.             this->ReadLabelHandler(magicBytes, &flags, &bufSize,
  236.                      &majorVersion, &minorVersion,
  237.                      &tocOffset, &tocSize);
  238.         }
  239.     }
  240.  
  241.     return ((CMRefCon) this);
  242. }
  243.  
  244. void ODFSBentoHandlers::CloseHandler()
  245. {
  246.     if (fBufferDirty)
  247.         this->FlushBuffer();
  248.     if (fBuffer != kODNULL) {
  249.         ODDisposePtr(fBuffer);
  250.         fBuffer = kODNULL;
  251.     }
  252.     if (fOpenReadOnly == kODFalse) {
  253.         fFile->SetEndOfFile(fFileSize);        /* remove the reserved space */
  254.     }
  255.     fFile->Close();
  256.     fHasLabel = kODFalse;
  257. }
  258.  
  259. CMSize ODFSBentoHandlers::FlushHandler()
  260. {
  261.     Environment* ev = somGetGlobalEnvironment();
  262.     int result = 0;
  263.     
  264.     ODVolatile(result);
  265.     
  266.     if (fBufferDirty)
  267.         this->FlushBuffer();
  268.     fFile->FlushVolume();
  269.  
  270.     return result;
  271. }
  272.  
  273. CMSize ODFSBentoHandlers::SeekHandler(CM_LONG posOff, CMSeekMode mode)
  274. {
  275.     if (mode == kCMSeekEnd)
  276.         fLogicalPos = fFileSize + posOff;
  277.     else if (mode == kCMSeekCurrent) {
  278.         fLogicalPos = fLogicalPos + posOff;
  279.     }
  280.     else
  281.         fLogicalPos = posOff;
  282.     
  283.     return 0;
  284. }
  285.  
  286. CMSize ODFSBentoHandlers::TellHandler()
  287. {    
  288.     return fLogicalPos;
  289. }
  290.  
  291. CMSize ODFSBentoHandlers::ReadHandler(CMPtr buffer, CMSize elementSize, CMCount theCount)
  292. {
  293.     ODULong    endOfRead, firstReadBlock, lastReadBlock;
  294.  
  295.     ODSLong amountRead = elementSize * theCount;
  296.     endOfRead = fLogicalPos + amountRead;
  297.     if (endOfRead > fFileSize) {
  298.         amountRead = fFileSize - fLogicalPos;
  299.         endOfRead = fFileSize;
  300.     }
  301.     firstReadBlock = fLogicalPos & ChunkHighBitsMask;
  302.     lastReadBlock = (endOfRead-1) & ChunkHighBitsMask;
  303.         
  304.     if (firstReadBlock == lastReadBlock) {
  305.         /* the content to read can be in a single buffer */
  306.         if (firstReadBlock != fBufferBegin) /* the block is not loaded */
  307.             this->ReloadBuffer();
  308.         /* After we make sure the buffer is loaded, we just copy it from the buffer */
  309.         ODBlockMove(fBuffer+fLogicalPos-fBufferBegin, buffer, amountRead);
  310.     }
  311.     else { /* for bigger block we read it directly bypassing the buffer */
  312.         /* if we read directly and part of data is in dirty buffer then write it first */
  313.         if ((fBufferDirty != kODFalse) && (firstReadBlock <= fBufferBegin) && (fBufferBegin <= lastReadBlock))
  314.             this->FlushBuffer();
  315.         fFile->SetFilePos(fsFromStart, fLogicalPos);
  316.         fFile->Read((ODSByte*) buffer, &amountRead);
  317.     }
  318.     
  319.     fLogicalPos = endOfRead;
  320.     
  321.     return ((CMSize)amountRead);
  322. }
  323.  
  324. CMSize ODFSBentoHandlers::WriteHandler(CMPtr buffer, CMSize elementSize, CMCount theCount)
  325. {
  326.     ODULong            endOfWrite, newEndOfFile, beginWriteBlock, toMove, theGap;
  327.     ODSLong            labelSize, amountWritten;
  328.     ODBoolean        needToWrite;
  329.     
  330.     if (theCount > 0) {    
  331.     
  332.         amountWritten = elementSize * theCount;
  333.         endOfWrite = fLogicalPos + amountWritten;
  334.         beginWriteBlock = fLogicalPos & ChunkHighBitsMask;
  335.         needToWrite = kODTrue;
  336.  
  337.         if ((beginWriteBlock == ((endOfWrite-1) & ChunkHighBitsMask)) && (beginWriteBlock != fBufferBegin)) {
  338.             /* changes are all in a single buffer but data not loaded, load it now */
  339.             this->ReloadBuffer();
  340.         }
  341.  
  342.         if (fBufferBegin != kInvalidBuffer) { /* we have a buffer */
  343.             if (fLogicalPos < fBufferBegin) { /* the tail of the write may touch the buffer */
  344.                 if (endOfWrite > fBufferBegin) { /* yes, the tail touches the buffer */
  345.                     /*
  346.                     
  347.                         fLogicalPos     fBufferBegin      endOfWrite
  348.                              |              |                 |       |
  349.                                             <-       ChunkSize      ->
  350.                                             <-  toMove      ->
  351.                     */
  352.                     toMove = endOfWrite - fBufferBegin;  /* move so many bytes into the buffer */
  353.                     if (toMove > fChunkSize)             /* but no larger than the buffer itself */
  354.                         toMove = fChunkSize;
  355.                     /* update the part of the buffer that has been changed */
  356.                     ODBlockMove((char *)buffer+fBufferBegin-fLogicalPos, fBuffer, toMove);
  357.                     /* note that we do not need to dirty it because we still write it out */
  358.                 }
  359.             }
  360.             else { /* the front part of the write may touch the buffer */
  361.                 theGap = fLogicalPos - fBufferBegin;
  362.                 if (theGap < fChunkSize) { /* yes, it does touch the buffer */
  363.                     /*
  364.                     
  365.                         fBufferBegin    fLogicalPos            endOfWrite
  366.                              |               |        |            |
  367.                              <-       ChunkSize      ->
  368.                              <-   theGap    ->
  369.                                              <-   amountWritten   ->
  370.                                              <-toMove->
  371.  
  372.                     */
  373.                     toMove = amountWritten;
  374.                     if (toMove + theGap > fChunkSize)
  375.                         toMove = fChunkSize - theGap;
  376.                     else {
  377.                         fBufferDirty = kODTrue; /* dirty it so we would write it out later */
  378.                         needToWrite = kODFalse;    /* for now, no writing is necessary */
  379.                     }
  380.                     ODBlockMove(buffer, fBuffer + theGap, toMove); /* update the buffer */
  381.                 }
  382.             }
  383.         }
  384.          
  385.         if (endOfWrite > fFileSize) { /* we are appending */
  386.             if (endOfWrite > fWriteLimit) {
  387.                 ODSLong    newWriteLimit;
  388.                 /* extend it to block boundry */
  389.                 newEndOfFile = ((endOfWrite + fChunkSize)) & ChunkHighBitsMask;
  390.                 if (fHasLabel != kODFalse) {
  391.                     /* must have enough room to end of file to fit in a label */
  392.                     if ((newEndOfFile - endOfWrite) < sizeof(ContainerLabelFmt))
  393.                         newEndOfFile = newEndOfFile + fChunkSize;
  394.                     newWriteLimit = newEndOfFile - sizeof(ContainerLabelFmt);
  395.                 }
  396.                 else
  397.                     newWriteLimit = newEndOfFile;
  398.                 /* We will add at least another block to file, so we need a new label at end */
  399.                 fFile->SetEndOfFile(newEndOfFile);
  400.                 fPhysicalFileSize = newEndOfFile;
  401.                 fWriteLimit = newWriteLimit;
  402.                 if (fHasLabel != kODFalse) {
  403.                     if ((fWriteLimit & ChunkHighBitsMask) == fBufferBegin) {
  404.                         /* the label at the end will overlap with the buffer, put it in the buffer */
  405.                         ODBlockMove(&fLabel, fBuffer + fChunkSize - sizeof(ContainerLabelFmt), sizeof(ContainerLabelFmt));
  406.                     }
  407.                     fFile->SetFilePos(fsFromStart, fWriteLimit);
  408.                     labelSize = sizeof(ContainerLabelFmt);
  409.                         fFile->Write((const ODSByte*)&fLabel, &labelSize);
  410.                         /* if fails, no safety label at end of end, that is not end of the world */
  411.                 }
  412.             }
  413.             fFileSize = endOfWrite;
  414.         }
  415.         if (needToWrite != kODFalse) {
  416.             fFile->SetFilePos(fsFromStart, fLogicalPos);
  417.             fFile->Write((const ODSByte*)buffer, &amountWritten);
  418.         }
  419.         fLogicalPos = endOfWrite;
  420.     } else
  421.         amountWritten = 0;
  422.  
  423.     return ((CMSize)amountWritten);
  424. }
  425.  
  426. void ODFSBentoHandlers::FlushBuffer()
  427. {
  428.     ODSLong        theSize = fChunkSize;    
  429.  
  430.     fFile->SetFilePos(fsFromStart, fBufferBegin);
  431.     if (fPhysicalFileSize - fBufferBegin < fChunkSize)
  432.         theSize = fPhysicalFileSize - fBufferBegin;
  433.     fFile->Write(fBuffer, &theSize);
  434.     fBufferDirty = kODFalse;
  435. }
  436.  
  437. void ODFSBentoHandlers::ReloadBuffer()
  438. {
  439.     ODSLong        theSize;    
  440.  
  441.     if (fBufferDirty != kODFalse)
  442.         this->FlushBuffer();
  443.     fBufferBegin = fLogicalPos & ChunkHighBitsMask;
  444.     fFile->SetFilePos(fsFromStart, fBufferBegin);
  445.     theSize = fChunkSize;
  446.     if (fPhysicalFileSize - fBufferBegin < fChunkSize)
  447.         theSize = fPhysicalFileSize - fBufferBegin;
  448.     fFile->Read(fBuffer, &theSize);
  449. }
  450.  
  451. CMEofStatus ODFSBentoHandlers::EOFHandler()
  452. {
  453.     return ((CMEofStatus) kODFalse);
  454.  
  455. }
  456.  
  457. CMBoolean ODFSBentoHandlers::TruncHandler(CMSize containerSize)
  458. {
  459.     fFileSize = containerSize;        
  460.     return kODTrue;
  461. }
  462.  
  463. CMSize ODFSBentoHandlers::ContainerSizeHandler()
  464. {
  465.     return ((CMSize) fFileSize);
  466. }
  467.  
  468. void ODFSBentoHandlers::ReadLabelHandler(CMMagicBytes magicByteSequence,
  469.                                      CMContainerFlags *flags, CM_USHORT *bufSize,
  470.                                      CM_USHORT *majorVersion, CM_USHORT *minorVersion,
  471.                                      CMSize *tocOffset, CMSize *tocSize)
  472. {
  473.     ODULong        endOfTOC, tempFileEnd;
  474.     char *magicSequence = "\xA4""CM""\xA5""Hdr""\xD7";        /* Must be 8 characters        */
  475.     ODBoolean         labelMatches = fHasLabel;
  476.  
  477.     /* Seek to the end of the label at the end of the container and read it...*/
  478.     
  479.     tempFileEnd = fFileSize;
  480.     while (tempFileEnd > sizeof(ContainerLabelFmt)) {
  481.         fLogicalPos = tempFileEnd - sizeof(ContainerLabelFmt);
  482.         /* if we really want to speed it up, we could compare it directly from the buffer     */
  483.         /* but since we only need to loop through this in corrupted file and that does not    */
  484.         /* occur very often, and even when it happens, the current speed is acceptable          */
  485.         /* so we would leave it as it is now                                                */
  486.         if (this->ReadHandler((CMPtr)&fLabel, (CMSize)sizeof(unsigned char), 8) !=  8)
  487.                 THROW(kODErrBentoErr);
  488.         if (memcmp(&fLabel.magicBytes, magicSequence, 8) == 0)
  489.             labelMatches = kODTrue;
  490.         if (labelMatches) {
  491.             /* Return all the label info... */
  492.             fLogicalPos = tempFileEnd - sizeof(ContainerLabelFmt);
  493.             if (this->ReadHandler((CMPtr)&fLabel, 
  494.                                   (CMSize)sizeof(unsigned char), 
  495.                                   sizeof(ContainerLabelFmt)) !=  sizeof(ContainerLabelFmt))
  496.                     THROW(kODErrBentoErr);
  497.             ODBlockMove(&fLabel.magicBytes, magicByteSequence, 8);
  498. #if kCMDefaultEndian
  499.             /* little endian machine */
  500.             if ((fLabel.flags & kCMLittleEndianTwin) == 0) {
  501. #else
  502.             /* big endian machine */
  503.             if (fLabel.flags & kCMLittleEndianTwin) {
  504. #endif
  505.                 fReverseEndian = kODTrue;
  506.                 *flags = ODFlipShort(fLabel.flags);
  507.                 *bufSize = ODFlipShort(fLabel.bufSize);
  508.                 *majorVersion = ODFlipShort(fLabel.majorVersion);
  509.                 *minorVersion = ODFlipShort(fLabel.minorVersion);
  510.                 *tocOffset = ODFlipLong(fLabel.tocOffset);
  511.                 *tocSize = ODFlipLong(fLabel.tocSize);
  512.             }
  513.             else {
  514.                 fReverseEndian = kODFalse;
  515.                 *flags = (CMContainerFlags)fLabel.flags;
  516.                 *bufSize = (CM_USHORT)fLabel.bufSize;
  517.                 *majorVersion = (CM_USHORT)fLabel.majorVersion;
  518.                 *minorVersion = (CM_USHORT)fLabel.minorVersion;
  519.                 *tocOffset = (CMSize)fLabel.tocOffset;
  520.                 *tocSize = (CMSize)fLabel.tocSize;
  521.             }
  522.             endOfTOC = *tocOffset + *tocSize + sizeof(ContainerLabelFmt);
  523.             if (endOfTOC == tempFileEnd) {
  524.                 /* match exactly, this is most likely to be the label */
  525.                 if (endOfTOC != fFileSize) {
  526.                     WARNMSG_DEBUG(WARN_INDEX(-1),
  527.                     "The file was corrupted! I will just do my best to read it");
  528.                     fFileSize = endOfTOC;
  529.                 }
  530.                 fHasLabel = kODTrue;
  531.                 break;
  532.             }
  533.             if (endOfTOC < tempFileEnd) {
  534.                 ContainerLabelFmt tempLabel;
  535.                 fLogicalPos = endOfTOC - sizeof(ContainerLabelFmt);
  536.                 if (this->ReadHandler((CMPtr)&tempLabel, 
  537.                                       (CMSize)sizeof(unsigned char), 
  538.                                       sizeof(ContainerLabelFmt)) !=  sizeof(ContainerLabelFmt))
  539.                     THROW(kODErrBentoErr);
  540.                 if (memcmp(&tempLabel, &fLabel, sizeof(ContainerLabelFmt)) == 0) {
  541. //#if ODDebug
  542. //                    WARN("The file was not closed properly! You get away with it this time");
  543. //#endif
  544.                     /* we passed the sanity check, so we can truncate the file and use the label */
  545.                     fFileSize = endOfTOC;
  546.                     fHasLabel = kODTrue;
  547.                     break;
  548.                 }
  549.                 /* even if we did not pass the test, if the label was at the end, still accept it */
  550.                 if (tempFileEnd == fFileSize) {
  551.                     WARNMSG_DEBUG(WARN_INDEX(0),
  552.                          "File looks funny! Send a copy to Bento folks");
  553.                     fHasLabel = kODTrue;
  554.                     break;
  555.                 }
  556.             }
  557.         } /* it is a label */
  558.         /* otherwise keep scanning backwards */
  559.         labelMatches = kODFalse;
  560.         tempFileEnd -= 1;
  561.     }
  562.     if (fHasLabel) {
  563.         fPhysicalFileSize = fFileSize;
  564.         fWriteLimit = fFileSize;
  565.         if ((fOpenReadOnly == kODFalse) && (fFile->GetEndOfFile() != fFileSize)) {
  566.             fFile->SetEndOfFile(fFileSize);        /* get back the correct size */
  567.         }
  568.     }
  569.     else
  570.         WARNMSG_DEBUG(WARN_INDEX(0),
  571.              "File has no valid Bento label. Cannot be recovered");
  572. }
  573.  
  574. void ODFSBentoHandlers::WriteLabelHandler(CMMagicBytes magicByteSequence,
  575.                                         CMContainerFlags flags, CM_USHORT bufSize,
  576.                                         CM_USHORT majorVersion, CM_USHORT minorVersion,
  577.                                         CMSize tocOffset, CMSize tocSize)
  578. {
  579.     ODULong                labelSize;
  580.     ContainerLabelFmt    theLabel;
  581.         
  582.     /* Fill in the label buffer with the info...                                                                                    */
  583.     
  584.     flags = (CMContainerFlags) ((CM_USHORT)flags & ~kCMLittleEndianTwin);    /* ignore what is passed in */
  585.     if (fReverseEndian) {
  586.         theLabel.flags = ODFlipShort(flags | (kCMLittleEndianTwin & ~kCMDefaultEndian));
  587.         theLabel.bufSize = ODFlipShort(bufSize);
  588.         theLabel.majorVersion = ODFlipShort(majorVersion); 
  589.         theLabel.minorVersion = ODFlipShort(minorVersion);
  590.         theLabel.tocOffset = ODFlipLong(tocOffset);
  591.         theLabel.tocSize = ODFlipLong(tocSize);
  592.     }
  593.     else {
  594.         theLabel.flags = (ODUShort)(flags | kCMDefaultEndian);
  595.         theLabel.bufSize = (ODUShort)bufSize;
  596.         theLabel.majorVersion = (ODUShort)majorVersion; 
  597.         theLabel.minorVersion = (ODUShort)minorVersion;
  598.         theLabel.tocOffset = (ODULong)tocOffset;
  599.         theLabel.tocSize = (ODULong)tocSize;
  600.     }
  601.     
  602.     ODBlockMove(magicByteSequence, theLabel.magicBytes, 8);
  603.  
  604.     /* Write the label to the end of the container value...                                                                */
  605.     
  606.     this->SeekHandler(0, kCMSeekEnd);
  607.     labelSize = (unsigned long)this->WriteHandler((CMPtr)&theLabel,
  608.                                             (CMSize)sizeof(unsigned char),
  609.                                             (CMCount)sizeof(ContainerLabelFmt));
  610.     
  611.     if (labelSize != sizeof(ContainerLabelFmt))
  612.         THROW(kODErrBentoErr);
  613.  
  614.     ODBlockMove(&theLabel, &fLabel, sizeof(ContainerLabelFmt));
  615.     fHasLabel = kODTrue;
  616.     fPhysicalFileSize = fFileSize;
  617.     fWriteLimit = fFileSize;
  618.     fFile->SetEndOfFile(fFileSize);        /* get back the correct size */
  619. }
  620.  
  621. CMValue ODFSBentoHandlers::ReturnParentValueHandler()
  622. {
  623.     return kODNULL;
  624. }
  625.  
  626. CM_UCHAR* ODFSBentoHandlers::ReturnContainerNameHandler()
  627. {
  628.     static Str63    name;
  629.     
  630.     fFile->GetAsciiName((char*)name,sizeof(name));
  631.     return ((CM_UCHAR *) name);
  632. }
  633.  
  634. CMType ODFSBentoHandlers::ReturnTargetTypeHandler(CMContainer container)
  635. {
  636. ODUnused(container);
  637.  
  638.     return kODNULL;
  639. }
  640.  
  641. void ODFSBentoHandlers::ExtractDataHandler(CMDataBuffer buffer,
  642.                                                  CMSize size, CMPrivateData data)
  643. {
  644.     ODBoolean    reverseEndian = fReverseEndian;
  645.     
  646.     if ((CM_LONG)size < 0) {    /* this means it is endian-ness netural    */
  647.         size = -(CM_LONG)size;
  648.         reverseEndian = kODFalse;
  649.     }
  650.     
  651.     if (reverseEndian)
  652.         ODFlipMove(buffer, data, (size_t)size);
  653.     else
  654.         ODBlockMove(buffer, data, (size_t)size);
  655. }
  656.  
  657. void ODFSBentoHandlers::FormatDataHandler(CMDataBuffer buffer,
  658.                                      CMSize size, CMPrivateData data)
  659. {
  660.     ODBoolean    reverseEndian = fReverseEndian;
  661.     
  662.     if ((CM_LONG)size < 0) {    /* this means it is endian-ness netural    */
  663.         size = -(CM_LONG)size;
  664.         reverseEndian = kODFalse;
  665.     }
  666.     
  667.     if (reverseEndian)
  668.         ODFlipMove(data, buffer, (size_t)size);
  669.     else
  670.         ODBlockMove(data, buffer, (size_t)size);
  671. }
  672.