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

  1. //====START_GENERATED_PROLOG======================================
  2. //
  3. //
  4. //   COMPONENT_NAME: odutils
  5. //
  6. //   CLASSES: none
  7. //
  8. //   ORIGINS: 82,27
  9. //
  10. //
  11. //   (C) COPYRIGHT International Business Machines Corp. 1995,1996
  12. //   All Rights Reserved
  13. //   Licensed Materials - Property of IBM
  14. //   US Government Users Restricted Rights - Use, duplication or
  15. //   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  16. //       
  17. //   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  18. //   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  19. //   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  20. //   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  21. //   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  22. //   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
  23. //   OR PERFORMANCE OF THIS SOFTWARE.
  24. //
  25. //====END_GENERATED_PROLOG========================================
  26. //
  27. // @(#) 1.19 com/src/utils/IPlfmFil.cpp, odutils, od96os2, odos29712d 3/4/97 15:39:31 [ 3/21/97 17:37:45 ]
  28. /*
  29.  
  30.     File:        PlfmFile.cpp
  31.  
  32.     Contains:    Implmentation for PlatformFile class
  33.  
  34.     Owned by:    Vincent Lo
  35.  
  36.     Copyright:    ⌐ 1993-95 by Apple Computer, Inc., all rights reserved.
  37.  
  38. */
  39.  
  40. #include <stdio.h>
  41. #include <string.h>
  42. #include <wcstr.h>
  43. #include <time.h>
  44.  
  45. #ifndef _ODTYPES_
  46. #include "ODTypes.h"
  47. #endif
  48.  
  49. #ifndef _PLFMFILE_
  50. #include "PlfmFile.h"
  51. #endif
  52.  
  53. #ifndef _ODMEMORY_
  54. #include "ODMemory.h"
  55. #endif
  56.  
  57. #ifndef _EXCEPT_
  58. #include "Except.h"
  59. #endif
  60.  
  61. #ifndef _PASCLSTR_
  62. #include "PasclStr.h"
  63. #endif
  64.  
  65. #ifndef _ITEXT_
  66. #include "IText.h"
  67. #endif
  68.  
  69. #ifndef __ODTYPESP__
  70. #include <ODTypesP.h>
  71. #endif
  72.  
  73. #ifndef __ODPAGTUN__
  74. #include <ODPagTun.h>
  75. #endif
  76.  
  77. #ifndef __ODDEBUG__
  78. #include <ODDebug.h>
  79. #endif
  80.  
  81. #ifndef __ERRORS__
  82. #include <Errors.h>
  83. #endif
  84.  
  85. #if defined(_PLATFORM_UNIX_)
  86. #include <errno.h>
  87. #endif // defined(_PLATFORM_UNIX_)
  88.  
  89. //==============================================================================
  90. // Constants
  91. //==============================================================================
  92.  
  93. const ODULong    kMaxCopyBufferSize            = 32 * 1024L;
  94. const unsigned long kODMaxFileNameBufferSize = kODMaxFileNameSize + 1;
  95. const unsigned long kODMaxWcsFileNameSize = kODMaxFileNameSize * sizeof(wchar_t);
  96. const unsigned long kODMaxWcsFileNameBufferSize = kODMaxWcsFileNameSize + sizeof(wchar_t);
  97.  
  98. //==============================================================================
  99. // Scalar Types
  100. //==============================================================================
  101.  
  102. //==============================================================================
  103. // Local Classes
  104. //==============================================================================
  105.  
  106. //==============================================================================
  107. // Global Variables
  108. //==============================================================================
  109.  
  110. //==============================================================================
  111. // Function Prototype
  112. //==============================================================================
  113.  
  114. //==============================================================================
  115. // PlatformFile
  116. //==============================================================================
  117.  
  118. const ODOSType kBogusOSType = 0;    // Default type/creator value until it's read
  119.  
  120. //------------------------------------------------------------------------------
  121. // PlatformFile::PlatformFile
  122. //------------------------------------------------------------------------------
  123. PlatformFile::PlatformFile()
  124. {
  125.     fCreator = kBogusOSType;
  126.     fFileType = kBogusOSType;
  127.     fScriptTag = 0;
  128.     
  129.     fFileSpec.name[0] = 0;
  130.     fPermission = kODFileRead | kODFileWrite;
  131.     fDataRefNum = kODNoFileRefNum;
  132. }
  133.  
  134. //------------------------------------------------------------------------------
  135. // PlatformFile::~PlatformFile
  136. //------------------------------------------------------------------------------
  137. PlatformFile::~PlatformFile()
  138. {
  139. }
  140.  
  141. #if defined(_PLATFORM_WIN32_) || defined(_PLATFORM_OS2_) || defined(_PLATFORM_UNIX_)
  142. //------------------------------------------------------------------------------
  143. // PlatformFile::UniquifyAndCreate
  144. //------------------------------------------------------------------------------
  145. // This routine combines the UniquifyName and Create functions into one call
  146. // because of a window resulting from a multitasking environment.  A race
  147. // condition exists between different threads making a call to UniquifyName
  148. // followed by a call to Create.  Different threads could conceivably have
  149. // the same unique name returned, as long as no thread has yet created a file
  150. // with that unique name.  The subsequent Create could fail due to a "file
  151. // already exists" error, which lessens the value of calling UniquifyName in
  152. // the first place.
  153.  
  154. // To make things easier on the caller, UniquifyName and Create have been
  155. // rolled into one function.  This function iteratively calls UniquifyName and
  156. // Create until a file with a unique name is successfully created (or until an
  157. // error other than "file already exists" is encountered).
  158. void PlatformFile::UniquifyAndCreate(ODOSType creator, ODOSType fileType,
  159.                                      ODScriptCode scriptCode, short copyCount,
  160.                                      ODBoolean forceNewName)
  161. {
  162.     int fileCreated = 0;
  163.     short count = copyCount;
  164.     ODFileSpec savedFileSpec = fFileSpec;
  165.  
  166.     do
  167.     {
  168.         // Create unique name (or use current one if not forcing new name)
  169.         UniquifyName(kODNoResourceID, kODNULL, kODNoResourceID, kODNULL, count,
  170.                      kSpecifyNewNameOnly, forceNewName);
  171.         TRY
  172.             Create(creator, fileType, scriptCode);
  173.             fileCreated = 1;
  174.         CATCH_ALL
  175.             // If a "file already exists" error occurred, keep trying.  Otherwise,
  176.             // rethrow the exception
  177. #if defined(_PLATFORM_WIN32_)
  178.             if (_exception.error != ERROR_FILE_EXISTS)
  179. #elif defined(_PLATFORM_OS2_)
  180.             if (_exception.error != ERROR_OPEN_FAILED || !Exists())
  181. #elif defined(_PLATFORM_UNIX_)
  182.             if (_exception.error != EEXIST)
  183. #else // unimplemented platform
  184.             #error Function not implemented on specified platform
  185. #endif // defined(_PLATFORM_UNIX_)
  186.                 RERAISE;
  187.             // On each iteration, the name must be reset to the original name;
  188.             // otherwise numbers (appended from UniquifyName) will keep getting
  189.             // appended on each iteration of this loop, instead of simply
  190.             // incremented.
  191.             fFileSpec = savedFileSpec;
  192.             // UniquifyName may have had to increment more than this, but
  193.             // at least one check will be avoided
  194.             count++;
  195.         ENDTRY;
  196.         forceNewName = kODTrue;
  197.     } while (!fileCreated);
  198. }
  199. #endif // defined(_PLATFORM_WIN32_) || defined(_PLATFORM_OS2_) || defined(_PLATFORM_UNIX_)
  200.  
  201.  
  202. //------------------------------------------------------------------------------
  203. // PlatformFile::Specify
  204. //------------------------------------------------------------------------------
  205. void PlatformFile::Specify(const ODFileSpec* fileSpec)
  206. {
  207.  
  208. #if defined(_PLATFORM_WIN32_)
  209.         // Store the fully qualify file name so as to avoid problem
  210.         // creating by changing working directory in a file dialog.
  211.         char *fullPathName = (char *) malloc(kODMaxFileNameSize+1);
  212.         char *fileNameInPath;
  213.         DWORD pathLength = GetFullPathName((char *)fileSpec->name, 
  214.                                            kODMaxFileNameSize+1, 
  215.                                            fullPathName, 
  216.                                            &fileNameInPath);
  217.         if (pathLength && pathLength <= kODMaxFileNameSize)
  218.            strcpy((char *)fFileSpec.name, fullPathName);
  219.         free(fullPathName);
  220. #else
  221.     // Note:  The following strncpy and null terminator assignment replaces a
  222.     //        direct structure assignment because various callers were
  223.     //        (incorrectly) casting char * to ODFileSpec *, and did not
  224.     //        necessarily have sizeof(fFileSpec.name) bytes addressable.
  225.     strncpy((char *)fFileSpec.name, (char *)fileSpec->name, sizeof(fFileSpec.name));
  226.     fFileSpec.name[sizeof(fFileSpec.name) - 1] = '\0';
  227. #endif
  228.     fCreator = kBogusOSType;
  229.     fFileType = kBogusOSType;
  230. }
  231.  
  232. void PlatformFile::SpecifyFromFile(PlatformFile* file)
  233. {
  234.     const ODFileSpec &fileSpec = file->GetFileSpec();
  235.     this->Specify(&fileSpec);
  236. }
  237.  
  238. //------------------------------------------------------------------------------
  239. // PlatformFile::SetAsciiname
  240. //------------------------------------------------------------------------------
  241. void PlatformFile::SetAsciiName(const char* asciiName)
  242. {
  243.     wchar_t *wcsFileName;
  244.     size_t nameLength, copyLength;
  245.  
  246.     /******************************************************************
  247.     Note: To copy the specified mbs (multi-byte string) string, strncpy
  248.           cannot be used, because the string may contain a mixture of
  249.           double and single byte characters, and the string must not be
  250.           truncated so that it ends with half of a double-byte
  251.           character.
  252.  
  253.           The input string must be converted to a wcs (wide character
  254.           string) string and converted back to an mbs with the
  255.           desired max length.  This way, only complete characters
  256.           are copied, up to the given length.
  257.     ******************************************************************/
  258.     wcsFileName = (wchar_t *)malloc(kODMaxWcsFileNameBufferSize);
  259.  
  260.     mbstowcs(wcsFileName, asciiName, kODMaxWcsFileNameBufferSize);
  261.     copyLength = sizeof(fFileSpec.name) - 1;
  262.     nameLength = wcstombs((char *)fFileSpec.name, wcsFileName,
  263.                          copyLength);
  264.     if (nameLength == copyLength)
  265.         fFileSpec.name[nameLength] = '\0';
  266.  
  267.     free(wcsFileName);
  268. }
  269.  
  270. //------------------------------------------------------------------------------
  271. // PlatformFile::IsLocked
  272. //------------------------------------------------------------------------------
  273. ODBoolean PlatformFile::IsLocked()
  274. {
  275.     return  kODFalse;
  276. }
  277.  
  278. //------------------------------------------------------------------------------
  279. // PlatformFile::Lock
  280. //------------------------------------------------------------------------------
  281. void PlatformFile::Lock()
  282. {
  283. }
  284.  
  285. //------------------------------------------------------------------------------
  286. // PlatformFile::Unlock
  287. //------------------------------------------------------------------------------
  288. void PlatformFile::Unlock()
  289. {
  290. }
  291.  
  292. //------------------------------------------------------------------------------
  293. // PlatformFile::GetName
  294. //------------------------------------------------------------------------------
  295. ODName* PlatformFile::GetName()
  296. {
  297.     return CreateIText(fScriptTag, 0, (char *)fFileSpec.name);
  298. }
  299.  
  300. //------------------------------------------------------------------------------
  301. // PlatformFile::GetAsciiName
  302. //------------------------------------------------------------------------------
  303. void PlatformFile::GetAsciiName(char* asciiName, ODULong maxLength)
  304. {
  305.     wchar_t *wcsFileName;
  306.     size_t nameLength;
  307.  
  308.     /******************************************************************
  309.     Note: To copy the specified mbs (multi-byte string) string, strncpy
  310.           cannot be used, because the string may contain a mixture of
  311.           double and single byte characters, and the string must not be
  312.           truncated so that it ends with half of a double-byte
  313.           character.
  314.  
  315.           The input string must be converted to a wcs (wide character
  316.           string) string and converted back to an mbs with the
  317.           desired max length.  This way, only complete characters
  318.           are copied, up to the given length.
  319.     ******************************************************************/
  320.  
  321.     wcsFileName = (wchar_t *)malloc(kODMaxWcsFileNameBufferSize);
  322.  
  323.     mbstowcs(wcsFileName, (char *)fFileSpec.name, kODMaxWcsFileNameBufferSize);
  324.     nameLength = wcstombs(asciiName, wcsFileName, maxLength);
  325.     // Note:  The original DR4 code does this (i.e., potentially nulls out
  326.     //        byte maxLength + 1).
  327.     if (nameLength == maxLength)
  328.         asciiName[maxLength] = '\0';
  329.  
  330.     free(wcsFileName);
  331. }
  332.  
  333. //------------------------------------------------------------------------------
  334. // PlatformFile::GetPlatformCreator
  335. //------------------------------------------------------------------------------
  336. ODOSType PlatformFile::GetPlatformCreator()
  337. {
  338.     return fCreator;
  339. }    
  340.  
  341. //------------------------------------------------------------------------------
  342. // PlatformFile::GetPlatformType
  343. //------------------------------------------------------------------------------
  344. ODOSType PlatformFile::GetPlatformType()
  345. {
  346.     return fFileType;
  347. }    
  348.  
  349. //------------------------------------------------------------------------------
  350. // PlatformFile::SetPlatformType
  351. //------------------------------------------------------------------------------
  352. void PlatformFile::SetPlatformType(ODOSType fileType)
  353. {
  354.     fFileType = fileType;
  355. }    
  356.  
  357.  
  358.  
  359. //------------------------------------------------------------------------------
  360. // PlatformFile::GetAllocationBlockSize
  361. //------------------------------------------------------------------------------
  362. ODULong PlatformFile::GetAllocationBlockSize()
  363. {
  364.     return 8192; // 8K
  365. }
  366.  
  367. //------------------------------------------------------------------------------
  368. // PlatformFile::CopyFrom
  369. //------------------------------------------------------------------------------
  370. void PlatformFile::CopyFrom( PlatformFile* src )
  371. {
  372.     ODBoolean srcIsOpen = (src->GetFileRefNum() != kODNoFileRefNum);
  373.     if ( !srcIsOpen )
  374.         src->Open();
  375.     this->SetPermission( fsRdWrPerm );        // currently this is the default value
  376.     if (!this->Exists())
  377.         this->Create(src->GetPlatformCreator(), src->GetPlatformType(), 0 /*$$$$$ scriptcode?*/);
  378.  
  379.     this->Open();
  380.             
  381.     src->SetFilePos( fsFromStart, 0 );
  382.     this->SetFilePos( fsFromStart, 0 );
  383.     
  384.     ODSLong bytesLeft = src->GetEndOfFile();
  385.  
  386.     void *hbuffer = kODNULL;
  387.     ODSLong bufferSize = kMaxCopyBufferSize;
  388.     if( bufferSize > bytesLeft )
  389.         bufferSize = bytesLeft;
  390.  
  391.     if (bufferSize > 0)
  392.     {
  393.         hbuffer = new char [bufferSize];
  394.         THROW_IF_NULL(hbuffer);
  395.         void *buffer = hbuffer;
  396.  
  397.         ODSLong count;
  398.  
  399.         while( bytesLeft > 0 )
  400.         {
  401.             count = bytesLeft < bufferSize? bytesLeft: bufferSize ;
  402.             src->Read( buffer, &count );
  403.             this->Write( buffer, &count );
  404.             bytesLeft -= count ;
  405.         }
  406.         delete hbuffer;
  407.     }
  408.     
  409.     if ( !srcIsOpen )
  410.         src->Close();
  411.     this->Close();
  412. }
  413.  
  414.  
  415. //------------------------------------------------------------------------------
  416. // PlatformFile::UniquifyName
  417. // This function generates a unique name based on the filespec of this
  418. // PlatformFile object.  A unique name is generated by appending the
  419. // copyCount parameter value to the fileSpec.  The copyCount value is
  420. // incremented until a unique name is generated.
  421. // 
  422. // This implementation is a simplified version of the original Apple version.
  423. // Mac-specific parameters are ignored, and code for unused options was
  424. // removed.  Only the copyCount and forceNewName parameters are used.
  425. //------------------------------------------------------------------------------
  426.  
  427. const int kODMaxBaseFileNameSize = 8;
  428.  
  429. void PlatformFile::UniquifyName( ODSShort uniquifyingStringID,
  430.             StringHandle uniquifyingString, 
  431.             ODSShort uniquifyingNumberID,
  432.             StringHandle uniquifyingNumberString, 
  433.             short copyCount,
  434.             PFUniquifyAction action, 
  435.             ODBoolean forceNewName)
  436.  
  437.     if ((forceNewName != kODTryCurrentName) || this->Exists())
  438.     {
  439.         PlatformFile possibleOther;
  440.         possibleOther.SpecifyFromFile(this);
  441.  
  442.         ODFileSpec originalFileSpec = this->GetFileSpec();
  443.     
  444.         char suffixString[kODMaxFileNameSize+1];
  445.         sprintf(suffixString, "%d", copyCount);
  446.             
  447.         while (1)
  448.         {
  449.             ODFilePathname newFilePathname;
  450.             strcpy ((char *)newFilePathname, (char *)originalFileSpec.name);
  451.             ConcatenateSuffix (newFilePathname, suffixString);
  452.     
  453.             possibleOther.SetAsciiName((char *)newFilePathname);
  454.             if (!possibleOther.Exists())
  455.             {
  456.                 this->SetAsciiName((char *)newFilePathname);
  457.                 break;
  458.             }
  459.  
  460.             // Increment suffix in quest to find unused name
  461.             copyCount++;
  462.             sprintf (suffixString, "%d", copyCount);
  463.         }
  464.     }
  465. }    // UniquifyName
  466.  
  467. /**************************************************************************
  468.  This routine is used to concatenate a suffix onto the end of a file name.
  469.  Both the suffix and pathname are passed in by the caller.  The pathname
  470.  is assumed to be anything from a fully-qualified pathname to just a
  471.  file name.
  472.  
  473.  This routine must work with mbs (multi-byte string) strings, which
  474.  complicates things quite a bit.  The basic approach is to convert the
  475.  pathname to a wcs (wide character string) string and parse the wcs string
  476.  into a pathname (without file name), file name (without extension), and
  477.  extension.  Once these strings are determined, the path and extension are
  478.  converted back to mbs strings, since no more manipulation on them will be
  479.  necessary, except copying or concatenating them.
  480.  
  481.  The next step is to concatenate the suffix onto the file name.  This is
  482.  done with wcs strings.  After the suffix is concatenated, the resulting
  483.  name must be checked to make sure it does not exceed the maximum
  484.  allowed file name length.  This must be done by converting the name to
  485.  an mbs string and comparing its length to the maximum allowed length.  If
  486.  truncation is necessary, the number of bytes that must be truncated is
  487.  known, but not the characters, since mbs strings can be a mixture of
  488.  single- and double-byte characters.  So that no more characters are
  489.  truncated than necessary, the number of bytes to truncate is divided
  490.  by two (rounding up), and that many characters are truncated from the
  491.  wcs copy of the file name.  Since the name may consist of mostly
  492.  single byte characters, more truncation may be necessary.  Thus
  493.  the name truncation is an interative process.  The loop ends when
  494.  no more truncation is necessary.  An exception is thrown if the name
  495.  becomes completely truncated.
  496.  
  497.  Once the name is truncated, the length entire pathname (with the suffix
  498.  added to the file name) is compared to the maximum allowd pathname
  499.  length.  More truncation from the name may be required.  If necessary,
  500.  truncation is continued in the same manner as above until the pathname
  501.  is short enough or until an exception is thrown because the original
  502.  file name has become completely truncated.
  503. **************************************************************************/
  504. void PlatformFile::ConcatenateSuffix(ODFilePathname filePathname, char *suffixString)
  505. {
  506.     wchar_t *wcsNamePtr, *wcsExtPtr;
  507.     wchar_t *wcsFilePathname, *wcsFileName;
  508.     char *pathNoName, *fileName, *fileExtension;
  509.     long truncateLength, fileNameLengthInChars, suffixLength,
  510.          lengthOfAllButName;
  511.     ODError error = 0;
  512.     wchar_t driveSeparator = L';', extSeparator = L'.';
  513. #if defined(_PLATFORM_OS2_) || defined(_PLATFORM_WIN32_)
  514.     wchar_t pathSeparator = L'\\';
  515. #elif defined(_PLATFORM_UNIX_)
  516.     wchar_t pathSeparator = L'/';
  517. #else // unknown platform
  518.     #error IPlfmFil.cpp:  This platform not supported.
  519. #endif // defined(_PLATFORM_OS2_) || defined(_PLATFORM_WIN32_)
  520.  
  521.     wcsFilePathname = (wchar_t *)malloc(kODMaxWcsFileNameBufferSize);
  522.     wcsFileName = (wchar_t *)malloc(kODMaxWcsFileNameBufferSize);
  523.     pathNoName = (char *)malloc(kODMaxFileNameBufferSize);
  524.     fileName = (char *)malloc(kODMaxFileNameBufferSize);
  525.     fileExtension = (char *)malloc(kODMaxFileNameBufferSize);
  526.  
  527.     suffixLength = strlen(suffixString);
  528.  
  529.     if (wcsFilePathname && wcsFileName && pathNoName && fileName && fileExtension)
  530.     {
  531.         // Convert the mbs pathname to wcs
  532.         mbstowcs(wcsFilePathname, (char *)filePathname, kODMaxWcsFileNameBufferSize);
  533.  
  534.         /****************************************************************
  535.         Find file name in wcs copy of pathname and copy to another
  536.         buffer.  Strip the file name from the pathname.
  537.         ****************************************************************/
  538.         wcsNamePtr = wcsrchr(wcsFilePathname, pathSeparator);
  539.         if (!wcsNamePtr)
  540.             wcsNamePtr = wcsrchr(wcsFilePathname, driveSeparator);
  541.         if (wcsNamePtr)
  542.             wcsNamePtr++;
  543.         else
  544.             wcsNamePtr = wcsFilePathname;
  545.  
  546.         // Make wcs copy of file name
  547.         wcscpy(wcsFileName, wcsNamePtr);
  548.  
  549.         // Strip the file name from the wcs copy of the the pathname
  550.         *wcsNamePtr = L'\0';
  551.     
  552.         /****************************************************************
  553.         Locate file name extension in wcs copy of file name and copy to
  554.         another buffer in mbs format.  Then strip the extension from
  555.         the file name.
  556.         ****************************************************************/
  557.         wcsExtPtr = wcschr(wcsFileName, extSeparator);
  558.         if (wcsExtPtr)
  559.         {
  560.             wcstombs(fileExtension, wcsExtPtr, kODMaxFileNameBufferSize);
  561.             *wcsExtPtr = L'\0';
  562.         }
  563.         else
  564.             fileExtension[0] = '\0';
  565.  
  566.         /****************************************************************
  567.         Copy pathname (without file name) into another buffer in mbs
  568.         format. Deallocate wcs pathname buffer.
  569.         ****************************************************************/
  570.         wcstombs(pathNoName, wcsFilePathname, kODMaxFileNameBufferSize);
  571.         free (wcsFilePathname);
  572.         wcsFilePathname = NULL;
  573.  
  574.         /****************************************************************
  575.         Truncate the file name, if necessary, so that adding the suffix
  576.         will not cause the name to exceed the maximum allowed length.
  577.         ****************************************************************/
  578.         fileNameLengthInChars = wcslen(wcsFileName);
  579.         do
  580.         {
  581.             // Create an mbs copy of the file name
  582.             wcstombs(fileName, wcsFileName, kODMaxFileNameBufferSize);
  583.             // Calculate the number of bytes that must be truncated
  584.             // from the file name
  585.             truncateLength = strlen(fileName) + suffixLength -
  586.                              kODMaxBaseFileNameSize;
  587.             // Assume characters are double-byte, so divide the truncate
  588.             // length by two, rounding up
  589.             truncateLength++;
  590.             truncateLength >>= 1;
  591.             if (truncateLength > 0)
  592.             {
  593.                 if (truncateLength > fileNameLengthInChars)
  594.                 {
  595. #if defined(_PLATFORM_WIN32_) || defined(_PLATFORM_OS2_)
  596.                     error = ERROR_CANNOT_MAKE;
  597. #else // defined(_PLATFORM_UNIX_)
  598.                     error = ENAMETOOLONG;
  599. #endif // defined(_PLATFORM_WIN32_) || defined(_PLATFORM_OS2_)
  600.                     goto errexit;
  601.                 }
  602.  
  603.                 // Truncate temporary copy of file name
  604.                 fileNameLengthInChars -= truncateLength;
  605.                 wcsFileName[fileNameLengthInChars] = L'\0';
  606.             }
  607.             else
  608.                 truncateLength = 0;
  609.         } while (truncateLength > 0);
  610.  
  611.  
  612.         /****************************************************************
  613.         Truncate the file name some more, if necessary, so that adding
  614.         the suffix will not cause the entire path name to exceed the
  615.         maximum allowed length.
  616.         ****************************************************************/
  617.         lengthOfAllButName  = strlen(pathNoName) + suffixLength +
  618.                               strlen(fileExtension);
  619.         do
  620.         {
  621.             // Create an mbs copy of the file name
  622.             wcstombs(fileName, wcsFileName, kODMaxFileNameBufferSize);
  623.             // If total path name is still too long
  624.             truncateLength =  lengthOfAllButName + strlen(fileName) - 
  625.                               kODMaxFileNameSize;
  626.             // Assume characters are double-byte, so divide the truncate
  627.             // length by two, rounding up
  628.             truncateLength++;
  629.             truncateLength >>= 1;
  630.             if (truncateLength > 0)
  631.             {
  632.                 if (truncateLength > fileNameLengthInChars)
  633.                 {
  634. #if defined(_PLATFORM_WIN32_) || defined(_PLATFORM_OS2_)
  635.                     error = ERROR_CANNOT_MAKE;
  636. #else // defined(_PLATFORM_UNIX_)
  637.                     error = ENAMETOOLONG;
  638. #endif // defined(_PLATFORM_WIN32_) || defined(_PLATFORM_OS2_)
  639.                     goto errexit;
  640.                 }
  641.  
  642.                 // Truncate temporary copy of file name some more
  643.                 fileNameLengthInChars -= truncateLength;
  644.                 wcsFileName[fileNameLengthInChars] = L'\0';
  645.             }
  646.         } while (truncateLength > 0);
  647.  
  648.  
  649.         /****************************************************************
  650.         Copy/concatenate path, filename, suffix, and file extension
  651.         to caller's pathname buffer.
  652.         ****************************************************************/
  653.         strcpy((char *)filePathname, pathNoName);
  654.         strcat((char *)filePathname, fileName);
  655.         strcat((char *)filePathname, suffixString);
  656.         strcat((char *)filePathname, fileExtension);
  657.     }
  658.     else
  659.         error = kODErrOutOfMemory;
  660.  
  661. errexit:
  662.     
  663.     if (wcsFilePathname)
  664.         free (wcsFilePathname);
  665.     if (wcsFileName)
  666.         free (wcsFileName);
  667.     if (pathNoName)
  668.         free (pathNoName);
  669.     if (fileName)
  670.         free (fileName);
  671.     if (fileExtension)
  672.         free (fileExtension);
  673.  
  674.     if (error)
  675.         THROW(error);
  676. }
  677.